From: Shamus Hammons Date: Fri, 22 Feb 2013 16:50:43 +0000 (-0600) Subject: In the middle of refactoring objects for loading/saving. X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eb0057e8a8145032152e4c417fcd102ef5a21484;p=architektonas In the middle of refactoring objects for loading/saving. This is a bit more hairy than it would seem: it requires clarity in the data structures which isn't quite there yet. Hopefully that clarity will be coming sooner than later. :-P --- diff --git a/architektonas.pro b/architektonas.pro index 68ced07..1d1000d 100644 --- a/architektonas.pro +++ b/architektonas.pro @@ -51,6 +51,7 @@ HEADERS = \ src/drawingview.h \ src/drawcircleaction.h \ src/drawlineaction.h \ + src/ellipse.h \ src/fileio.h \ src/generaltab.h \ src/line.h \ @@ -72,6 +73,7 @@ SOURCES = \ src/drawingview.cpp \ src/drawcircleaction.cpp \ src/drawlineaction.cpp \ + src/ellipse.cpp \ src/fileio.cpp \ src/generaltab.cpp \ src/line.cpp \ diff --git a/src/applicationwindow.cpp b/src/applicationwindow.cpp index a9c7fb6..0911b8e 100644 --- a/src/applicationwindow.cpp +++ b/src/applicationwindow.cpp @@ -118,6 +118,7 @@ void ApplicationWindow::FileOpen(void) return; } +printf("FileOpen: container size = %li\n", container.objects.size()); drawing->document = container; drawing->update(); documentName = filename; diff --git a/src/arc.cpp b/src/arc.cpp index c9eab15..a4efa39 100644 --- a/src/arc.cpp +++ b/src/arc.cpp @@ -24,10 +24,12 @@ Arc::Arc(Vector p1, double r, double a1, double a2, Object * p/*= NULL*/): Objec { } + Arc::~Arc() { } + /*virtual*/ void Arc::Draw(Painter * painter) { QPen pen; @@ -117,11 +119,13 @@ Arc::~Arc() painter->DrawArc(position, radius, startAngle, angleSpan); } + /*virtual*/ Vector Arc::Center(void) { return position; } + /* We need at least *four* handles for this object: - one for moving @@ -225,6 +229,7 @@ so let's do like this: return false; } + /*virtual*/ void Arc::PointerMoved(Vector point) { // The TLC will send these messages if the object is selected but not clicked on. @@ -265,6 +270,7 @@ so let's do like this: needUpdate = true; } + /*virtual*/ void Arc::PointerReleased(void) { hitHandle1 = hitHandle2 = hitHandle3 = hitHandle4 = false; @@ -293,6 +299,7 @@ but this is actually more compact and cleaner. } #endif + /* start = 350, span = 20, end = 10, angle = 5 angle < start, so angle = 365 @@ -312,3 +319,10 @@ bool Arc::AngleInArcSpan(double angle) return (passedInSpan <= angleSpan ? true : false); } + + +/*virtual*/ void Arc::Enumerate(FILE * file) +{ + fprintf(file, "ARC (%lf,%lf) %lf, %lf, %lf\n", position.x, position.y, radius, startAngle, angleSpan); +} + diff --git a/src/arc.h b/src/arc.h index ee9c567..262fc85 100644 --- a/src/arc.h +++ b/src/arc.h @@ -15,6 +15,8 @@ class Arc: public Object virtual void PointerMoved(Vector); virtual void PointerReleased(void); // virtual bool NeedsUpdate(void); + virtual void Enumerate(FILE *); + virtual Object * Copy(void); private: bool AngleInArcSpan(double angle); diff --git a/src/circle.cpp b/src/circle.cpp index 8e5f6cd..af8f91f 100644 --- a/src/circle.cpp +++ b/src/circle.cpp @@ -24,10 +24,12 @@ Circle::Circle(Vector p1, double r, Object * p/*= NULL*/): Object(p1, p), radius { } + Circle::~Circle() { } + /*virtual*/ void Circle::Draw(Painter * painter) { if (state == OSSelected || hitCircle || hitCenter) @@ -52,11 +54,13 @@ Circle::~Circle() painter->DrawHandle(dragPoint); } + /*virtual*/ Vector Circle::Center(void) { return position; } + /*virtual*/ bool Circle::Collided(Vector point) { // We can assume this, since this is a mouse down event here. @@ -79,6 +83,7 @@ Circle::~Circle() return false; } + /*virtual*/ void Circle::PointerMoved(Vector point) { // Hit test tells us what we hit (if anything) through boolean variables. It @@ -95,6 +100,7 @@ Circle::~Circle() dragPoint = point; } + /*virtual*/ void Circle::PointerReleased(void) { // Mouse went up, so our dragging is done (if any *was* done, that is) @@ -107,6 +113,7 @@ Circle::~Circle() state = oldState; } + bool Circle::HitTest(Point point) { SaveState(); @@ -129,12 +136,14 @@ since we generally *don't* want those to scale with the zoom level. ;-) return StateChanged(); } + void Circle::SaveState(void) { oldHitCenter = hitCenter; oldHitCircle = hitCircle; } + bool Circle::StateChanged(void) { if ((hitCenter != oldHitCenter) || (hitCircle != oldHitCircle)) @@ -142,3 +151,10 @@ bool Circle::StateChanged(void) return false; } + + +/*virtual*/ void Circle::Enumerate(FILE * file) +{ + fprintf(file, "CIRCLE (%lf,%lf) %lf\n", position.x, position.y, radius); +} + diff --git a/src/circle.h b/src/circle.h index cae0308..72bdea2 100644 --- a/src/circle.h +++ b/src/circle.h @@ -14,6 +14,8 @@ class Circle: public Object virtual bool Collided(Vector); virtual void PointerMoved(Vector); virtual void PointerReleased(void); + virtual void Enumerate(FILE *); + virtual Object * Copy(void); protected: bool HitTest(Point); diff --git a/src/container.cpp b/src/container.cpp index 2ee9c7a..48e412a 100644 --- a/src/container.cpp +++ b/src/container.cpp @@ -35,30 +35,29 @@ Container::Container(const Container & copy): Object(copy.position, copy.parent) Container::~Container() { -#if 0 - // No memory leaks! - while (objects.size() > 0) - { - delete objects[0]; - objects.erase(objects.begin()); - } -#else Clear(); -#endif } // Assignment operator -Container & Container::operator=(const Container & copy) +Container & Container::operator=(const Container & from) { // Take care of self-assignment - if (this == ©) + if (this == &from) return *this; Clear(); - for(int i=0; i<(int)copy.objects.size(); i++) - objects.push_back(copy.objects[i]); + // Small problem with this approach: if the copied object goes out of scope, + // all of the objects we copied in here will be deleted. D'oh! + for(uint i=0; iDraw(painter); + } } @@ -152,7 +154,9 @@ Like so: { Dimension * dimension = objects[i]->GetAttachedDimension(); - objects.erase(objects.begin() + i); // Calls the destructor, (deletes the object, I presume... O_o) + Object * objectToDelete = objects[i]; + objects.erase(objects.begin() + i); // Calls the destructor, (deletes the object, I presume... O_o) [NOPE! SURE DOESN'T!] + delete objectToDelete; // If this object had an attached dimension, reattach it to another object, if any... // The only problem with that approach is if the object it gets attached to is deleted, @@ -246,7 +250,7 @@ about keeping track of old states... { needUpdate = false; - for(int i=0; i<(int)objects.size(); i++) + for(uint i=0; iNeedsUpdate()) needUpdate = true; @@ -259,6 +263,7 @@ about keeping track of old states... /*virtual*/ void Container::Add(Object * object) { objects.push_back(object); +printf("Container: Added object (=$%X). size = %li\n", object, objects.size()); } @@ -267,7 +272,23 @@ void Container::Clear(void) // No memory leaks! while (objects.size() > 0) { +printf("Container: Deleting object ($%X)...\n", objects[0]); delete objects[0]; objects.erase(objects.begin()); } } + + +/*virtual*/ void Container::Enumerate(FILE * file) +{ + // Only put "CONTAINER" markers if *not* the top level container + if (parent != NULL) + fprintf(file, "CONTAINER\n"); + + for(uint i=0; iEnumerate(file); + + if (parent != NULL) + fprintf(file, "ENDCONTAINER\n"); +} + diff --git a/src/container.h b/src/container.h index ac26722..e7bf355 100644 --- a/src/container.h +++ b/src/container.h @@ -20,13 +20,15 @@ class Container: public Object virtual void PointerReleased(void); virtual bool NeedsUpdate(void); virtual void Add(Object *); + virtual void Enumerate(FILE *); void Clear(void); protected: Vector oldPoint; // Used for dragging - private: + public: std::vector objects; + private: bool dragging; bool draggingHandle1; bool draggingHandle2; diff --git a/src/dimension.cpp b/src/dimension.cpp index 3060ff1..ad2ffcb 100644 --- a/src/dimension.cpp +++ b/src/dimension.cpp @@ -25,6 +25,7 @@ Dimension::Dimension(Vector p1, Vector p2, DimensionType dt/*= DTLinear*/ ,Objec { } + // This is bad, p1 & p2 could be NULL, causing much consternation... Dimension::Dimension(Vector * p1, Vector * p2, DimensionType dt/*= DTLinear*/ , Object * p/*= NULL*/): Object(*p1, p), endpoint(*p2), @@ -33,10 +34,12 @@ Dimension::Dimension(Vector * p1, Vector * p2, DimensionType dt/*= DTLinear*/ , { } + Dimension::~Dimension() { } + /*virtual*/ void Dimension::Draw(Painter * painter) { // If there are valid Vector pointers in here, use them to update the internal @@ -130,6 +133,7 @@ retarded is that? :-/ */ } + /*virtual*/ Vector Dimension::Center(void) { // Technically, this is the midpoint but who are we to quibble? :-) @@ -137,6 +141,7 @@ retarded is that? :-/ return endpoint + v; } + /*virtual*/ bool Dimension::Collided(Vector /*point*/) { #if 0 @@ -237,6 +242,7 @@ Like so: return false; } + /*virtual*/ void Dimension::PointerMoved(Vector point) { // We know this is true because mouse move messages don't come here unless @@ -277,6 +283,7 @@ Like so: needUpdate = false; } + /*virtual*/ void Dimension::PointerReleased(void) { if (draggingHandle1 || draggingHandle2) @@ -319,28 +326,33 @@ about keeping track of old states... state = oldState; } + void Dimension::SetPoint1(Vector * v) { point1 = v; needUpdate = true; } + void Dimension::SetPoint2(Vector * v) { point2 = v; needUpdate = true; } + Vector Dimension::GetPoint1(void) { return position; } + Vector Dimension::GetPoint2(void) { return endpoint; } + void Dimension::FlipSides(void) { #if 0 @@ -355,3 +367,9 @@ void Dimension::FlipSides(void) needUpdate = true; } + +/*virtual*/ void Dimension::Enumerate(FILE * file) +{ + fprintf(file, "DIMENSION (%lf,%lf) (%lf,%lf) %i\n", position.x, position.y, endpoint.x, endpoint.y, type); +} + diff --git a/src/dimension.h b/src/dimension.h index 0cda929..52f838f 100644 --- a/src/dimension.h +++ b/src/dimension.h @@ -17,6 +17,8 @@ class Dimension: public Object virtual bool Collided(Vector); virtual void PointerMoved(Vector); virtual void PointerReleased(void); + virtual void Enumerate(FILE *); + virtual Object * Copy(void); void SetPoint1(Vector *); void SetPoint2(Vector *); Vector GetPoint1(void); diff --git a/src/ellipse.cpp b/src/ellipse.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ellipse.h b/src/ellipse.h new file mode 100644 index 0000000..e69de29 diff --git a/src/fileio.cpp b/src/fileio.cpp index 7cd6816..fedddea 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -16,24 +16,159 @@ //#include #include +#include +#include +#include "arc.h" +#include "circle.h" #include "container.h" +#include "dimension.h" +#include "line.h" + +enum ObjectType { OTContainer, OTContainerEnd, OTLine, OTCircle, OTArc, OTDimension, + OTPolygon, OTText, OTImage, OTBlock, OTEndOfFile }; /*static*/ bool FileIO::SaveAtnsFile(FILE * file, Container * object) { -// QString filename2 = QFileDialog::getSaveFileName(NULL, tr("Save Drawing"), -// "", tr("Architektonas files (*.drawing)")); + /* Approach: loop through the container, doing a depth-first traversal. Any extra + containers found are looped through until there aren't any more down, then + ordinary objects are described. This can be handled by a virtual Object function + that reports the object by itself if it's a non-Container, otherwise it + enumerates all objects within itself. */ + fprintf(file, "ARCHITEKTONAS DRAWING V1.0\n"); +#if 1 + object->Enumerate(file); + fprintf(file, "END\n"); + return true; +#else return false; +#endif } -/*static*/ bool FileIO::LoadAtnsFile(FILE * file, Container * object) +/*static*/ bool FileIO::LoadAtnsFile(FILE * file, Container * drawing) { -// QString filename2 = QFileDialog::getOpenFileName(NULL, tr("Open Drawing"), -// "", tr("Architektonas files (*.drawing)")); +// char buffer[256]; + float version; + + fscanf(file, "ARCHITEKTONAS DRAWING V%f", &version); + +//printf("Load: version = %f\n", version); + if (version != 1.0) + return false; + /* Approach: read each object in the file, one by one. If the object is a Container, + add objects to it until an "endContainer" marker is found. This will require a + stack to maintain the current Container. */ + +#if 1 + std::vector containerStack; + Container * currentTopContainer = drawing;//new Container(Vector(0, 0)); + Object * object; +// ObjectType objectType; + int objectType; + + while (!feof(file)) + { + if (FileIO::GetObjectFromFile(file, currentTopContainer, &object, &objectType) == false) + return false; + + // object->type down below can be replaced with objType. + // Above could be: bool FileIO::GetObjectFromFile(FILE *, Object *, ObjectType *); + // where the return value tells if it's a valid object, Object * returns the + // reconstructed object and ObjectType * returns the object type. + + if (objectType == OTEndOfFile) + { +printf("Load: container size = %li\n", drawing->objects.size()); + return true; + } + else if (objectType == OTContainer) + { + containerStack.push_back(currentTopContainer); + currentTopContainer = new Container(Vector(0, 0), currentTopContainer); + } + else if (objectType == OTContainerEnd) + { + Container * containerToAdd = currentTopContainer; + currentTopContainer = containerStack.back(); + containerStack.pop_back(); + currentTopContainer->Add(containerToAdd); + } + else + { + currentTopContainer->Add(object); +printf("Load: Adding object. Container size = %li (%li)\n", drawing->objects.size(), currentTopContainer->objects.size()); + } + } return false; +#else + return false; +#endif } +/*static*/ bool FileIO::GetObjectFromFile(FILE * file, Object * parent, Object ** object, int * objectType) +{ + char buffer[256]; + fscanf(file, "%s ", buffer); + bool recognized = false; +//printf("Load: buffer = \"%s\"\n", buffer); + + if (strcmp(buffer, "LINE") == 0) + { +//printf(" Found LINE.\n"); + recognized = true; + Vector v1, v2; + fscanf(file, "(%lf,%lf) (%lf,%lf)", &v1.x, &v1.y, &v2.x, &v2.y); +//printf(" Number of params recognized: %i\n", n); + *object = new Line(v1, v2, parent); + *objectType = OTLine; + } + else if (strcmp(buffer, "CIRCLE") == 0) + { + recognized = true; + Vector v; + double r; + fscanf(file, "(%lf,%lf) %lf", &v.x, &v.y, &r); + *object = new Circle(v, r, parent); + *objectType = OTCircle; + } + else if (strcmp(buffer, "ARC") == 0) + { + recognized = true; + Vector v; + double r, a1, a2; + fscanf(file, "(%lf,%lf) %lf, %lf, %lf", &v.x, &v.y, &r, &a1, &a2); + *object = new Arc(v, r, a1, a2, parent); + *objectType = OTArc; + } + else if (strcmp(buffer, "DIMENSION") == 0) + { + recognized = true; + Vector v1, v2; + DimensionType type; + fscanf(file, "(%lf,%lf) (%lf,%lf) %i", &v1.x, &v1.y, &v2.x, &v2.y, &type); + *object = new Dimension(v1, v2, type, parent); + *objectType = OTDimension; + } + else if (strcmp(buffer, "CONTAINER") == 0) + { + recognized = true; + *objectType = OTContainer; + } + else if (strcmp(buffer, "ENDCONTAINER") == 0) + { + recognized = true; + *objectType = OTContainerEnd; + } + else if (strcmp(buffer, "END") == 0) + { + recognized = true; + *objectType = OTEndOfFile; + } + + return recognized; +} + diff --git a/src/fileio.h b/src/fileio.h index 5994e27..a30ad48 100644 --- a/src/fileio.h +++ b/src/fileio.h @@ -4,6 +4,7 @@ #include class Container; +class Object; // NB: The methods in this class are all static, so there's no need to // instantiate an object of this type to use its functions. @@ -13,6 +14,9 @@ class FileIO public: static bool SaveAtnsFile(FILE *, Container *); static bool LoadAtnsFile(FILE *, Container *); + + private: + static bool GetObjectFromFile(FILE *, Object *, Object **, int *); }; #endif // __FILEIO_H__ diff --git a/src/line.cpp b/src/line.cpp index 880a79d..739842b 100644 --- a/src/line.cpp +++ b/src/line.cpp @@ -580,3 +580,23 @@ else } */ +/*virtual*/ void Line::Enumerate(FILE * file) +{ + fprintf(file, "LINE (%lf,%lf) (%lf,%lf)\n", position.x, position.y, endpoint.x, endpoint.y); +} + + +/*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); +} + diff --git a/src/line.h b/src/line.h index 816bfc2..de1bbfe 100644 --- a/src/line.h +++ b/src/line.h @@ -17,6 +17,8 @@ class Line: public Object virtual void PointerMoved(Vector); virtual void PointerReleased(void); virtual Vector * GetPointAt(Vector); + virtual void Enumerate(FILE *); + virtual Object * Copy(void); // void SetDimensionOnPoint1(Dimension *); // void SetDimensionOnPoint2(Dimension *); void SetDimensionOnLine(Dimension * d = 0); diff --git a/src/object.cpp b/src/object.cpp index ab95c0e..8f9377b 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -32,77 +32,105 @@ Object::Object(): position(Vector(0, 0)), parent(0), state(OSInactive), oldState { } + Object::Object(Vector v, Object * passedInParent/*= 0*/): position(v), parent(passedInParent), state(OSInactive), oldState(OSInactive), needUpdate(false), attachedDimension(0) { } + Object::~Object() { } + /*virtual*/ void Object::Draw(Painter *) { } + /*virtual*/ Vector Object::Center(void) { return Vector(); } + /*virtual*/ bool Object::Collided(Vector) { return false; } + /*virtual*/ void Object::PointerMoved(Vector) { } + /*virtual*/ void Object::PointerReleased(void) { } + /*virtual*/ bool Object::NeedsUpdate(void) { return needUpdate; } + // This is intended to be overridden by the Container class, for object morphing /*virtual*/ void Object::Transmute(Object *, Object *) { } + /*virtual*/ Object * Object::GetParent(void) { return parent; } + /*virtual*/ void Object::Add(Object *) { } + // This returns a pointer to the point passed in, if it coincides. Otherwise returns NULL. /*virtual*/ Vector * Object::GetPointAt(Vector) { return 0; } + +// This is meant for writing object data to a file. +/*virtual*/ void Object::Enumerate(FILE *) +{ +} + + +/*virtual*/ Object * Object::Copy(void) +{ + return new Object(position, parent); +} + + ObjectState Object::GetState(void) { return state; } + void Object::Reparent(Object * newParent) { parent = newParent; } + Dimension * Object::GetAttachedDimension(void) { return attachedDimension; } + // Class methods... void Object::SetFixedAngle(bool state/*= true*/) @@ -110,31 +138,37 @@ void Object::SetFixedAngle(bool state/*= true*/) fixedAngle = state; } + void Object::SetFixedLength(bool state/*= true*/) { fixedLength = state; } + void Object::SetFont(QFont * f) { font = f; } + void Object::SetViewportHeight(int height) { viewportHeight = height; } + void Object::SetDeleteActive(bool state/*= true*/) { deleteActive = state; } + void Object::SetDimensionActive(bool state/*= true*/) { dimensionActive = state; } + void Object::SetSnapMode(bool state/*= true*/) { snapToGrid = state; diff --git a/src/object.h b/src/object.h index efcffe1..5b19505 100644 --- a/src/object.h +++ b/src/object.h @@ -3,10 +3,12 @@ #include // This is a container #include "vector.h" // This is the mathematical construct +#include class Painter; class QFont; class Dimension; +//class FILE; enum ObjectState { OSInactive, OSSelected }; @@ -27,6 +29,8 @@ class Object virtual Object * GetParent(void); virtual void Add(Object *); virtual Vector * GetPointAt(Vector); + virtual void Enumerate(FILE *); + virtual Object * Copy(void); ObjectState GetState(void); void Reparent(Object *); Dimension * GetAttachedDimension(void);