From 70297ac8ec7453e4196f4b58056bcfe4b04f2aca Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Sat, 10 Aug 2013 20:49:20 -0500 Subject: [PATCH] Added ability to translate groups with Lines. --- TODO | 23 +++++++++ res/architektonas.qrc | 2 + res/connect-tool.png | Bin 0 -> 1921 bytes res/disconnect-tool.png | Bin 0 -> 1907 bytes src/applicationwindow.cpp | 8 +++ src/applicationwindow.h | 2 + src/container.cpp | 101 +++++++++++++++++++++++++------------- src/container.h | 1 + src/dimension.cpp | 8 ++- src/line.cpp | 99 ++++++++++++++++++++----------------- src/line.h | 3 ++ src/object.cpp | 15 ++++++ src/object.h | 3 ++ src/vector.cpp | 10 +++- src/vector.h | 1 + 15 files changed, 194 insertions(+), 82 deletions(-) create mode 100644 TODO create mode 100644 res/connect-tool.png create mode 100644 res/disconnect-tool.png diff --git a/TODO b/TODO new file mode 100644 index 0000000..540d541 --- /dev/null +++ b/TODO @@ -0,0 +1,23 @@ +Stuff To Be Implemented/Fixed +----------------------------- + + - Add Arc + - Add Polygon + - Manipulate Dimension + - Object connections + - Group selection (kind done, needs more work though) + - Take movement code out of Objects and put it into top level Container + - Fix snap to grid to honor both states (right now, it's a weird mix of states) + - Add OSD routines so they don't have to be implemented in Objects + - Add OSD to Object creation + - Add layers + - Add blocks + - Add page layout + - Add pen color/style/width to Objects + - Add fill/hatch to Objects + - Fix zooming to be more intuitive + - Add other Dimension types, like radial, diametric, leader + - Add Ellipse + - Add Spline + - Add Text + diff --git a/res/architektonas.qrc b/res/architektonas.qrc index 8e79c6d..16d12d0 100644 --- a/res/architektonas.qrc +++ b/res/architektonas.qrc @@ -22,5 +22,7 @@ eye-closed.png lock-open.png lock-closed.png + connect-tool.png + disconnect-tool.png diff --git a/res/connect-tool.png b/res/connect-tool.png new file mode 100644 index 0000000000000000000000000000000000000000..daac138689f7efcb8876c83ee5905e3604cb5f6b GIT binary patch literal 1921 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 Hu0mjfSfjE- literal 0 HcmV?d00001 diff --git a/res/disconnect-tool.png b/res/disconnect-tool.png new file mode 100644 index 0000000000000000000000000000000000000000..e7ae516c4506e5acb7077ed6e0c038ad8c72eb85 GIT binary patch literal 1907 zcmV-(2aNcMP)tID1gt2K#p#`mC8|;cUL?3zMX^2-O#3TG6JPtHz z6K_aEdtpo)0xfMRnqV8FsHqtj!Jx3-Nzx`hdpL1o$98<|*eNZaWHqtlbNu@*zweTi z7-M*qMZzmC%6bDtM3!@nyj)q&z}I~U5K;BWWHPvX`7%zPJc+AUuVQR$Ol*y{N`mzk zA0Hn_GMR)d%hl`YblNop);tMjG8x>wc@wc%46-bPF$N;S%*@RC^#G&wRaLEm)~&s; zuz%!cxFJRswxo?7-NXVVnX2kgaB&*9xm4c5oQqM`E)wXG);pfNw|CW zuDC)ygn;M=!}0>5{j=FD?cKXq*aJir;MKCU8sH6KLL%Tr6(ADtEJOv^?msm(rQ<|8 zoo0TG;HCgCWEX}KEc;JRPLiT1Cif;HY~8xmmlFKc0iiR!ljL%_DtJxPplKQa;KGFq zRksha8S<)8s=J3ZsVvj}s;ZJCNv3pIEEaL;(j}ZYaiY;06jV3ZGRy1v-0qxS^c0Il zWHK2yBec93q9E#m`W&ySDjBQ2LZN_(i3z8cmx53LTTSabo!2xCM1*`kk3)wJiROCN z>VXLPwY(j8V~HzCQnkZdOA{d>GBh+Z%xFH@4 zK77~&Jcv#QNckkpTPlfzbU|u3SMp9!D~n#K6FSuQIwR*JxlI zAr>_$ASwgz#esoNurp=_h)!%Ayv3^$gu7X#S;8~PCn=z>4eT2m>-R-~{oQ;=jex%w zfNOK2-p2$L!Ga_~@&tZ&0_bbEy^VGy2nTuqh4^&|z&r6q>rw-N%)@zC9EwM`vR~}& z4q#`(*78I|IJ()+*WE^9jd&=qFKHA%v1N(pJzZdD9Z0Xg6VU2>O=G~FMgF=|0k(Gl z^CjTlWni&n2OzXBW)y*im>^MEZ{8Ro4EGowhk&1-0r&I#ZI=QZ?B%Jm#DMWx;C87I zAQmL}PzNHkv7N`g(OI4pYv4O%;L9Ek9^m}2DI)SLZbvAku<+tk5ey|Oq-SvZU!K?A zf6)!Z>m0CMZh0>t%mEg5KG4Hcn=XGX0@r5w>!H_x-gff>6N^B;%wK<;0(#r5qUk#6Dnjo*rP&|X* z76tYsYv37xu?qMtQQ-Zg`SWE4{5j8Gf7%6Xi(9#Db_KXT7e?F7+?3$G68xZx|2^~2 zYNmZ%WMP%X67Xc1Gyb-iJ&`|Mu7*d@EwGys6i?O%7`}hxe8UFGYW>L+DN)Yt`F|!!ASYg0V(?CQ9zUr}0A`HNdIqo3=SziZQuLvh4ICg_} znzWTo?SzA`TY+U~c$ypNbgrgv%mcsAhc*GS!%(jT#W!$(uq6t7-fcdsF<_)ZiYD-N zF7i(vxV;qW_=_<{cAjAJ6ywGoz&Dnm1ff6STsqxe1a2%i5}(L(i01o7Yca;iIM!k< zIrjIsj^tYPET-=T0<*rG#1+yzzNYynh!AN?0Y^6zUX+0!o&x!@=N{cp+y|u`3kMi- zzP}CLicr0KLj&;R6X4m3#qC2GaJt32QypL`cy=cUgNd3d&OQ`-+It0ajw>-!cWoc{6OW`H|OyvE;`0@}#A3^slP$H7G;J_0A#hiU0_$18ZN2jt7Ze-+aDC{+Wf z0r>SfaH}%Oy`MLiwO{uUGV$tMuGLoe3%=?BCL#oYsKopCD)?u>y-IkbJAe<9fF6E& z*B4+%7dB}3p=e$MCYE@wer>h}o)chgc&SycuLAhMh}7;!$qi+=7ueWV>-s8$w`TwU t(6a*GXyX%}$Hg^md69vLXdGfK%m0Syf!nMXZV&(f002ovPDHLkV1n2`cFX_( literal 0 HcmV?d00001 diff --git a/src/applicationwindow.cpp b/src/applicationwindow.cpp index bf181a8..daae37c 100644 --- a/src/applicationwindow.cpp +++ b/src/applicationwindow.cpp @@ -578,6 +578,10 @@ void ApplicationWindow::CreateActions(void) groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g")); connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping())); + connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c")); + + disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d")); + //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing... // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick. /* QActionGroup * group = new QActionGroup(this); @@ -646,6 +650,8 @@ void ApplicationWindow::CreateMenus(void) menu->addAction(fixAngleAct); menu->addAction(fixLengthAct); menu->addAction(rotateAct); + menu->addAction(connectAct); + menu->addAction(disconnectAct); menu->addSeparator(); menu->addAction(deleteAct); menu->addSeparator(); @@ -687,6 +693,8 @@ void ApplicationWindow::CreateToolbars(void) toolbar->addAction(fixLengthAct); toolbar->addAction(rotateAct); toolbar->addAction(deleteAct); + toolbar->addAction(connectAct); + toolbar->addAction(disconnectAct); toolbar->addSeparator(); toolbar->addAction(addLineAct); toolbar->addAction(addCircleAct); diff --git a/src/applicationwindow.h b/src/applicationwindow.h index 0db2265..8322abc 100644 --- a/src/applicationwindow.h +++ b/src/applicationwindow.h @@ -89,6 +89,8 @@ class ApplicationWindow: public QMainWindow QAction * zoomOutAct; QAction * snapToGridAct; QAction * groupAct; + QAction * connectAct; + QAction * disconnectAct; }; #endif // __APPLICATIONWINDOW_H__ diff --git a/src/container.cpp b/src/container.cpp index e909c04..757828a 100644 --- a/src/container.cpp +++ b/src/container.cpp @@ -72,21 +72,18 @@ Container & Container::operator=(const Container & from) QRectF boundary; for(std::vector::iterator i=objects.begin(); i!=objects.end(); i++) -// for(int i=0; i<(int)objects.size(); i++) { -#if 0 -//printf("Container: About to draw (object = $%X)\n", objects[i]); - objects[i]->Draw(painter); - bounds = bounds.united(objects[i].RectangularExtents()); -#else (*i)->Draw(painter); boundary = boundary.united((*i)->Extents()); -#endif } - if (state == OSSelected) + if ((state == OSSelected) || hit) { - painter->SetPen(QPen(Qt::magenta, 2.0, Qt::DashLine)); + if (hit) + painter->SetPen(QPen(Qt::magenta, 1.0, Qt::DashLine)); + else + painter->SetPen(QPen(Qt::blue, 2.0, Qt::DashLine)); + painter->SetBrush(QBrush(Qt::NoBrush)); painter->DrawRect(boundary); } @@ -98,6 +95,7 @@ Container & Container::operator=(const Container & from) return position; } + /* We need at least *three* handles for this object: - one for moving @@ -163,7 +161,11 @@ printf("Container::Collided: Deleting object ($%X)\n", *i); state = (collision ? OSSelected : OSInactive); if (state == OSSelected) + { DeselectAll(); + dragging = true; + oldPoint = point; + } } return collision; @@ -191,34 +193,62 @@ class so that we can leverage that stuff here as well. // every object for collision. /*virtual*/ void Container::PointerMoved(Vector point) { + std::vector::iterator i; + if (!isTopLevelContainer) { // check for selection rectangle too + if (selectionInProgress) + { + if (selection.contains(Extents())) + state = OSSelected; + else + state = OSInactive; + return; + } - needUpdate = true; + // No need to do any checking if we're already selected... +// if (state == OSSelected) +// return; - for(std::vector::iterator i=objects.begin(); i!=objects.end(); i++) +// oldState = state; +// needUpdate = true; +// if (dragging && + bool oldHit = hit; + hit = false; + + for(i=objects.begin(); i!=objects.end(); i++) { if ((*i)->HitTest(point)) { - state = OSSelected; - return; +// state = OSSelected; +// return; + hit = true; + break; } } - state = OSInactive; + needUpdate = (oldHit != hit ? true : false); +// state = oldState; + + if (dragging) + { + Vector delta = point - oldPoint; + + for(i=objects.begin(); i!=objects.end(); i++) + (*i)->Translate(delta); + + oldPoint = point; + needUpdate = true; + } + return; } -// objectWasDragged = true; -//printf("CONTAINER: PointerMoved()\n"); - for(std::vector::iterator i=objects.begin(); i!=objects.end(); i++) -// for(int i=0; i<(int)objects.size(); i++) { -//// if (objects[i]->GetState() == OSSelected) -// objects[i]->PointerMoved(point); +// if (objects[i]->GetState() == OSSelected) (*i)->PointerMoved(point); } @@ -229,6 +259,12 @@ class so that we can leverage that stuff here as well. /*virtual*/ void Container::PointerReleased(void) { + if (!isTopLevelContainer) + { + dragging = false; + return; + } +#if 0 dragging = false; draggingHandle1 = false; draggingHandle2 = false; @@ -236,15 +272,19 @@ class so that we can leverage that stuff here as well. // Here we check for just a click: If object was clicked and dragged, then // revert to the old state (OSInactive). Otherwise, keep the new state that // we set. -/*Maybe it would be better to just check for "object was dragged" state and not have to worry -about keeping track of old states... +/* +Maybe it would be better to just check for "object was dragged" state and not +have to worry about keeping track of old states... */ if (objectWasDragged) state = oldState; //Note that the preceeding is unnecessary for a generic container! +#endif - for(int i=0; i<(int)objects.size(); i++) - objects[i]->PointerReleased(); +// for(int i=0; i<(int)objects.size(); i++) +// objects[i]->PointerReleased(); + for(std::vector::iterator i=objects.begin(); i!=objects.end(); i++) + (*i)->PointerReleased(); } @@ -425,17 +465,10 @@ void Container::ResizeAllDimensions(double newSize) { for(std::vector::iterator i=objects.begin(); i!=objects.end(); i++) { -// Object * object = *i; - if ((*i)->type == OTDimension) -// if (object->type == OTDimension) - { ((Dimension *)(*i))->size = newSize; - } if ((*i)->type == OTContainer) - { ((Container *)(*i))->ResizeAllDimensions(newSize); - } } } @@ -443,13 +476,15 @@ void Container::ResizeAllDimensions(double newSize) /*virtual*/ void Container::Enumerate(FILE * file) { // Only put "CONTAINER" markers if *not* the top level container - if (parent != NULL) +// if (parent != NULL) + if (!isTopLevelContainer) fprintf(file, "CONTAINER\n"); for(uint i=0; iEnumerate(file); - if (parent != NULL) +// if (parent != NULL) + if (!isTopLevelContainer) fprintf(file, "ENDCONTAINER\n"); } diff --git a/src/container.h b/src/container.h index 6be759d..fd574da 100644 --- a/src/container.h +++ b/src/container.h @@ -44,6 +44,7 @@ class Container: public Object bool draggingHandle1; bool draggingHandle2; bool objectWasDragged; + bool hit; }; #endif // __CONTAINER_H__ diff --git a/src/dimension.cpp b/src/dimension.cpp index 2b49ff8..6f561be 100644 --- a/src/dimension.cpp +++ b/src/dimension.cpp @@ -92,10 +92,14 @@ 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, 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)); //printf("Dimension::Draw(): t = %lf\n", t); - if (t > 0.42) +// On the screen, it's acting like this is actually 58%... +// This is correct, we want it to happen at > 50% + if (t > 0.58) { // Draw main dimension line + arrowheads painter->DrawLine(p1, p2); diff --git a/src/line.cpp b/src/line.cpp index aa5054b..9054bbc 100644 --- a/src/line.cpp +++ b/src/line.cpp @@ -132,8 +132,11 @@ Line::~Line() { // We can assume this, since this is a mouse down event here. objectWasDragged = false; + SaveState(); HitTest(point); +// return StateChanged(); +// this is shite. this should be checked for in the Container, not here! // If we're part of a non-top-level container, send this signal to it if (parent->type == OTContainer && !((Container *)parent)->isTopLevelContainer && (hitLine || hitPoint1 || hitPoint2)) @@ -300,8 +303,10 @@ Like so: #if 0 if (selection.normalized().contains(Extents())) #else - if (selection.normalized().contains(position.x, position.y) - && selection.normalized().contains(endpoint.x, endpoint.y)) +// if (selection.normalized().contains(position.x, position.y) +// && selection.normalized().contains(endpoint.x, endpoint.y)) + if (selection.contains(position.x, position.y) + && selection.contains(endpoint.x, endpoint.y)) #endif state = OSSelected; else @@ -310,9 +315,11 @@ Like so: return; } - // Hit test tells us what we hit (if anything) through boolean variables. It - // also tells us whether or not the state changed. - needUpdate = HitTest(point); + // 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) + SaveState(); + HitTest(point); + needUpdate = StateChanged(); objectWasDragged = (draggingLine | draggingHandle1 | draggingHandle2); @@ -363,16 +370,6 @@ try to do the right thing, most of the time. :-) 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; - - //bleh - if (!Object::fixedLength) - v2 = point2; -#endif - if (Object::fixedAngle) { // Here we calculate the component of the current vector along the fixed angle. @@ -424,22 +421,21 @@ the horizontal line or vertical line that intersects from the current mouse posi } else // endpoint { -// Vector v1 = endpoint - position; Vector v = Vector(endpoint - position).Unit() * length; endpoint = position + v; } } else { - // Otherwise, we calculate the new length, just in case on the next move - // it turns out to have a fixed length. :-) + // 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(); } if (!Object::fixedAngle) { - // Calculate the new angle, just in case on the next move it turns out to - // be fixed. :-) + // Calculate the new angle, just in case on the next move it turns + // out to be fixed. :-) angle = Vector(endpoint - position).Unit(); } } @@ -448,14 +444,6 @@ the horizontal line or vertical line that intersects from the current mouse posi draggingHandle1 = false; draggingHandle2 = false; -// hitPoint1 = hitPoint2 = hitLine = false; - - // Here we check for just a click: If object was clicked and dragged, then - // revert to the old state (OSInactive). Otherwise, keep the new state that - // we set. -/*Maybe it would be better to just check for "object was dragged" state and not have to worry -about keeping track of old states... -*/ if (objectWasDragged) state = oldState; } @@ -463,28 +451,23 @@ about keeping track of old states... /*virtual*/ bool Line::HitTest(Point point) { - SaveState(); +// 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; + double t = Vector::Parameter(position, endpoint, point); + double 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()); + // The parameter "t" on the vector lineSegment is where the normal of + // lineSegment coincides with point. If t < 0, the normal lies beyond the + // 1st endpoint. If t > 1, then the normal lies beyond the 2nd endpoint. We + // only calculate the length of the normal between the point and the + // lineSegment when the parameter is between 0 and 1. - // Geometric interpretation of the above: + // Geometric interpretation of "distance = ?Det?(ls, v1) / |ls|": // 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. @@ -502,9 +485,15 @@ about keeping track of old states... // 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 (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) @@ -512,7 +501,8 @@ about keeping track of old states... else if ((distance * Painter::zoom) < 5.0) hitLine = true; - return StateChanged(); + return (hitPoint1 | hitPoint2 | hitLine ? true : false); +// return StateChanged(); } @@ -579,6 +569,23 @@ you then *definitely* do not want them to have the same reference number. } +/*virtual*/ void Line::Translate(Vector amount) +{ + position += amount; + endpoint += amount; +} + + +/*virtual*/ void Line::Rotate(Vector point, double angle) +{ +} + + +/*virtual*/ void Line::Scale(Vector point, double amount) +{ +} + + void Line::SetDimensionOnLine(Dimension * dimension/*=NULL*/) { // If they don't pass one in, create it for the caller. diff --git a/src/line.h b/src/line.h index fb17f2e..3d46551 100644 --- a/src/line.h +++ b/src/line.h @@ -23,6 +23,9 @@ class Line: public Object virtual Vector GetPointAtParameter(double parameter); virtual QRectF Extents(void); // virtual ObjectType Type(void); + virtual void Translate(Vector); + virtual void Rotate(Vector, double); + virtual void Scale(Vector, double); void SetDimensionOnLine(Dimension * d = 0); Object * FindAttachedDimension(void); diff --git a/src/object.cpp b/src/object.cpp index 99d73ce..523601d 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -189,6 +189,21 @@ printf("Object: Destroyed!\n"); #endif +/*virtual*/ void Object::Translate(Vector) +{ +} + + +/*virtual*/ void Object::Rotate(Vector, double) +{ +} + + +/*virtual*/ void Object::Scale(Vector, double) +{ +} + + ObjectState Object::GetState(void) { return state; diff --git a/src/object.h b/src/object.h index 532723a..513b677 100644 --- a/src/object.h +++ b/src/object.h @@ -41,6 +41,9 @@ class Object virtual void DisconnectAll(Object *); virtual QRectF Extents(void); // virtual ObjectType Type(void);// = 0; // Pure virtual, must be implemented + virtual void Translate(Vector); + virtual void Rotate(Vector, double); + virtual void Scale(Vector, double); ObjectState GetState(void); void Reparent(Object *); // Dimension * GetAttachedDimension(void); diff --git a/src/vector.cpp b/src/vector.cpp index ab1433f..23bd783 100644 --- a/src/vector.cpp +++ b/src/vector.cpp @@ -248,7 +248,15 @@ double Vector::Parameter(Vector v1, Vector v2, Vector p) double magnitude = lineSegment.Magnitude(); Vector pointSegment = p - v1; double t = lineSegment.Dot(pointSegment) / (magnitude * magnitude); - return t; } + +// Return the normal to the linesegment formed by the passed in points. +// (Not sure which is head or tail, or which hand the normal lies) +/*static*/ Vector Vector::Normal(Vector v1, Vector v2) +{ + Vector v = (v2 - v1).Unit(); + return Vector(-v.y, v.x); +} + diff --git a/src/vector.h b/src/vector.h index 0e7fc86..6c0ad20 100644 --- a/src/vector.h +++ b/src/vector.h @@ -48,6 +48,7 @@ class Vector static double Dot(Vector v1, Vector v2); static double Magnitude(Vector v1, Vector v2); static double Parameter(Vector v1, Vector v2, Vector p); + static Vector Normal(Vector v1, Vector v2); public: double x, y, z; -- 2.37.2