]> Shamusworld >> Repos - architektonas/commitdiff
Added ability to translate groups with Lines.
authorShamus Hammons <jlhamm@acm.org>
Sun, 11 Aug 2013 01:49:20 +0000 (20:49 -0500)
committerShamus Hammons <jlhamm@acm.org>
Sun, 11 Aug 2013 01:49:20 +0000 (20:49 -0500)
15 files changed:
TODO [new file with mode: 0644]
res/architektonas.qrc
res/connect-tool.png [new file with mode: 0644]
res/disconnect-tool.png [new file with mode: 0644]
src/applicationwindow.cpp
src/applicationwindow.h
src/container.cpp
src/container.h
src/dimension.cpp
src/line.cpp
src/line.h
src/object.cpp
src/object.h
src/vector.cpp
src/vector.h

diff --git a/TODO b/TODO
new file mode 100644 (file)
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
+
index 8e79c6d54181c3003c0daeb9a27ca022556c2a23..16d12d0cb99a9b8bf354d20fb56931286b3cd1ef 100644 (file)
@@ -22,5 +22,7 @@
                <file>eye-closed.png</file>
                <file>lock-open.png</file>
                <file>lock-closed.png</file>
+               <file>connect-tool.png</file>
+               <file>disconnect-tool.png</file>
        </qresource>
 </RCC>
diff --git a/res/connect-tool.png b/res/connect-tool.png
new file mode 100644 (file)
index 0000000..daac138
Binary files /dev/null and b/res/connect-tool.png differ
diff --git a/res/disconnect-tool.png b/res/disconnect-tool.png
new file mode 100644 (file)
index 0000000..e7ae516
Binary files /dev/null and b/res/disconnect-tool.png differ
index bf181a882d50629fb27c30e079a34c4ba29af86f..daae37cf0e4fd61898f1eac1998d1184e7c91922 100644 (file)
@@ -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);
index 0db2265340fb9969ff79dbe7da1834c257438626..8322abced90307c2f43a834567b2754baae67a76 100644 (file)
@@ -89,6 +89,8 @@ class ApplicationWindow: public QMainWindow
                QAction * zoomOutAct;
                QAction * snapToGridAct;
                QAction * groupAct;
+               QAction * connectAct;
+               QAction * disconnectAct;
 };
 
 #endif // __APPLICATIONWINDOW_H__
index e909c04ae14b1ba8f9a7e6c0af4b2464cf76aff0..757828aad73e064af821d04816807a82fa93702a 100644 (file)
@@ -72,21 +72,18 @@ Container & Container::operator=(const Container & from)
        QRectF boundary;
 
        for(std::vector<Object *>::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<Object *>::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<Object *>::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<Object *>::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<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
+               (*i)->PointerReleased();
 }
 
 
@@ -425,17 +465,10 @@ void Container::ResizeAllDimensions(double newSize)
 {
        for(std::vector<Object *>::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; i<objects.size(); i++)
                objects[i]->Enumerate(file);
 
-       if (parent != NULL)
+//     if (parent != NULL)
+       if (!isTopLevelContainer)
                fprintf(file, "ENDCONTAINER\n");
 }
 
index 6be759dc0090e87b03c101a6d0cbd2082b914486..fd574daa4fbadd68836961471476f4c575aa58c3 100644 (file)
@@ -44,6 +44,7 @@ class Container: public Object
                bool draggingHandle1;
                bool draggingHandle2;
                bool objectWasDragged;
+               bool hit;
 };
 
 #endif // __CONTAINER_H__
index 2b49ff8d08e3d7564c5ae2c9c37ad223ec901188..6f561be7da4896efd7b5226277bde827bd3c91f8 100644 (file)
@@ -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);
index aa5054bab3da9ea9bb79ca65b8cf695093ccb687..9054bbc8c2bcda9be454356eb552a4e3ab76a423 100644 (file)
@@ -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.
index fb17f2e2f41d9601108150bb0c9fb9db0b081ac0..3d46551d6d1bedb7fe19a66fe5b2711068c8feaa 100644 (file)
@@ -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);
 
index 99d73ce7c5b61a628adce7ed53027b13f0418c0e..523601dd755b438f20e0857bad2a127b0aa33f2e 100644 (file)
@@ -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;
index 532723a73229c7bc360955e9bbcb0e1764625ac0..513b677fba566421b6999859b705a8d051e76fba 100644 (file)
@@ -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);
index ab1433f9c6a5123e6ca6a8475cbe852210ecb933..23bd783cf2fcce61dd3c6ab6627972ca7678813a 100644 (file)
@@ -248,7 +248,15 @@ double Vector::Parameter(Vector v1, Vector v2, Vector p)
        double magnitude = lineSegment.Magnitude();\r
        Vector pointSegment = p - v1;\r
        double t = lineSegment.Dot(pointSegment) / (magnitude * magnitude);\r
-\r
        return t;\r
 }\r
 \r
+\r
+// Return the normal to the linesegment formed by the passed in points.\r
+// (Not sure which is head or tail, or which hand the normal lies)\r
+/*static*/ Vector Vector::Normal(Vector v1, Vector v2)\r
+{\r
+       Vector v = (v2 - v1).Unit();\r
+       return Vector(-v.y, v.x);\r
+}\r
+\r
index 0e7fc864f371c4d3c3478a47c9119c583ff3948d..6c0ad200e067051ea646042a6ce4451ecd8f731e 100644 (file)
@@ -48,6 +48,7 @@ class Vector
                static double Dot(Vector v1, Vector v2);\r
                static double Magnitude(Vector v1, Vector v2);\r
                static double Parameter(Vector v1, Vector v2, Vector p);\r
+               static Vector Normal(Vector v1, Vector v2);\r
 \r
        public:\r
                double x, y, z;\r