]> Shamusworld >> Repos - architektonas/blob - src/fileio.cpp
Fixes for the Layer widget.
[architektonas] / src / fileio.cpp
1 //
2 // fileio.cpp: Architektonas file save/load support
3 //
4 // Part of the Architektonas Project
5 // (C) 2013 Underground Software
6 // See the README and GPLv3 files for licensing and warranty information
7 //
8 // JLH = James Hammons <jlhamm@acm.org>
9 //
10 // Who  When        What
11 // ---  ----------  -------------------------------------------------------------
12 // JLH  02/20/2013  Created this file
13 //
14
15 #include "fileio.h"
16
17 //#include <stdio.h>
18 #include <errno.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <vector>
22 #include "structs.h"
23
24 /*
25 How to handle connected objects
26 -------------------------------
27
28 Every Object has a vector<Object *> which enumerates all Objects connected to
29 the one we're looking at. So it looks like we'll have to take a two pass
30 approach to loading and saving.
31
32 Basically, in the saving case, first we write out all objects, keeping a
33 pointer-to-index-number record. Second, we loop through all the objects we
34 wrote out, writing connection lists. Format (indices are 1-based):
35
36 CONNECTIONS
37 1: 12 3
38 3: 1
39 12: 1
40 ENDCONNECTIONS
41
42 In the reading case, we do pretty much the same: we construct pointer-to-index-
43 number list, then read the connection list. The PTIN connects the index to the
44 Object pointers we've created. Then we simply call the Object's Connect()
45 function to connect the objects.
46
47 Small problem though: How does a Dimension know which points on a Line it's
48 connected to? This approach tells the Dimension it's connected to the Line and
49 the Line that it's connected to the Dimension, but not which points.
50
51 How to handle them then? Do we list the point with the Object pointed at? A
52 Line can contain an infinite number of points to connect with besides its
53 endpoints.
54
55 So with each connection Object in the vector, there would also have to be a
56 corresponding point to go with it, that would be gotten from the other Object's
57 Connect() function. Or, instead of a point, a parameter value?
58
59 Doing that, with the Line and a parameter "t", if t == 0 we have endpoint 1.
60 if t == 1, then we have endpoint 2. With a Circle, the parameter is a number
61 between 0 and 1 (scaled to 0 to 2π). With an Arc, the parameter goes from 0 to
62 1, 0 being enpoint 1 and 1 being endpoint 2.
63
64 How does this work for moving objects that are connected? Again, with the Line
65 and Dimension. The Line's connections looks like this:
66
67 Object *: dim1, t = 0
68 Object *: dim1, t = 1
69
70 Dimension looks like this:
71
72 Object *: line1, t = 0
73 Object *: line1, t = 1
74
75 For Dimensions, it can query the connected object (if any) using something like
76 GetPointForParameter(). That way it can figure out where its endpoints are. If
77 there is no connected point, then it uses its internal point.
78
79
80 Dimensions are special cases of lines: They have exactly *two* points and none
81 in between. Therefore, the Dimension object only needs to have two points. But
82 those points can be connected to multiple objects. The can also be connected to
83 no points/Objects too.
84
85 How to describe them and their connections (or lack thereof)?
86
87 Would have to be a 2nd pass, after all objects have been written out in order.
88 Then you could do something like:
89
90 DIMCONNECTIONS
91 8 (the Dimension #): 1 (the Object # for point 1) 1 (the Object # for point 2)
92 ENDDIMCONNECTIONS
93
94
95
96 Connection attributes: E.g., between a Line a Circle, it can be tangent,
97 perpendicular, or an arbitrary angle. How to encode that information? It's not
98 intrinsic to either the Line or the Circle, but is a function of the
99 relationship between them by virtue of their connection.
100
101
102 OTHER CONSIDERATIONS:
103 ---------------------
104
105   - Need to figure out how to store the Layer list (should layer list be optional?)
106   - Need to figure out how to store the Block list and blocks
107
108
109 */
110
111 enum ObjectTypeFile { OTFContainer, OTFContainerEnd, OTFLine, OTFCircle, OTFArc,
112         OTFDimension, OTFPolygon, OTFText, OTFImage, OTFBlock, OTFEndOfFile };
113
114
115 /*static*/ bool FileIO::SaveAtnsFile(FILE * file, Container * object)
116 {
117         /* Approach: loop through the container, doing a depth-first traversal. Any extra
118            containers found are looped through until there aren't any more down, then
119            ordinary objects are described. This can be handled by a virtual Object function
120            that reports the object by itself if it's a non-Container, otherwise it
121            enumerates all objects within itself. */
122
123         fprintf(file, "ARCHITEKTONAS DRAWING V1.0\n");
124 #if 0
125         object->Enumerate(file);
126         fprintf(file, "END\n");
127         return true;
128 #else
129         return false;
130 #endif
131 }
132
133
134 /*static*/ bool FileIO::LoadAtnsFile(FILE * file, Container * drawing)
135 {
136 //      char buffer[256];
137         float version;
138
139         fscanf(file, "ARCHITEKTONAS DRAWING V%f", &version);
140
141 //printf("Load: version = %f\n", version);
142         if (version != 1.0)
143                 return false;
144         /* Approach: read each object in the file, one by one. If the object is a Container,
145            add objects to it until an "endContainer" marker is found. This will require a
146            stack to maintain the current Container. */
147
148 #if 0
149         std::vector<Container *> containerStack;
150         Container * currentTopContainer = drawing;//new Container(Vector(0, 0));
151         Object * object;
152 //      ObjectType objectType;
153         int objectType;
154
155         while (!feof(file))
156         {
157                 if (FileIO::GetObjectFromFile(file, currentTopContainer, &object, &objectType) == false)
158                         return false;
159
160                 // object->type down below can be replaced with objType.
161                 // Above could be: bool FileIO::GetObjectFromFile(FILE *, Object *, ObjectType *);
162                 // where the return value tells if it's a valid object, Object * returns the
163                 // reconstructed object and ObjectType * returns the object type.
164
165                 if (objectType == OTFEndOfFile)
166                 {
167 //printf("Load: container size = %li\n", drawing->objects.size());
168                         return true;
169                 }
170                 else if (objectType == OTFContainer)
171                 {
172                         containerStack.push_back(currentTopContainer);
173                         currentTopContainer = new Container(Vector(0, 0), currentTopContainer);
174                 }
175                 else if (objectType == OTFContainerEnd)
176                 {
177                         Container * containerToAdd = currentTopContainer;
178                         currentTopContainer = containerStack.back();
179                         containerStack.pop_back();
180                         currentTopContainer->Add(containerToAdd);
181                 }
182                 else
183                 {
184                         currentTopContainer->Add(object);
185 //printf("Load: Adding object. Container size = %li (%li)\n", drawing->objects.size(), currentTopContainer->objects.size());
186                 }
187         }
188
189         return false;
190 #else
191         return false;
192 #endif
193 }
194
195
196 /*static*/ bool FileIO::GetObjectFromFile(FILE * file, Object * parent, Object ** object, int * objectType)
197 {
198 #if 0
199         char buffer[256];
200         int foundLayer = 0;
201         int num = fscanf(file, "%s", buffer);
202         bool recognized = false;
203         *object = NULL;
204 //printf("FileIO: fscanf returned %i, buffer = \"%s\"\n", num, buffer);
205
206 // The following fugliness is for troubleshooting. Can remove later.
207         if ((strcmp(buffer, "END") != 0) && (strcmp(buffer, "ENDCONTAINER") != 0))
208 {
209 errno = 0;
210                 num = fscanf(file, " %i ", &foundLayer);
211 //printf("FileIO: fscanf returned %i, foundLayer = %i\n", num, foundLayer);
212 if (errno)
213 {
214         if (errno == EAGAIN)
215                 printf("EAGAIN\n");
216         else if (errno == EBADF)
217                 printf("EBADF\n");
218         else if (errno == EILSEQ)
219                 printf("EILSEQ\n");
220         else if (errno == EINTR)
221                 printf("EINTR\n");
222         else if (errno == EINVAL)
223                 printf("EINVAL\n");
224         else if (errno == ENOMEM)
225                 printf("ENOMEM\n");
226         else if (errno == ERANGE)
227                 printf("ERANGE\n");
228         else
229                 printf("errno = %i\n", errno);
230 }
231 }
232
233         if (strcmp(buffer, "LINE") == 0)
234         {
235 //printf("      Found LINE.\n");
236                 recognized = true;
237                 Vector v1, v2;
238                 fscanf(file, "(%lf,%lf) (%lf,%lf)", &v1.x, &v1.y, &v2.x, &v2.y);
239 //printf("      Number of params recognized: %i\n", n);
240                 *object = new Line(v1, v2, parent);
241                 *objectType = OTFLine;
242         }
243         else if (strcmp(buffer, "CIRCLE") == 0)
244         {
245                 recognized = true;
246                 Vector v;
247                 double r;
248                 fscanf(file, "(%lf,%lf) %lf", &v.x, &v.y, &r);
249                 *object = new Circle(v, r, parent);
250                 *objectType = OTFCircle;
251         }
252         else if (strcmp(buffer, "ARC") == 0)
253         {
254                 recognized = true;
255                 Vector v;
256                 double r, a1, a2;
257                 fscanf(file, "(%lf,%lf) %lf, %lf, %lf", &v.x, &v.y, &r, &a1, &a2);
258                 *object = new Arc(v, r, a1, a2, parent);
259                 *objectType = OTFArc;
260         }
261         else if (strcmp(buffer, "DIMENSION") == 0)
262         {
263                 recognized = true;
264                 Vector v1, v2;
265                 DimensionType type;
266                 fscanf(file, "(%lf,%lf) (%lf,%lf) %i", &v1.x, &v1.y, &v2.x, &v2.y, &type);
267                 *object = new Dimension(v1, v2, type, parent);
268                 *objectType = OTFDimension;
269         }
270         else if (strcmp(buffer, "CONTAINER") == 0)
271         {
272                 recognized = true;
273                 *objectType = OTFContainer;
274         }
275         else if (strcmp(buffer, "ENDCONTAINER") == 0)
276         {
277                 recognized = true;
278                 *objectType = OTFContainerEnd;
279         }
280         else if (strcmp(buffer, "END") == 0)
281         {
282                 recognized = true;
283                 *objectType = OTFEndOfFile;
284         }
285
286         if (*object)
287                 (*object)->layer = foundLayer;
288
289         return recognized;
290 #else
291         return false;
292 #endif
293 }
294