예제 #1
0
        private static void AddBezierPlate(int count, BezierSegment3D seg1, BezierSegment3D seg2, Model3DGroup group, Material material)
        {
            // Since the bezier curves will have the same number of points, create a bunch of squares linking them (it's up to the caller
            // to make sure the curves don't cross, or you would get a bow tie)
            Point3D[] rim1 = BezierUtil.GetPoints(count, seg1);
            Point3D[] rim2 = BezierUtil.GetPoints(count, seg2);

            Point3D[] allPoints = UtilityCore.Iterate(rim1, rim2).ToArray();

            List <TriangleIndexed> triangles = new List <TriangleIndexed>();

            for (int cntr = 0; cntr < count - 1; cntr++)
            {
                triangles.Add(new TriangleIndexed(count + cntr, count + cntr + 1, cntr, allPoints));    // bottom left
                triangles.Add(new TriangleIndexed(cntr + 1, cntr, count + cntr + 1, allPoints));        // top right
            }

            // Geometry Model
            GeometryModel3D geometry = new GeometryModel3D();

            geometry.Material     = material;
            geometry.BackMaterial = material;
            geometry.Geometry     = UtilityWPF.GetMeshFromTriangles(triangles.ToArray());

            group.Children.Add(geometry);
        }
예제 #2
0
        private static BezierSegment3D[] GetModel_Symetrical_Segments(Point3D[] endPoints, AxeSymetricalProps arg)
        {
            const int TOPLEFT     = 0;
            const int BOTTOMLEFT  = 1;
            const int TOPRIGHT    = 2;
            const int BOTTOMRIGHT = 3;

            // Edge
            Point3D         controlTR = BezierUtil.GetControlPoint_End(endPoints[TOPRIGHT], endPoints[BOTTOMRIGHT], endPoints[TOPLEFT], true, arg.edgeAngle, arg.edgePercent);
            Point3D         controlBR = BezierUtil.GetControlPoint_End(endPoints[BOTTOMRIGHT], endPoints[TOPRIGHT], endPoints[BOTTOMLEFT], true, arg.edgeAngle, arg.edgePercent);
            BezierSegment3D edge      = new BezierSegment3D(TOPRIGHT, BOTTOMRIGHT, new[] { controlTR, controlBR }, endPoints);

            // Bottom
            Point3D controlBL = BezierUtil.GetControlPoint_End(endPoints[BOTTOMLEFT], endPoints[BOTTOMRIGHT], endPoints[TOPRIGHT], arg.leftAway, arg.leftAngle, arg.leftPercent);

            controlBR = BezierUtil.GetControlPoint_End(endPoints[BOTTOMRIGHT], endPoints[BOTTOMLEFT], endPoints[TOPRIGHT], arg.rightAway, arg.rightAngle, arg.rightPercent);
            BezierSegment3D bottom = new BezierSegment3D(BOTTOMLEFT, BOTTOMRIGHT, new[] { controlBL, controlBR }, endPoints);

            // Top
            Point3D controlTL = BezierUtil.GetControlPoint_End(endPoints[TOPLEFT], endPoints[TOPRIGHT], endPoints[BOTTOMRIGHT], arg.leftAway, arg.leftAngle, arg.leftPercent);

            controlTR = BezierUtil.GetControlPoint_End(endPoints[TOPRIGHT], endPoints[TOPLEFT], endPoints[BOTTOMRIGHT], arg.rightAway, arg.rightAngle, arg.rightPercent);
            BezierSegment3D top = new BezierSegment3D(TOPLEFT, TOPRIGHT, new[] { controlTL, controlTR }, endPoints);

            return(new[] { bottom, top, edge });
        }
예제 #3
0
        private void DrawBell3()
        {
            Point[] points = GetBellPoints(txtBell3.Text);
            if (points == null)
            {
                txtBell3.Effect = _errorEffect;
                return;
            }

            txtBell3.Effect = null;

            BezierSegment3D bezier = new BezierSegment3D(0, 1, points.Select(o => o.ToPoint3D()).ToArray(), new[] { new Point3D(0, 0, 0), new Point3D(1, 1, 0) });

            Random rand = StaticRandom.GetRandomForThread();

            IEnumerable <double> samples = Enumerable.Range(0, 100000).
                                           Select(o => BezierUtil.GetPoint(rand.NextDouble(), bezier).Y);

            IEnumerable <Point> idealLine = BezierUtil.GetPoints(100, bezier).
                                            Select(o => o.ToPoint2D());

            DrawGraph(samples, idealLine);

            Rect bounds = GetBounds();

            for (int cntr = 0; cntr < bezier.ControlPoints.Length - 1; cntr++)
            {
                Point from = GetScaledPoint(bezier.ControlPoints[cntr], bounds);
                Point to   = GetScaledPoint(bezier.ControlPoints[cntr + 1], bounds);
                AddLine(from, to, _brushLightBlue);
            }

            if (bezier.ControlPoints.Length > 0)
            {
                Point from = GetScaledPoint(bezier.EndPoint0, bounds);
                Point to   = GetScaledPoint(bezier.ControlPoints[0], bounds);
                AddLine(from, to, _brushLightBlue);

                from = GetScaledPoint(bezier.EndPoint1, bounds);
                to   = GetScaledPoint(bezier.ControlPoints[bezier.ControlPoints.Length - 1], bounds);
                AddLine(from, to, _brushLightBlue);
            }
        }
예제 #4
0
        private static BezierSegment3D[] GetModel_Second_Segments(AxeSecondProps arg)
        {
            Point3D[] points = arg.GetAllPoints();

            // Top
            BezierSegment3D top = new BezierSegment3D(arg.IndexTL, arg.IndexTR, null, points);

            // Edge
            Point3D         controlTR = BezierUtil.GetControlPoint_End(arg.EndTR, arg.EndBR, arg.EndBL_1, true, arg.EdgeAngleT, arg.EdgePercentT);
            Point3D         controlBR = BezierUtil.GetControlPoint_End(arg.EndBR, arg.EndTR, arg.EndTL, true, arg.EdgeAngleB, arg.EdgePercentB);
            BezierSegment3D edge      = new BezierSegment3D(arg.IndexTR, arg.IndexBR, new[] { controlTR, controlBR }, points);

            // Bottom (right portion)
            BezierSegment3D bottomRight = null;

            if (arg.EndBL_2 == null)
            {
                Point3D controlR = BezierUtil.GetControlPoint_End(arg.EndBR, arg.EndBL_1, arg.EndTR, false, arg.B1AngleR, arg.B1PercentR);
                Point3D controlL = BezierUtil.GetControlPoint_End(arg.EndBL_1, arg.EndBR, arg.EndTR, false, arg.B1AngleL, arg.B1PercentL);
                bottomRight = new BezierSegment3D(arg.IndexBR, arg.IndexBL_1, new[] { controlR, controlL }, points);
            }
            else
            {
                bottomRight = new BezierSegment3D(arg.IndexBR, arg.IndexBL_1, null, points);
            }

            // Bottom (left portion)
            BezierSegment3D bottomLeft = null;

            if (arg.EndBL_2 != null)
            {
                Point3D controlR = BezierUtil.GetControlPoint_End(arg.EndBL_1, arg.EndBL_2.Value, arg.EndTR, false, arg.B2AngleR, arg.B2PercentR);
                Point3D controlL = BezierUtil.GetControlPoint_End(arg.EndBL_2.Value, arg.EndBL_1, arg.EndTR, false, arg.B2AngleL, arg.B2PercentL);
                bottomLeft = new BezierSegment3D(arg.IndexBL_1, arg.IndexBL_2, new[] { controlR, controlL }, points);
            }

            return(UtilityCore.Iterate <BezierSegment3D>(top, edge, bottomRight, bottomLeft).ToArray());
        }
예제 #5
0
        private static Model3D GetModel_Symetrical_Axe(BezierSegment3D[][] segmentSets, MaterialGroup materialMiddle, MaterialGroup materialEdge, AxeSymetricalProps arg)
        {
            Model3DGroup retVal = new Model3DGroup();

            int squareCount = 8;

            // 2 is z=0.  0,4 are z=max.  1,3 are intermediate z's

            AddBezierPlates(squareCount, segmentSets[0], segmentSets[1], retVal, materialMiddle);

            AddBezierPlates(squareCount, new[] { segmentSets[1][0], segmentSets[1][1] }, new[] { segmentSets[2][0], segmentSets[2][1] }, retVal, materialMiddle);
            AddBezierPlate(squareCount, segmentSets[1][2], segmentSets[2][2], retVal, materialEdge);

            AddBezierPlates(squareCount, new[] { segmentSets[2][0], segmentSets[2][1] }, new[] { segmentSets[3][0], segmentSets[3][1] }, retVal, materialMiddle);
            AddBezierPlate(squareCount, segmentSets[2][2], segmentSets[3][2], retVal, materialEdge);

            AddBezierPlates(squareCount, segmentSets[3], segmentSets[4], retVal, materialMiddle);

            // End cap plates
            if (arg.isCenterFilled)
            {
                for (int cntr = 0; cntr < 2; cntr++)
                {
                    int index = cntr == 0 ? 0 : 4;

                    AddBezierPlate(squareCount, segmentSets[index][0], segmentSets[index][1], retVal, materialMiddle);        // top - bottom

                    BezierSegment3D extraSeg = new BezierSegment3D(segmentSets[index][2].EndIndex0, segmentSets[index][2].EndIndex1, null, segmentSets[index][2].AllEndPoints);
                    AddBezierPlate(squareCount, extraSeg, segmentSets[index][2], retVal, materialMiddle);     // edge
                }
            }
            else
            {
                AddBezierPlates(squareCount, segmentSets[0], segmentSets[4], retVal, materialMiddle);
            }

            return(retVal);
        }
예제 #6
0
        private void DrawBell2()
        {
            Point[] points = GetBellPoints(txtBell2.Text);
            if (points == null)
            {
                txtBell2.Effect = _errorEffect;
                return;
            }

            txtBell2.Effect = null;

            BezierSegment3D[] bezier = BezierUtil.GetBezierSegments(points.Select(o => o.ToPoint3D()).ToArray(), trkBell2.Value);



            for (int cntr = 0; cntr < bezier.Length; cntr++)
            {
                bezier[cntr] = new BezierSegment3D(bezier[cntr].EndIndex0, bezier[cntr].EndIndex1, new Point3D[0], bezier[cntr].AllEndPoints);
            }



            Random rand = StaticRandom.GetRandomForThread();

            IEnumerable <double> samples = Enumerable.Range(0, 50000).
                                           Select(o => BezierUtil.GetPoint(rand.NextDouble(), bezier).Y);

            IEnumerable <Point> idealLine = BezierUtil.GetPath(100, bezier).
                                            Select(o => o.ToPoint2D());

            DrawGraph(samples, idealLine);



            var samples2 = Enumerable.Range(0, 1000).
                           Select(o =>
            {
                double randPercent = rand.NextDouble();
                Point3D point      = BezierUtil.GetPoint(randPercent, bezier);
                return(Tuple.Create(randPercent, point.X, point.Y, point.Z));
            }).
                           OrderBy(o => o.Item1).
                           ToArray();


            if (!samples2.All(o => o.Item4.IsNearZero()))
            {
                int three = 2;
            }

            if (!samples2.All(o => o.Item2.IsNearValue(o.Item3)))
            {
                int four = 7;
            }


            var samples2a = samples2.
                            Select(o => Tuple.Create(o.Item1, o.Item2, o.Item1 - o.Item2)).
                            ToArray();



            //IEnumerable<Point> testLine = Enumerable.Range(0, 150).
            //    Select(o => BezierUtil.GetPoint(o / 150d, bezier).ToPoint2D());

            //Rect bounds = GetBounds();

            //IEnumerable<Point> testLineFinal = idealLine
            //    .Select(o => new Point(bounds.Left + (o.X * bounds.Width), bounds.Bottom - (o.Y * bounds.Height)));

            //AddLine(testLineFinal, new SolidColorBrush(UtilityWPF.ColorFromHex("FF0000")), 1, "test line");
        }
예제 #7
0
        private void DrawBellFail()
        {
            double midX = trkBellFailPeak.Value;

            BezierSegment3D[] bezier = BezierUtil.GetBezierSegments(new[] { new Point3D(0, 0, 0), new Point3D(midX, 1, 0), new Point3D(1, 0, 0) }, trkBellFailPinch.Value);

            // Add a control point so the curve will be attracted to the x axis at the two end points
            double run;

            if (trkBellFailLeftZero.Value > 0)
            {
                run       = (bezier[0].EndPoint1.X - bezier[0].EndPoint0.X) * trkBellFailLeftZero.Value;
                bezier[0] = new BezierSegment3D(bezier[0].EndIndex0, bezier[0].EndIndex1, new[] { new Point3D(run, 0, 0), bezier[0].ControlPoints[0] }, bezier[0].AllEndPoints);
            }

            if (trkBellFailRightZero.Value > 0)
            {
                run       = (bezier[1].EndPoint1.X - bezier[1].EndPoint0.X) * trkBellFailRightZero.Value;
                bezier[1] = new BezierSegment3D(bezier[1].EndIndex0, bezier[1].EndIndex1, new[] { bezier[1].ControlPoints[0], new Point3D(bezier[1].EndPoint1.X - run, 0, 0), }, bezier[1].AllEndPoints);
            }

            Random rand = StaticRandom.GetRandomForThread();

            //TODO: There is still a bug with calculating percent, or something
            //It might be treating X as a percent.  Maybe need to get the length of the lines, and take the percent of those???? - should be the same though

            IEnumerable <double> samples = Enumerable.Range(0, 50000).
                                           Select(o =>
            {
                double percent = rand.NextDouble();

                int index;
                if (percent < midX)
                {
                    index   = 0;
                    percent = percent / midX;
                }
                else
                {
                    index   = 1;
                    percent = (percent - midX) / (1d - midX);
                }

                double retVal = BezierUtil.GetPoint(percent, bezier[index]).Y;

                if (retVal < 0)
                {
                    retVal = 0;
                }
                else if (retVal > 1)
                {
                    retVal = 1;
                }

                return(retVal);
            });

            IEnumerable <Point> idealLine = BezierUtil.GetPath(100, bezier).
                                            Select(o => o.ToPoint2D());

            DrawGraph(samples, idealLine);
        }
예제 #8
0
        private void BellFailDebug_Click(object sender, RoutedEventArgs e)
        {
            const int COUNT = 25;


            // The problem that this method illustrates is that rand.nextdouble() is thought of as x, but it's really % along arc length of the curve
            // And because there are two curves, it's some hacked up hybrid
            //
            // The original intent was to get the y coord at some fixed x.  But there's no one single calculation that would get that.  Samples would
            // need to be taken to figure out which percent along curve to use to get the desired x, and corresponding y



            try
            {
                double midX = trkBellFailPeak.Value;

                BezierSegment3D[] bezier = BezierUtil.GetBezierSegments(new[] { new Point3D(0, 0, 0), new Point3D(midX, 1, 0), new Point3D(1, 0, 0) }, trkBellFailPinch.Value);

                // Add a control point so the curve will be attracted to the x axis at the two end points
                double run;
                if (trkBellFailLeftZero.Value > 0)
                {
                    run       = (bezier[0].EndPoint1.X - bezier[0].EndPoint0.X) * trkBellFailLeftZero.Value;
                    bezier[0] = new BezierSegment3D(bezier[0].EndIndex0, bezier[0].EndIndex1, new[] { new Point3D(run, 0, 0), bezier[0].ControlPoints[0] }, bezier[0].AllEndPoints);
                }

                if (trkBellFailRightZero.Value > 0)
                {
                    run       = (bezier[1].EndPoint1.X - bezier[1].EndPoint0.X) * trkBellFailRightZero.Value;
                    bezier[1] = new BezierSegment3D(bezier[1].EndIndex0, bezier[1].EndIndex1, new[] { bezier[1].ControlPoints[0], new Point3D(bezier[1].EndPoint1.X - run, 0, 0), }, bezier[1].AllEndPoints);
                }



                //bezier[0] = new BezierSegment3D(bezier[0].EndIndex0, bezier[0].EndIndex1, new Point3D[0], bezier[0].AllEndPoints);
                //bezier[1] = new BezierSegment3D(bezier[1].EndIndex0, bezier[1].EndIndex1, new Point3D[0], bezier[1].AllEndPoints);



                var samples = Enumerable.Range(0, COUNT).
                              Select(o =>
                {
                    double percentOrig = o.ToDouble() / COUNT.ToDouble();

                    int index;
                    double percent;
                    if (percentOrig < midX)
                    {
                        index   = 0;
                        percent = percentOrig / midX;
                    }
                    else
                    {
                        index   = 1;
                        percent = (percentOrig - midX) / (1d - midX);
                    }

                    Point3D point = BezierUtil.GetPoint(percent, bezier[index]);

                    //if (retVal < 0) retVal = 0;
                    //else if (retVal > 1) retVal = 1;

                    return(new
                    {
                        PercentOrig = percentOrig,
                        PercentSub = percent,
                        Index = index,
                        Point = point,
                    });
                }).
                              ToArray();



                Clear();

                Rect bounds = GetBounds();

                // Grid
                AddLine(bounds.BottomLeft, bounds.TopRight, _brushVeryLight);                         // diagonal

                AddLine(bounds.TopLeft, bounds.TopRight, _brushVeryLight);                            // 1
                double y = bounds.Bottom - (bounds.Height * .75);
                AddLine(new Point(bounds.Left, y), new Point(bounds.Right, y), _brushVeryLight);      // .75
                y = bounds.Bottom - (bounds.Height * .5);
                AddLine(new Point(bounds.Left, y), new Point(bounds.Right, y), _brushVeryLight);      // .5
                y = bounds.Bottom - (bounds.Height * .25);
                AddLine(new Point(bounds.Left, y), new Point(bounds.Right, y), _brushVeryLight);      // .25

                AddLine(new[] { bounds.TopLeft, bounds.BottomLeft, bounds.BottomRight }, _brushDark); // axiis

                // Samples
                foreach (var sample in samples)
                {
                    AddLine(new Point(bounds.Left + (sample.PercentOrig * bounds.Width), bounds.Bottom), new Point(bounds.Left + (sample.Point.X * bounds.Width), bounds.Bottom - (sample.Point.Y * bounds.Height)), Brushes.Black);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
예제 #9
0
        private static BezierSegment3D[][] GetModel_Second_Curves(AxeSecondProps arg)
        {
            BezierSegment3D[][] retVal = new BezierSegment3D[5][];

            AxeSecondProps[] argLevels = new AxeSecondProps[5];

            argLevels[2] = arg;     // Edge
            #region Middle

            argLevels[1] = UtilityCore.Clone_Shallow(arg);

            // Right
            argLevels[1].EndTR = new Point3D(argLevels[1].EndTR.X * .8, argLevels[1].EndTR.Y * .9, .15);

            Vector3D   offsetTR = new Point3D(argLevels[1].EndTR.X, argLevels[1].EndTR.Y, 0) - arg.EndTR;
            Quaternion angleTR  = Math3D.GetRotation((arg.EndTL - arg.EndTR), offsetTR);

            Vector3D rotated = (arg.EndBL_1 - arg.EndBR).ToUnit() * offsetTR.Length;
            rotated = rotated.GetRotatedVector(angleTR.Axis, angleTR.Angle * -1.3);

            argLevels[1].EndBR = new Point3D(argLevels[1].EndBR.X + rotated.X, argLevels[1].EndBR.Y + rotated.Y, .15);      // can't just use percents of coordinates.  Instead use the same offset angle,distance that top left had

            // Left
            argLevels[1].EndTL = new Point3D(argLevels[1].EndTL.X, argLevels[1].EndTL.Y * .95, .3);

            if (argLevels[1].EndBL_2 == null)
            {
                argLevels[1].EndBL_1 = new Point3D(argLevels[1].EndBL_1.X, argLevels[1].EndBL_1.Y * .9, .3);
            }
            else
            {
                Vector3D offsetBL1 = arg.EndBR - arg.EndBL_1;
                double   lengthBL1 = (new Point3D(argLevels[1].EndBR.X, argLevels[1].EndBR.Y, 0) - arg.EndBR).Length;
                offsetBL1 = offsetBL1.ToUnit() * (offsetBL1.Length - lengthBL1);

                argLevels[1].EndBL_1 = argLevels[1].EndBR - offsetBL1;
                argLevels[1].EndBL_1 = new Point3D(argLevels[1].EndBL_1.X, argLevels[1].EndBL_1.Y, .18);

                argLevels[1].EndBL_2 = new Point3D(argLevels[1].EndBL_2.Value.X, argLevels[1].EndBL_2.Value.Y * .9, .3);
            }

            argLevels[3] = argLevels[1].CloneNegateZ();

            #endregion
            #region Far

            argLevels[0] = UtilityCore.Clone_Shallow(arg);

            argLevels[0].EndTL = new Point3D(argLevels[0].EndTL.X, argLevels[0].EndTL.Y * .7, .4);

            argLevels[0].EndTR = new Point3D(argLevels[0].EndTR.X * .5, argLevels[0].EndTR.Y * .6, .25);

            if (argLevels[0].EndBL_2 == null)
            {
                argLevels[0].EndBR   = new Point3D(argLevels[0].EndBR.X * .5, argLevels[0].EndBR.Y * .6, .25);
                argLevels[0].EndBL_1 = new Point3D(argLevels[0].EndBL_1.X, argLevels[0].EndBL_1.Y * .6, .4);
            }
            else
            {
                // Bottom Right
                Vector3D offset     = (argLevels[1].EndBR - argLevels[1].EndBL_1) * .5;
                Point3D  startPoint = argLevels[1].EndBL_1 + offset;    // midway along bottom edge

                offset = argLevels[1].EndTR - startPoint;

                argLevels[0].EndBR = startPoint + (offset * .15);                                  // from midway point toward upper right point
                argLevels[0].EndBR = new Point3D(argLevels[0].EndBR.X, argLevels[0].EndBR.Y, .25); // fix z

                // Left of bottom right (where the circle cutout ends)
                offset = argLevels[1].EndBR - argLevels[1].EndBL_1;
                argLevels[0].EndBL_1 = Math3D.GetClosestPoint_Line_Point(argLevels[0].EndBR, offset, argLevels[0].EndBL_1);

                offset *= .05;
                Point3D  minBL1     = argLevels[0].EndBR - offset;
                Vector3D testOffset = argLevels[0].EndBL_1 - argLevels[0].EndBR;
                if (Vector3D.DotProduct(testOffset, offset) < 0 || testOffset.LengthSquared < offset.LengthSquared)
                {
                    argLevels[0].EndBL_1 = minBL1;
                }

                // Bottom Left
                argLevels[0].EndBL_2 = new Point3D(argLevels[0].EndBL_2.Value.X, argLevels[0].EndBL_2.Value.Y * .6, .4);

                // Reduce the curve a bit
                argLevels[0].B2AngleL   = argLevels[0].B2AngleL * .9;
                argLevels[0].B2PercentL = argLevels[0].B2PercentL * .95;

                argLevels[0].B2AngleR   = argLevels[0].B2AngleR * .85;
                argLevels[0].B2PercentR = argLevels[0].B2PercentR * .95;
            }

            argLevels[4] = argLevels[0].CloneNegateZ();

            #endregion

            for (int cntr = 0; cntr < 5; cntr++)
            {
                BezierSegment3D[] segments = GetModel_Second_Segments(argLevels[cntr]);
                retVal[cntr] = segments;
            }

            return(retVal);
        }
예제 #10
0
        private static BezierSegment3D[][] GetModel_Symetrical_Curves(AxeSymetricalProps arg)
        {
            BezierSegment3D[][] retVal = new BezierSegment3D[5][];

            //TODO: Come up with a transform based on arg's extremes and dna.Scale
            Transform3D transform = Transform3D.Identity;

            for (int cntr = 0; cntr < 5; cntr++)
            {
                #region scale, z

                double zL, zR, scaleX, scaleY;

                switch (cntr)
                {
                case 0:
                case 4:
                    zL     = arg.Z2L;
                    zR     = arg.Z2R;
                    scaleX = arg.Scale2X;
                    scaleY = arg.Scale2Y;
                    break;

                case 1:
                case 3:
                    zL     = zR = arg.Z1;
                    scaleX = arg.Scale1X;
                    scaleY = arg.Scale1Y;
                    break;

                case 2:
                    zL     = zR = 0;
                    scaleX = scaleY = 1;
                    break;

                default:
                    throw new ApplicationException("Unknown cntr: " + cntr.ToString());
                }

                if (cntr < 2)
                {
                    zL *= -1d;
                    zR *= -1d;
                }

                #endregion

                Point3D[] endPoints = new[]
                {
                    new Point3D(arg.leftX, -arg.leftY * scaleY, zL),            // top left
                    new Point3D(arg.leftX, arg.leftY * scaleY, zL),             // bottom left
                    new Point3D(arg.rightX * scaleX, -arg.rightY * scaleY, zR), // top right
                    new Point3D(arg.rightX * scaleX, arg.rightY * scaleY, zR),  // bottom right
                }.Select(o => transform.Transform(o)).ToArray();

                BezierSegment3D[] segments = GetModel_Symetrical_Segments(endPoints, arg);
                retVal[cntr] = segments;
            }

            return(retVal);
        }