X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdimension.cpp;h=c9777e50bd673688bc5d06dee646c6a4753cd19d;hb=2549a213bacfb2f6993ec143083d72b716854345;hp=2dc7fce924956d2f51c070d390b3e7cd0aecb22b;hpb=669a05b5a52bd759f0ea08772e0ed17222b015a0;p=architektonas diff --git a/src/dimension.cpp b/src/dimension.cpp index 2dc7fce..c9777e5 100644 --- a/src/dimension.cpp +++ b/src/dimension.cpp @@ -15,6 +15,7 @@ #include "dimension.h" #include +#include "geometry.h" #include "mathconstants.h" #include "painter.h" @@ -43,6 +44,21 @@ Dimension::~Dimension() } +/* +The approach used below creates a hierarchy: Dimension is subservient to Line. + +Does this solve our problem of connected objects? Maybe, partially. Let's think this +through. It only works for endpoints, not points in the middle... + +Also: this is bad, depending on the Draw() function to update the internal + position(s) of the data of the object! (is it though?) + +How to move: click once moves only the object/point clicked on, all connected +objects deform themselves accordingly. click twice selects ALL connected objects; +all objects move as a unified whole. + +*/ + /*virtual*/ void Dimension::Draw(Painter * painter) { // If there are valid Vector pointers in here, use them to update the internal @@ -53,10 +69,19 @@ Dimension::~Dimension() if (point2.object) endpoint = point2.object->GetPointAtParameter(point2.t); + painter->SetPen(QPen(Qt::magenta, 2.0, Qt::DotLine)); + + if ((state == OSSelected) || ((state == OSInactive) && hitPoint1)) + painter->DrawHandle(position); + + if ((state == OSSelected) || ((state == OSInactive) && hitPoint2)) + painter->DrawHandle(endpoint); +#if 0 if (state == OSSelected) painter->SetPen(QPen(Qt::red, 2.0, Qt::DotLine)); else // painter->SetPen(QPen(Qt::blue, 1.0, Qt::SolidLine)); +#endif painter->SetPen(QPen(Qt::blue, 1.0 * Painter::zoom * size, Qt::SolidLine)); painter->SetBrush(QBrush(QColor(Qt::blue))); @@ -93,8 +118,7 @@ I believe they are pixels. // Calculate whether or not the arrowheads are too crowded to put inside // the extension lines. 9.0 is the length of the arrowhead. // double t = Vector::Parameter(position, endpoint, endpoint - (unit * 9.0 * size)); -// double t = Vector::Parameter(position, endpoint, position + (unit * 9.0 * size)); - double t = Vector::Parameter(endpoint, position, position + (unit * 9.0 * size)); + double t = Geometry::ParameterOfLineAndPoint(position, endpoint, endpoint - (unit * 9.0 * size)); //printf("Dimension::Draw(): t = %lf\n", t); // On the screen, it's acting like this is actually 58%... @@ -154,101 +178,37 @@ I believe they are pixels. } -/*virtual*/ bool Dimension::Collided(Vector /*point*/) +/*virtual*/ bool Dimension::Collided(Vector point) { -#if 0 + // Someone told us to fuck off, so we'll fuck off. :-) + if (ignoreClicks) + return false; + + // We can assume this, since this is a mouse down event here. objectWasDragged = false; - Vector lineSegment = endpoint - position; - Vector v1 = point - position; - Vector v2 = point - endpoint; - double parameterizedPoint = lineSegment.Dot(v1) / lineSegment.Magnitude(), distance; - - // Geometric interpretation: - // pp is the paremeterized point on the vector ls where the perpendicular intersects ls. - // 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()); - - // 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 - // ex ey 1 - // px py 1 - // - // By translating the start point to the origin, this can be rewritten as: - // By subtracting row 1 from all rows, you get the following: - // [because sx = sy = 0. you could leave out the -sx/y terms below. because we subtracted - // row 1 from all rows (including row 1) row 1 turns out to be zero. duh!] - // - // 0 0 0 0 0 0 - // (ex - sx) (ey - sy) 0 ==> ex ey 0 - // (px - sx) (py - sy) 0 px py 0 - // - // which greatly simplifies the calculation of the determinant. - - if (state == OSInactive) + HitTest(point); + + // Now that we've done our hit testing on the non-snapped point, snap it if + // necessary... + if (snapToGrid) + point = SnapPointToGrid(point); + + if (hitPoint1) { -//printf("Line: pp = %lf, length = %lf, distance = %lf\n", parameterizedPoint, lineSegment.Magnitude(), distance); -//printf(" v1.Magnitude = %lf, v2.Magnitude = %lf\n", v1.Magnitude(), v2.Magnitude()); -//printf(" point = %lf,%lf,%lf; p1 = %lf,%lf,%lf; p2 = %lf,%lf,%lf\n", point.x, point.y, point.z, position.x, position.y, position.z, endpoint.x, endpoint.y, endpoint.z); -//printf(" \n", ); -//How to translate this into pixels from Document space??? -//Maybe we need to pass a scaling factor in here from the caller? That would make sense, as -//the caller knows about the zoom factor and all that good kinda crap - if (v1.Magnitude() < 10.0) - { - oldState = state; - state = OSSelected; - oldPoint = position; //maybe "position"? - draggingHandle1 = true; - return true; - } - else if (v2.Magnitude() < 10.0) - { - oldState = state; - state = OSSelected; - oldPoint = endpoint; //maybe "position"? - draggingHandle2 = true; - return true; - } - else if (distance < 2.0) - { - oldState = state; - state = OSSelected; - oldPoint = point; - dragging = true; - return true; - } + oldState = state; + state = OSSelected; + oldPoint = position; + draggingHandle1 = true; + return true; } - else if (state == OSSelected) + else if (hitPoint2) { - // Here we test for collision with handles as well! (SOON!) -/* -Like so: - if (v1.Magnitude() < 2.0) // Handle #1 - else if (v2.Magnitude() < 2.0) // Handle #2 -*/ - if (distance < 2.0) - { - oldState = state; -// state = OSInactive; - oldPoint = point; - dragging = true; - return true; - } + oldState = state; + state = OSSelected; + oldPoint = endpoint; + draggingHandle2 = true; + return true; } -#endif state = OSInactive; return false; @@ -257,12 +217,13 @@ Like so: /*virtual*/ void Dimension::PointerMoved(Vector point) { +#if 0 // We know this is true because mouse move messages don't come here unless // the object was actually clicked on--therefore we *know* we're being // dragged... objectWasDragged = true; - if (dragging) +/* if (dragging) { // Here we need to check whether or not we're dragging a handle or the object itself... Vector delta = point - oldPoint; @@ -273,7 +234,7 @@ Like so: oldPoint = point; needUpdate = true; } - else if (draggingHandle1) + else*/ if (draggingHandle1) { Vector delta = point - oldPoint; @@ -293,12 +254,35 @@ Like so: } else needUpdate = false; +#else + // Hit test tells us what we hit (if anything) through boolean variables. (It + // also tells us whether or not the state changed. --not any more) + SaveHitState(); + HitTest(point); + needUpdate = HitStateChanged(); + + objectWasDragged = (/*draggingLine |*/ draggingHandle1 | draggingHandle2); + + if (objectWasDragged) + { + Vector delta = point - oldPoint; + + if (draggingHandle1)// || draggingLine) + position += delta; + + if (draggingHandle2)// || draggingLine) + endpoint += delta; + + oldPoint = point; + needUpdate = true; + } +#endif } /*virtual*/ void Dimension::PointerReleased(void) { - if (draggingHandle1 || draggingHandle2) +/* if (draggingHandle1 || draggingHandle2) { // Set the length (in case the global state was set to fixed (or not)) if (Object::fixedLength) @@ -306,23 +290,22 @@ Like so: if (draggingHandle1) // startpoint { - Vector v = Vector(position - endpoint).Unit() * length; + Vector v = Vector(endpoint, position).Unit() * length; position = endpoint + v; } else // endpoint { -// Vector v1 = endpoint - position; - Vector v = Vector(endpoint - position).Unit() * length; + Vector v = Vector(position, endpoint).Unit() * length; endpoint = position + v; } } - else + else*/ { // Otherwise, we calculate the new length, just in case on the next move // it turns out to have a fixed length. :-) length = Vector(endpoint - position).Magnitude(); } - } +/* }*/ dragging = false; draggingHandle1 = false; @@ -339,9 +322,53 @@ about keeping track of old states... } +/*virtual*/ bool Dimension::HitTest(Point point) +{ + hitPoint1 = hitPoint2 = false; +// Vector lineSegment(position, endpoint); + Vector v1(position, point); + Vector v2(endpoint, point); +// double t = Geometry::ParameterOfLineAndPoint(position, endpoint, point); +// double distance; + +// if (t < 0.0) +// distance = v1.Magnitude(); +// else if (t > 1.0) +// distance = v2.Magnitude(); +// else + // distance = ?Det?(ls, v1) / |ls| +// distance = fabs((lineSegment.x * v1.y - v1.x * lineSegment.y) +// / lineSegment.Magnitude()); + + if ((v1.Magnitude() * Painter::zoom) < 8.0) + hitPoint1 = true; + else if ((v2.Magnitude() * Painter::zoom) < 8.0) + hitPoint2 = true; + + return (hitPoint1 || hitPoint2 ? true : false); +} + + +void Dimension::SaveHitState(void) +{ + oldHitPoint1 = hitPoint1; + oldHitPoint2 = hitPoint2; +// oldHitLine = hitLine; +} + + +bool Dimension::HitStateChanged(void) +{ + if ((hitPoint1 != oldHitPoint1) || (hitPoint2 != oldHitPoint2)) + return true; + + return false; +} + + /*virtual*/ void Dimension::Enumerate(FILE * file) { - fprintf(file, "DIMENSION (%lf,%lf) (%lf,%lf) %i\n", position.x, position.y, endpoint.x, endpoint.y, type); + fprintf(file, "DIMENSION %i (%lf,%lf) (%lf,%lf) %i\n", layer, position.x, position.y, endpoint.x, endpoint.y, type); }