]> Shamusworld >> Repos - architektonas/blobdiff - src/geometry.cpp
More polyline upgrading: points and arcs are now editable with the GUI.
[architektonas] / src / geometry.cpp
index f4918560990d8ddcd61709daf54aae49c6b4fadc..82d24e84c492ca81e2f116b23b1d84d14fc53d1a 100644 (file)
@@ -525,6 +525,21 @@ Vector Geometry::GetNormalOfPointAndLine(Point p, Line * l)
        return normal;
 }
 
+//
+// Returns the orientation of the points when traversed in order (from p1 to
+// p2 to p3).  +1 = CCW, -1 = CW, 0 = colinear
+//
+int Geometry::Orientation(Point p1, Point p2, Point p3)
+{
+       double xx = p2.x - p1.x, yy = p2.y - p1.y;
+       double aa = p3.x - p1.x, bb = p3.y - p1.y;
+
+       // Mult by -1 if screen coords already transformed
+       double zz = (xx * bb) - (yy * aa);
+
+       return (zz < 0 ? -1 : (zz == 0 ? 0 : 1));
+}
+
 Circle Geometry::FindCircleForThreePoints(Point p1, Point p2, Point p3)
 {
        // We use matrices and determinants to find the center and radius of the
@@ -582,6 +597,27 @@ Circle Geometry::FindCircleForThreePoints(Point p1, Point p2, Point p3)
        return c;
 }
 
+Arc Geometry::FindArcForThreePoints(Point p1, Point p2, Point p3)
+{
+       int orientation = Orientation(p1, p2, p3);
+
+       // Sanity check: if points are colinear, there is no arc
+       if (orientation == 0)
+               return Arc();
+
+       Circle c = FindCircleForThreePoints(p1, p2, p3);
+       double a1 = Vector::Angle(c.p[0], p1);
+       double a2 = Vector::Angle(c.p[0], p2);
+       double span = a2 - a1;
+
+       if (orientation < 0 && span > 0)
+               span -= TAU;
+       else if (orientation > 0 && span < 0)
+               span += TAU;
+
+       return Arc(c.p[0], c.radius[0], a1, span);
+}
+
 double Geometry::Determinant3x3(double a11, double a12, double a13, double a21, double a22, double a23, double a31, double a32, double a33)
 {
        return (a11 * ((a22 * a33) - (a32 * a23)))
@@ -602,7 +638,6 @@ Arc Geometry::Unpack(Point tail, Point head, double bump)
 
        // N.B.: The radius can also be found with r = (a² + h²) / 2h where a is
        // the 1/2 length of the line segment and h is the bump length.
-//     double radius = (length + (1.0 / length)) / 2.0;
        double radius = 0.5 * (((length * length) + (bumpLen * bumpLen)) / bumpLen);
        Vector ctrVec = mpNormal * (radius - bumpLen);
        Point center = midpoint + ctrVec;
@@ -621,3 +656,19 @@ Arc Geometry::Unpack(Point tail, Point head, double bump)
 
        return Arc(center, radius, angle1, span);
 }
+
+double Geometry::Pack(Arc * a)
+{
+       Point p1 = a->p[0] + (Vector(cos(a->angle[0]), sin(a->angle[0])) * a->radius[0]);
+       Point p2 = a->p[0] + (Vector(cos(a->angle[0] + a->angle[1]), sin(a->angle[0] + a->angle[1])) * a->radius[0]);
+       double endpointLen = Vector::Magnitude(p1, p2) / 2.0;
+
+       // Bump height can be found with h = r ± sqr(r² - a²) where r is the
+       // radius, and a is the 1/2 length of the endpoint's line segment.  The
+       // plus/minus term is positive if the arc span is less than 1/2 TAU,
+       // negative if the arc span is greater than 1/2 TAU.
+       double discriminant = sqrt((a->radius[0] * a->radius[0]) - (endpointLen * endpointLen));
+       double bumpLen = a->radius[0] + (discriminant * (fabs(a->angle[1]) < HALF_TAU ? 1.0 : -1.0));
+
+       return (bumpLen / endpointLen) * (a->angle[1] > 0 ? -1.0 : 1.0);
+}