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; }
private static BezierSegment3D[] TestAxeSimple2_Segments(Curves_AxeSimple2 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(); }
/// <summary> /// Get a single point along the curve /// </summary> public static Point3D GetPoint(double percent, BezierSegment3D segment) { return GetPoint(percent, UtilityCore.Iterate<Point3D>(segment.EndPoint0, segment.ControlPoints, segment.EndPoint1).ToArray()); }
//TODO: Put this in Math3D public static Point3D BicubicInterpolation(BezierSegment3D top, BezierSegment3D bottom, BezierSegment3D left, BezierSegment3D right, double percentX, double percentY) { Point3D valueTop = BezierUtil.GetPoint(percentX, top); Point3D valueBottom = BezierUtil.GetPoint(percentX, bottom); Point3D valueLeft = BezierUtil.GetPoint(percentY, left); Point3D valueRight = BezierUtil.GetPoint(percentY, right); var points = new[] { Tuple.Create(valueTop, 1 - percentY), Tuple.Create(valueBottom, percentY), Tuple.Create(valueLeft, 1 - percentX), Tuple.Create(valueRight, percentX), }; return Math3D.GetCenter(points); }
/// <summary> /// This returns points across sets of segment definition. Each set is run through the other path overload. So the endpoints /// of each set are guaranteed to be included in the return points (deduped) /// </summary> /// <param name="countPerPath">This is how many points per set (the total number of points will be countPerPath * segmentSets.Length)</param> public static Point3D[] GetPath(int countPerPath, BezierSegment3D[][] segmentSets) { //TODO: Make an overload that takes in total count instead of per path // Get the points for each set of beziers List<Point3D[]> perPathPoints = new List<Point3D[]>(); foreach (BezierSegment3D[] segments in segmentSets) { if (segments.Length == 1) { perPathPoints.Add(GetPoints(countPerPath, segments[0])); } else { perPathPoints.Add(GetPath(countPerPath, segments)); } } // Dedupe them List<Point3D> retVal = new List<Point3D>(); retVal.AddRange(perPathPoints[0]); for (int cntr = 1; cntr < perPathPoints.Count; cntr++) { if (Math3D.IsNearValue(retVal[retVal.Count - 1], perPathPoints[cntr][0])) { // First point dupes with the last retVal.AddRange(perPathPoints[cntr].Skip(1)); } else { retVal.AddRange(perPathPoints[cntr]); } } if (Math3D.IsNearValue(retVal[0], retVal[retVal.Count - 1])) { retVal.RemoveAt(retVal.Count - 1); } return retVal.ToArray(); }
private static BezierSegment3D[] GetBezierSegments_Open(Point3D[] ends, double along = .25) { // Precalculate the control points Tuple<Point3D, Point3D>[] controls = new Tuple<Point3D, Point3D>[ends.Length - 2]; for (int cntr = 1; cntr < ends.Length - 1; cntr++) { Tuple<double, double> adjustedAlong = GetAdjustedRatios(ends[cntr - 1], ends[cntr], ends[cntr + 1], along); controls[cntr - 1] = GetControlPoints_Middle(ends[cntr - 1], ends[cntr], ends[cntr + 1], adjustedAlong.Item1, adjustedAlong.Item2); } // Build the return segments BezierSegment3D[] retVal = new BezierSegment3D[ends.Length - 1]; for (int cntr = 0; cntr < ends.Length - 1; cntr++) { Point3D? ctrl0 = cntr == 0 ? (Point3D?)null : controls[cntr - 1].Item2; Point3D? ctrl1 = cntr == ends.Length - 2 ? (Point3D?)null : controls[cntr].Item1; retVal[cntr] = new BezierSegment3D(cntr, cntr + 1, UtilityCore.Iterate<Point3D>(ctrl0, ctrl1).ToArray(), ends); } return retVal; }
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); }
private void DrawBezierPlate(int count, BezierSegment3D seg1, BezierSegment3D seg2, Color color, bool isShiny, bool ensureNormalsPointTheSame = false) { 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 } #region Ensure all normals point the same way //Doesn't work //if (ensureNormalsPointTheSame) //{ // Vector3D firstNormal = triangles[0].Normal; // bool[] sameNormals = triangles.Select(o => Vector3D.DotProduct(firstNormal, o.Normal) > 0).ToArray(); // int sameCount = sameNormals.Where(o => o).Count(); // if (sameCount != triangles.Count) // { // // Some up, some down. Majority rules // bool fixDifferents = sameCount > triangles.Count / 2; // for(int cntr = 0; cntr < triangles.Count; cntr++) // { // if(sameNormals[cntr] != fixDifferents) // { // triangles[cntr] = new TriangleIndexed(triangles[cntr].Index1, triangles[cntr].Index0, triangles[cntr].Index2, triangles[cntr].AllPoints); // } // } // } //} #endregion // Material MaterialGroup materials = new MaterialGroup(); materials.Children.Add(new DiffuseMaterial(new SolidColorBrush(color))); if (isShiny) { materials.Children.Add(new SpecularMaterial(new SolidColorBrush(UtilityWPF.AlphaBlend(color, Colors.White, .5d)), 5d)); } else { Color derivedColor = UtilityWPF.AlphaBlend(color, Colors.White, .8d); materials.Children.Add(new SpecularMaterial(new SolidColorBrush(Color.FromArgb(128, derivedColor.R, derivedColor.G, derivedColor.B)), 2d)); } // Geometry Model GeometryModel3D geometry = new GeometryModel3D(); geometry.Material = materials; geometry.BackMaterial = materials; geometry.Geometry = UtilityWPF.GetMeshFromTriangles(triangles.ToArray()); // Model Visual ModelVisual3D model = new ModelVisual3D(); model.Content = geometry; // Temporarily add to the viewport _viewport.Children.Add(model); _visuals.Add(model); }
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); }
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); } }
// WPF models private static void AddBezierPlates(int count, BezierSegment3D[] seg1, BezierSegment3D[] seg2, Model3DGroup group, Material material) { for (int cntr = 0; cntr < seg1.Length; cntr++) { AddBezierPlate(count, seg1[cntr], seg2[cntr], group, material); } }
private static Model3D GetModel_Second_Axe(BezierSegment3D[][] segmentSets, MaterialGroup materialMiddle, MaterialGroup materialEdge) { Model3DGroup retVal = new Model3DGroup(); int numSegments = segmentSets[0].Length; int squareCount = 8; // 2 is z=0. 0,4 are z=max. 1,3 are intermediate z's // Z to Z AddBezierPlates(squareCount, segmentSets[0], segmentSets[1], retVal, materialMiddle); if (numSegments == 3) { AddBezierPlates(squareCount, new[] { segmentSets[1][0], segmentSets[1][2] }, new[] { segmentSets[2][0], segmentSets[2][2] }, retVal, materialMiddle); AddBezierPlate(squareCount, segmentSets[1][1], segmentSets[2][1], retVal, materialEdge); AddBezierPlates(squareCount, new[] { segmentSets[2][0], segmentSets[2][2] }, new[] { segmentSets[3][0], segmentSets[3][2] }, retVal, materialMiddle); AddBezierPlate(squareCount, segmentSets[2][1], segmentSets[3][1], retVal, materialEdge); } else { AddBezierPlates(squareCount, new[] { segmentSets[1][0], segmentSets[1][3] }, new[] { segmentSets[2][0], segmentSets[2][3] }, retVal, materialMiddle); AddBezierPlates(squareCount, new[] { segmentSets[1][1], segmentSets[1][2] }, new[] { segmentSets[2][1], segmentSets[2][2] }, retVal, materialEdge); AddBezierPlates(squareCount, new[] { segmentSets[2][0], segmentSets[2][3] }, new[] { segmentSets[3][0], segmentSets[3][3] }, retVal, materialMiddle); AddBezierPlates(squareCount, new[] { segmentSets[2][1], segmentSets[2][2] }, new[] { segmentSets[3][1], segmentSets[3][2] }, retVal, materialEdge); } AddBezierPlates(squareCount, segmentSets[3], segmentSets[4], retVal, materialMiddle); // End cap plates for (int cntr = 0; cntr < 2; cntr++) { int index = cntr == 0 ? 0 : 4; // Turn the end cap into a polygon, then triangulate it Point3D[] endCapPoly = BezierUtil.GetPath(squareCount, segmentSets[index].Select(o => new[] { o }).ToArray()); // Call the jagged array overload so that the individual bezier end points don't get smoothed out TriangleIndexed[] endCapTriangles = Math2D.GetTrianglesFromConcavePoly3D(endCapPoly); if (cntr == 0) { endCapTriangles = endCapTriangles.Select(o => new TriangleIndexed(o.Index0, o.Index2, o.Index1, o.AllPoints)).ToArray(); // need to do this so the normals point in the proper direction } AddPolyPlate(endCapTriangles, retVal, materialMiddle); } return retVal; }
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; }
private void DrawBezierLines(BezierSegment3D[] beziers, bool showLines, bool showControls, bool showEnds) { // Main Line if (showLines) { foreach (BezierSegment3D bezier in beziers) { AddLines(BezierUtil.GetPoints(100, bezier), _mainLineC, 2); } } // Control Lines if (showControls) { foreach (BezierSegment3D bezier in beziers) { if (bezier.ControlPoints == null) { continue; } AddLines(bezier.Combined, _controlLineC); for (int cntr = 0; cntr < bezier.ControlPoints.Length; cntr++) { AddDot(bezier.ControlPoints[cntr], _controlPointC); } } } // End Points if (showEnds) { foreach (Point3D points in beziers[0].AllEndPoints) { AddDot(points, _endPointC); } } }
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"); }
private void DrawBezierPlates(int count, BezierSegment3D[] seg1, BezierSegment3D[] seg2, Color color, bool isShiny, bool ensureNormalsPointTheSame = false) { for (int cntr = 0; cntr < seg1.Length; cntr++) { DrawBezierPlate(count, seg1[cntr], seg2[cntr], color, isShiny, ensureNormalsPointTheSame); } }
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); } }
/// <summary> /// This returns points across several segment definitions. count is the total number of sample points to return /// </summary> /// <remarks> /// This assumes that the segments are linked together into a single path /// /// If the first and last point of segments are the same, then this will only return that shared point once (but the point count /// will still be how many were requested /// </remarks> public static Point3D[] GetPath(int count, BezierSegment3D[] segments) { // Get the total length of the curve double totalLength = 0; double[] cumulativeLengths = new double[segments.Length + 1]; for (int cntr = 1; cntr < segments.Length + 1; cntr++) { totalLength += segments[cntr - 1].Length_quick; cumulativeLengths[cntr] = cumulativeLengths[cntr - 1] + segments[cntr - 1].Length_quick; } double countD = count - 1; Point3D[] retVal = new Point3D[count]; retVal[0] = segments[0].EndPoint0; retVal[count - 1] = segments[segments.Length - 1].EndPoint1; //NOTE: If the segment is a closed curve, this is the same point as retVal[0]. May want a boolean that tells whether the last point should be replicated int index = 0; for (int cntr = 1; cntr < count - 1; cntr++) { // Get the location along the entire path double totalPercent = cntr / countD; double portionTotalLength = totalLength * totalPercent; // Advance to the appropriate segment while (cumulativeLengths[index + 1] < portionTotalLength) { index++; } // Get the percent of the current segment double localLength = portionTotalLength - cumulativeLengths[index]; double localPercent = localLength / segments[index].Length_quick; // Calculate the bezier point retVal[cntr] = GetPoint(localPercent, segments[index].Combined); } return retVal; }
private void Test2Segments2D(Point end1, Point end2, Point end3) { // Control points for 2 var controlPoints = BezierUtil.GetControlPoints_Middle(end1, end2, end3, trkSingleLine2Segments2DPercent.Value, trkSingleLine2Segments2DPercent.Value); Point3D[] allEndPoints = new[] { end1, end2, end3 }.Select(o => o.ToPoint3D()).ToArray(); var segment12 = new BezierSegment3D(0, 1, new[] { end1.ToPoint3D(), controlPoints.Item1.ToPoint3D() }, allEndPoints); var segment23 = new BezierSegment3D(1, 2, new[] { controlPoints.Item2.ToPoint3D(), end3.ToPoint3D() }, allEndPoints); // Calculate the beziers Point3D[] bezierPoints12 = BezierUtil.GetPoints(100, segment12); Point3D[] bezierPoints23 = BezierUtil.GetPoints(100, segment23); #region Draw PrepFor2D(); foreach (var bezier in new[] { Tuple.Create(segment12, bezierPoints12), Tuple.Create(segment23, bezierPoints23) }) { // Main Line for (int cntr = 0; cntr < bezier.Item2.Length - 1; cntr++) { AddLine(bezier.Item2[cntr].ToPoint2D(), bezier.Item2[cntr + 1].ToPoint2D(), _mainLineB, 3); } if (chkShowDots.IsChecked.Value) { foreach (Point3D point in bezier.Item2) { AddDot(point.ToPoint2D(), _mainLineB, 8); } // Control Lines Point[] allPoints = UtilityCore.Iterate<Point3D>(bezier.Item1.EndPoint0, bezier.Item1.ControlPoints, bezier.Item1.EndPoint1).Select(o => o.ToPoint2D()).ToArray(); for (int cntr = 0; cntr < allPoints.Length - 1; cntr++) { AddLine(allPoints[cntr], allPoints[cntr + 1], _controlLineB, 1); } for (int cntr = 0; cntr < bezier.Item1.ControlPoints.Length; cntr++) { AddDot(bezier.Item1.ControlPoints[cntr].ToPoint2D(), _controlPointB); } } } // End Points if (chkShowDots.IsChecked.Value) { AddDot(end1, _endPointB); AddDot(end2, _endPointB); AddDot(end3, _endPointB); } #endregion }
private static BezierSegment3D[] GetBezierSegments_Closed(Point3D[] ends, double along = .25) { //NOTE: The difference between closed and open is closed has one more segment that loops back to zero (and a control point for point zero) // Precalculate the control points Tuple<Point3D, Point3D>[] controls = new Tuple<Point3D, Point3D>[ends.Length - 1]; for (int cntr = 1; cntr < ends.Length; cntr++) { int lastIndex = cntr == ends.Length - 1 ? 0 : cntr + 1; Tuple<double, double> adjustedAlong = GetAdjustedRatios(ends[cntr - 1], ends[cntr], ends[lastIndex], along); controls[cntr - 1] = GetControlPoints_Middle(ends[cntr - 1], ends[cntr], ends[lastIndex], adjustedAlong.Item1, adjustedAlong.Item2); } Tuple<double, double> adjustedAlong2 = GetAdjustedRatios(ends[ends.Length - 1], ends[0], ends[1], along); var extraControl = GetControlPoints_Middle(ends[ends.Length - 1], ends[0], ends[1], adjustedAlong2.Item1, adjustedAlong2.Item2); // loop back // Build the return segments BezierSegment3D[] retVal = new BezierSegment3D[ends.Length]; for (int cntr = 0; cntr < ends.Length; cntr++) { Point3D? ctrl0 = cntr == 0 ? extraControl.Item2 : controls[cntr - 1].Item2; Point3D? ctrl1 = cntr == ends.Length - 1 ? extraControl.Item1 : controls[cntr].Item1; int lastIndex = cntr == ends.Length - 1 ? 0 : cntr + 1; retVal[cntr] = new BezierSegment3D(cntr, lastIndex, UtilityCore.Iterate<Point3D>(ctrl0, ctrl1).ToArray(), ends); } return retVal; }
private void TestAxeSimple1(AxeSimple1 arg) { BezierSegment3D[][] segmentSets = new BezierSegment3D[5][]; PrepFor3D(); #region Lines for (int cntr = 0; cntr < 5; cntr++) { if (!chkAxe3D.IsChecked.Value && cntr != 2) { continue; } #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 }; BezierSegment3D[] segments = TestAxeSimple1_Segments(endPoints, arg); segmentSets[cntr] = segments; DrawBezierLines(segments, chkAxeLine.IsChecked.Value, chkAxeControl.IsChecked.Value, chkAxeEnd.IsChecked.Value); } #endregion #region Plates if (chkAxe3D.IsChecked.Value) { Color edgeColor = Colors.GhostWhite; Color middleColor = Colors.DimGray; int squareCount = 8; DrawBezierPlates(squareCount, segmentSets[0], segmentSets[1], middleColor, false); DrawBezierPlates(squareCount, new[] { segmentSets[1][0], segmentSets[1][1] }, new[] { segmentSets[2][0], segmentSets[2][1] }, middleColor, false); DrawBezierPlate(squareCount, segmentSets[1][2], segmentSets[2][2], edgeColor, true); DrawBezierPlates(squareCount, new[] { segmentSets[2][0], segmentSets[2][1] }, new[] { segmentSets[3][0], segmentSets[3][1] }, middleColor, false); DrawBezierPlate(squareCount, segmentSets[2][2], segmentSets[3][2], edgeColor, true); DrawBezierPlates(squareCount, segmentSets[3], segmentSets[4], middleColor, false); // End cap plates if (arg.isCenterFilled) { for (int cntr = 0; cntr < 2; cntr++) { int index = cntr == 0 ? 0 : 4; DrawBezierPlate(squareCount, segmentSets[index][0], segmentSets[index][1], middleColor, false); // top - bottom BezierSegment3D extraSeg = new BezierSegment3D(segmentSets[index][2].EndIndex0, segmentSets[index][2].EndIndex1, null, segmentSets[index][2].AllEndPoints); DrawBezierPlate(squareCount, extraSeg, segmentSets[index][2], middleColor, false); // edge } } else { DrawBezierPlates(squareCount, segmentSets[0], segmentSets[4], middleColor, false); } } #endregion }
public static Point3D[] GetPoints(int count, BezierSegment3D segment) { return GetPoints(count, UtilityCore.Iterate<Point3D>(segment.EndPoint0, segment.ControlPoints, segment.EndPoint1).ToArray()); }
private static BezierSegment3D[] TestAxeSimple1_Segments(Point3D[] endPoints, AxeSimple1 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 }; }
private static Tuple<double[], BezierSegment3D[][], double[], BezierSegment3D[][]> ConvertToBezier(double[] axisX, double[] axisY, double[] valuesZ) { #region validate // X length if (axisX == null || axisX.Length < 2) { throw new ArgumentException(string.Format("axisX must have at least 2 items: len={0}", axisX == null ? "null" : axisX.Length.ToString())); } // Y length if (axisY == null || axisY.Length < 2) { throw new ArgumentException(string.Format("axisY must have at least 2 items: len={0}", axisY == null ? "null" : axisY.Length.ToString())); } // Z area if (valuesZ == null || valuesZ.Length != axisX.Length * axisY.Length) { throw new ArgumentException(string.Format("valuesZ is invalid length: values={0}, axis1={1}, axis2={2}", valuesZ == null ? "null" : valuesZ.Length.ToString(), axisX.Length, axisY.Length)); } // X equality if (Enumerable.Range(0, axisX.Length - 1).Any(o => axisX[o].IsNearValue(axisX[o + 1]))) { throw new ArgumentException("Values can't be the same in x axis"); } // Y equality if (Enumerable.Range(0, axisY.Length - 1).Any(o => axisY[o].IsNearValue(axisY[o + 1]))) { throw new ArgumentException("Values can't be the same in y axis"); } #endregion bool isAccendingX = axisX[1] > axisX[0]; bool isAccendingY = axisY[1] > axisY[0]; #region validate // X ascending if (Enumerable.Range(0, axisX.Length - 1).Any(o => isAccendingX ? axisX[o + 1] < axisX[o] : axisX[o + 1] > axisX[o])) { throw new ArgumentException("The values in axisX must all ascend or descend"); } // Y ascending if (Enumerable.Range(0, axisY.Length - 1).Any(o => isAccendingY ? axisY[o + 1] < axisY[o] : axisY[o + 1] > axisY[o])) { throw new ArgumentException("The values in axisX must all ascend or descend"); } #endregion #region ensure ascending X if (!isAccendingX) { axisX = axisX.Reverse().ToArray(); double[] newZ = new double[valuesZ.Length]; for (int oldX = 0; oldX < axisX.Length; oldX++) { int newX = axisX.Length - 1 - oldX; for (int y = 0; y < axisY.Length; y++) { int yIndex = y * axisX.Length; newZ[yIndex + newX] = valuesZ[yIndex + oldX]; } } valuesZ = newZ; } #endregion #region ensure ascending Y if (!isAccendingY) { axisY = axisY.Reverse().ToArray(); double[] newZ = new double[valuesZ.Length]; for (int oldY = 0; oldY < axisY.Length; oldY++) { int newY = axisY.Length - 1 - oldY; int yIndexOld = oldY * axisX.Length; int yIndexNew = newY * axisX.Length; for (int x = 0; x < axisX.Length; x++) { newZ[yIndexNew + x] = valuesZ[yIndexOld + x]; } } valuesZ = newZ; } #endregion BezierSegment3D[][] horizontal = new BezierSegment3D[axisY.Length][]; // there is a horizontal set for each y BezierSegment3D[][] vertical = new BezierSegment3D[axisX.Length][]; //TODO: Make an option of this that figures out the percent to use: //if you pass in .25, that is the max. // if both segments are equal length then it will be .25 for each // if they are different lengths, the smaller will use .25. the larger will use the ratio of lengths*.25 //BezierSegmentDef.GetBezierSegments(); #region horizontal for (int y = 0; y < axisY.Length; y++) { int yIndex = y * axisX.Length; Point3D[] ends = Enumerable.Range(0, axisX.Length). Select(x => new Point3D(axisX[x], axisY[y], valuesZ[yIndex + x])). ToArray(); horizontal[y] = BezierUtil.GetBezierSegments(ends); } #endregion #region vertical for (int x = 0; x < axisX.Length; x++) { Point3D[] ends = Enumerable.Range(0, axisY.Length). Select(y => new Point3D(axisX[x], axisY[y], valuesZ[(y * axisX.Length) + x])). ToArray(); vertical[x] = BezierUtil.GetBezierSegments(ends); } #endregion return Tuple.Create(axisX, horizontal, axisY, vertical); }
private void TestAxeSimple2(Curves_AxeSimple2 arg) { BezierSegment3D[][] segmentSets = new BezierSegment3D[5][]; Curves_AxeSimple2[] argLevels = new Curves_AxeSimple2[5]; argLevels[2] = arg; // Edge #region Middle argLevels[1] = UtilityCore.Clone(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(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 PrepFor3D(); #region Lines for (int cntr = 0; cntr < 5; cntr++) { if (!chkAxe3D.IsChecked.Value && cntr != 2) { continue; } Curves_AxeSimple2 argCurrent = argLevels[cntr]; BezierSegment3D[] segments = TestAxeSimple2_Segments(argCurrent); segmentSets[cntr] = segments; DrawBezierLines(segments, chkAxeLine.IsChecked.Value, chkAxeControl.IsChecked.Value, chkAxeEnd.IsChecked.Value); } #endregion #region Plates if (chkAxe3D.IsChecked.Value) { Color edgeColor = Colors.GhostWhite; Color middleColor = Colors.DimGray; int numSegments = segmentSets[0].Length; int squareCount = 20; // Z to Z DrawBezierPlates(squareCount, segmentSets[0], segmentSets[1], middleColor, false); if (numSegments == 3) { DrawBezierPlates(squareCount, new[] { segmentSets[1][0], segmentSets[1][2] }, new[] { segmentSets[2][0], segmentSets[2][2] }, middleColor, false); DrawBezierPlate(squareCount, segmentSets[1][1], segmentSets[2][1], edgeColor, true); DrawBezierPlates(squareCount, new[] { segmentSets[2][0], segmentSets[2][2] }, new[] { segmentSets[3][0], segmentSets[3][2] }, middleColor, false); DrawBezierPlate(squareCount, segmentSets[2][1], segmentSets[3][1], edgeColor, true); } else { DrawBezierPlates(squareCount, new[] { segmentSets[1][0], segmentSets[1][3] }, new[] { segmentSets[2][0], segmentSets[2][3] }, middleColor, false); DrawBezierPlates(squareCount, new[] { segmentSets[1][1], segmentSets[1][2] }, new[] { segmentSets[2][1], segmentSets[2][2] }, edgeColor, true); DrawBezierPlates(squareCount, new[] { segmentSets[2][0], segmentSets[2][3] }, new[] { segmentSets[3][0], segmentSets[3][3] }, middleColor, false); DrawBezierPlates(squareCount, new[] { segmentSets[2][1], segmentSets[2][2] }, new[] { segmentSets[3][1], segmentSets[3][2] }, edgeColor, true); } DrawBezierPlates(squareCount, segmentSets[3], segmentSets[4], middleColor, false); // End cap plates for (int cntr = 0; cntr < 2; cntr++) { int index = cntr == 0 ? 0 : 4; // Turn the end cap into a polygon, then triangulate it Point3D[] endCapPoly = BezierUtil.GetPath(squareCount, segmentSets[index].Select(o => new[] { o }).ToArray()); // Call the jagged array overload so that the individual bezier end points don't get smoothed out TriangleIndexed[] endCapTriangles = Math2D.GetTrianglesFromConcavePoly3D(endCapPoly); if (cntr == 0) { endCapTriangles = endCapTriangles.Select(o => new TriangleIndexed(o.Index0, o.Index2, o.Index1, o.AllPoints)).ToArray(); // need to do this so the normals point in the proper direction } DrawPolyPlate(endCapTriangles, middleColor, false); //AddLines(endCapTriangles.Select(o => Tuple.Create(o.GetCenterPoint(), o.GetCenterPoint() + o.Normal)), _controlLineC, 2); } } #endregion }
public static Point3D GetPoint(double percent, BezierSegment3D[] bezier) { //TODO: If the bezier is closed, make it circular if (percent < 0) return bezier[0].EndPoint0; double totalLength = bezier.Sum(o => o.Length_quick); double fromPercent = 0d; for(int cntr = 0; cntr < bezier.Length; cntr++) { double toPercent = fromPercent + (bezier[cntr].Length_quick / totalLength); if(percent >= fromPercent && percent <= toPercent) { double localPercent = ((percent - fromPercent) * totalLength) / bezier[cntr].Length_quick; return GetPoint(localPercent, bezier[cntr]); } fromPercent = toPercent; } return bezier[bezier.Length - 1].EndPoint1; }
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; }