]> Shamusworld >> Repos - architektonas/commitdiff
Added bounding calcs to Arc, more fixes for groups.
authorShamus Hammons <jlhamm@acm.org>
Thu, 11 Jul 2013 20:38:47 +0000 (15:38 -0500)
committerShamus Hammons <jlhamm@acm.org>
Thu, 11 Jul 2013 20:38:47 +0000 (15:38 -0500)
14 files changed:
architektonas.pro
src/arc.cpp
src/blockwidget.cpp [new file with mode: 0644]
src/blockwidget.h [new file with mode: 0644]
src/container.cpp
src/container.h
src/drawlineaction.cpp
src/layerwidget.cpp [new file with mode: 0644]
src/layerwidget.h [new file with mode: 0644]
src/line.cpp
src/line.h
src/mathconstants.h
src/object.cpp
src/object.h

index a634111d69402ccbc0beddaf2fa7e5dd860a7720..609aaf677e8bb061691c4229d368522a9031e083 100644 (file)
@@ -45,6 +45,7 @@ HEADERS = \
        src/action.h \
        src/applicationwindow.h \
        src/arc.h \
+       src/blockwidget.h \
        src/circle.h \
        src/connection.h \
        src/container.h \
@@ -57,6 +58,7 @@ HEADERS = \
        src/ellipse.h \
        src/fileio.h \
        src/generaltab.h \
+       src/layerwidget.h \
        src/line.h \
        src/main.h \
        src/mathconstants.h \
@@ -71,6 +73,7 @@ SOURCES = \
        src/action.cpp \
        src/applicationwindow.cpp \
        src/arc.cpp \
+       src/blockwidget.cpp \
        src/circle.cpp \
        src/connection.cpp \
        src/container.cpp \
@@ -83,6 +86,7 @@ SOURCES = \
        src/ellipse.cpp \
        src/fileio.cpp \
        src/generaltab.cpp \
+       src/layerwidget.cpp \
        src/line.cpp \
        src/main.cpp \
        src/object.cpp \
index 8fc66319bbe540ef96a153ed193c6ec4635993e9..355d7a76f2b5b425ddc5b882f7e21e86a22d8dc4 100644 (file)
@@ -121,6 +121,7 @@ Arc::~Arc()
        }
 
        painter->DrawArc(position, radius, startAngle, angleSpan);
+//     painter->DrawRect(Extents());
 }
 
 
@@ -236,6 +237,17 @@ so let's do like this:
 
 /*virtual*/ void Arc::PointerMoved(Vector point)
 {
+       if (selectionInProgress)
+       {
+               // Check for whether or not the rect contains this circle
+               if (selection.normalized().contains(Extents()))
+                       state = OSSelected;
+               else
+                       state = OSInactive;
+
+               return;
+       }
+
        // The TLC will send these messages if the object is selected but not clicked on.
        // So we have to be careful with our assumptions here.
        // This is actually untrue in that case, we need to come up with something better
@@ -281,10 +293,11 @@ so let's do like this:
        // 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...
-Well, we can't know if it was dragged from Inactive or not, that's the problem. We could make
-a variable called "needToRevertToInactive" instead
+/*
+Maybe it would be better to just check for "object was dragged" state and not
+have to worry about keeping track of old states...
+Well, we can't know if it was dragged from Inactive or not, that's the problem.
+We could make a variable called "needToRevertToInactive" instead
 
 I mean, we could write like:
        if (objectWasDragged && oldState == OSInactive)
@@ -299,23 +312,64 @@ but this is actually more compact and cleaner.
 
 /*virtual*/ QRectF Arc::Extents(void)
 {
-#warning "!!! Arc extents not calculated !!!"
-       return QRectF();
-}
+       double start = startAngle;
+       double end = start + angleSpan;
+       QPointF p1(cos(start), sin(start));
+       QPointF p2(cos(end), sin(end));
+       QRectF bounds(p1, p2);
+
+       // Swap X/Y coordinates if they're backwards...
+       if (bounds.left() > bounds.right())
+       {
+               double temp = bounds.left();
+               bounds.setLeft(bounds.right());
+               bounds.setRight(temp);
+       }
 
+       if (bounds.bottom() > bounds.top())
+       {
+               double temp = bounds.bottom();
+               bounds.setBottom(bounds.top());
+               bounds.setTop(temp);
+       }
 
-#if 0
-/*virtual*/ bool Arc::NeedsUpdate(void)
-{
-       return needUpdate;
+       // If the end of the arc is before the beginning, add 360 degrees to it
+       if (end < start)
+               end += 2.0 * PI;
+
+       // Adjust the bounds depending on which axes are crossed
+       if ((start < PI_OVER_2) && (end > PI_OVER_2))
+               bounds.setTop(1.0);
+
+       if ((start < PI) && (end > PI))
+               bounds.setLeft(-1.0);
+
+       if ((start < (PI + PI_OVER_2)) && (end > (PI + PI_OVER_2)))
+               bounds.setBottom(-1.0);
+
+       if ((start < (2.0 * PI)) && (end > (2.0 * PI)))
+               bounds.setRight(1.0);
+
+       if ((start < ((2.0 * PI) + PI_OVER_2)) && (end > ((2.0 * PI) + PI_OVER_2)))
+               bounds.setTop(1.0);
+
+       if ((start < (3.0 * PI)) && (end > (3.0 * PI)))
+               bounds.setLeft(-1.0);
+
+       if ((start < ((3.0 * PI) + PI_OVER_2)) && (end > ((3.0 * PI) + PI_OVER_2)))
+               bounds.setBottom(-1.0);
+
+       bounds.setTopLeft(QPointF(bounds.left() * radius, bounds.top() * radius));
+       bounds.setBottomRight(QPointF(bounds.right() * radius, bounds.bottom() * radius));
+       bounds.translate(position.x, position.y);
+       return bounds;
 }
-#endif
 
 
 #if 0
-/*virtual*/ ObjectType Arc::Type(void)
+/*virtual*/ bool Arc::NeedsUpdate(void)
 {
-       return OTArc;
+       return needUpdate;
 }
 #endif
 
diff --git a/src/blockwidget.cpp b/src/blockwidget.cpp
new file mode 100644 (file)
index 0000000..3e1e4d8
--- /dev/null
@@ -0,0 +1,14 @@
+// blockwidget.cpp: Block add/remove/use widget
+//
+// Part of the Architektonas Project
+// (C) 2011 Underground Software
+// See the README and GPLv3 files for licensing and warranty information
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// WHO  WHEN        WHAT
+// ---  ----------  ------------------------------------------------------------
+// JLH  07/11/2013  Created this file
+//
+
+#include "blockwidget.h"
diff --git a/src/blockwidget.h b/src/blockwidget.h
new file mode 100644 (file)
index 0000000..e69de29
index bd37b7738610a1e4c54586699b2932cf57cec417..47295f40f043576fdcd24b9d37ef803af439918d 100644 (file)
@@ -169,6 +169,18 @@ printf("Container::Collided: Deleting object ($%X)\n", *i);
        return collision;
 }
 
+/*
+What we need to do is check for whether or not we're a top level container,
+and override the passing of stuff into the objects held. So here, if we're *NOT*
+a top level container, instead of passing PointerMoved to our contained objects,
+we check to see if our bounds are met (for selection rectangle, e.g.).
+
+Also, for things like being able to split point's hot spots we need to be able
+to check for that crap in the top level container. Which means that objects can
+still know how to move themselves, but they can also defer to their container
+as well. Which also means that things like HitTest() need to be in the Object
+class so that we can leverage that stuff here as well.
+*/
 
 // The TLC is passing all mouse movement here, so we're doing the same here.
 // Need to adjust all other objects to handle things correctly.
@@ -237,6 +249,17 @@ printf("Container: Added object (=$%X). size = %li\n", object, objects.size());
 }
 
 
+/*virtual*/ QRectF Container::Extents(void)
+{
+       QRectF bounds;
+
+       for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
+               bounds = bounds.united((*i)->Extents());
+
+       return bounds;
+}
+
+
 void Container::Delete(Object * objectToDelete)
 {
        std::vector<Object *>::iterator i = objects.begin();
@@ -337,8 +360,12 @@ void Container::MoveContentsTo(Container * newContainer)
                return;
 
        // Shuffle the contents of this container to the new one
-       for(unsigned int i=0; i<objects.size(); i++)
-               newContainer->Add(objects[i]);
+//     for(unsigned int i=0; i<objects.size(); i++)
+       for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
+       {
+               newContainer->Add(*i);
+               (*i)->Reparent(newContainer);
+       }
 
        // & clear our vector
        objects.clear();
@@ -361,6 +388,7 @@ void Container::MoveSelectedContentsTo(Container * newContainer)
                }
 
                newContainer->Add(*i);
+               (*i)->Reparent(newContainer);
                objects.erase(i);
        }
 }
index 7e6a14d1b0647feaad94caf94ff9356ec3639668..d94357cd545b837187fb0554beb40705f2b15181 100644 (file)
@@ -20,6 +20,7 @@ class Container: public Object
                virtual void PointerReleased(void);
                virtual bool NeedsUpdate(void);
                virtual void Add(Object *);
+               virtual QRectF Extents(void);
                virtual void Enumerate(FILE *);
                void Delete(Object *);
                void DeleteSelectedItems(void);
index b0b992a3de7e1d077d2222087ecc40eb54464da3..887e9c4c3795f33d1eeb9af34b26acfba283739e 100644 (file)
@@ -82,7 +82,8 @@ DrawLineAction::~DrawLineAction()
                // We don't need no stinkin' sentinels, when we have signals & slots!
                emit ObjectReady(line);
 
-               p1 = p2;
+//             p1 = p2;
+               state = FIRST_POINT;
        }
 }
 
diff --git a/src/layerwidget.cpp b/src/layerwidget.cpp
new file mode 100644 (file)
index 0000000..2272253
--- /dev/null
@@ -0,0 +1,14 @@
+// layerwidget.cpp: Layer add/remove/use widget
+//
+// Part of the Architektonas Project
+// (C) 2011 Underground Software
+// See the README and GPLv3 files for licensing and warranty information
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// WHO  WHEN        WHAT
+// ---  ----------  ------------------------------------------------------------
+// JLH  07/11/2013  Created this file
+//
+
+#include "layerwidget.h"
diff --git a/src/layerwidget.h b/src/layerwidget.h
new file mode 100644 (file)
index 0000000..e69de29
index da9717c1af65810bbe2975e33b9c8048c3798610..156b55e6b6b05a812a83cb247e3c0d275e93ac9c 100644 (file)
@@ -19,7 +19,9 @@
 #include "line.h"
 
 #include <QtGui>
+#include "container.h"
 #include "dimension.h"
+#include "mathconstants.h"
 #include "painter.h"
 
 
@@ -88,6 +90,35 @@ Line::~Line()
        else
 //             painter->DrawLine((int)position.x, (int)position.y, (int)endpoint.x, (int)endpoint.y);
                painter->DrawLine(position, endpoint);
+
+       // If we're rotating or setting the span, draw an information panel
+       // showing both absolute and relative angles being set.
+       if (draggingHandle1 || draggingHandle2)
+       {
+               double absAngle = (Vector(endpoint - position).Angle()) * RADIANS_TO_DEGREES;
+//             double relAngle = (startAngle >= oldAngle ? startAngle - oldAngle :
+//                     startAngle - oldAngle + (2.0 * PI)) * RADIANS_TO_DEGREES;
+               double absLength = Vector(position - endpoint).Magnitude();
+
+               QString text;
+
+               text = QObject::tr("Length: %1 in.\n") + QChar(0x2221) + QObject::tr(": %2");
+               text = text.arg(absLength).arg(absAngle);
+
+               QPen pen = QPen(QColor(0x00, 0xFF, 0x00), 1.0, Qt::SolidLine);
+               painter->SetPen(pen);
+               painter->SetBrush(QBrush(QColor(0x40, 0xFF, 0x40, 0x9F)));
+               QRectF textRect(10.0, 10.0, 270.0, 70.0);       // x, y, w, h
+               painter->DrawRoundedRect(textRect, 7.0, 7.0);
+
+               textRect.setLeft(textRect.left() + 14);
+               painter->SetFont(*Object::font);
+//                     pen = QPen(QColor(0xDF, 0x5F, 0x00), 1.0, Qt::SolidLine);
+               pen = QPen(QColor(0x00, 0x5F, 0xDF));
+               painter->SetPen(pen);
+               painter->DrawText(textRect, Qt::AlignVCenter, text);
+//             painter->SetPen(QPen(QColor(0xDF, 0x5F, 0x00)));
+       }
 }
 
 /*virtual*/ Vector Line::Center(void)
@@ -103,6 +134,14 @@ Line::~Line()
        objectWasDragged = false;
        HitTest(point);
 
+       // 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))
+       {
+               parent->state = OSSelected;
+               return true;
+       }
+
 /*
 There's a small problem here with the implementation: You can have a dimension tied
 to only one point while at the same time you can have a dimension sitting on this line.
@@ -255,6 +294,22 @@ Like so:
 
 /*virtual*/ void Line::PointerMoved(Vector point)
 {
+       if (selectionInProgress)
+       {
+               // Check for whether or not the rect contains this line
+#if 0
+               if (selection.normalized().contains(Extents()))
+#else
+               if (selection.normalized().contains(position.x, position.y)
+                       && selection.normalized().contains(endpoint.x, endpoint.y))
+#endif
+                       state = OSSelected;
+               else
+                       state = OSInactive;
+
+               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);
@@ -406,6 +461,61 @@ about keeping track of old states...
 }
 
 
+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();
+}
+
+
 // 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)
@@ -469,14 +579,6 @@ you then *definitely* do not want them to have the same reference number.
 }
 
 
-#if 0
-/*virtual*/ ObjectType Line::Type(void)
-{
-       return OTLine;
-}
-#endif
-
-
 void Line::SetDimensionOnLine(Dimension * dimension/*=NULL*/)
 {
        // If they don't pass one in, create it for the caller.
@@ -530,60 +632,6 @@ Object * Line::FindAttachedDimension(void)
 }
 
 
-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;
@@ -591,6 +639,7 @@ void Line::SaveState(void)
        oldHitLine = hitLine;
 }
 
+
 bool Line::StateChanged(void)
 {
        if ((hitPoint1 != oldHitPoint1) || (hitPoint2 != oldHitPoint2) || (hitLine != oldHitLine))
@@ -599,6 +648,7 @@ bool Line::StateChanged(void)
        return false;
 }
 
+
 /*
 Intersection of two lines:
 
index bb4d5c1ac85efe0c60e9c93a0ea866f05d8a37c1..fb17f2e2f41d9601108150bb0c9fb9db0b081ac0 100644 (file)
@@ -16,6 +16,7 @@ class Line: public Object
                virtual bool Collided(Vector);
                virtual void PointerMoved(Vector);
                virtual void PointerReleased(void);
+               virtual bool HitTest(Point);
                virtual Vector * GetPointAt(Vector);
                virtual void Enumerate(FILE *);
                virtual Object * Copy(void);
@@ -26,7 +27,6 @@ class Line: public Object
                Object * FindAttachedDimension(void);
 
        protected:
-               bool HitTest(Point);
                void SaveState(void);
                bool StateChanged(void);
 
index 78d7d7021f928257ec472db39b8677634d4bc00f..c180d14d6fc786768ab9a9c0c300c6fe0682d704 100644 (file)
@@ -14,6 +14,7 @@
 // JLH  04/01/2011  Created this file
 //
 
-#define PI 3.14159265358979323846264338327
+#define PI                 3.14159265358979323846264338327
+#define PI_OVER_2          (PI / 2.0)
 #define RADIANS_TO_DEGREES (180.0 / PI)
 #define DEGREES_TO_RADIANS (PI / 180.0)
index 8ba3295b5510088a68f13ff8646838c6dd738432..99d73ce7c5b61a628adce7ed53027b13f0418c0e 100644 (file)
@@ -87,6 +87,12 @@ printf("Object: Destroyed!\n");
 }
 
 
+/*virtual*/ bool Object::HitTest(Point)
+{
+       return false;
+}
+
+
 // This is intended to be overridden by the Container class, for object morphing
 /*virtual*/ void Object::Transmute(Object *, Object *)
 {
index 5d51f57d79f254ea933b8b58f3c7dc218c6bc877..532723a73229c7bc360955e9bbcb0e1764625ac0 100644 (file)
@@ -28,6 +28,7 @@ class Object
                virtual void PointerMoved(Vector);
                virtual void PointerReleased(void);
                virtual bool NeedsUpdate(void);
+               virtual bool HitTest(Point);
                virtual void Transmute(Object *, Object *);
                virtual Object * GetParent(void);
                virtual void Add(Object *);