private void TestToStringWithCulture(CultureInfo culture) { CultureInfo originalCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = culture; try { string listSeparator = culture.TextInfo.ListSeparator; string decimalSeparator = culture.NumberFormat.NumberDecimalSeparator; var o = new Seg2F(new Vec2F(1.1f, 2.2f), new Vec2F(3.3f, 4.4f)); string s = o.ToString(null, null); TestToStringResults(o, s, listSeparator, decimalSeparator); string s2 = o.ToString(); Assert.AreEqual(s, s2); s = o.ToString("G", culture); TestToStringResults(o, s, listSeparator, decimalSeparator); s = o.ToString("R", culture); TestToStringResults(o, s, listSeparator, decimalSeparator); } finally { Thread.CurrentThread.CurrentCulture = originalCulture; } }
/// <summary> /// Projects a point onto a segment</summary> /// <param name="seg">Segment</param> /// <param name="p">Point to project</param> /// <returns>Point on the segment nearest to the point</returns> public static Vec2F Project(Seg2F seg, Vec2F p) { Vec2F result = new Vec2F(); Vec2F dir = seg.P2 - seg.P1; Vec2F vec = p - seg.P1; float lengthSquared = Vec2F.Dot(dir, dir); if (lengthSquared < DegenerateLength * DegenerateLength) // degenerate segment? { result = seg.P1; } else { float projection = Vec2F.Dot(dir, vec); if (projection < 0) { result = seg.P1; } else if (projection > lengthSquared) { result = seg.P2; } else { double scale = projection / lengthSquared; result.X = (float)(seg.P1.X + scale * dir.X); result.Y = (float)(seg.P1.Y + scale * dir.Y); } } return result; }
/// <summary> /// Gets the distance from a point p to its projection on a segment</summary> /// <param name="seg">Segment</param> /// <param name="p">Point to project</param> /// <returns>Distance from point p to its projection on segment</returns> public static float DistanceToSegment(Seg2F seg, Vec2F p) { Vec2F projection = Project(seg, p); float d = Vec2F.Distance(p, projection); return(d); }
/// <summary> /// Projects a point onto a segment</summary> /// <param name="seg">Segment</param> /// <param name="p">Point to project</param> /// <returns>Point on the segment nearest to the point</returns> public static Vec2F Project(Seg2F seg, Vec2F p) { Vec2F result = new Vec2F(); Vec2F dir = seg.P2 - seg.P1; Vec2F vec = p - seg.P1; float lengthSquared = Vec2F.Dot(dir, dir); if (lengthSquared < DegenerateLength * DegenerateLength) // degenerate segment? { result = seg.P1; } else { float projection = Vec2F.Dot(dir, vec); if (projection < 0) { result = seg.P1; } else if (projection > lengthSquared) { result = seg.P2; } else { double scale = projection / lengthSquared; result.X = (float)(seg.P1.X + scale * dir.X); result.Y = (float)(seg.P1.Y + scale * dir.Y); } } return(result); }
private void TestToStringResults(Seg2F o, string s, string listSeparator, string decimalSeparator) { string[] results = s.Split(new[] { listSeparator }, StringSplitOptions.RemoveEmptyEntries); Assert.AreEqual(results.Length, 4); foreach (string oneFloatString in results) Assert.True(oneFloatString.Contains(decimalSeparator)); Assert.AreEqual(float.Parse(results[0]), o.P1.X); Assert.AreEqual(float.Parse(results[1]), o.P1.Y); Assert.AreEqual(float.Parse(results[2]), o.P2.X); Assert.AreEqual(float.Parse(results[3]), o.P2.Y); }
/// <summary> /// Picks the specified curve</summary> /// <param name="curve">Curve</param> /// <param name="p">Picking point</param> /// <param name="tolerance">Pick tolerance</param> /// <param name="hitPoint">Hit point</param> /// <returns>True if curve found; false otherwise</returns> public static bool Pick(BezierCurve2F curve, Vec2F p, float tolerance, ref Vec2F hitPoint) { Queue <BezierCurve2F> curves = new Queue <BezierCurve2F>(); curves.Enqueue(curve); float dMin = float.MaxValue; Vec2F closestPoint = new Vec2F(); while (curves.Count > 0) { BezierCurve2F current = curves.Dequeue(); // project p onto segment connecting curve endpoints Seg2F seg = new Seg2F(current.P1, current.P4); Vec2F projection = Seg2F.Project(seg, p); float d = Vec2F.Distance(p, projection); // reject - point not near enough to segment, expanded by curve "thickness" float flatness = current.Flatness; if (d - flatness > tolerance) { continue; } // accept - point within tolerance of curve if (flatness <= tolerance) { if (d < dMin) { dMin = d; closestPoint = projection; } } else { BezierCurve2F left, right; current.Subdivide(0.5f, out left, out right); curves.Enqueue(left); curves.Enqueue(right); } } if (dMin < tolerance) { hitPoint = closestPoint; return(true); } return(false); }
/// <summary> /// Picks the specified curve</summary> /// <param name="curve">Curve</param> /// <param name="p">Picking point</param> /// <param name="tolerance">Pick tolerance</param> /// <param name="hitPoint">Hit point</param> /// <returns>True if curve found; false otherwise</returns> public static bool Pick(BezierCurve2F curve, Vec2F p, float tolerance, ref Vec2F hitPoint) { Queue<BezierCurve2F> curves = new Queue<BezierCurve2F>(); curves.Enqueue(curve); float dMin = float.MaxValue; Vec2F closestPoint = new Vec2F(); while (curves.Count > 0) { BezierCurve2F current = curves.Dequeue(); // project p onto segment connecting curve endpoints Seg2F seg = new Seg2F(current.P1, current.P4); Vec2F projection = Seg2F.Project(seg, p); float d = Vec2F.Distance(p, projection); // reject - point not near enough to segment, expanded by curve "thickness" float flatness = current.Flatness; if (d - flatness > tolerance) continue; // accept - point within tolerance of curve if (flatness <= tolerance) { if (d < dMin) { dMin = d; closestPoint = projection; } } else { BezierCurve2F left, right; current.Subdivide(0.5f, out left, out right); curves.Enqueue(left); curves.Enqueue(right); } } if (dMin < tolerance) { hitPoint = closestPoint; return true; } return false; }
/// <summary> /// Gets the distance from a point p to its projection on a segment</summary> /// <param name="seg">Segment</param> /// <param name="p">Point to project</param> /// <returns>Distance from point p to its projection on segment</returns> public static float DistanceToSegment(Seg2F seg, Vec2F p) { Vec2F projection = Project(seg, p); float d = Vec2F.Distance(p, projection); return d; }
/// <summary> /// Picks one or more control points within given rectangle</summary> /// <param name="curves">Curves on which to pick points</param> /// <param name="pickRect">Rectangle bounding picked control points</param> /// <param name="points">Points picked</param> /// <param name="regions">PointSelectionRegions of picked points</param> public void PickPoints(ReadOnlyCollection<ICurve> curves, RectangleF pickRect, List<IControlPoint> points, List<PointSelectionRegions> regions) { points.Clear(); regions.Clear(); if (curves == null) return; foreach (ICurve curve in curves) { if (!curve.Visible) continue; ReadOnlyCollection<IControlPoint> curvePoints = curve.ControlPoints; for (int i = 0; i < curvePoints.Count; i++) { IControlPoint cpt = curvePoints[i]; Vec2F clientcpt = m_canvas.GraphToClient(cpt.X, cpt.Y); if (pickRect.Contains(clientcpt)) { points.Add(cpt); regions.Add(PointSelectionRegions.Point); } else if (curve.CurveInterpolation != InterpolationTypes.Linear && cpt.EditorData.SelectedRegion != PointSelectionRegions.None) { bool pickTanOut = cpt.TangentOutType != CurveTangentTypes.Stepped && cpt.TangentOutType != CurveTangentTypes.SteppedNext; if (pickTanOut) { Vec2F tangOut = Vec2F.Normalize(m_canvas.GraphToClientTangent(cpt.TangentOut)); Seg2F seg = new Seg2F(clientcpt, (clientcpt + tangOut * m_tangentLength)); if (GdiUtil.Intersects(seg, pickRect)) { points.Add(cpt); regions.Add(PointSelectionRegions.TangentOut); continue; } } bool pickTanIn = true; if (i > 0) { IControlPoint prevCpt = curvePoints[i - 1]; pickTanIn = prevCpt.TangentOutType != CurveTangentTypes.Stepped && prevCpt.TangentOutType != CurveTangentTypes.SteppedNext; } if (pickTanIn) { // pick tangentIn. Vec2F tangIn = Vec2F.Normalize(m_canvas.GraphToClientTangent(cpt.TangentIn)); tangIn.X = -tangIn.X; tangIn.Y = -tangIn.Y; Seg2F seg = new Seg2F(clientcpt, (clientcpt + tangIn * m_tangentLength)); if (GdiUtil.Intersects(seg, pickRect)) { points.Add(cpt); regions.Add(PointSelectionRegions.TangentIn); } } } } } // foreach curve in curves }