+void Line::SetDimensionOnLine(Dimension * dimension/*=NULL*/)
+{
+ // If they don't pass one in, create it for the caller.
+ if (dimension == NULL)
+ {
+//printf("Line::SetDimensionOnLine(): Creating new dimension...\n");
+// dimension = new Dimension(position, endpoint, DTLinear, this);
+ dimension = new Dimension(Connection(this, 0), Connection(this, 1.0), DTLinear, this);
+
+ if (parent)
+//{
+//printf("Line::SetDimensionOnLine(): Adding to parent...\n");
+ parent->Add(dimension);
+//}
+ }
+ else
+ {
+ dimension->Connect(this, 0);
+ dimension->Connect(this, 1.0);
+ }
+
+ // Make sure the Dimension is connected to us...
+ Connect(dimension, 0);
+ Connect(dimension, 1.0);
+}
+
+
+Object * Line::FindAttachedDimension(void)
+{
+ // Is there anything connected to this line? If not, return NULL
+ if (connected.size() < 2)
+ return NULL;
+
+ // Otherwise, we have to search our objects to see if there's a likely
+ // candidate. In this case, we're looking for a pointer to the same object
+ // with a parameter of 0 and 1 respectively. This is O((n^2)/2).
+ for(uint i=0; i<connected.size(); i++)
+ {
+ for(uint j=i+1; j<connected.size(); j++)
+ {
+//printf("Line: connected[i]=%X, connected[j]=%X, connected[i].t=%lf, connected[j].t=%lf\n", connected[i].object, connected[j].object, connected[i].t, connected[j].t);
+ if ((connected[i].object == connected[j].object)
+ && ((connected[i].t == 0 && connected[j].t == 1.0)
+ || (connected[i].t == 1.0 && connected[j].t == 0)))
+ return connected[i].object;
+ }
+ }
+
+ // Didn't find anything, so return NULL
+ return NULL;
+}
+
+
+bool Line::HitTest(Point point)
+{
+ SaveState();
+
+ hitPoint1 = hitPoint2 = hitLine = false;
+ Vector lineSegment = endpoint - position;
+ Vector v1 = point - position;
+ Vector v2 = point - endpoint;
+ double parameterizedPoint = lineSegment.Dot(v1) / lineSegment.Magnitude(), distance;
+
+ // Geometric interpretation:
+ // The parameterized point on the vector lineSegment is where the perpendicular
+ // intersects lineSegment. If pp < 0, then the perpendicular lies beyond the 1st
+ // endpoint. If pp > length of ls, then the perpendicular lies beyond the 2nd endpoint.
+
+ if (parameterizedPoint < 0.0)
+ distance = v1.Magnitude();
+ else if (parameterizedPoint > lineSegment.Magnitude())
+ distance = v2.Magnitude();
+ else
+ // distance = ?Det?(ls, v1) / |ls|
+ distance = fabs((lineSegment.x * v1.y - v1.x * lineSegment.y) / lineSegment.Magnitude());
+
+ // Geometric interpretation of the above:
+ // If the segment endpoints are s and e, and the point is p, then the test
+ // for the perpendicular intercepting the segment is equivalent to insisting
+ // that the two dot products {s-e}.{s-p} and {e-s}.{e-p} are both non-negative.
+ // Perpendicular distance from the point to the segment is computed by first
+ // computing the area of the triangle the three points form, then dividing by
+ // the length of the segment. Distances are done just by the Pythagorean
+ // theorem. Twice the area of the triangle formed by three points is the
+ // determinant of the following matrix:
+ //
+ // sx sy 1 0 0 1 0 0 0
+ // ex ey 1 ==> ex ey 1 ==> ex ey 0
+ // px py 1 px py 1 px py 0
+ //
+ // By translating the start point to the origin, and subtracting row 1 from
+ // all other rows, we end up with the matrix on the right which greatly
+ // simplifies the calculation of the determinant.
+
+//How do we determine distance here? Especially if zoomed in or out???
+//#warning "!!! Distances tested for may not be valid if zoomed in or out !!!"
+// [FIXED]
+ if ((v1.Magnitude() * Painter::zoom) < 8.0)
+ hitPoint1 = true;
+ else if ((v2.Magnitude() * Painter::zoom) < 8.0)
+ hitPoint2 = true;
+ else if ((distance * Painter::zoom) < 5.0)
+ hitLine = true;
+
+ return StateChanged();
+}
+
+void Line::SaveState(void)
+{
+ oldHitPoint1 = hitPoint1;
+ oldHitPoint2 = hitPoint2;
+ oldHitLine = hitLine;
+}
+
+bool Line::StateChanged(void)
+{
+ if ((hitPoint1 != oldHitPoint1) || (hitPoint2 != oldHitPoint2) || (hitLine != oldHitLine))
+ return true;
+
+ return false;