/// <summary> /// Apply a transform to us. /// </summary> private void TransformInternal <T>(T transform) where T : ITransform { // NOTES: // Arcs can go to lines, and lines to arcs. // Rotations may reverse arc directions as well. // Arc centers can't be transformed directly. // NOTE: We must calc this before altering the endpoints. Vector3D mid = Midpoint; if (Infinity.IsInfinite(mid)) { mid = Infinity.IsInfinite(P1) ? P2 * Infinity.FiniteScale : P1 * Infinity.FiniteScale; } P1 = transform.Apply(P1); P2 = transform.Apply(P2); mid = transform.Apply(mid); // Can we make a circle out of the transformed points? Circle temp = new Circle(); if (!Infinity.IsInfinite(P1) && !Infinity.IsInfinite(P2) && !Infinity.IsInfinite(mid) && temp.From3Points(P1, mid, P2)) { Type = SegmentType.Arc; Center = temp.Center; // Work out the orientation of the arc. Vector3D t1 = P1 - Center; Vector3D t2 = mid - Center; Vector3D t3 = P2 - Center; double a1 = Euclidean2D.AngleToCounterClock(t2, t1); double a2 = Euclidean2D.AngleToCounterClock(t3, t1); Clockwise = a2 > a1; } else { // The circle construction fails if the points // are colinear (if the arc has been transformed into a line). Type = SegmentType.Line; // XXX - need to do something about this. // Turn into 2 segments? //if( isInfinite( mid ) ) // Actually the check should just be whether mid is between p1 and p2. } }
public static Segment Arc(Vector3D start, Vector3D mid, Vector3D end) { Segment newSeg = new Segment(); newSeg.Type = SegmentType.Arc; newSeg.P1 = start; newSeg.P2 = end; Circle c = new Circle(); c.From3Points(start, mid, end); newSeg.Center = c.Center; // Obtain vectors from center point of circle (as if at the origin) Vector3D startOrigin = start - c.Center; Vector3D midOrigin = mid - c.Center; Vector3D endOrigin = end - c.Center; // Calculate the normal vector and angle to traverse. // ZZZ - worry about failure of cross product here. Vector3D normalVector = startOrigin.Cross(endOrigin); newSeg.Clockwise = normalVector.Z < 0; double angleToTraverse = startOrigin.AngleTo(endOrigin); // The normal vector might need to be reversed and the angleToTraverse adjusted. // This happens depending on the location of the midpoint relative to the start and end points. double compareAngle = startOrigin.AngleTo(midOrigin) + midOrigin.AngleTo(endOrigin); bool reverse = !Tolerance.Equal(angleToTraverse, compareAngle); if (reverse) { newSeg.Clockwise = !newSeg.Clockwise; } return(newSeg); }