X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fline.cpp;h=d37106e5a7846df0f9fe8fabed88aee129ea42c5;hb=9d59b5831000704a1ed39c22a6043ba658993159;hp=60e5ab0c1095ff67856aa5b333bf72a0d46afbcf;hpb=d41ddd699001f6bbf6ac621f5c467bd13efb6087;p=architektonas diff --git a/src/line.cpp b/src/line.cpp index 60e5ab0..d37106e 100644 --- a/src/line.cpp +++ b/src/line.cpp @@ -4,7 +4,7 @@ // (C) 2011 Underground Software // See the README and GPLv3 files for licensing and warranty information // -// JLH = James L. Hammons +// JLH = James Hammons // // WHO WHEN WHAT // --- ---------- ------------------------------------------------------------ @@ -20,15 +20,22 @@ #include #include "dimension.h" +#include "painter.h" + Line::Line(Vector p1, Vector p2, Object * p/*= NULL*/): Object(p1, p), endpoint(p2), draggingLine(false), draggingHandle1(false), draggingHandle2(false), //needUpdate(false), - length(Vector::Magnitude(p2, p1)), hitPoint1(false), hitPoint2(false), hitLine(false) + length(Vector::Magnitude(p2, p1)), angle(Vector(endpoint - position).Unit()), + hitPoint1(false), hitPoint2(false), hitLine(false) { } + Line::~Line() { +// Taking care of connections should be done by the Container, as we don't know +// anything about any other object connected to this one. +#if 0 // If there are any attached Dimensions, we must set the attachment points // to NULL since they will no longer be valid. if (attachedDimension) @@ -39,20 +46,22 @@ Line::~Line() // IT WOULD BE NICE to have any object points attached to this line automagically // connect to this dimension object at this point, instead of just becoming // detached. +#endif } -/*virtual*/ void Line::Draw(QPainter * painter) + +/*virtual*/ void Line::Draw(Painter * painter) { - painter->setPen(QPen(Qt::red, 2.0, Qt::DotLine)); + painter->SetPen(QPen(Qt::red, 2.0, Qt::DotLine)); if ((state == OSSelected) || ((state == OSInactive) && hitPoint1)) - painter->drawEllipse(QPointF(position.x, position.y), 4.0, 4.0); + painter->DrawHandle(position); if ((state == OSSelected) || ((state == OSInactive) && hitPoint2)) - painter->drawEllipse(QPointF(endpoint.x, endpoint.y), 4.0, 4.0); + painter->DrawHandle(endpoint); if ((state == OSInactive) && !hitLine) - painter->setPen(QPen(Qt::black, 1.0, Qt::SolidLine)); + painter->SetPen(QPen(Qt::black, 1.0, Qt::SolidLine)); if (Object::fixedLength && (draggingHandle1 || draggingHandle2)) { @@ -62,16 +71,21 @@ Line::~Line() Vector current(point2 - point1); Vector v = current.Unit() * length; Vector v2 = point1 + v; - painter->drawLine((int)point1.x, (int)point1.y, (int)v2.x, (int)v2.y); +// painter->DrawLine((int)point1.x, (int)point1.y, (int)v2.x, (int)v2.y); + painter->DrawLine(point1, v2); if (current.Magnitude() > length) { - painter->setPen(QPen(QColor(128, 0, 0), 1.0, Qt::DashLine)); - painter->drawLine((int)v2.x, (int)v2.y, (int)point2.x, (int)point2.y); + painter->SetPen(QPen(QColor(128, 0, 0), 1.0, Qt::DashLine)); +// painter->DrawLine((int)v2.x, (int)v2.y, (int)point2.x, (int)point2.y); + painter->DrawLine(v2, point2); } } +// Problem: when drawing at large zoom levels, this throws away precision thus +// causing the line to rendered too short. !!! FIX !!! [DONE] else - painter->drawLine((int)position.x, (int)position.y, (int)endpoint.x, (int)endpoint.y); +// painter->DrawLine((int)position.x, (int)position.y, (int)endpoint.x, (int)endpoint.y); + painter->DrawLine(position, endpoint); } /*virtual*/ Vector Line::Center(void) @@ -83,8 +97,7 @@ Line::~Line() /*virtual*/ bool Line::Collided(Vector point) { -// Can't assume this! -// Actually, we can, since this is a mouse down event here. + // We can assume this, since this is a mouse down event here. objectWasDragged = false; HitTest(point); @@ -97,7 +110,7 @@ We solve this by allowing only *one* Dimension object to be attached to the Line Arc, etc. and by giving the Dimension object a pointer to our endpoints. Problem still arises when we delete this object; The attached Dimension object will -then have bad pointers! What is *should* do is delete the object if and only if this +then have bad pointers! What it *should* do is delete the object if and only if this line is not attached to any other object. If it is, then one of those attachment points should be sent to the dimension object (done for position & endpoint). @@ -116,6 +129,7 @@ TODO: Make Dimension preview with modifier keys for showing on other side // (Priorities are taken care of in HitTest()...) if (hitLine) { +#if 0 if (attachedDimension == NULL) { // How to get this object into the top level container??? @@ -125,7 +139,7 @@ level container, it won't get drawn... But we can fix that by making this object call any attached object's (like a dimension only) Draw() function... :-/ */ - attachedDimension = new Dimension(&position, &endpoint, this); + attachedDimension = new Dimension(&position, &endpoint, DTLinear, this); if (parent != NULL) parent->Add(attachedDimension); @@ -135,6 +149,26 @@ a dimension only) Draw() function... :-/ // If there's one already there, tell it to flip sides... attachedDimension->FlipSides(); } +#else + // New approach here: We look for connected objects. + Object * attachedDimension = FindAttachedDimension(); + + if (attachedDimension) + { + // If there's an attached Dimension, tell it to switch sides... + ((Dimension *)attachedDimension)->FlipSides(); + } + else + { + // Otherwise, we make a new one and attach it here. + attachedDimension = new Dimension(Connection(this, 0), Connection(this, 1.0), DTLinear, this); + connected.push_back(Connection(attachedDimension, 0)); + connected.push_back(Connection(attachedDimension, 1.0)); + + if (parent != NULL) + parent->Add(attachedDimension); + } +#endif return true; } @@ -206,6 +240,7 @@ Like so: return false; } + /*virtual*/ void Line::PointerMoved(Vector point) { // Hit test tells us what we hit (if anything) through boolean variables. It @@ -257,6 +292,7 @@ software currently out there: the GUI will try to do the right thing, most of th Vector point1 = (draggingHandle1 ? endpoint : position); Vector point2 = (draggingHandle1 ? position : endpoint); +#if 0 Vector current(point2, point1); Vector v = current.Unit() * length; Vector v2 = point1 + v; @@ -264,6 +300,26 @@ software currently out there: the GUI will try to do the right thing, most of th //bleh if (!Object::fixedLength) v2 = point2; +#endif + + if (Object::fixedAngle) + { + // Here we calculate the component of the current vector along the fixed angle. + // A_compB = (A . Bu) * Bu + double magnitudeAlongB = Vector::Dot(Vector(point2 - point1), angle); +/* +Actually, this isn't quite right. What we want to do is look for the intersection along either +the horizontal line or vertical line that intersects from the current mouse position. +*/ + + if (draggingHandle1) + position = endpoint + (angle * magnitudeAlongB); + + if (draggingHandle2) + endpoint = position + (angle * magnitudeAlongB); + } +// else +// v2 = point2; //If we tell the dimension to flip sides, this is no longer a valid //assumption. !!! FIX !!! @@ -282,6 +338,7 @@ software currently out there: the GUI will try to do the right thing, most of th } } + /*virtual*/ void Line::PointerReleased(void) { if (draggingHandle1 || draggingHandle2) @@ -307,6 +364,13 @@ software currently out there: the GUI will try to do the right thing, most of th // it turns out to have a fixed length. :-) length = Vector(endpoint - position).Magnitude(); } + + if (!Object::fixedAngle) + { + // Calculate the new angle, just in case on the next move it turns out to + // be fixed. :-) + angle = Vector(endpoint - position).Unit(); + } } draggingLine = false; @@ -325,44 +389,115 @@ about keeping track of old states... state = oldState; } -#if 0 -void Line::SetDimensionOnPoint1(Dimension * dimension) + +// Check to see if the point passed in coincides with any we have. If so, return a +// pointer to it; otherwise, return NULL. +/*virtual*/ Vector * Line::GetPointAt(Vector v) { - dimPoint1 = dimension; + if (v == position) + return &position; + else if (v == endpoint) + return &endpoint; - if (dimension) - dimension->SetPoint1(position); + return 0; } -void Line::SetDimensionOnPoint2(Dimension * dimension) + +/*virtual*/ void Line::Enumerate(FILE * file) { - dimPoint2 = dimension; + fprintf(file, "LINE (%lf,%lf) (%lf,%lf)\n", position.x, position.y, endpoint.x, endpoint.y); +} - if (dimension) - dimension->SetPoint2(endpoint); + +/*virtual*/ Object * Line::Copy(void) +{ +#warning "!!! This doesn't take care of attached Dimensions !!!" +/* +This is a real problem. While having a pointer in the Dimension to this line's points is fast & easy, +it creates a huge problem when trying to replicate an object like this. + +Maybe a way to fix that then, is to have reference numbers instead of pointers. That way, if you copy +them, ... you might still have problems. Because you can't be sure if a copy will be persistant or not, +you then *definitely* do not want them to have the same reference number. +*/ + return new Line(position, endpoint, parent); } -#else + + +/*virtual*/ Vector Line::GetPointAtParameter(double parameter) +{ + if (parameter <= 0) + return position; + else if (parameter >= 1.0) + return endpoint; + + // Our parameter lies between zero and one, so calculate it! + Vector v(endpoint, position); + double length = v.Magnitude(); + // We scale the magnitude of v so that it lies between 0 and 1... + // By multiplying the parameter by the magnitude, we obtain the point we + // want. No scaling necessary as it's inherent in the approach! + double spotOnLength = length * parameter; + + // To get our point, we use the initial point of the line and add in our + // scaled point. + Vector result = position + (v * spotOnLength); + return result; +} + + void Line::SetDimensionOnLine(Dimension * dimension/*=NULL*/) { // If they don't pass one in, create it for the caller. if (dimension == NULL) { - dimension = new Dimension(&position, &endpoint, this); +//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); +} - attachedDimension = dimension; - // After we set the points here, we don't have to care about them anymore. - if (dimension) +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; iSetPoint1(&position); - dimension->SetPoint2(&endpoint); + for(uint j=i+1; j