Exemplo n.º 1
0
            public AxeSecondProps CloneNegateZ()
            {
                AxeSecondProps retVal = UtilityCore.Clone_Shallow(this);

                retVal.EndTL   = new Point3D(retVal.EndTL.X, retVal.EndTL.Y, retVal.EndTL.Z * -1);
                retVal.EndTR   = new Point3D(retVal.EndTR.X, retVal.EndTR.Y, retVal.EndTR.Z * -1);
                retVal.EndBR   = new Point3D(retVal.EndBR.X, retVal.EndBR.Y, retVal.EndBR.Z * -1);
                retVal.EndBL_1 = new Point3D(retVal.EndBL_1.X, retVal.EndBL_1.Y, retVal.EndBL_1.Z * -1);

                if (retVal.EndBL_2 != null)
                {
                    retVal.EndBL_2 = new Point3D(retVal.EndBL_2.Value.X, retVal.EndBL_2.Value.Y, retVal.EndBL_2.Value.Z * -1);
                }

                return(retVal);
            }
Exemplo n.º 2
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());
        }
Exemplo n.º 3
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);
        }
Exemplo n.º 4
0
        private static AxeSecondProps GetModel_Second_Props(SortedList <string, double> from, SortedList <string, double> to, bool hasBeard)
        {
            AxeSecondProps retVal = new AxeSecondProps();

            Random rand = StaticRandom.GetRandomForThread();

            #region Points

            // Edge
            retVal.EndTR = new Point3D(2, -1.1, 0) + WeaponDNA.GetKeyValue_Vector("EndTR", from, to, Math3D.GetRandomVector_Circular(.25));
            retVal.EndBR = new Point3D(1.3, 1.8, 0) + WeaponDNA.GetKeyValue_Vector("EndBR", from, to, Math3D.GetRandomVector_Circular(.25));

            // Left
            retVal.EndTL   = new Point3D(-1.5, -1, 0);
            retVal.EndBL_1 = new Point3D(-1.5, .5, 0);

            if (hasBeard)
            {
                // Put an extra point along the bottom (left of this is that circle cutout)
                retVal.EndBL_2 = retVal.EndBL_1;        // 2 is now the last point
                retVal.EndBL_1 = new Point3D(.3, 1.2, 0) + WeaponDNA.GetKeyValue_Vector("EndBL_1", from, to, Math3D.GetRandomVector_Circular(.25));
            }
            else
            {
                retVal.EndBL_2 = null;
            }

            if (retVal.EndBL_2 != null && WeaponDNA.GetKeyValue_Bool("shouldExtendBeard", from, to, rand.NextBool()))
            {
                // Extend the beard
                retVal.EndBR   += new Vector3D(0, WeaponDNA.GetKeyValue("extendBR", from, to, rand.NextDouble(.25, 2.2)), 0);
                retVal.EndBL_1 += new Vector3D(0, WeaponDNA.GetKeyValue("extendBL", from, to, rand.NextDouble(.25, 1.8)), 0);
            }

            double maxY = retVal.EndBR.Y - .25;

            if (retVal.EndBL_2 != null && retVal.EndBL_1.Y > maxY)
            {
                retVal.EndBL_1 = new Point3D(retVal.EndBL_1.X, maxY, retVal.EndBL_1.Z);       // can't let the middle point get lower, because the 3D would look wrong)
            }

            #endregion

            #region Curve Controls

            retVal.EdgeAngleT   = WeaponDNA.GetKeyValue("EdgeAngleT", from, to, rand.NextPercent(15, .25));
            retVal.EdgePercentT = WeaponDNA.GetKeyValue("EdgePercentT", from, to, rand.NextPercent(.3, .25));

            retVal.EdgeAngleB   = WeaponDNA.GetKeyValue("EdgeAngleB", from, to, rand.NextPercent(15, .25));
            retVal.EdgePercentB = WeaponDNA.GetKeyValue("EdgePercentB", from, to, rand.NextPercent(.3, .25));

            // Only used if EndBL_2 is null
            retVal.B1AngleR   = WeaponDNA.GetKeyValue("B1AngleR", from, to, rand.NextPercent(10, .25));
            retVal.B1PercentR = WeaponDNA.GetKeyValue("B1PercentR", from, to, rand.NextPercent(.5, .25));

            retVal.B1AngleL   = WeaponDNA.GetKeyValue("B1AngleL", from, to, rand.NextPercent(10, .25));
            retVal.B1PercentL = WeaponDNA.GetKeyValue("B1PercentL", from, to, rand.NextPercent(.33, .25));

            // Only used if EndBL_2 is populated
            retVal.B2AngleR   = WeaponDNA.GetKeyValue("B2AngleR", from, to, rand.NextDouble(40, 80));
            retVal.B2PercentR = WeaponDNA.GetKeyValue("B2PercentR", from, to, rand.NextPercent(.6, .25));

            retVal.B2AngleL   = WeaponDNA.GetKeyValue("B2AngleL", from, to, rand.NextDouble(40, 80));
            retVal.B2PercentL = WeaponDNA.GetKeyValue("B2PercentL", from, to, rand.NextPercent(.4, .25));

            #endregion

            return(retVal);
        }
Exemplo n.º 5
0
        // Second design
        private static Model3DGroup GetModel_Second(WeaponAxeDNA dna, WeaponAxeDNA finalDNA, WeaponMaterialCache materials, bool hasBeard)
        {
            Model3DGroup retVal = new Model3DGroup();
            var          from   = dna.KeyValues;
            var          to     = finalDNA.KeyValues;

            // Define the curves
            AxeSecondProps arg = GetModel_Second_Props(from, to, hasBeard);

            BezierSegment3D[][] segmentSets = GetModel_Second_Curves(arg);

            //TODO: Use WeaponMaterialCache
            MaterialGroup materialMiddle = new MaterialGroup();

            materialMiddle.Children.Add(new DiffuseMaterial(new SolidColorBrush(Colors.DimGray)));
            Color derivedColor = UtilityWPF.AlphaBlend(Colors.DimGray, Colors.White, .8d);

            materialMiddle.Children.Add(new SpecularMaterial(new SolidColorBrush(Color.FromArgb(128, derivedColor.R, derivedColor.G, derivedColor.B)), 2d));

            MaterialGroup materialEdge = new MaterialGroup();

            materialEdge.Children.Add(new DiffuseMaterial(new SolidColorBrush(Colors.GhostWhite)));
            materialEdge.Children.Add(new SpecularMaterial(new SolidColorBrush(UtilityWPF.AlphaBlend(Colors.GhostWhite, Colors.White, .5d)), 5d));

            #region Axe Blade (right)

            Model3D model = GetModel_Second_Axe(segmentSets, materialMiddle, materialEdge);

            double scale = dna.SizeSingle / (((arg.EndBL_2 ?? arg.EndBL_1).Y - arg.EndTL.Y) * 2);

            Transform3DGroup transform = new Transform3DGroup();
            transform.Children.Add(new TranslateTransform3D(-arg.EndTL.X, 0, 0));
            transform.Children.Add(new ScaleTransform3D(scale, scale, scale));

            model.Transform = transform;
            retVal.Children.Add(model);

            #endregion

            if (dna.Sides == WeaponAxeSides.Double)
            {
                #region Axe Blade (left)

                model = GetModel_Second_Axe(segmentSets, materialMiddle, materialEdge);

                transform = new Transform3DGroup();
                transform.Children.Add(new TranslateTransform3D(-arg.EndTL.X, 0, 0));
                transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 180)));
                transform.Children.Add(new ScaleTransform3D(scale, scale, scale));

                model.Transform = transform;

                retVal.Children.Add(model);

                #endregion
            }

            Point3D topLeft    = segmentSets[2][0].EndPoint0;
            Point3D bottomLeft = segmentSets[2][segmentSets[2].Length - 1].EndPoint1;
            double  z          = Math.Abs(segmentSets[0][0].EndPoint0.Z);

            if (dna.Sides == WeaponAxeSides.Single_BackSpike)
            {
                // Spike
                retVal.Children.Add(GetAxeSpike(z * .9, Math.Abs(topLeft.Y - bottomLeft.Y) * WeaponDNA.GetKeyValue("spikeLength", from, to, StaticRandom.NextDouble(.9, 1.4)), scale, -.2, materialMiddle, materialEdge));
            }

            if (dna.Sides != WeaponAxeSides.Double)     // double centerfilled is the only case that shouldn't have a collar
            {
                // Collar
                retVal.Children.Add(GetAxeCylinder(z * 1.33, Math.Abs(topLeft.Y - bottomLeft.Y) * 1.15, scale, -.2, materialMiddle));
            }

            return(retVal);
        }
Exemplo n.º 6
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();
        }
Exemplo n.º 7
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;
        }
Exemplo n.º 8
0
        private static AxeSecondProps GetModel_Second_Props(SortedList<string, double> from, SortedList<string, double> to, bool hasBeard)
        {
            AxeSecondProps retVal = new AxeSecondProps();

            Random rand = StaticRandom.GetRandomForThread();

            #region Points

            // Edge
            retVal.EndTR = new Point3D(2, -1.1, 0) + WeaponDNA.GetKeyValue_Vector("EndTR", from, to, Math3D.GetRandomVector_Circular(.25));
            retVal.EndBR = new Point3D(1.3, 1.8, 0) + WeaponDNA.GetKeyValue_Vector("EndBR", from, to, Math3D.GetRandomVector_Circular(.25));

            // Left
            retVal.EndTL = new Point3D(-1.5, -1, 0);
            retVal.EndBL_1 = new Point3D(-1.5, .5, 0);

            if (hasBeard)
            {
                // Put an extra point along the bottom (left of this is that circle cutout)
                retVal.EndBL_2 = retVal.EndBL_1;        // 2 is now the last point
                retVal.EndBL_1 = new Point3D(.3, 1.2, 0) + WeaponDNA.GetKeyValue_Vector("EndBL_1", from, to, Math3D.GetRandomVector_Circular(.25));
            }
            else
            {
                retVal.EndBL_2 = null;
            }

            if (retVal.EndBL_2 != null && WeaponDNA.GetKeyValue_Bool("shouldExtendBeard", from, to, rand.NextBool()))
            {
                // Extend the beard
                retVal.EndBR += new Vector3D(0, WeaponDNA.GetKeyValue("extendBR", from, to, rand.NextDouble(.25, 2.2)), 0);
                retVal.EndBL_1 += new Vector3D(0, WeaponDNA.GetKeyValue("extendBL", from, to, rand.NextDouble(.25, 1.8)), 0);
            }

            double maxY = retVal.EndBR.Y - .25;

            if (retVal.EndBL_2 != null && retVal.EndBL_1.Y > maxY)
            {
                retVal.EndBL_1 = new Point3D(retVal.EndBL_1.X, maxY, retVal.EndBL_1.Z);       // can't let the middle point get lower, because the 3D would look wrong)
            }

            #endregion

            #region Curve Controls

            retVal.EdgeAngleT = WeaponDNA.GetKeyValue("EdgeAngleT", from, to, rand.NextPercent(15, .25));
            retVal.EdgePercentT = WeaponDNA.GetKeyValue("EdgePercentT", from, to, rand.NextPercent(.3, .25));

            retVal.EdgeAngleB = WeaponDNA.GetKeyValue("EdgeAngleB", from, to, rand.NextPercent(15, .25));
            retVal.EdgePercentB = WeaponDNA.GetKeyValue("EdgePercentB", from, to, rand.NextPercent(.3, .25));

            // Only used if EndBL_2 is null
            retVal.B1AngleR = WeaponDNA.GetKeyValue("B1AngleR", from, to, rand.NextPercent(10, .25));
            retVal.B1PercentR = WeaponDNA.GetKeyValue("B1PercentR", from, to, rand.NextPercent(.5, .25));

            retVal.B1AngleL = WeaponDNA.GetKeyValue("B1AngleL", from, to, rand.NextPercent(10, .25));
            retVal.B1PercentL = WeaponDNA.GetKeyValue("B1PercentL", from, to, rand.NextPercent(.33, .25));

            // Only used if EndBL_2 is populated
            retVal.B2AngleR = WeaponDNA.GetKeyValue("B2AngleR", from, to, rand.NextDouble(40, 80));
            retVal.B2PercentR = WeaponDNA.GetKeyValue("B2PercentR", from, to, rand.NextPercent(.6, .25));

            retVal.B2AngleL = WeaponDNA.GetKeyValue("B2AngleL", from, to, rand.NextDouble(40, 80));
            retVal.B2PercentL = WeaponDNA.GetKeyValue("B2PercentL", from, to, rand.NextPercent(.4, .25));

            #endregion

            return retVal;
        }