private MechanismBase MakeRodRopeOrSpring(Stroke stroke, RigidBodyBase headbody, RigidBodyBase tailbody) { // Rod, Rope, or Spring: we decide based on straightness, curvyness, and loopiness. int np = stroke.PacketCount; Point head = stroke.GetPoint(0), tail = stroke.GetPoint(np - 1); double distance = Geometry.DistanceBetween(head, tail); StrokeGeometry sg = new StrokeGeometry(stroke); double length = sg.IntegrateLength(); // Consider spring: analyze total net curvature of the stroke, and call it a // spring if it makes at least 540 degrees (1.5 loops) in the same direction. double tt = StrokeAnalyzer.AnalyzeTotalCurvature(stroke, 100.0); if (Math.Abs(Geometry.Rad2Deg(tt)) > 540.0) { dbg.WriteLine("new SpringMech"); SpringMech newmech = new SpringMech(); newmech.EndpointA = BodyRef.For(headbody, head); newmech.EndpointB = BodyRef.For(tailbody, tail); newmech.extension = distance; newmech.stiffness = MathEx.Square(tt) / 100; //Heuristic: th²/100 feels about right. newmech.strokeid = stroke.Id; doc.Mechanisms.Add(newmech); return(newmech); } // Straight and narrow? double rodropethreshold = 1.1; //heuristic if (length / distance < rodropethreshold) { dbg.WriteLine("new RodMech"); RodMech newmech = new RodMech(); newmech.EndpointA = BodyRef.For(headbody, head); newmech.EndpointB = BodyRef.For(tailbody, tail); newmech.length = distance; newmech.strokeid = stroke.Id; doc.Mechanisms.Add(newmech); return(newmech); } else { dbg.WriteLine("new RopeMech"); RopeMech newmech = new RopeMech(); newmech.EndpointA = BodyRef.For(headbody, head); newmech.EndpointB = BodyRef.For(tailbody, tail); newmech.length = length; newmech.strokeid = stroke.Id; doc.Mechanisms.Add(newmech); return(newmech); } }
public static void AnalyzeClosedness(Stroke stroke, double tolerance, out bool closed, out Point[] vertices) // out double tAB, out double tPQ) { closed = false; vertices = null; // Formulate closure gap-tolerance, based on stroke length (but clipped to <= 500isu). double len = StrokeGeometry.IntegrateLength(stroke); double segtol = Math.Max(50, Math.Min(tolerance, len / 20.0)); double gaptol = Math.Max(150, Math.Min(tolerance, len / 7.0)); dbg.WriteLine(String.Format("length: {0}", len)); dbg.WriteLine(String.Format("segtol: {0}", segtol)); dbg.WriteLine(String.Format("gaptol: {0}", gaptol)); // Break the stroke down into indices. int[] indices; vertices = SegmentizeStroke(stroke, segtol, out indices); int nv = vertices.Length; // Do the head/tail segments intersect? Are they close? if (nv >= 4) { Point headA = (Point)vertices[0]; Point headB = (Point)vertices[1]; Point tailP = (Point)vertices[nv - 2]; Point tailQ = (Point)vertices[nv - 1]; double tAB, tPQ; SegmentCollision.HitTest(headA, headB, tailP, tailQ, out tAB, out tPQ); Point virtualIntersectH = Geometry.Interpolate(headA, headB, tAB); Point virtualIntersectT = Geometry.Interpolate(tailP, tailQ, tPQ); Point virtualIntersect = Geometry.Interpolate(virtualIntersectH, virtualIntersectT, 0.5); double dh2i = Geometry.DistanceBetween(headA, virtualIntersect); double dt2i = Geometry.DistanceBetween(tailQ, virtualIntersect); #if DEBUG dbg.WriteLine(String.Format("numV: {0}", nv)); dbg.WriteLine(String.Format("tAB: {0}", tAB)); dbg.WriteLine(String.Format("tPQ: {0}", tPQ)); dbg.WriteLine(String.Format("isct: {0}", virtualIntersect)); dbg.WriteLine(String.Format("dh2i: {0}", dh2i)); dbg.WriteLine(String.Format("dt2i: {0}", dt2i)); #endif if (dh2i < gaptol && dt2i < gaptol) { closed = true; // Adjust the head point to the actual intersection. vertices[0] = virtualIntersect; dbg.WriteLine("Closed! Why? dh/t2i < gaptol"); } else if ((-0.3 < tAB && tAB < 0.3) && (0.7 < tPQ && tPQ < 1.3)) { closed = true; // Adjust the head point to the actual intersection. vertices[0] = virtualIntersect; dbg.WriteLine("Closed! Why? |t*| < 0.3"); } else { // Last chance: measure nearest distance from head to tail segment. int closeI = StrokeGeometry.FindClosestPointTo( stroke, headA, indices[nv - 2], indices[nv - 1]); Point close = stroke.GetPoint(closeI); double d = Geometry.DistanceBetween(headA, close); if (d < gaptol) { closed = true; // Keep the head point; discard the tail point below. dbg.WriteLine("Closed! Why? Last chance head/tail distance < gaptol"); } } // Remove the last point as redundant if it's closed. if (closed) { Point[] verticesX = new Point[nv - 1]; Array.Copy(vertices, verticesX, nv - 1); vertices = verticesX; } } }
public static double IntegrateLength(Stroke stroke) { StrokeGeometry sg = new StrokeGeometry(stroke); return sg.IntegrateLength(); }
private MechanismBase MakeRodRopeOrSpring(Stroke stroke, RigidBodyBase headbody, RigidBodyBase tailbody) { // Rod, Rope, or Spring: we decide based on straightness, curvyness, and loopiness. int np = stroke.PacketCount; Point head = stroke.GetPoint(0), tail = stroke.GetPoint(np-1); double distance = Geometry.DistanceBetween(head,tail); StrokeGeometry sg = new StrokeGeometry(stroke); double length = sg.IntegrateLength(); // Consider spring: analyze total net curvature of the stroke, and call it a // spring if it makes at least 540 degrees (1.5 loops) in the same direction. double tt = StrokeAnalyzer.AnalyzeTotalCurvature(stroke,100.0); if (Math.Abs(Geometry.Rad2Deg(tt)) > 540.0) { dbg.WriteLine("new SpringMech"); SpringMech newmech = new SpringMech(); newmech.EndpointA = BodyRef.For(headbody,head); newmech.EndpointB = BodyRef.For(tailbody,tail); newmech.extension = distance; newmech.stiffness = MathEx.Square(tt)/100; //Heuristic: th²/100 feels about right. newmech.strokeid = stroke.Id; doc.Mechanisms.Add(newmech); return newmech; } // Straight and narrow? double rodropethreshold = 1.1; //heuristic if (length/distance < rodropethreshold) { dbg.WriteLine("new RodMech"); RodMech newmech = new RodMech(); newmech.EndpointA = BodyRef.For(headbody,head); newmech.EndpointB = BodyRef.For(tailbody,tail); newmech.length = distance; newmech.strokeid = stroke.Id; doc.Mechanisms.Add(newmech); return newmech; } else { dbg.WriteLine("new RopeMech"); RopeMech newmech = new RopeMech(); newmech.EndpointA = BodyRef.For(headbody,head); newmech.EndpointB = BodyRef.For(tailbody,tail); newmech.length = length; newmech.strokeid = stroke.Id; doc.Mechanisms.Add(newmech); return newmech; } }
public static double IntegrateLength(Stroke stroke) { StrokeGeometry sg = new StrokeGeometry(stroke); return(sg.IntegrateLength()); }