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