FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Blaming solvespace/src/exportvector.cpp at master · solvespace/solvespace · GitHub

Blaming solvespace/src/exportvector.cpp at master · solvespace/solvespace · GitHub
Skip to content

Navigation Menu

Latest commit

 

History

History
1365 lines (1200 loc) · 45.9 KB

File metadata and controls

1365 lines (1200 loc) · 45.9 KB
 
1
//-----------------------------------------------------------------------------
2
// The file format-specific stuff for all of the 2d vector output formats.
Jul 28, 2013
Jul 28, 2013
3
//
4
// Copyright 2008-2013 Jonathan Westhues.
5
//-----------------------------------------------------------------------------
Feb 19, 2016
Feb 19, 2016
6
#include <libdxfrw.h>
7
#include "solvespace.h"
8
Sep 12, 2025
Sep 12, 2025
9
namespace SolveSpace {
10
11
//-----------------------------------------------------------------------------
12
// Routines for DXF export
13
//-----------------------------------------------------------------------------
Feb 19, 2016
Feb 19, 2016
14
class DxfWriteInterface : public DRW_Interface {
Jun 29, 2016
Jun 29, 2016
15
public:
Feb 19, 2016
Feb 19, 2016
16
DxfFileWriter *writer;
Jun 29, 2016
Jun 29, 2016
17
dxfRW *dxf;
18
19
std::set<std::string> messages;
Feb 19, 2016
Feb 19, 2016
20
Feb 19, 2016
Feb 19, 2016
21
static DRW_Coord toCoord(const Vector &v) {
22
return DRW_Coord(v.x, v.y, v.z);
23
}
24
25
Vector xfrm(Vector v) {
26
return writer->Transform(v);
27
}
28
May 18, 2016
May 18, 2016
29
void writeTextstyles() override {
Feb 19, 2016
Feb 19, 2016
30
DRW_Textstyle ts;
31
ts.name = "unicode";
32
ts.font = "unicode";
33
dxf->writeTextstyle(&ts);
34
}
35
May 18, 2016
May 18, 2016
36
void writeLayers() override {
Feb 19, 2016
Feb 19, 2016
37
DRW_Layer layer;
Apr 14, 2016
Apr 14, 2016
38
Feb 19, 2016
Feb 19, 2016
39
layer.name = "dimensions";
40
dxf->writeLayer(&layer);
41
layer.name = "text";
42
dxf->writeLayer(&layer);
Apr 14, 2016
Apr 14, 2016
43
Aug 13, 2016
Aug 13, 2016
44
std::set<uint32_t> usedStyles;
45
46
for(DxfFileWriter::BezierPath &path : writer->paths) {
47
for(SBezier *sb : path.beziers) {
48
usedStyles.insert((uint32_t)sb->auxA);
Apr 14, 2016
Apr 14, 2016
49
}
Aug 13, 2016
Aug 13, 2016
50
}
Apr 14, 2016
Apr 14, 2016
51
Aug 13, 2016
Aug 13, 2016
52
for(uint32_t v : usedStyles) {
53
Style *s = Style::Get(hStyle{v});
Apr 14, 2016
Apr 14, 2016
54
layer.name = s->DescriptionString();
55
dxf->writeLayer(&layer);
56
}
Feb 19, 2016
Feb 19, 2016
57
}
58
May 18, 2016
May 18, 2016
59
void writeLTypes() override {
May 25, 2016
May 25, 2016
60
for(uint32_t i = 0; i <= (uint32_t)StipplePattern::LAST; i++) {
61
StipplePattern st = (StipplePattern)i;
Mar 5, 2016
Mar 5, 2016
62
DRW_LType type;
63
// LibreCAD requires the line type to have one of these exact names,
64
// or otherwise it overwrites it with its own (continuous) style.
May 25, 2016
May 25, 2016
65
type.name = DxfFileWriter::lineTypeName(st);
Mar 5, 2016
Mar 5, 2016
66
double sw = 1.0;
May 25, 2016
May 25, 2016
67
switch(st) {
68
case StipplePattern::CONTINUOUS:
Mar 5, 2016
Mar 5, 2016
69
break;
70
May 27, 2016
May 27, 2016
71
case StipplePattern::SHORT_DASH:
72
type.path.push_back(sw);
73
type.path.push_back(-sw * 2.0);
74
break;
75
May 25, 2016
May 25, 2016
76
case StipplePattern::DASH:
Mar 5, 2016
Mar 5, 2016
77
type.path.push_back(sw);
78
type.path.push_back(-sw);
79
break;
80
May 25, 2016
May 25, 2016
81
case StipplePattern::LONG_DASH:
Mar 5, 2016
Mar 5, 2016
82
type.path.push_back(sw * 2.0);
83
type.path.push_back(-sw);
84
break;
85
May 25, 2016
May 25, 2016
86
case StipplePattern::DASH_DOT:
Mar 5, 2016
Mar 5, 2016
87
type.path.push_back(sw);
88
type.path.push_back(-sw);
89
type.path.push_back(0.0);
90
type.path.push_back(-sw);
91
break;
92
May 25, 2016
May 25, 2016
93
case StipplePattern::DOT:
Mar 5, 2016
Mar 5, 2016
94
type.path.push_back(sw);
95
type.path.push_back(0.0);
96
break;
97
May 25, 2016
May 25, 2016
98
case StipplePattern::DASH_DOT_DOT:
Mar 5, 2016
Mar 5, 2016
99
type.path.push_back(sw);
100
type.path.push_back(-sw);
101
type.path.push_back(0.0);
102
type.path.push_back(-sw);
103
type.path.push_back(0.0);
104
type.path.push_back(-sw);
105
break;
May 26, 2016
May 26, 2016
106
107
case StipplePattern::FREEHAND:
108
case StipplePattern::ZIGZAG:
Jun 29, 2016
Jun 29, 2016
109
// Not implemented; exported as continuous.
110
break;
Mar 5, 2016
Mar 5, 2016
111
}
112
dxf->writeLineType(&type);
113
}
114
}
115
Apr 23, 2016
Apr 23, 2016
116
void writePolylines() {
117
PolylineBuilder builder;
118
119
for(DxfFileWriter::BezierPath &path : writer->paths) {
120
for(SBezier *sb : path.beziers) {
121
if(sb->deg != 1) continue;
Oct 13, 2016
Oct 13, 2016
122
builder.AddEdge(sb->ctrl[0], sb->ctrl[1], (uint32_t)sb->auxA);
Apr 23, 2016
Apr 23, 2016
123
}
124
}
125
Nov 26, 2016
Nov 26, 2016
126
DRW_Polyline polyline;
Apr 23, 2016
Apr 23, 2016
127
Oct 13, 2016
Oct 13, 2016
128
auto startFunc = [&](PolylineBuilder::Vertex *start,
129
PolylineBuilder::Vertex *next,
130
PolylineBuilder::Edge *e) {
131
hStyle hs = { e->kind };
132
polyline = {};
133
assignEntityDefaults(&polyline, hs);
Feb 5, 2017
Feb 5, 2017
134
135
if(!(EXACT(start->pos.z == 0.0) && EXACT(next->pos.z == 0.0))) {
136
polyline.flags |= 8 /* 3d polyline */;
137
}
Nov 26, 2016
Nov 26, 2016
138
polyline.vertlist.push_back(
Aug 10, 2025
Aug 10, 2025
139
std::make_shared<DRW_Vertex>(start->pos.x, start->pos.y, start->pos.z, 0.0));
Nov 26, 2016
Nov 26, 2016
140
polyline.vertlist.push_back(
Aug 10, 2025
Aug 10, 2025
141
std::make_shared<DRW_Vertex>(next->pos.x, next->pos.y, next->pos.z, 0.0));
Oct 13, 2016
Oct 13, 2016
142
};
Apr 23, 2016
Apr 23, 2016
143
Oct 13, 2016
Oct 13, 2016
144
auto nextFunc = [&](PolylineBuilder::Vertex *next, PolylineBuilder::Edge *e) {
Feb 5, 2017
Feb 5, 2017
145
if(!EXACT(next->pos.z == 0.0)) {
146
polyline.flags |= 8 /* 3d polyline */;
147
}
Nov 26, 2016
Nov 26, 2016
148
polyline.vertlist.push_back(
Aug 10, 2025
Aug 10, 2025
149
std::make_shared<DRW_Vertex>(next->pos.x, next->pos.y, next->pos.z, 0.0));
Oct 13, 2016
Oct 13, 2016
150
};
Apr 23, 2016
Apr 23, 2016
151
Oct 13, 2016
Oct 13, 2016
152
auto endFunc = [&]() {
Nov 26, 2016
Nov 26, 2016
153
dxf->writePolyline(&polyline);
Oct 13, 2016
Oct 13, 2016
154
};
Apr 23, 2016
Apr 23, 2016
155
Oct 13, 2016
Oct 13, 2016
156
auto aloneFunc = [&](PolylineBuilder::Edge *e) {
157
hStyle hs = { e->kind };
158
writeLine(e->a->pos, e->b->pos, hs);
159
};
160
161
builder.Generate(startFunc, nextFunc, aloneFunc, endFunc);
Apr 23, 2016
Apr 23, 2016
162
}
163
May 18, 2016
May 18, 2016
164
void writeEntities() override {
Apr 23, 2016
Apr 23, 2016
165
writePolylines();
166
Feb 19, 2016
Feb 19, 2016
167
for(DxfFileWriter::BezierPath &path : writer->paths) {
168
for(SBezier *sb : path.beziers) {
Apr 23, 2016
Apr 23, 2016
169
if(sb->deg == 1) continue;
Feb 19, 2016
Feb 19, 2016
170
writeBezier(sb);
171
}
Feb 19, 2016
Feb 19, 2016
172
}
Feb 19, 2016
Feb 19, 2016
173
174
if(writer->constraint) {
May 12, 2021
May 12, 2021
175
for(Constraint &c : *writer->constraint) {
176
if(!writer->NeedToOutput(&c)) continue;
177
switch(c.type) {
May 25, 2016
May 25, 2016
178
case Constraint::Type::PT_PT_DISTANCE: {
May 12, 2021
May 12, 2021
179
Vector ap = SK.GetEntity(c.ptA)->PointGetNum();
180
Vector bp = SK.GetEntity(c.ptB)->PointGetNum();
181
Vector ref = ((ap.Plus(bp)).ScaledBy(0.5)).Plus(c.disp.offset);
Feb 19, 2016
Feb 19, 2016
182
writeAlignedDimension(xfrm(ap), xfrm(bp), xfrm(ref),
May 12, 2021
May 12, 2021
183
xfrm(ref), c.Label(), c.GetStyle(), c.valA);
Feb 19, 2016
Feb 19, 2016
184
break;
185
}
186
May 25, 2016
May 25, 2016
187
case Constraint::Type::PT_LINE_DISTANCE: {
May 12, 2021
May 12, 2021
188
Vector pt = SK.GetEntity(c.ptA)->PointGetNum();
189
Entity *line = SK.GetEntity(c.entityA);
Feb 19, 2016
Feb 19, 2016
190
Vector lA = SK.GetEntity(line->point[0])->PointGetNum();
191
Vector lB = SK.GetEntity(line->point[1])->PointGetNum();
192
Vector dl = lB.Minus(lA);
193
194
Vector closest = pt.ClosestPointOnLine(lA, dl);
195
196
if(pt.Equals(closest)) break;
197
May 12, 2021
May 12, 2021
198
Vector ref = ((closest.Plus(pt)).ScaledBy(0.5)).Plus(c.disp.offset);
Feb 19, 2016
Feb 19, 2016
199
Vector refClosest = ref.ClosestPointOnLine(lA, dl);
200
201
double ddl = dl.Dot(dl);
202
if(fabs(ddl) > LENGTH_EPS * LENGTH_EPS) {
203
double t = refClosest.Minus(lA).Dot(dl) / ddl;
204
if(t < 0.0) {
205
refClosest = lA;
206
} else if(t > 1.0) {
207
refClosest = lB;
208
}
209
}
210
211
Vector xdl = xfrm(lB).Minus(xfrm(lA));
212
writeLinearDimension(xfrm(pt), xfrm(refClosest), xfrm(ref),
May 12, 2021
May 12, 2021
213
xfrm(ref), c.Label(),
May 17, 2016
May 17, 2016
214
atan2(xdl.y, xdl.x) / PI * 180.0 + 90.0, 0.0,
May 12, 2021
May 12, 2021
215
c.GetStyle(), c.valA);
Feb 19, 2016
Feb 19, 2016
216
break;
217
}
218
May 25, 2016
May 25, 2016
219
case Constraint::Type::DIAMETER: {
May 12, 2021
May 12, 2021
220
Entity *circle = SK.GetEntity(c.entityA);
Feb 19, 2016
Feb 19, 2016
221
Vector center = SK.GetEntity(circle->point[0])->PointGetNum();
222
Quaternion q = SK.GetEntity(circle->normal)->NormalGetNum();
223
Vector n = q.RotationN().WithMagnitude(1);
224
double r = circle->CircleGetRadiusNum();
225
May 12, 2021
May 12, 2021
226
Vector ref = center.Plus(c.disp.offset);
Feb 19, 2016
Feb 19, 2016
227
// Force the label into the same plane as the circle.
228
ref = ref.Minus(n.ScaledBy(n.Dot(ref) - n.Dot(center)));
229
230
Vector rad = ref.Minus(center).WithMagnitude(r);
May 12, 2021
May 12, 2021
231
if(/*isRadius*/c.other) {
Feb 19, 2016
Feb 19, 2016
232
writeRadialDimension(
233
xfrm(center), xfrm(center.Plus(rad)),
May 12, 2021
May 12, 2021
234
xfrm(ref), c.Label(), c.GetStyle(), c.valA);
Feb 19, 2016
Feb 19, 2016
235
} else {
236
writeDiametricDimension(
237
xfrm(center.Minus(rad)), xfrm(center.Plus(rad)),
May 12, 2021
May 12, 2021
238
xfrm(ref), c.Label(), c.GetStyle(), c.valA);
Feb 19, 2016
Feb 19, 2016
239
}
240
break;
241
}
242
May 25, 2016
May 25, 2016
243
case Constraint::Type::ANGLE: {
May 12, 2021
May 12, 2021
244
Entity *a = SK.GetEntity(c.entityA);
245
Entity *b = SK.GetEntity(c.entityB);
Feb 19, 2016
Feb 19, 2016
246
247
Vector a0 = a->VectorGetStartPoint();
248
Vector b0 = b->VectorGetStartPoint();
249
Vector da = a->VectorGetNum();
250
Vector db = b->VectorGetNum();
May 12, 2021
May 12, 2021
251
if(/*otherAngle*/c.other) {
Feb 19, 2016
Feb 19, 2016
252
a0 = a0.Plus(da);
253
da = da.ScaledBy(-1);
254
}
255
256
bool skew = false;
May 12, 2021
May 12, 2021
257
Vector ref = c.disp.offset;
Feb 19, 2016
Feb 19, 2016
258
Vector pi = Vector::AtIntersectionOfLines(a0, a0.Plus(da), b0, b0.Plus(db),
259
&skew);
May 12, 2021
May 12, 2021
260
if(!skew) ref = pi.Plus(c.disp.offset);
Feb 19, 2016
Feb 19, 2016
261
May 17, 2016
May 17, 2016
262
Vector norm = da.Cross(db);
263
Vector dna = norm.Cross(da).WithMagnitude(1.0);
264
265
double thetaf = acos(da.DirectionCosineWith(db));
May 18, 2016
May 18, 2016
266
May 17, 2016
May 17, 2016
267
// Calculate median
268
Vector m = da.WithMagnitude(1.0).ScaledBy(cos(thetaf/2)).Plus(
269
dna.ScaledBy(sin(thetaf/2)));
270
Vector rm = ref.Minus(pi);
271
272
// Test which side we have to place an arc
273
if(m.Dot(rm) < 0) {
274
da = da.ScaledBy(-1); dna = dna.ScaledBy(-1);
275
db = db.ScaledBy(-1);
276
}
277
278
Vector bisect = da.WithMagnitude(1.0).ScaledBy(cos(thetaf / 2.0)).Plus(
279
dna.ScaledBy(sin(thetaf / 2.0)));
280
May 12, 2021
May 12, 2021
281
ref = pi.Plus(bisect.WithMagnitude(c.disp.offset.Magnitude()));
May 17, 2016
May 17, 2016
282
Jul 12, 2018
Jul 12, 2018
283
// Get lines again to write exact line.
May 17, 2016
May 17, 2016
284
a0 = a->VectorGetStartPoint();
285
b0 = b->VectorGetStartPoint();
286
da = a->VectorGetNum();
287
db = b->VectorGetNum();
288
Feb 19, 2016
Feb 19, 2016
289
writeAngularDimension(
290
xfrm(a0), xfrm(a0.Plus(da)), xfrm(b0), xfrm(b0.Plus(db)), xfrm(ref),
May 12, 2021
May 12, 2021
291
xfrm(ref), c.Label(), c.GetStyle(), c.valA);
Feb 19, 2016
Feb 19, 2016
292
break;
293
}
294
May 25, 2016
May 25, 2016
295
case Constraint::Type::COMMENT: {
May 12, 2021
May 12, 2021
296
Style *st = SK.style.FindById(c.GetStyle());
297
writeText(xfrm(c.disp.offset), c.Label(),
298
Style::TextHeight(c.GetStyle()) / SS.GW.scale,
299
st->textAngle, st->textOrigin, c.GetStyle());
Feb 19, 2016
Feb 19, 2016
300
break;
301
}
May 26, 2016
May 26, 2016
302
303
default:
304
// Other types of constraints do not have a DXF dimension equivalent.
305
break;
Feb 19, 2016
Feb 19, 2016
306
}
307
}
308
}
Feb 19, 2016
Feb 19, 2016
309
}
310
May 17, 2016
May 17, 2016
311
int findDxfColor(const RgbaColor &src) {
312
int best = 0;
313
double minDist = VERY_POSITIVE;
Apr 8, 2026
Apr 8, 2026
314
Vector srcv = {src.redF(), src.greenF(), src.blueF()};
May 17, 2016
May 17, 2016
315
for(int i = 1; i < 256; i++) {
316
RgbaColor dst = RGBi(DRW::dxfColors[i][0], DRW::dxfColors[i][1], DRW::dxfColors[i][2]);
Apr 8, 2026
Apr 8, 2026
317
Vector dstv = {dst.redF(), dst.greenF(), dst.blueF()};
May 17, 2016
May 17, 2016
318
double dist = srcv.Minus(dstv).Magnitude();
319
if(dist < minDist || best == 0) {
320
best = i;
321
minDist = dist;
322
}
323
}
324
return best;
325
}
326
Apr 14, 2016
Apr 14, 2016
327
void assignEntityDefaults(DRW_Entity *entity, hStyle hs) {
Mar 5, 2016
Mar 5, 2016
328
Style *s = Style::Get(hs);
Sep 11, 2019
Sep 11, 2019
329
RgbaColor color = Style::Color(hs, /*forExport=*/true);
May 17, 2016
May 17, 2016
330
entity->color24 = color.ToPackedIntBGRA();
331
entity->color = findDxfColor(color);
Apr 14, 2016
Apr 14, 2016
332
entity->layer = s->DescriptionString();
May 7, 2016
May 7, 2016
333
entity->lineType = DxfFileWriter::lineTypeName(s->stippleType);
Mar 5, 2016
Mar 5, 2016
334
entity->ltypeScale = Style::StippleScaleMm(s->h);
Apr 14, 2016
Apr 14, 2016
335
entity->setWidthMm(Style::WidthMm(hs.v));
Jun 29, 2016
Jun 29, 2016
336
337
if(s->stippleType == StipplePattern::FREEHAND) {
Jan 7, 2017
Jan 7, 2017
338
messages.insert(_("freehand lines were replaced with continuous lines"));
Jun 29, 2016
Jun 29, 2016
339
} else if(s->stippleType == StipplePattern::ZIGZAG) {
Jan 7, 2017
Jan 7, 2017
340
messages.insert(_("zigzag lines were replaced with continuous lines"));
Jun 29, 2016
Jun 29, 2016
341
}
Feb 19, 2016
Feb 19, 2016
342
}
343
May 17, 2016
May 17, 2016
344
void assignDimensionDefaults(DRW_Dimension *dimension, hStyle hs) {
345
assignEntityDefaults(dimension, hs);
Feb 19, 2016
Feb 19, 2016
346
dimension->layer = "dimensions";
347
}
348
Apr 14, 2016
Apr 14, 2016
349
void writeLine(const Vector &p0, const Vector &p1, hStyle hs) {
Feb 19, 2016
Feb 19, 2016
350
DRW_Line line;
Apr 14, 2016
Apr 14, 2016
351
assignEntityDefaults(&line, hs);
Feb 19, 2016
Feb 19, 2016
352
line.basePoint = toCoord(p0);
353
line.secPoint = toCoord(p1);
Feb 19, 2016
Feb 19, 2016
354
dxf->writeLine(&line);
355
}
356
Apr 14, 2016
Apr 14, 2016
357
void writeArc(const Vector &c, double r, double sa, double ea, hStyle hs) {
Feb 19, 2016
Feb 19, 2016
358
DRW_Arc arc;
Apr 14, 2016
Apr 14, 2016
359
assignEntityDefaults(&arc, hs);
Feb 19, 2016
Feb 19, 2016
360
arc.radious = r;
Feb 19, 2016
Feb 19, 2016
361
arc.basePoint = toCoord(c);
Feb 19, 2016
Feb 19, 2016
362
arc.staangle = sa;
363
arc.endangle = ea;
364
dxf->writeArc(&arc);
365
}
366
367
void writeBezierAsPwl(SBezier *sb) {
368
List<Vector> lv = {};
369
sb->MakePwlInto(&lv, SS.ExportChordTolMm());
Apr 14, 2016
Apr 14, 2016
370
hStyle hs = { (uint32_t)sb->auxA };
Nov 26, 2016
Nov 26, 2016
371
DRW_Polyline polyline;
Apr 14, 2016
Apr 14, 2016
372
assignEntityDefaults(&polyline, hs);
Feb 19, 2016
Feb 19, 2016
373
for(int i = 0; i < lv.n; i++) {
Aug 20, 2019
Aug 20, 2019
374
Vector *v = &lv[i];
Aug 10, 2025
Aug 10, 2025
375
polyline.vertlist.push_back(std::make_shared<DRW_Vertex>(v->x, v->y, v->z, 0.0));
Feb 19, 2016
Feb 19, 2016
376
}
Nov 26, 2016
Nov 26, 2016
377
dxf->writePolyline(&polyline);
Feb 19, 2016
Feb 19, 2016
378
lv.Clear();
379
}
380
Feb 19, 2016
Feb 19, 2016
381
void makeKnotsFor(DRW_Spline *spline) {
382
// QCad/LibreCAD require this for some reason.
383
if(spline->degree == 3) {
384
spline->nknots = 8;
385
spline->knotslist.push_back(0.0);
386
spline->knotslist.push_back(0.0);
387
spline->knotslist.push_back(0.0);
388
spline->knotslist.push_back(0.0);
389
spline->knotslist.push_back(1.0);
390
spline->knotslist.push_back(1.0);
391
spline->knotslist.push_back(1.0);
392
spline->knotslist.push_back(1.0);
393
} else if(spline->degree == 2) {
394
spline->nknots = 6;
395
spline->knotslist.push_back(0.0);
396
spline->knotslist.push_back(0.0);
397
spline->knotslist.push_back(0.0);
398
spline->knotslist.push_back(1.0);
399
spline->knotslist.push_back(1.0);
400
spline->knotslist.push_back(1.0);
May 20, 2016
May 20, 2016
401
} else ssassert(false, "Unexpected degree of spline");
Feb 19, 2016
Feb 19, 2016
402
}
403
404
void writeSpline(SBezier *sb) {
405
bool isRational = sb->IsRational();
Apr 14, 2016
Apr 14, 2016
406
hStyle hs = { (uint32_t)sb->auxA };
Feb 19, 2016
Feb 19, 2016
407
DRW_Spline spline;
Apr 14, 2016
Apr 14, 2016
408
assignEntityDefaults(&spline, hs);
Feb 19, 2016
Feb 19, 2016
409
spline.flags = (isRational) ? 0x04 : 0x08;
410
spline.degree = sb->deg;
411
spline.ncontrol = sb->deg + 1;
412
makeKnotsFor(&spline);
413
for(int i = 0; i <= sb->deg; i++) {
Nov 26, 2016
Nov 26, 2016
414
spline.controllist.push_back(
Aug 10, 2025
Aug 10, 2025
415
std::make_shared<DRW_Coord>(sb->ctrl[i].x, sb->ctrl[i].y, sb->ctrl[i].z));
Feb 19, 2016
Feb 19, 2016
416
if(isRational) spline.weightlist.push_back(sb->weight[i]);
417
}
418
dxf->writeSpline(&spline);
419
}
420
Feb 19, 2016
Feb 19, 2016
421
void writeBezier(SBezier *sb) {
Apr 14, 2016
Apr 14, 2016
422
hStyle hs = { (uint32_t)sb->auxA };
Feb 19, 2016
Feb 19, 2016
423
Vector c;
Apr 8, 2026
Apr 8, 2026
424
Vector n = {0.0, 0.0, 1.0};
Feb 19, 2016
Feb 19, 2016
425
double r;
426
427
if(sb->deg == 1) {
428
// Line
Apr 14, 2016
Apr 14, 2016
429
writeLine(sb->ctrl[0], sb->ctrl[1], hs);
Feb 19, 2016
Feb 19, 2016
430
} else if(sb->IsInPlane(n, 0) && sb->IsCircle(n, &c, &r)) {
431
// Circle perpendicular to camera
432
double theta0 = atan2(sb->ctrl[0].y - c.y, sb->ctrl[0].x - c.x);
433
double theta1 = atan2(sb->ctrl[2].y - c.y, sb->ctrl[2].x - c.x);
434
double dtheta = WRAP_SYMMETRIC(theta1 - theta0, 2.0 * PI);
435
if(dtheta < 0.0) swap(theta0, theta1);
436
Apr 14, 2016
Apr 14, 2016
437
writeArc(c, r, theta0, theta1, hs);
Feb 19, 2016
Feb 19, 2016
438
} else if(sb->IsRational()) {
439
// Rational bezier
440
// We'd like to export rational beziers exactly, but the resulting DXF
441
// files can only be read by AutoCAD; LibreCAD/QCad simply do not
Jul 12, 2018
Jul 12, 2018
442
// implement the feature. So, export as piecewise linear for compatibility.
Feb 19, 2016
Feb 19, 2016
443
writeBezierAsPwl(sb);
Feb 19, 2016
Feb 19, 2016
444
} else {
445
// Any other curve
Feb 19, 2016
Feb 19, 2016
446
writeSpline(sb);
Feb 19, 2016
Feb 19, 2016
447
}
448
}
Feb 19, 2016
Feb 19, 2016
449
Feb 19, 2016
Feb 19, 2016
450
void writeAlignedDimension(Vector def1, Vector def2, Vector dimp,
May 17, 2016
May 17, 2016
451
Vector textp, const std::string &text, hStyle hs, double actual) {
Feb 19, 2016
Feb 19, 2016
452
DRW_DimAligned dim;
May 17, 2016
May 17, 2016
453
assignDimensionDefaults(&dim, hs);
Feb 19, 2016
Feb 19, 2016
454
dim.setDef1Point(toCoord(def1));
455
dim.setDef2Point(toCoord(def2));
456
dim.setDimPoint(toCoord(dimp));
457
dim.setTextPoint(toCoord(textp));
458
dim.setText(text);
May 17, 2016
May 17, 2016
459
dim.setActualMeasurement(actual);
Feb 19, 2016
Feb 19, 2016
460
dxf->writeDimension(&dim);
461
}
462
463
void writeLinearDimension(Vector def1, Vector def2, Vector dimp,
464
Vector textp, const std::string &text,
May 17, 2016
May 17, 2016
465
double angle, double oblique, hStyle hs, double actual) {
Feb 19, 2016
Feb 19, 2016
466
DRW_DimLinear dim;
May 17, 2016
May 17, 2016
467
assignDimensionDefaults(&dim, hs);
Feb 19, 2016
Feb 19, 2016
468
dim.setDef1Point(toCoord(def1));
469
dim.setDef2Point(toCoord(def2));
470
dim.setDimPoint(toCoord(dimp));
471
dim.setTextPoint(toCoord(textp));
472
dim.setText(text);
473
dim.setAngle(angle);
474
dim.setOblique(oblique);
May 17, 2016
May 17, 2016
475
dim.setActualMeasurement(actual);
Feb 19, 2016
Feb 19, 2016
476
dxf->writeDimension(&dim);
477
}
478
479
void writeRadialDimension(Vector center, Vector radius,
May 17, 2016
May 17, 2016
480
Vector textp, const std::string &text, hStyle hs, double actual) {
Feb 19, 2016
Feb 19, 2016
481
DRW_DimRadial dim;
May 17, 2016
May 17, 2016
482
assignDimensionDefaults(&dim, hs);
Feb 19, 2016
Feb 19, 2016
483
dim.setCenterPoint(toCoord(center));
484
dim.setDiameterPoint(toCoord(radius));
485
dim.setTextPoint(toCoord(textp));
486
dim.setText(text);
May 17, 2016
May 17, 2016
487
dim.setActualMeasurement(actual);
Feb 19, 2016
Feb 19, 2016
488
dxf->writeDimension(&dim);
489
}
490
491
void writeDiametricDimension(Vector def1, Vector def2,
May 17, 2016
May 17, 2016
492
Vector textp, const std::string &text, hStyle hs, double actual) {
Feb 19, 2016
Feb 19, 2016
493
DRW_DimDiametric dim;
May 17, 2016
May 17, 2016
494
assignDimensionDefaults(&dim, hs);
Feb 19, 2016
Feb 19, 2016
495
dim.setDiameter1Point(toCoord(def1));
496
dim.setDiameter2Point(toCoord(def2));
497
dim.setTextPoint(toCoord(textp));
498
dim.setText(text);
May 17, 2016
May 17, 2016
499
dim.setActualMeasurement(actual);
Feb 19, 2016
Feb 19, 2016
500
dxf->writeDimension(&dim);
501
}
502
503
void writeAngularDimension(Vector fl1, Vector fl2, Vector sl1, Vector sl2, Vector dimp,
May 17, 2016
May 17, 2016
504
Vector textp, const std::string &text, hStyle hs, double actual) {
Feb 19, 2016
Feb 19, 2016
505
DRW_DimAngular dim;
May 17, 2016
May 17, 2016
506
assignDimensionDefaults(&dim, hs);
Feb 19, 2016
Feb 19, 2016
507
dim.setFirstLine1(toCoord(fl1));
508
dim.setFirstLine2(toCoord(fl2));
509
dim.setSecondLine1(toCoord(sl1));
510
dim.setSecondLine2(toCoord(sl2));
511
dim.setDimPoint(toCoord(dimp));
512
dim.setTextPoint(toCoord(textp));
513
dim.setText(text);
May 17, 2016
May 17, 2016
514
dim.setActualMeasurement(actual * PI / 180.0);
Feb 19, 2016
Feb 19, 2016
515
dxf->writeDimension(&dim);
516
}
517
518
void writeText(Vector textp, const std::string &text,
May 25, 2016
May 25, 2016
519
double height, double angle, Style::TextOrigin origin, hStyle hs) {
Feb 19, 2016
Feb 19, 2016
520
DRW_Text txt;
May 17, 2016
May 17, 2016
521
assignEntityDefaults(&txt, hs);
Feb 19, 2016
Feb 19, 2016
522
txt.layer = "text";
Feb 19, 2016
Feb 19, 2016
523
txt.style = "unicode";
524
txt.basePoint = toCoord(textp);
525
txt.secPoint = txt.basePoint;
526
txt.text = text;
527
txt.height = height;
528
txt.angle = angle;
529
txt.alignH = DRW_Text::HCenter;
May 25, 2016
May 25, 2016
530
if((uint32_t)origin & (uint32_t)Style::TextOrigin::LEFT) {
Feb 19, 2016
Feb 19, 2016
531
txt.alignH = DRW_Text::HLeft;
May 25, 2016
May 25, 2016
532
} else if((uint32_t)origin & (uint32_t)Style::TextOrigin::RIGHT) {
Feb 19, 2016
Feb 19, 2016
533
txt.alignH = DRW_Text::HRight;
534
}
535
txt.alignV = DRW_Text::VMiddle;
May 25, 2016
May 25, 2016
536
if((uint32_t)origin & (uint32_t)Style::TextOrigin::TOP) {
Feb 19, 2016
Feb 19, 2016
537
txt.alignV = DRW_Text::VTop;
May 25, 2016
May 25, 2016
538
} else if((uint32_t)origin & (uint32_t)Style::TextOrigin::BOT) {
Feb 19, 2016
Feb 19, 2016
539
txt.alignV = DRW_Text::VBaseLine;
540
}
541
dxf->writeText(&txt);
542
}
Feb 19, 2016
Feb 19, 2016
543
};
544
Feb 19, 2016
Feb 19, 2016
545
bool DxfFileWriter::OutputConstraints(IdList<Constraint,hConstraint> *constraint) {
546
this->constraint = constraint;
547
return true;
548
}
549
May 20, 2016
May 20, 2016
550
void DxfFileWriter::StartFile() {
Feb 19, 2016
Feb 19, 2016
551
paths.clear();
Sep 6, 2020
Sep 6, 2020
554
void DxfFileWriter::Background(RgbaColor color) {
555
}
556
Jul 10, 2015
Jul 10, 2015
557
void DxfFileWriter::StartPath(RgbaColor strokeRgb, double lineWidth,
Apr 14, 2016
Apr 14, 2016
558
bool filled, RgbaColor fillRgb, hStyle hs)
Oct 30, 2009
Oct 30, 2009
559
{
Feb 19, 2016
Feb 19, 2016
560
BezierPath path = {};
561
paths.push_back(path);
Oct 30, 2009
Oct 30, 2009
562
}
Jul 10, 2015
Jul 10, 2015
563
void DxfFileWriter::FinishPath(RgbaColor strokeRgb, double lineWidth,
Aug 13, 2026
Aug 13, 2026
564
bool filled, RgbaColor fillRgb, hStyle hs, bool closed)
Oct 30, 2009
Oct 30, 2009
565
{
566
}
567
568
void DxfFileWriter::Triangle(STriangle *tr) {
569
}
570
571
void DxfFileWriter::Bezier(SBezier *sb) {
Feb 19, 2016
Feb 19, 2016
572
paths.back().beziers.push_back(sb);
May 20, 2016
May 20, 2016
575
void DxfFileWriter::FinishAndCloseFile() {
Oct 9, 2016
Oct 9, 2016
576
dxfRW dxf;
577
Jun 29, 2016
Jun 29, 2016
578
DxfWriteInterface interface = {};
579
interface.writer = this;
580
interface.dxf = &dxf;
Oct 9, 2016
Oct 9, 2016
581
Oct 9, 2016
Oct 9, 2016
582
std::stringstream stream;
Oct 9, 2016
Oct 9, 2016
583
dxf.write(stream, &interface, DRW::AC1021, /*bin=*/false);
Feb 19, 2016
Feb 19, 2016
584
paths.clear();
Feb 19, 2016
Feb 19, 2016
585
constraint = NULL;
Jun 29, 2016
Jun 29, 2016
586
Oct 9, 2016
Oct 9, 2016
587
if(!WriteFile(filename, stream.str())) {
Mar 11, 2017
Mar 11, 2017
588
Error("Couldn't write to '%s'", filename.raw.c_str());
Oct 9, 2016
Oct 9, 2016
589
return;
590
}
591
Jun 29, 2016
Jun 29, 2016
592
if(!interface.messages.empty()) {
Jan 7, 2017
Jan 7, 2017
593
std::string text = _("Some aspects of the drawing have no DXF equivalent and "
594
"were not exported:\n");
Jun 29, 2016
Jun 29, 2016
595
for(const std::string &message : interface.messages) {
596
text += " * " + message + "\n";
597
}
598
Message(text.c_str());
599
}
Apr 8, 2016
Apr 8, 2016
602
bool DxfFileWriter::NeedToOutput(Constraint *c) {
603
switch(c->type) {
May 25, 2016
May 25, 2016
604
case Constraint::Type::PT_PT_DISTANCE:
605
case Constraint::Type::PT_LINE_DISTANCE:
606
case Constraint::Type::DIAMETER:
607
case Constraint::Type::ANGLE:
608
case Constraint::Type::COMMENT:
Apr 8, 2016
Apr 8, 2016
609
return c->IsVisible();
May 26, 2016
May 26, 2016
610
611
default: // See writeEntities().
612
break;
Apr 8, 2016
Apr 8, 2016
613
}
614
return false;
615
}
616
May 25, 2016
May 25, 2016
617
const char *DxfFileWriter::lineTypeName(StipplePattern stippleType) {
May 7, 2016
May 7, 2016
618
switch(stippleType) {
May 25, 2016
May 25, 2016
619
case StipplePattern::CONTINUOUS: return "CONTINUOUS";
May 27, 2016
May 27, 2016
620
case StipplePattern::SHORT_DASH: return "DASHED";
May 25, 2016
May 25, 2016
621
case StipplePattern::DASH: return "DASHED";
622
case StipplePattern::LONG_DASH: return "DASHEDX2";
623
case StipplePattern::DASH_DOT: return "DASHDOT";
624
case StipplePattern::DASH_DOT_DOT: return "DIVIDE";
625
case StipplePattern::DOT: return "DOT";
May 7, 2016
May 7, 2016
626
Jun 29, 2016
Jun 29, 2016
627
case StipplePattern::FREEHAND:
628
case StipplePattern::ZIGZAG:
629
/* no corresponding DXF line type */
Oct 12, 2016
Oct 12, 2016
630
break;
Jun 29, 2016
Jun 29, 2016
631
}
Oct 12, 2016
Oct 12, 2016
632
633
return "CONTINUOUS";
May 7, 2016
May 7, 2016
634
}
635
636
//-----------------------------------------------------------------------------
637
// Routines for EPS output
638
//-----------------------------------------------------------------------------
Apr 8, 2016
Apr 8, 2016
639
May 25, 2016
May 25, 2016
640
static std::string MakeStipplePattern(StipplePattern pattern, double scale, char delimiter,
Apr 14, 2016
Apr 14, 2016
641
bool inkscapeWorkaround = false) {
Apr 8, 2016
Apr 8, 2016
642
scale /= 2.0;
643
Apr 14, 2016
Apr 14, 2016
644
// Inkscape ignores all elements that are exactly zero instead of drawing
645
// them as dots.
646
double zero = inkscapeWorkaround ? 1e-6 : 0;
647
Apr 8, 2016
Apr 8, 2016
648
std::string result;
649
switch(pattern) {
May 25, 2016
May 25, 2016
650
case StipplePattern::CONTINUOUS:
Apr 8, 2016
Apr 8, 2016
651
return "";
652
May 27, 2016
May 27, 2016
653
case StipplePattern::SHORT_DASH:
654
result = ssprintf("%.3f_%.3f", scale, scale * 2.0);
655
break;
May 25, 2016
May 25, 2016
656
case StipplePattern::DASH:
Apr 8, 2016
Apr 8, 2016
657
result = ssprintf("%.3f_%.3f", scale, scale);
658
break;
May 25, 2016
May 25, 2016
659
case StipplePattern::DASH_DOT:
Apr 14, 2016
Apr 14, 2016
660
result = ssprintf("%.3f_%.3f_%.6f_%.3f",
661
scale, scale * 0.5, zero, scale * 0.5);
Apr 8, 2016
Apr 8, 2016
662
break;
May 25, 2016
May 25, 2016
663
case StipplePattern::DASH_DOT_DOT:
Apr 14, 2016
Apr 14, 2016
664
result = ssprintf("%.3f_%.3f_%.6f_%.3f_%.6f_%.3f",
665
scale, scale * 0.5, zero,
666
scale * 0.5, scale * 0.5, zero);
Apr 8, 2016
Apr 8, 2016
667
break;
May 25, 2016
May 25, 2016
668
case StipplePattern::DOT:
Apr 14, 2016
Apr 14, 2016
669
result = ssprintf("%.6f_%.3f", zero, scale * 0.5);
Apr 8, 2016
Apr 8, 2016
670
break;
May 25, 2016
May 25, 2016
671
case StipplePattern::LONG_DASH:
Apr 8, 2016
Apr 8, 2016
672
result = ssprintf("%.3f_%.3f", scale * 2.0, scale * 0.5);
673
break;
Apr 14, 2016
Apr 14, 2016
674
May 26, 2016
May 26, 2016
675
case StipplePattern::FREEHAND:
676
case StipplePattern::ZIGZAG:
Aug 5, 2026
Aug 5, 2026
677
dbp("Freehand and zigzag export not implemented; "
678
"exporting as continuous line");
679
break;
Apr 8, 2016
Apr 8, 2016
680
}
681
std::replace(result.begin(), result.end(), '_', delimiter);
682
return result;
683
}
684
May 20, 2016
May 20, 2016
685
void EpsFileWriter::StartFile() {
686
fprintf(f,
687
"%%!PS-Adobe-2.0\r\n"
688
"%%%%Creator: SolveSpace\r\n"
689
"%%%%Title: title\r\n"
690
"%%%%Pages: 0\r\n"
691
"%%%%PageOrder: Ascend\r\n"
692
"%%%%BoundingBox: 0 0 %d %d\r\n"
693
"%%%%HiResBoundingBox: 0 0 %.3f %.3f\r\n"
694
"%%%%EndComments\r\n"
695
"\r\n"
696
"gsave\r\n"
697
"\r\n",
698
(int)ceil(MmToPts(ptMax.x - ptMin.x)),
699
(int)ceil(MmToPts(ptMax.y - ptMin.y)),
700
MmToPts(ptMax.x - ptMin.x),
701
MmToPts(ptMax.y - ptMin.y));
702
}
703
Sep 6, 2020
Sep 6, 2020
704
void EpsFileWriter::Background(RgbaColor color) {
705
double width = ptMax.x - ptMin.x;
706
double height = ptMax.y - ptMin.y;
707
708
fprintf(f,
709
"%.3f %.3f %.3f setrgbcolor\r\n"
710
"newpath\r\n"
711
" %.3f %.3f moveto\r\n"
712
" %.3f %.3f lineto\r\n"
713
" %.3f %.3f lineto\r\n"
714
" %.3f %.3f lineto\r\n"
715
" closepath\r\n"
716
"gsave fill grestore\r\n",
717
color.redF(), color.greenF(), color.blueF(),
718
MmToPts(0), MmToPts(0),
719
MmToPts(width), MmToPts(0),
720
MmToPts(width), MmToPts(height),
721
MmToPts(0), MmToPts(height));
722
723
// same issue with cracks, stroke it to avoid them
724
double sw = max(width, height) / 1000;
725
fprintf(f,
726
"1 setlinejoin\r\n"
727
"1 setlinecap\r\n"
728
"%.3f setlinewidth\r\n"
729
"gsave stroke grestore\r\n",
730
MmToPts(sw));
731
}
732
Jul 10, 2015
Jul 10, 2015
733
void EpsFileWriter::StartPath(RgbaColor strokeRgb, double lineWidth,
Apr 14, 2016
Apr 14, 2016
734
bool filled, RgbaColor fillRgb, hStyle hs)
Oct 30, 2009
Oct 30, 2009
735
{
736
fprintf(f, "newpath\r\n");
Apr 8, 2026
Apr 8, 2026
737
prevPt = {VERY_POSITIVE, VERY_POSITIVE, VERY_POSITIVE};
Oct 30, 2009
Oct 30, 2009
738
}
Jul 10, 2015
Jul 10, 2015
739
void EpsFileWriter::FinishPath(RgbaColor strokeRgb, double lineWidth,
Aug 13, 2026
Aug 13, 2026
740
bool filled, RgbaColor fillRgb, hStyle hs, bool closed)
Oct 30, 2009
Oct 30, 2009
741
{
May 25, 2016
May 25, 2016
742
StipplePattern pattern = Style::PatternType(hs);
Apr 8, 2016
Apr 8, 2016
743
double stippleScale = MmToPts(Style::StippleScaleMm(hs));
744
Oct 30, 2009
Oct 30, 2009
745
fprintf(f, " %.3f setlinewidth\r\n"
746
" %.3f %.3f %.3f setrgbcolor\r\n"
747
" 1 setlinejoin\r\n" // rounded
748
" 1 setlinecap\r\n" // rounded
Apr 8, 2016
Apr 8, 2016
749
" [%s] 0 setdash\r\n"
Oct 30, 2009
Oct 30, 2009
750
" gsave stroke grestore\r\n",
751
MmToPts(lineWidth),
Apr 8, 2016
Apr 8, 2016
752
strokeRgb.redF(), strokeRgb.greenF(), strokeRgb.blueF(),
May 25, 2016
May 25, 2016
753
MakeStipplePattern(pattern, stippleScale, ' ').c_str());
Oct 30, 2009
Oct 30, 2009
754
if(filled) {
755
fprintf(f, " %.3f %.3f %.3f setrgbcolor\r\n"
756
" gsave fill grestore\r\n",
Oct 25, 2013
Oct 25, 2013
757
fillRgb.redF(), fillRgb.greenF(), fillRgb.blueF());
Oct 30, 2009
Oct 30, 2009
758
}
759
}
760
761
void EpsFileWriter::MaybeMoveTo(Vector st, Vector fi) {
762
if(!prevPt.Equals(st)) {
763
fprintf(f, " %.3f %.3f moveto\r\n",
764
MmToPts(st.x - ptMin.x), MmToPts(st.y - ptMin.y));
765
}
766
prevPt = fi;
767
}
768
769
void EpsFileWriter::Triangle(STriangle *tr) {
770
fprintf(f,
771
"%.3f %.3f %.3f setrgbcolor\r\n"
772
"newpath\r\n"
773
" %.3f %.3f moveto\r\n"
774
" %.3f %.3f lineto\r\n"
775
" %.3f %.3f lineto\r\n"
776
" closepath\r\n"
Oct 30, 2009
Oct 30, 2009
777
"gsave fill grestore\r\n",
Oct 25, 2013
Oct 25, 2013
778
tr->meta.color.redF(), tr->meta.color.greenF(), tr->meta.color.blueF(),
779
MmToPts(tr->a.x - ptMin.x), MmToPts(tr->a.y - ptMin.y),
780
MmToPts(tr->b.x - ptMin.x), MmToPts(tr->b.y - ptMin.y),
781
MmToPts(tr->c.x - ptMin.x), MmToPts(tr->c.y - ptMin.y));
782
783
// same issue with cracks, stroke it to avoid them
784
double sw = max(ptMax.x - ptMin.x, ptMax.y - ptMin.y) / 1000;
785
fprintf(f,
Oct 30, 2009
Oct 30, 2009
786
"1 setlinejoin\r\n"
787
"1 setlinecap\r\n"
788
"%.3f setlinewidth\r\n"
Oct 30, 2009
Oct 30, 2009
789
"gsave stroke grestore\r\n",
790
MmToPts(sw));
Oct 30, 2009
Oct 30, 2009
793
void EpsFileWriter::Bezier(SBezier *sb) {
Apr 8, 2026
Apr 8, 2026
794
Vector c, n = {0, 0, 1};
Oct 30, 2009
Oct 30, 2009
796
if(sb->deg == 1) {
797
MaybeMoveTo(sb->ctrl[0], sb->ctrl[1]);
798
fprintf(f, " %.3f %.3f lineto\r\n",
799
MmToPts(sb->ctrl[1].x - ptMin.x),
800
MmToPts(sb->ctrl[1].y - ptMin.y));
801
} else if(sb->IsCircle(n, &c, &r)) {
802
Vector p0 = sb->ctrl[0], p1 = sb->ctrl[2];
803
double theta0 = atan2(p0.y - c.y, p0.x - c.x),
804
theta1 = atan2(p1.y - c.y, p1.x - c.x),
805
dtheta = WRAP_SYMMETRIC(theta1 - theta0, 2*PI);
Oct 30, 2009
Oct 30, 2009
806
MaybeMoveTo(p0, p1);
Oct 30, 2009
Oct 30, 2009
808
" %.3f %.3f %.3f %.3f %.3f %s\r\n",
809
MmToPts(c.x - ptMin.x), MmToPts(c.y - ptMin.y),
810
MmToPts(r),
Oct 30, 2009
Oct 30, 2009
811
theta0*180/PI, theta1*180/PI,
812
dtheta < 0 ? "arcn" : "arc");
813
} else if(sb->deg == 3 && !sb->IsRational()) {
Oct 30, 2009
Oct 30, 2009
814
MaybeMoveTo(sb->ctrl[0], sb->ctrl[3]);
Oct 30, 2009
Oct 30, 2009
816
" %.3f %.3f %.3f %.3f %.3f %.3f curveto\r\n",
817
MmToPts(sb->ctrl[1].x - ptMin.x), MmToPts(sb->ctrl[1].y - ptMin.y),
818
MmToPts(sb->ctrl[2].x - ptMin.x), MmToPts(sb->ctrl[2].y - ptMin.y),
Oct 30, 2009
Oct 30, 2009
819
MmToPts(sb->ctrl[3].x - ptMin.x), MmToPts(sb->ctrl[3].y - ptMin.y));
Oct 30, 2009
Oct 30, 2009
821
BezierAsNonrationalCubic(sb);
May 20, 2016
May 20, 2016
825
void EpsFileWriter::FinishAndCloseFile() {
826
fprintf(f,
827
"\r\n"
828
"grestore\r\n"
829
"\r\n");
830
fclose(f);
831
}
832
833
//-----------------------------------------------------------------------------
834
// Routines for PDF output, some extra complexity because we have to generate
835
// a correct xref table.
836
//-----------------------------------------------------------------------------
May 20, 2016
May 20, 2016
837
void PdfFileWriter::StartFile() {
Jul 10, 2015
Jul 10, 2015
838
if((ptMax.x - ptMin.x) > 200*25.4 ||
Dec 15, 2009
Dec 15, 2009
839
(ptMax.y - ptMin.y) > 200*25.4)
840
{
Jan 7, 2017
Jan 7, 2017
841
Message(_("PDF page size exceeds 200 by 200 inches; many viewers may "
842
"reject this file."));
Dec 15, 2009
Dec 15, 2009
843
}
844
845
fprintf(f,
846
"%%PDF-1.1\r\n"
847
"%%%c%c%c%c\r\n",
848
0xe2, 0xe3, 0xcf, 0xd3);
Jul 10, 2015
Jul 10, 2015
849
Oct 2, 2013
Oct 2, 2013
850
xref[1] = (uint32_t)ftell(f);
851
fprintf(f,
852
"1 0 obj\r\n"
853
" << /Type /Catalog\r\n"
854
" /Outlines 2 0 R\r\n"
855
" /Pages 3 0 R\r\n"
856
" >>\r\n"
857
"endobj\r\n");
858
Oct 2, 2013
Oct 2, 2013
859
xref[2] = (uint32_t)ftell(f);
860
fprintf(f,
861
"2 0 obj\r\n"
862
" << /Type /Outlines\r\n"
863
" /Count 0\r\n"
864
" >>\r\n"
865
"endobj\r\n");
866
Oct 2, 2013
Oct 2, 2013
867
xref[3] = (uint32_t)ftell(f);
868
fprintf(f,
869
"3 0 obj\r\n"
870
" << /Type /Pages\r\n"
871
" /Kids [4 0 R]\r\n"
872
" /Count 1\r\n"
873
" >>\r\n"
874
"endobj\r\n");
875
Oct 2, 2013
Oct 2, 2013
876
xref[4] = (uint32_t)ftell(f);
877
fprintf(f,
878
"4 0 obj\r\n"
879
" << /Type /Page\r\n"
880
" /Parent 3 0 R\r\n"
881
" /MediaBox [0 0 %.3f %.3f]\r\n"
882
" /Contents 5 0 R\r\n"
883
" /Resources << /ProcSet 7 0 R\r\n"
884
" /Font << /F1 8 0 R >>\r\n"
885
" >>\r\n"
886
" >>\r\n"
887
"endobj\r\n",
888
MmToPts(ptMax.x - ptMin.x),
889
MmToPts(ptMax.y - ptMin.y));
890
Oct 2, 2013
Oct 2, 2013
891
xref[5] = (uint32_t)ftell(f);
892
fprintf(f,
893
"5 0 obj\r\n"
894
" << /Length 6 0 R >>\r\n"
895
"stream\r\n");
Oct 2, 2013
Oct 2, 2013
896
bodyStart = (uint32_t)ftell(f);
May 20, 2016
May 20, 2016
899
void PdfFileWriter::FinishAndCloseFile() {
Oct 2, 2013
Oct 2, 2013
900
uint32_t bodyEnd = (uint32_t)ftell(f);
901
902
fprintf(f,
903
"endstream\r\n"
904
"endobj\r\n");
905
Oct 2, 2013
Oct 2, 2013
906
xref[6] = (uint32_t)ftell(f);
907
fprintf(f,
908
"6 0 obj\r\n"
909
" %d\r\n"
910
"endobj\r\n",
911
bodyEnd - bodyStart);
912
Oct 2, 2013
Oct 2, 2013
913
xref[7] = (uint32_t)ftell(f);
914
fprintf(f,
915
"7 0 obj\r\n"
916
" [/PDF /Text]\r\n"
917
"endobj\r\n");
918
Oct 2, 2013
Oct 2, 2013
919
xref[8] = (uint32_t)ftell(f);
920
fprintf(f,
921
"8 0 obj\r\n"
922
" << /Type /Font\r\n"
923
" /Subtype /Type1\r\n"
924
" /Name /F1\r\n"
925
" /BaseFont /Helvetica\r\n"
926
" /Encoding /WinAnsiEncoding\r\n"
927
" >>\r\n"
928
"endobj\r\n");
929
Oct 2, 2013
Oct 2, 2013
930
xref[9] = (uint32_t)ftell(f);
931
fprintf(f,
932
"9 0 obj\r\n"
933
" << /Creator (SolveSpace)\r\n"
934
" >>\r\n");
Jul 10, 2015
Jul 10, 2015
935
Oct 2, 2013
Oct 2, 2013
936
uint32_t xrefStart = (uint32_t)ftell(f);
937
fprintf(f,
938
"xref\r\n"
939
"0 10\r\n"
940
"0000000000 65535 f\r\n");
Jul 10, 2015
Jul 10, 2015
941
942
int i;
943
for(i = 1; i <= 9; i++) {
944
fprintf(f, "%010d %05d n\r\n", xref[i], 0);
945
}
946
947
fprintf(f,
948
"\r\n"
949
"trailer\r\n"
950
" << /Size 10\r\n"
951
" /Root 1 0 R\r\n"
952
" /Info 9 0 R\r\n"
953
" >>\r\n"
954
"startxref\r\n"
955
"%d\r\n"
956
"%%%%EOF\r\n",
957
xrefStart);
958
959
fclose(f);
960
961
}
962
Sep 6, 2020
Sep 6, 2020
963
void PdfFileWriter::Background(RgbaColor color) {
964
double width = ptMax.x - ptMin.x;
965
double height = ptMax.y - ptMin.y;
966
double sw = max(width, height) / 1000;
967
968
fprintf(f,
969
"1 J 1 j\r\n"
970
"%.3f %.3f %.3f RG\r\n"
971
"%.3f %.3f %.3f rg\r\n"
972
"%.3f w\r\n"
973
"%.3f %.3f m\r\n"
974
"%.3f %.3f l\r\n"
975
"%.3f %.3f l\r\n"
976
"%.3f %.3f l\r\n"
977
"b\r\n",
978
color.redF(), color.greenF(), color.blueF(),
979
color.redF(), color.greenF(), color.blueF(),
980
MmToPts(sw),
981
MmToPts(0), MmToPts(0),
982
MmToPts(width), MmToPts(0),
983
MmToPts(width), MmToPts(height),
984
MmToPts(0), MmToPts(height));
985
}
986
Jul 10, 2015
Jul 10, 2015
987
void PdfFileWriter::StartPath(RgbaColor strokeRgb, double lineWidth,
Apr 14, 2016
Apr 14, 2016
988
bool filled, RgbaColor fillRgb, hStyle hs)
Oct 30, 2009
Oct 30, 2009
989
{
May 25, 2016
May 25, 2016
990
StipplePattern pattern = Style::PatternType(hs);
Apr 8, 2016
Apr 8, 2016
991
double stippleScale = MmToPts(Style::StippleScaleMm(hs));
992
Oct 30, 2009
Oct 30, 2009
993
fprintf(f, "1 J 1 j " // round endcaps and joins
Apr 8, 2016
Apr 8, 2016
994
"%.3f w [%s] 0 d "
Oct 30, 2009
Oct 30, 2009
995
"%.3f %.3f %.3f RG\r\n",
996
MmToPts(lineWidth),
Apr 8, 2016
Apr 8, 2016
997
MakeStipplePattern(pattern, stippleScale, ' ').c_str(),
Oct 25, 2013
Oct 25, 2013
998
strokeRgb.redF(), strokeRgb.greenF(), strokeRgb.blueF());
Oct 30, 2009
Oct 30, 2009
999
if(filled) {
1000
fprintf(f, "%.3f %.3f %.3f rg\r\n",

Footer

© 2026 GitHub, Inc.

Back | FazBrowse Home | New Git URL