1 //-----------------------------------------------------------------------------
2 // All declarations not grouped specially elsewhere.
3 //
4 // Copyright 2008-2013 Jonathan Westhues.
5 //-----------------------------------------------------------------------------
6 
7 #ifndef __SOLVESPACE_H
8 #define __SOLVESPACE_H
9 
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <ctype.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <stddef.h>
16 #include <stdarg.h>
17 #include <math.h>
18 #include <limits.h>
19 #include <algorithm>
20 #include <memory>
21 #include <string>
22 #include <locale>
23 #include <vector>
24 #include <unordered_map>
25 #include <map>
26 #include <set>
27 #include <sstream>
28 #ifdef WIN32
29 #   include <windows.h> // required by GL headers
30 #endif
31 #ifdef __APPLE__
32 #   include <strings.h> // for strcasecmp in file.cpp
33 #   include <OpenGL/gl.h>
34 #   include <OpenGL/glu.h>
35 #else
36 #   include <GL/gl.h>
37 #   include <GL/glu.h>
38 #endif
39 
40 // We declare these in advance instead of simply using FT_Library
41 // (defined as typedef FT_LibraryRec_* FT_Library) because including
42 // freetype.h invokes indescribable horrors and we would like to avoid
43 // doing that every time we include solvespace.h.
44 struct FT_LibraryRec_;
45 struct FT_FaceRec_;
46 
47 // The few floating-point equality comparisons in SolveSpace have been
48 // carefully considered, so we disable the -Wfloat-equal warning for them
49 #ifdef __clang__
50 #   define EXACT(expr) \
51         (_Pragma("clang diagnostic push") \
52          _Pragma("clang diagnostic ignored \"-Wfloat-equal\"") \
53          (expr) \
54          _Pragma("clang diagnostic pop"))
55 #else
56 #   define EXACT(expr) (expr)
57 #endif
58 
59 // Debugging functions
60 #ifdef NDEBUG
61 #define oops() do { dbp("oops at line %d, file %s\n", __LINE__, __FILE__); \
62                     exit(-1); } while(0)
63 #else
64 #define oops() do { dbp("oops at line %d, file %s\n", __LINE__, __FILE__); \
65                     abort(); } while(0)
66 #endif
67 
68 #ifndef isnan
69 #   define isnan(x) (((x) != (x)) || (x > 1e11) || (x < -1e11))
70 #endif
71 
72 namespace SolveSpace {
73 
74 using std::min;
75 using std::max;
76 using std::swap;
77 
78 #if defined(__GNUC__)
79 __attribute__((__format__ (__printf__, 1, 2)))
80 #endif
81 std::string ssprintf(const char *fmt, ...);
82 
WRAP(int v,int n)83 inline int WRAP(int v, int n) {
84     // Clamp it to the range [0, n)
85     while(v >= n) v -= n;
86     while(v < 0) v += n;
87     return v;
88 }
WRAP_NOT_0(double v,double n)89 inline double WRAP_NOT_0(double v, double n) {
90     // Clamp it to the range (0, n]
91     while(v > n) v -= n;
92     while(v <= 0) v += n;
93     return v;
94 }
WRAP_SYMMETRIC(double v,double n)95 inline double WRAP_SYMMETRIC(double v, double n) {
96     // Clamp it to the range (-n/2, n/2]
97     while(v >   n/2) v -= n;
98     while(v <= -n/2) v += n;
99     return v;
100 }
101 
102 // Why is this faster than the library function?
ffabs(double v)103 inline double ffabs(double v) { return (v > 0) ? v : (-v); }
104 
105 #define CO(v) (v).x, (v).y, (v).z
106 
107 #define ANGLE_COS_EPS   (1e-6)
108 #define LENGTH_EPS      (1e-6)
109 #define VERY_POSITIVE   (1e10)
110 #define VERY_NEGATIVE   (-1e10)
111 
112 #define isforname(c) (isalnum(c) || (c) == '_' || (c) == '-' || (c) == '#')
113 
114 #if defined(WIN32)
115 std::string Narrow(const wchar_t *s);
116 std::wstring Widen(const char *s);
117 std::string Narrow(const std::wstring &s);
118 std::wstring Widen(const std::string &s);
119 #endif
120 
Random(double vmax)121 inline double Random(double vmax) {
122     return (vmax*rand()) / RAND_MAX;
123 }
124 
125 class Expr;
126 class ExprVector;
127 class ExprQuaternion;
128 class RgbaColor;
129 
130 //================
131 // From the platform-specific code.
132 #if defined(WIN32)
133 #define PATH_SEP "\\"
134 #else
135 #define PATH_SEP "/"
136 #endif
137 
138 FILE *ssfopen(const std::string &filename, const char *mode);
139 std::fstream ssfstream(const std::string &filename, std::ios_base::openmode mode);
140 void ssremove(const std::string &filename);
141 
142 #define MAX_RECENT 8
143 #define RECENT_OPEN     (0xf000)
144 #define RECENT_LINK     (0xf100)
145 extern std::string RecentFile[MAX_RECENT];
146 void RefreshRecentMenus(void);
147 
148 enum DialogChoice { DIALOG_YES = 1, DIALOG_NO = -1, DIALOG_CANCEL = 0 };
149 DialogChoice SaveFileYesNoCancel(void);
150 DialogChoice LoadAutosaveYesNo(void);
151 DialogChoice LocateImportedFileYesNoCancel(const std::string &filename,
152                                            bool canCancel);
153 
154 #define AUTOSAVE_SUFFIX "~"
155 
156 struct FileFilter {
157     const char *name;
158     const char *patterns[3];
159 };
160 
161 // SolveSpace native file format
162 const FileFilter SlvsFileFilter[] = {
163     { "SolveSpace models",          { "slvs" } },
164     { NULL, {} }
165 };
166 // PNG format bitmap
167 const FileFilter PngFileFilter[] = {
168     { "PNG",                        { "png" } },
169     { NULL, {} }
170 };
171 // Triangle mesh
172 const FileFilter MeshFileFilter[] = {
173     { "STL mesh",                   { "stl" } },
174     { "Wavefront OBJ mesh",         { "obj" } },
175     { "Three.js-compatible mesh, with viewer",  { "html" } },
176     { "Three.js-compatible mesh, mesh only",    { "js" } },
177     { NULL, {} }
178 };
179 // NURBS surfaces
180 const FileFilter SurfaceFileFilter[] = {
181     { "STEP file",                  { "step", "stp" } },
182     { NULL, {} }
183 };
184 // 2d vector (lines and curves) format
185 const FileFilter VectorFileFilter[] = {
186     { "PDF file",                   { "pdf" } },
187     { "Encapsulated PostScript",    { "eps",  "ps" } },
188     { "Scalable Vector Graphics",   { "svg" } },
189     { "STEP file",                  { "step", "stp" } },
190     { "DXF file (AutoCAD 2007)",    { "dxf" } },
191     { "HPGL file",                  { "plt",  "hpgl" } },
192     { "G Code",                     { "ngc",  "txt" } },
193     { NULL, {} }
194 };
195 // 3d vector (wireframe lines and curves) format
196 const FileFilter Vector3dFileFilter[] = {
197     { "STEP file",                  { "step", "stp" } },
198     { "DXF file (AutoCAD 2007)",    { "dxf" } },
199     { NULL, {} }
200 };
201 // All Importable formats
202 const FileFilter ImportableFileFilter[] = {
203     { "AutoCAD DXF and DWG files",  { "dxf", "dwg" } },
204     { NULL, {} }
205 };
206 // Comma-separated value, like a spreadsheet would use
207 const FileFilter CsvFileFilter[] = {
208     { "CSV",                        { "csv" } },
209     { NULL, {} }
210 };
211 
212 bool GetSaveFile(std::string *filename, const std::string &defExtension,
213                  const FileFilter filters[]);
214 bool GetOpenFile(std::string *filename, const std::string &defExtension,
215                  const FileFilter filters[]);
216 std::vector<std::string> GetFontFiles();
217 
218 void OpenWebsite(const char *url);
219 
220 void CheckMenuById(int id, bool checked);
221 void RadioMenuById(int id, bool selected);
222 void EnableMenuById(int id, bool enabled);
223 
224 void ShowGraphicsEditControl(int x, int y, int fontHeight, int minWidthChars,
225                              const std::string &str);
226 void HideGraphicsEditControl(void);
227 bool GraphicsEditControlIsVisible(void);
228 void ShowTextEditControl(int x, int y, const std::string &str);
229 void HideTextEditControl(void);
230 bool TextEditControlIsVisible(void);
231 void MoveTextScrollbarTo(int pos, int maxPos, int page);
232 
233 #define CONTEXT_SUBMENU     (-1)
234 #define CONTEXT_SEPARATOR   (-2)
235 void AddContextMenuItem(const char *legend, int id);
236 void CreateContextSubmenu(void);
237 int ShowContextMenu(void);
238 
239 void ToggleMenuBar(void);
240 bool MenuBarIsVisible(void);
241 void ShowTextWindow(bool visible);
242 void InvalidateText(void);
243 void InvalidateGraphics(void);
244 void PaintGraphics(void);
245 void ToggleFullScreen(void);
246 bool FullScreenIsActive(void);
247 void GetGraphicsWindowSize(int *w, int *h);
248 void GetTextWindowSize(int *w, int *h);
249 int64_t GetMilliseconds(void);
250 int64_t GetUnixTime(void);
251 
252 void dbp(const char *str, ...);
253 #define DBPTRI(tri) \
254     dbp("tri: (%.3f %.3f %.3f) (%.3f %.3f %.3f) (%.3f %.3f %.3f)", \
255         CO((tri).a), CO((tri).b), CO((tri).c))
256 
257 void SetCurrentFilename(const std::string &filename);
258 void SetMousePointerToHand(bool yes);
259 void DoMessageBox(const char *str, int rows, int cols, bool error);
260 void SetTimerFor(int milliseconds);
261 void SetAutosaveTimerFor(int minutes);
262 void ScheduleLater();
263 void ExitNow(void);
264 
265 void CnfFreezeInt(uint32_t val, const std::string &name);
266 void CnfFreezeFloat(float val, const std::string &name);
267 void CnfFreezeString(const std::string &val, const std::string &name);
268 std::string CnfThawString(const std::string &val, const std::string &name);
269 uint32_t CnfThawInt(uint32_t val, const std::string &name);
270 float CnfThawFloat(float val, const std::string &name);
271 
272 void *AllocTemporary(size_t n);
273 void FreeTemporary(void *p);
274 void FreeAllTemporary(void);
275 void *MemAlloc(size_t n);
276 void MemFree(void *p);
277 void InitHeaps(void);
278 void vl(void); // debug function to validate heaps
279 
280 // End of platform-specific functions
281 //================
282 
283 class Group;
284 class SSurface;
285 #include "dsc.h"
286 #include "polygon.h"
287 #include "srf/surface.h"
288 
289 class Entity;
290 class hEntity;
291 class Param;
292 class hParam;
293 typedef IdList<Entity,hEntity> EntityList;
294 typedef IdList<Param,hParam> ParamList;
295 
296 #include "sketch.h"
297 #include "ui.h"
298 #include "expr.h"
299 
300 
301 // Utility functions that are provided in the platform-independent code.
302 class utf8_iterator : std::iterator<std::forward_iterator_tag, char32_t> {
303     const char *p, *n;
304 public:
utf8_iterator(const char * p)305     utf8_iterator(const char *p) : p(p), n(NULL) {}
306     bool           operator==(const utf8_iterator &i) const { return p==i.p; }
307     bool           operator!=(const utf8_iterator &i) const { return p!=i.p; }
308     ptrdiff_t      operator- (const utf8_iterator &i) const { return p -i.p; }
309     utf8_iterator& operator++()    { **this; p=n; n=NULL; return *this; }
310     utf8_iterator  operator++(int) { utf8_iterator t(*this); operator++(); return t; }
311     char32_t       operator*();
312 };
313 class ReadUTF8 {
314     const std::string &str;
315 public:
ReadUTF8(const std::string & str)316     ReadUTF8(const std::string &str) : str(str) {}
begin()317     utf8_iterator begin() const { return utf8_iterator(&str[0]); }
end()318     utf8_iterator end()   const { return utf8_iterator(&str[str.length()]); }
319 };
320 
321 void ssglLineWidth(GLfloat width);
322 void ssglVertex3v(Vector u);
323 void ssglAxisAlignedQuad(double l, double r, double t, double b, bool lone = true);
324 void ssglAxisAlignedLineLoop(double l, double r, double t, double b);
325 #ifdef WIN32
326 #   define SSGL_CALLBACK __stdcall
327 #else
328 #   define SSGL_CALLBACK
329 #endif
330 extern "C" { typedef void SSGL_CALLBACK ssglCallbackFptr(void); }
331 void ssglTesselatePolygon(GLUtesselator *gt, SPolygon *p);
332 void ssglFillPolygon(SPolygon *p);
333 void ssglFillMesh(bool useSpecColor, RgbaColor color,
334     SMesh *m, uint32_t h, uint32_t s1, uint32_t s2);
335 void ssglDebugPolygon(SPolygon *p);
336 void ssglDrawEdges(SEdgeList *l, bool endpointsToo, hStyle hs);
337 void ssglDrawOutlines(SOutlineList *l, Vector projDir, hStyle hs);
338 void ssglDebugMesh(SMesh *m);
339 void ssglMarkPolygonNormal(SPolygon *p);
340 typedef void ssglLineFn(void *data, Vector a, Vector b);
341 void ssglWriteText(const std::string &str, double h, Vector t, Vector u, Vector v,
342     ssglLineFn *fn, void *fndata);
343 void ssglWriteTextRefCenter(const std::string &str, double h, Vector t, Vector u, Vector v,
344     ssglLineFn *fn, void *fndata);
345 double ssglStrCapHeight(double h);
346 double ssglStrFontSize(double h);
347 double ssglStrWidth(const std::string &str, double h);
348 void ssglLockColorTo(RgbaColor rgb);
349 void ssglStippledLine(Vector a, Vector b, double width,
350                       int stippleType, double stippleScale, bool maybeFat);
351 void ssglStippledLine(Vector a, Vector b, double width,
352                       const char *stipplePattern, double stippleScale, bool maybeFat);
353 void ssglFatLine(Vector a, Vector b, double width);
354 void ssglUnlockColor(void);
355 void ssglColorRGB(RgbaColor rgb);
356 void ssglColorRGBa(RgbaColor rgb, double a);
357 void ssglDepthRangeOffset(int units);
358 void ssglDepthRangeLockToFront(bool yes);
359 void ssglDrawPixelsWithTexture(uint8_t *data, int w, int h);
360 void ssglInitializeBitmapFont();
361 void ssglBitmapText(const std::string &str, Vector p);
362 void ssglBitmapCharQuad(char32_t chr, double x, double y);
363 int ssglBitmapCharWidth(char32_t chr);
364 #define TEXTURE_BACKGROUND_IMG  10
365 #define TEXTURE_DRAW_PIXELS     20
366 #define TEXTURE_COLOR_PICKER_2D 30
367 #define TEXTURE_COLOR_PICKER_1D 40
368 #define TEXTURE_BITMAP_FONT     50
369 
370 
371 #define arraylen(x) (sizeof((x))/sizeof((x)[0]))
372 #define PI (3.1415926535897931)
373 void MakeMatrix(double *mat, double a11, double a12, double a13, double a14,
374                              double a21, double a22, double a23, double a24,
375                              double a31, double a32, double a33, double a34,
376                              double a41, double a42, double a43, double a44);
377 std::string MakeAcceleratorLabel(int accel);
378 bool FilenameHasExtension(const std::string &str, const char *ext);
379 bool ReadFile(const std::string &filename, std::string *data);
380 bool WriteFile(const std::string &filename, const std::string &data);
381 void Message(const char *str, ...);
382 void Error(const char *str, ...);
383 void CnfFreezeBool(bool v, const std::string &name);
384 void CnfFreezeColor(RgbaColor v, const std::string &name);
385 bool CnfThawBool(bool v, const std::string &name);
386 RgbaColor CnfThawColor(RgbaColor v, const std::string &name);
387 
388 class System {
389 public:
390     enum { MAX_UNKNOWNS = 1024 };
391 
392     EntityList                      entity;
393     ParamList                       param;
394     IdList<Equation,hEquation>      eq;
395 
396     // A list of parameters that are being dragged; these are the ones that
397     // we should put as close as possible to their initial positions.
398     List<hParam>                    dragged;
399 
400     enum {
401         // In general, the tag indicates the subsys that a variable/equation
402         // has been assigned to; these are exceptions for variables:
403         VAR_SUBSTITUTED      = 10000,
404         VAR_DOF_TEST         = 10001,
405         // and for equations:
406         EQ_SUBSTITUTED       = 20000
407     };
408 
409     // The system Jacobian matrix
410     struct {
411         // The corresponding equation for each row
412         hEquation   eq[MAX_UNKNOWNS];
413 
414         // The corresponding parameter for each column
415         hParam      param[MAX_UNKNOWNS];
416 
417         // We're solving AX = B
418         int m, n;
419         struct {
420             Expr        *sym[MAX_UNKNOWNS][MAX_UNKNOWNS];
421             double       num[MAX_UNKNOWNS][MAX_UNKNOWNS];
422         }           A;
423 
424         double      scale[MAX_UNKNOWNS];
425 
426         // Some helpers for the least squares solve
427         double AAt[MAX_UNKNOWNS][MAX_UNKNOWNS];
428         double Z[MAX_UNKNOWNS];
429 
430         double      X[MAX_UNKNOWNS];
431 
432         struct {
433             Expr        *sym[MAX_UNKNOWNS];
434             double       num[MAX_UNKNOWNS];
435         }           B;
436     } mat;
437 
438     static const double RANK_MAG_TOLERANCE, CONVERGE_TOLERANCE;
439     int CalculateRank(void);
440     bool TestRank(void);
441     static bool SolveLinearSystem(double X[], double A[][MAX_UNKNOWNS],
442                                   double B[], int N);
443     bool SolveLeastSquares(void);
444 
445     bool WriteJacobian(int tag);
446     void EvalJacobian(void);
447 
448     void WriteEquationsExceptFor(hConstraint hc, Group *g);
449     void FindWhichToRemoveToFixJacobian(Group *g, List<hConstraint> *bad);
450     void SolveBySubstitution(void);
451 
452     bool IsDragged(hParam p);
453 
454     bool NewtonSolve(int tag);
455 
456     enum {
457         SOLVED_OKAY              = 0,
458         DIDNT_CONVERGE           = 10,
459         REDUNDANT_OKAY           = 11,
460         REDUNDANT_DIDNT_CONVERGE = 12,
461         TOO_MANY_UNKNOWNS        = 20
462     };
463     int Solve(Group *g, int *dof, List<hConstraint> *bad,
464                 bool andFindBad, bool andFindFree);
465 
466     void Clear(void);
467 };
468 
469 #include "ttf.h"
470 
471 class StepFileWriter {
472 public:
473     void ExportSurfacesTo(const std::string &filename);
474     void WriteHeader(void);
475 	void WriteProductHeader(void);
476     int ExportCurve(SBezier *sb);
477     int ExportCurveLoop(SBezierLoop *loop, bool inner);
478     void ExportSurface(SSurface *ss, SBezierList *sbl);
479     void WriteWireframe(void);
480     void WriteFooter(void);
481 
482     List<int> curves;
483     List<int> advancedFaces;
484     FILE *f;
485     int id;
486 };
487 
488 class VectorFileWriter {
489 protected:
490     Vector u, v, n, origin;
491     double cameraTan, scale;
492 
493 public:
494     FILE *f;
495     std::string filename;
496     Vector ptMin, ptMax;
497 
498     static double MmToPts(double mm);
499 
500     static VectorFileWriter *ForFile(const std::string &filename);
501 
502     ~VectorFileWriter();
503 
504     void SetModelviewProjection(const Vector &u, const Vector &v, const Vector &n,
505                                 const Vector &origin, double cameraTan, double scale);
506     Vector Transform(Vector &pos) const;
507 
508     void OutputLinesAndMesh(SBezierLoopSetSet *sblss, SMesh *sm);
509 
510     void BezierAsPwl(SBezier *sb);
511     void BezierAsNonrationalCubic(SBezier *sb, int depth=0);
512 
OutputConstraints(IdList<Constraint,hConstraint> *)513     virtual bool OutputConstraints(IdList<Constraint,hConstraint> *) { return false; }
CanOutputMesh()514     virtual bool CanOutputMesh() const { return false; }
515 
516     virtual void StartPath( RgbaColor strokeRgb, double lineWidth,
517                             bool filled, RgbaColor fillRgb, hStyle hs) = 0;
518     virtual void FinishPath(RgbaColor strokeRgb, double lineWidth,
519                             bool filled, RgbaColor fillRgb, hStyle hs) = 0;
520     virtual void Bezier(SBezier *sb) = 0;
521     virtual void Triangle(STriangle *tr) = 0;
522     virtual void StartFile(void) = 0;
523     virtual void FinishAndCloseFile(void) = 0;
524     virtual bool HasCanvasSize(void) = 0;
525 };
526 class DxfFileWriter : public VectorFileWriter {
527 public:
528     struct BezierPath {
529         std::vector<SBezier *> beziers;
530     };
531 
532     std::vector<BezierPath>         paths;
533     IdList<Constraint,hConstraint> *constraint;
534 
535     bool OutputConstraints(IdList<Constraint,hConstraint> *constraint);
536 
537     void StartPath( RgbaColor strokeRgb, double lineWidth,
538                     bool filled, RgbaColor fillRgb, hStyle hs);
539     void FinishPath(RgbaColor strokeRgb, double lineWidth,
540                     bool filled, RgbaColor fillRgb, hStyle hs);
541     void Triangle(STriangle *tr);
542     void Bezier(SBezier *sb);
543     void StartFile(void);
544     void FinishAndCloseFile(void);
HasCanvasSize(void)545     bool HasCanvasSize(void) { return false; }
546     bool NeedToOutput(Constraint *c);
547 
548     static const char *lineTypeName(int stippleType);
549 
550 };
551 class EpsFileWriter : public VectorFileWriter {
552 public:
553     Vector prevPt;
554     void MaybeMoveTo(Vector s, Vector f);
555 
556     void StartPath( RgbaColor strokeRgb, double lineWidth,
557                     bool filled, RgbaColor fillRgb, hStyle hs);
558     void FinishPath(RgbaColor strokeRgb, double lineWidth,
559                     bool filled, RgbaColor fillRgb, hStyle hs);
560     void Triangle(STriangle *tr);
561     void Bezier(SBezier *sb);
562     void StartFile(void);
563     void FinishAndCloseFile(void);
HasCanvasSize(void)564     bool HasCanvasSize(void) { return true; }
CanOutputMesh()565     bool CanOutputMesh() const { return true; }
566 };
567 class PdfFileWriter : public VectorFileWriter {
568 public:
569     uint32_t xref[10];
570     uint32_t bodyStart;
571     Vector prevPt;
572     void MaybeMoveTo(Vector s, Vector f);
573 
574     void StartPath( RgbaColor strokeRgb, double lineWidth,
575                     bool filled, RgbaColor fillRgb, hStyle hs);
576     void FinishPath(RgbaColor strokeRgb, double lineWidth,
577                     bool filled, RgbaColor fillRgb, hStyle hs);
578     void Triangle(STriangle *tr);
579     void Bezier(SBezier *sb);
580     void StartFile(void);
581     void FinishAndCloseFile(void);
HasCanvasSize(void)582     bool HasCanvasSize(void) { return true; }
CanOutputMesh()583     bool CanOutputMesh() const { return true; }
584 };
585 class SvgFileWriter : public VectorFileWriter {
586 public:
587     Vector prevPt;
588     void MaybeMoveTo(Vector s, Vector f);
589 
590     void StartPath( RgbaColor strokeRgb, double lineWidth,
591                     bool filled, RgbaColor fillRgb, hStyle hs);
592     void FinishPath(RgbaColor strokeRgb, double lineWidth,
593                     bool filled, RgbaColor fillRgb, hStyle hs);
594     void Triangle(STriangle *tr);
595     void Bezier(SBezier *sb);
596     void StartFile(void);
597     void FinishAndCloseFile(void);
HasCanvasSize(void)598     bool HasCanvasSize(void) { return true; }
CanOutputMesh()599     bool CanOutputMesh() const { return true; }
600 };
601 class HpglFileWriter : public VectorFileWriter {
602 public:
603     static double MmToHpglUnits(double mm);
604     void StartPath( RgbaColor strokeRgb, double lineWidth,
605                     bool filled, RgbaColor fillRgb, hStyle hs);
606     void FinishPath(RgbaColor strokeRgb, double lineWidth,
607                     bool filled, RgbaColor fillRgb, hStyle hs);
608     void Triangle(STriangle *tr);
609     void Bezier(SBezier *sb);
610     void StartFile(void);
611     void FinishAndCloseFile(void);
HasCanvasSize(void)612     bool HasCanvasSize(void) { return false; }
613 };
614 class Step2dFileWriter : public VectorFileWriter {
615     StepFileWriter sfw;
616     void StartPath( RgbaColor strokeRgb, double lineWidth,
617                     bool filled, RgbaColor fillRgb, hStyle hs);
618     void FinishPath(RgbaColor strokeRgb, double lineWidth,
619                     bool filled, RgbaColor fillRgb, hStyle hs);
620     void Triangle(STriangle *tr);
621     void Bezier(SBezier *sb);
622     void StartFile(void);
623     void FinishAndCloseFile(void);
HasCanvasSize(void)624     bool HasCanvasSize(void) { return false; }
625 };
626 class GCodeFileWriter : public VectorFileWriter {
627 public:
628     SEdgeList sel;
629     void StartPath( RgbaColor strokeRgb, double lineWidth,
630                     bool filled, RgbaColor fillRgb, hStyle hs);
631     void FinishPath(RgbaColor strokeRgb, double lineWidth,
632                     bool filled, RgbaColor fillRgb, hStyle hs);
633     void Triangle(STriangle *tr);
634     void Bezier(SBezier *sb);
635     void StartFile(void);
636     void FinishAndCloseFile(void);
HasCanvasSize(void)637     bool HasCanvasSize(void) { return false; }
638 };
639 
640 #ifdef LIBRARY
641 #   define ENTITY EntityBase
642 #   define CONSTRAINT ConstraintBase
643 #else
644 #   define ENTITY Entity
645 #   define CONSTRAINT Constraint
646 #endif
647 class Sketch {
648 public:
649     // These are user-editable, and define the sketch.
650     IdList<Group,hGroup>            group;
651     List<hGroup>                    groupOrder;
652     IdList<CONSTRAINT,hConstraint>  constraint;
653     IdList<Request,hRequest>        request;
654     IdList<Style,hStyle>            style;
655 
656     // These are generated from the above.
657     IdList<ENTITY,hEntity>          entity;
658     IdList<Param,hParam>            param;
659 
GetConstraint(hConstraint h)660     inline CONSTRAINT *GetConstraint(hConstraint h)
661         { return constraint.FindById(h); }
GetEntity(hEntity h)662     inline ENTITY  *GetEntity (hEntity  h) { return entity. FindById(h); }
GetParam(hParam h)663     inline Param   *GetParam  (hParam   h) { return param.  FindById(h); }
GetRequest(hRequest h)664     inline Request *GetRequest(hRequest h) { return request.FindById(h); }
GetGroup(hGroup h)665     inline Group   *GetGroup  (hGroup   h) { return group.  FindById(h); }
666     // Styles are handled a bit differently.
667 
668     void Clear(void);
669 
670     BBox CalculateEntityBBox(bool includingInvisible);
671     Group *GetRunningMeshGroupFor(hGroup h);
672 };
673 #undef ENTITY
674 #undef CONSTRAINT
675 
676 class SolveSpaceUI {
677 public:
678     TextWindow                 *pTW;
679     TextWindow                 &TW;
680     GraphicsWindow              GW;
681 
682     // The state for undo/redo
683     typedef struct {
684         IdList<Group,hGroup>            group;
685         List<hGroup>                    groupOrder;
686         IdList<Request,hRequest>        request;
687         IdList<Constraint,hConstraint>  constraint;
688         IdList<Param,hParam>            param;
689         IdList<Style,hStyle>            style;
690         hGroup                          activeGroup;
691 
Clear__anone5eefbcb0708692         void Clear(void) {
693             group.Clear();
694             request.Clear();
695             constraint.Clear();
696             param.Clear();
697             style.Clear();
698         }
699     } UndoState;
700     enum { MAX_UNDO = 16 };
701     typedef struct {
702         UndoState   d[MAX_UNDO];
703         int         cnt;
704         int         write;
705     } UndoStack;
706     UndoStack   undo;
707     UndoStack   redo;
708     void UndoEnableMenus(void);
709     void UndoRemember(void);
710     void UndoUndo(void);
711     void UndoRedo(void);
712     void PushFromCurrentOnto(UndoStack *uk);
713     void PopOntoCurrentFrom(UndoStack *uk);
714     void UndoClearState(UndoState *ut);
715     void UndoClearStack(UndoStack *uk);
716 
717     // Little bits of extra configuration state
718     enum { MODEL_COLORS = 8 };
719     RgbaColor modelColor[MODEL_COLORS];
720     Vector   lightDir[2];
721     double   lightIntensity[2];
722     double   ambientIntensity;
723     double   chordTol;
724     double   chordTolCalculated;
725     int      maxSegments;
726     double   exportChordTol;
727     int      exportMaxSegments;
728     double   cameraTangent;
729     float    gridSpacing;
730     float    exportScale;
731     float    exportOffset;
732     bool     fixExportColors;
733     bool     drawBackFaces;
734     bool     checkClosedContour;
735     bool     showToolbar;
736     RgbaColor backgroundColor;
737     bool     exportShadedTriangles;
738     bool     exportPwlCurves;
739     bool     exportCanvasSizeAuto;
740     bool     exportMode;
741     struct {
742         float   left;
743         float   right;
744         float   bottom;
745         float   top;
746     }        exportMargin;
747     struct {
748         float   width;
749         float   height;
750         float   dx;
751         float   dy;
752     }        exportCanvas;
753     struct {
754         float   depth;
755         int     passes;
756         float   feed;
757         float   plungeFeed;
758     }        gCode;
759 
760     typedef enum {
761         UNIT_MM = 0,
762         UNIT_INCHES
763     } Unit;
764     Unit     viewUnits;
765     int      afterDecimalMm;
766     int      afterDecimalInch;
767     int      autosaveInterval; // in minutes
768 
769     std::string MmToString(double v);
770     double ExprToMm(Expr *e);
771     double StringToMm(const std::string &s);
772     const char *UnitName(void);
773     double MmPerUnit(void);
774     int UnitDigitsAfterDecimal(void);
775     void SetUnitDigitsAfterDecimal(int v);
776     double ChordTolMm(void);
777     double ExportChordTolMm(void);
778     int GetMaxSegments(void);
779     bool usePerspectiveProj;
780     double CameraTangent(void);
781 
782     // Some stuff relating to the tangent arcs created non-parametrically
783     // as special requests.
784     double tangentArcRadius;
785     bool tangentArcManual;
786     bool tangentArcDeleteOld;
787 
788     // The platform-dependent code calls this before entering the msg loop
789     void Init(void);
790     bool OpenFile(const std::string &filename);
791     void Exit(void);
792 
793     // File load/save routines, including the additional files that get
794     // loaded when we have link groups.
795     FILE        *fh;
796     void AfterNewFile(void);
797     static void RemoveFromRecentList(const std::string &filename);
798     static void AddToRecentList(const std::string &filename);
799     std::string saveFile;
800     bool        fileLoadError;
801     bool        unsaved;
802     typedef struct {
803         char        type;
804         const char *desc;
805         char        fmt;
806         void       *ptr;
807     } SaveTable;
808     static const SaveTable SAVED[];
809     void SaveUsingTable(int type);
810     void LoadUsingTable(char *key, char *val);
811     struct {
812         Group        g;
813         Request      r;
814         Entity       e;
815         Param        p;
816         Constraint   c;
817         Style        s;
818     } sv;
819     static void MenuFile(int id);
820 	bool Autosave();
821     void RemoveAutosave();
822     bool GetFilenameAndSave(bool saveAs);
823     bool OkayToStartNewFile(void);
824     hGroup CreateDefaultDrawingGroup(void);
825     void UpdateWindowTitle(void);
826     void ClearExisting(void);
827     void NewFile(void);
828     bool SaveToFile(const std::string &filename);
829     bool LoadAutosaveFor(const std::string &filename);
830     bool LoadFromFile(const std::string &filename);
831     bool LoadEntitiesFromFile(const std::string &filename, EntityList *le,
832                               SMesh *m, SShell *sh);
833     bool ReloadAllImported(bool canCancel=false);
834     // And the various export options
835     void ExportAsPngTo(const std::string &filename);
836     void ExportMeshTo(const std::string &filename);
837     void ExportMeshAsStlTo(FILE *f, SMesh *sm);
838     void ExportMeshAsObjTo(FILE *f, SMesh *sm);
839     void ExportMeshAsThreeJsTo(FILE *f, const std::string &filename,
840                                SMesh *sm, SEdgeList *sel);
841     void ExportViewOrWireframeTo(const std::string &filename, bool wireframe);
842     void ExportSectionTo(const std::string &filename);
843     void ExportWireframeCurves(SEdgeList *sel, SBezierList *sbl,
844                                VectorFileWriter *out);
845     void ExportLinesAndMesh(SEdgeList *sel, SBezierList *sbl, SMesh *sm,
846                             Vector u, Vector v, Vector n, Vector origin,
847                                 double cameraTan,
848                             VectorFileWriter *out);
849 
850     static void MenuAnalyze(int id);
851 
852     // Additional display stuff
853     struct {
854         SContour    path;
855         hEntity     point;
856     } traced;
857     SEdgeList nakedEdges;
858     struct {
859         bool        draw;
860         Vector      ptA;
861         Vector      ptB;
862     } extraLine;
863     struct {
864         uint8_t     *fromFile;
865         int         w, h;
866         int         rw, rh;
867         double      scale; // pixels per mm
868         Vector      origin;
869     } bgImage;
870     struct {
871         bool        draw, showOrigin;
872         Vector      pt, u, v;
873     } justExportedInfo;
874 
875     class Clipboard {
876     public:
877         List<ClipboardRequest>  r;
878         List<Constraint>        c;
879 
880         void Clear(void);
881         bool ContainsEntity(hEntity old);
882         hEntity NewEntityFor(hEntity old);
883     };
884     Clipboard clipboard;
885 
886     void MarkGroupDirty(hGroup hg);
887     void MarkGroupDirtyByEntity(hEntity he);
888 
889     // Consistency checking on the sketch: stuff with missing dependencies
890     // will get deleted automatically.
891     struct {
892         int     requests;
893         int     groups;
894         int     constraints;
895         int     nonTrivialConstraints;
896     } deleted;
897     bool GroupExists(hGroup hg);
898     bool PruneOrphans(void);
899     bool EntityExists(hEntity he);
900     bool GroupsInOrder(hGroup before, hGroup after);
901     bool PruneGroups(hGroup hg);
902     bool PruneRequests(hGroup hg);
903     bool PruneConstraints(hGroup hg);
904 
905     enum GenerateType {
906         GENERATE_DIRTY,
907         GENERATE_ALL,
908         GENERATE_REGEN,
909         GENERATE_UNTIL_ACTIVE,
910     };
911 
912     void GenerateAll(GenerateType type = GENERATE_DIRTY, bool andFindFree = false,
913                      bool genForBBox = false);
914     void SolveGroup(hGroup hg, bool andFindFree);
915     void SolveGroupAndReport(hGroup hg, bool andFindFree);
916     void MarkDraggedParams(void);
917     void ForceReferences(void);
918 
919     bool ActiveGroupsOkay(void);
920 
921     // The system to be solved.
922     System     *pSys;
923     System     &sys;
924 
925     // All the TrueType fonts in memory
926     TtfFontList fonts;
927 
928     // Everything has been pruned, so we know there's no dangling references
929     // to entities that don't exist. Before that, we mustn't try to display
930     // the sketch!
931     bool allConsistent;
932 
933     struct {
934         bool    scheduled;
935         bool    showTW;
936         bool    generateAll;
937     } later;
938     void ScheduleShowTW();
939     void ScheduleGenerateAll();
940     void DoLater(void);
941 
942     static void MenuHelp(int id);
943 
944     void Clear(void);
945 
946     // We allocate TW and sys on the heap to work around an MSVC problem
947     // where it puts zero-initialized global data in the binary (~30M of zeroes)
948     // in release builds.
SolveSpaceUI()949     SolveSpaceUI()
950         : pTW(new TextWindow({})), TW(*pTW),
951           pSys(new System({})), sys(*pSys) {}
952 
~SolveSpaceUI()953     ~SolveSpaceUI() {
954         delete pTW;
955         delete pSys;
956     }
957 };
958 
959 void ImportDxf(const std::string &file);
960 void ImportDwg(const std::string &file);
961 
962 extern SolveSpaceUI SS;
963 extern Sketch SK;
964 
965 };
966 
967 #ifndef __OBJC__
968 using namespace SolveSpace;
969 #endif
970 
971 #endif
972