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