1 #include "solvespace.h"
2 #include "libdxfrw.h"
3 #include "libdwgr.h"
4
5 #ifdef WIN32
6 // Conflicts with DRW::TEXT.
7 # undef TEXT
8 #endif
9
10 namespace SolveSpace {
11
ToUpper(std::string str)12 static std::string ToUpper(std::string str) {
13 std::transform(str.begin(), str.end(), str.begin(), ::toupper);
14 return str;
15 }
16
17 class DxfReadInterface : public DRW_Interface {
18 public:
19 Vector blockX;
20 Vector blockY;
21 Vector blockT;
22
invertXTransform()23 void invertXTransform() {
24 blockX.x = -blockX.x;
25 blockY.x = -blockY.x;
26 blockT.x = -blockT.x;
27 }
28
multBlockTransform(double x,double y,double sx,double sy,double angle)29 void multBlockTransform(double x, double y, double sx, double sy, double angle) {
30 Vector oldX = blockX;
31 Vector oldY = blockY;
32 Vector oldT = blockT;
33
34 Vector newX = Vector::From(sx, 0.0, 0.0).RotatedAbout(Vector::From(0.0, 0.0, 1.0), angle);
35 Vector newY = Vector::From(0.0, sy, 0.0).RotatedAbout(Vector::From(0.0, 0.0, 1.0), angle);
36 Vector newT = Vector::From(x, y, 0.0);
37
38 blockX = oldX.ScaledBy(newX.x).Plus(
39 oldY.ScaledBy(newX.y));
40
41 blockY = oldX.ScaledBy(newY.x).Plus(
42 oldY.ScaledBy(newY.y));
43
44 blockT = oldX.ScaledBy(newT.x).Plus(
45 oldY.ScaledBy(newT.y)).Plus(oldT);
46 }
47
clearBlockTransform()48 void clearBlockTransform() {
49 blockX = Vector::From(1.0, 0.0, 0.0);
50 blockY = Vector::From(0.0, 1.0, 0.0);
51 blockT = Vector::From(0.0, 0.0, 0.0);
52 }
53
blockTransform(Vector v)54 Vector blockTransform(Vector v) {
55 Vector r = blockT;
56 r = r.Plus(blockX.ScaledBy(v.x));
57 r = r.Plus(blockY.ScaledBy(v.y));
58 return r;
59 }
60
blockTransformArc(Vector * c,Vector * p0,Vector * p1)61 void blockTransformArc(Vector *c, Vector *p0, Vector *p1) {
62 bool oldSign = p0->Minus(*c).Cross(p1->Minus(*c)).z > 0.0;
63
64 *c = blockTransform(*c);
65 *p0 = blockTransform(*p0);
66 *p1 = blockTransform(*p1);
67
68 bool newSign = p0->Minus(*c).Cross(p1->Minus(*c)).z > 0.0;
69 if(oldSign != newSign) std::swap(*p0, *p1);
70 }
71
toVector(const DRW_Coord & c,bool transform=true)72 Vector toVector(const DRW_Coord &c, bool transform = true) {
73 Vector result = Vector::From(c.x, c.y, 0.0);
74 if(transform) return blockTransform(result);
75 return result;
76 }
77
toVector(const DRW_Vertex2D & c)78 Vector toVector(const DRW_Vertex2D &c) {
79 Vector result = Vector::From(c.x, c.y, 0.0);
80 return blockTransform(result);
81 }
82
toVector(const DRW_Vertex & c)83 Vector toVector(const DRW_Vertex &c) {
84 Vector result = Vector::From(c.basePoint.x, c.basePoint.y, 0.0);
85 return blockTransform(result);
86 }
87
angleTo(Vector v0,Vector v1)88 double angleTo(Vector v0, Vector v1) {
89 Vector d = v1.Minus(v0);
90 double a = atan2(d.y, d.x);
91 return M_PI + remainder(a - M_PI, 2 * M_PI);
92 }
93
polar(double radius,double angle)94 Vector polar(double radius, double angle) {
95 return Vector::From(radius * cos(angle), radius * sin(angle), 0.0);
96 }
97
createBulge(Vector p0,Vector p1,double bulge)98 hRequest createBulge(Vector p0, Vector p1, double bulge) {
99 bool reversed = bulge < 0.0;
100 double alpha = atan(bulge) * 4.0;
101
102 Vector middle = p1.Plus(p0).ScaledBy(0.5);
103 double dist = p1.Minus(p0).Magnitude() / 2.0;
104 double angle = angleTo(p0, p1);
105
106 // alpha can't be 0.0 at this point
107 double radius = fabs(dist / sin(alpha / 2.0));
108 double wu = fabs(radius * radius - dist * dist);
109 double h = sqrt(wu);
110
111 if(bulge > 0.0) {
112 angle += M_PI_2;
113 } else {
114 angle -= M_PI_2;
115 }
116
117 if (fabs(alpha) > M_PI) {
118 h *= -1.0;
119 }
120
121 Vector center = polar(h, angle);
122 center = center.Plus(middle);
123
124 if(reversed) std::swap(p0, p1);
125 blockTransformArc(¢er, &p0, &p1);
126
127 hRequest hr = SS.GW.AddRequest(Request::ARC_OF_CIRCLE, false);
128 SK.GetEntity(hr.entity(1))->PointForceTo(center);
129 SK.GetEntity(hr.entity(2))->PointForceTo(p0);
130 SK.GetEntity(hr.entity(3))->PointForceTo(p1);
131 processPoint(hr.entity(1));
132 processPoint(hr.entity(2));
133 processPoint(hr.entity(3));
134 return hr;
135 }
136
137 struct Block {
138 std::vector<std::unique_ptr<DRW_Entity>> entities;
139 DRW_Block data;
140 };
141
142 unsigned unknownEntities = 0;
143 std::map<std::string, hStyle> styles;
144 std::map<std::string, Block> blocks;
145 std::map<std::string, DRW_Layer> layers;
146 Block *readBlock = NULL;
147 const DRW_Insert *insertInsert = NULL;
148
149 template<class T>
addPendingBlockEntity(const T & e)150 bool addPendingBlockEntity(const T &e) {
151 if(readBlock == NULL) return false;
152 readBlock->entities.emplace_back(new T(e));
153 return true;
154 }
155
addEntity(DRW_Entity * e)156 void addEntity(DRW_Entity *e) {
157 switch(e->eType) {
158 case DRW::POINT:
159 addPoint(*static_cast<DRW_Point *>(e));
160 break;
161 case DRW::LINE:
162 addLine(*static_cast<DRW_Line *>(e));
163 break;
164 case DRW::ARC:
165 addArc(*static_cast<DRW_Arc *>(e));
166 break;
167 case DRW::CIRCLE:
168 addCircle(*static_cast<DRW_Circle *>(e));
169 break;
170 case DRW::POLYLINE:
171 addPolyline(*static_cast<DRW_Polyline *>(e));
172 break;
173 case DRW::LWPOLYLINE:
174 addLWPolyline(*static_cast<DRW_LWPolyline *>(e));
175 break;
176 case DRW::SPLINE:
177 addSpline(static_cast<DRW_Spline *>(e));
178 break;
179 case DRW::INSERT:
180 addInsert(*static_cast<DRW_Insert *>(e));
181 break;
182 case DRW::TEXT:
183 addText(*static_cast<DRW_Text *>(e));
184 break;
185 case DRW::MTEXT:
186 addMText(*static_cast<DRW_MText *>(e));
187 break;
188 case DRW::DIMALIGNED:
189 addDimAlign(static_cast<DRW_DimAligned *>(e));
190 break;
191 case DRW::DIMLINEAR:
192 addDimLinear(static_cast<DRW_DimLinear *>(e));
193 break;
194 case DRW::DIMRADIAL:
195 addDimRadial(static_cast<DRW_DimRadial *>(e));
196 break;
197 case DRW::DIMDIAMETRIC:
198 addDimDiametric(static_cast<DRW_DimDiametric *>(e));
199 break;
200 case DRW::DIMANGULAR:
201 addDimAngular(static_cast<DRW_DimAngular *>(e));
202 break;
203 default:
204 unknownEntities++;
205 }
206 }
207
dxfAlignToOrigin(DRW_Text::HAlign alignH,DRW_Text::VAlign alignV)208 int dxfAlignToOrigin(DRW_Text::HAlign alignH, DRW_Text::VAlign alignV) {
209 int origin = 0;
210 switch(alignH) {
211 case DRW_Text::HLeft:
212 origin |= Style::ORIGIN_LEFT;
213 break;
214
215 case DRW_Text::HMiddle:
216 case DRW_Text::HCenter:
217 break;
218
219 case DRW_Text::HRight:
220 origin |= Style::ORIGIN_RIGHT;
221 break;
222
223 case DRW_Text::HAligned:
224 case DRW_Text::HFit:
225 default:
226 origin |= Style::ORIGIN_LEFT;
227 break;
228 }
229
230 switch(alignV) {
231 case DRW_Text::VBaseLine:
232 case DRW_Text::VBottom:
233 origin |= Style::ORIGIN_BOT;
234 break;
235
236 case DRW_Text::VMiddle:
237 break;
238
239 case DRW_Text::VTop:
240 origin |= Style::ORIGIN_TOP;
241 break;
242
243 default:
244 origin |= Style::ORIGIN_BOT;
245 break;
246 }
247
248 return origin;
249 }
250
getSourceLayer(const DRW_Entity * e)251 DRW_Layer *getSourceLayer(const DRW_Entity *e) {
252 DRW_Layer *layer = NULL;
253 if(insertInsert != NULL) {
254 std::string l = insertInsert->layer;
255 auto bi = layers.find(l);
256 if(bi != layers.end()) layer = &bi->second;
257 } else {
258 std::string l = e->layer;
259 auto bi = layers.find(l);
260 if(bi != layers.end()) layer = &bi->second;
261 }
262 return layer;
263 }
264
getColor(const DRW_Entity * e)265 int getColor(const DRW_Entity *e) {
266 int col = e->color;
267 if(col == DRW::ColorByBlock) {
268 if(insertInsert != NULL) {
269 col = insertInsert->color;
270 } else {
271 col = 7;
272 }
273 }
274 if(col == DRW::ColorByLayer) {
275 DRW_Layer *layer = getSourceLayer(e);
276 if(layer != NULL) {
277 col = layer->color;
278 } else {
279 col = 7;
280 }
281 }
282 return col;
283 }
284
getLineWidth(const DRW_Entity * e)285 DRW_LW_Conv::lineWidth getLineWidth(const DRW_Entity *e) {
286 DRW_LW_Conv::lineWidth result = e->lWeight;
287 if(result == DRW_LW_Conv::widthByBlock) {
288 if(insertInsert != NULL) {
289 result = insertInsert->lWeight;
290 } else {
291 result = DRW_LW_Conv::widthDefault;
292 }
293 }
294 if(result == DRW_LW_Conv::widthByLayer) {
295 DRW_Layer *layer = getSourceLayer(e);
296 if(layer != NULL) {
297 result = layer->lWeight;
298 } else {
299 result = DRW_LW_Conv::widthDefault;
300 }
301 }
302 return result;
303 }
304
getLineType(const DRW_Entity * e)305 std::string getLineType(const DRW_Entity *e) {
306 std::string result = e->lineType;
307 if(result == "BYBLOCK") {
308 if(insertInsert != NULL) {
309 result = ToUpper(insertInsert->lineType);
310 } else {
311 result = "CONTINUOUS";
312 }
313 }
314 if(result == "BYLAYER") {
315 DRW_Layer *layer = getSourceLayer(e);
316 if(layer != NULL) {
317 result = ToUpper(layer->lineType);
318 } else {
319 result = "CONTINUOUS";
320 }
321 }
322 return result;
323 }
324
invisibleStyle()325 hStyle invisibleStyle() {
326 std::string id = "@dxf-invisible";
327
328 auto si = styles.find(id);
329 if(si != styles.end()) {
330 return si->second;
331 }
332
333 hStyle hs = { Style::CreateCustomStyle(/*rememberForUndo=*/false) };
334 Style *s = Style::Get(hs);
335 s->name = id;
336 s->visible = false;
337
338 styles.emplace(id, hs);
339 return hs;
340 }
341
styleFor(const DRW_Entity * e)342 hStyle styleFor(const DRW_Entity *e) {
343 // Color.
344 // TODO: which color to choose: index or RGB one?
345 int col = getColor(e);
346 RgbaColor c = RgbaColor::From(DRW::dxfColors[col][0],
347 DRW::dxfColors[col][1],
348 DRW::dxfColors[col][2]);
349
350 // Line width.
351 DRW_LW_Conv::lineWidth lw = getLineWidth(e);
352 double width = DRW_LW_Conv::lineWidth2dxfInt(e->lWeight) / 100.0;
353 if(width < 0.0) width = 1.0;
354
355 // Line stipple.
356 // TODO: Probably, we can load default autocad patterns and match it with ours.
357 std::string lineType = getLineType(e);
358 int stipple = Style::STIPPLE_CONTINUOUS;
359 for(int i = 0; i <= Style::LAST_STIPPLE; i++) {
360 if(lineType == DxfFileWriter::lineTypeName(i)) {
361 stipple = i;
362 break;
363 }
364 }
365
366 // Text properties.
367 DRW_Text::HAlign alignH = DRW_Text::HLeft;
368 DRW_Text::VAlign alignV = DRW_Text::VBaseLine;
369 double textAngle = 0.0;
370 double textHeight = Style::DefaultTextHeight();
371
372 if(e->eType == DRW::TEXT || e->eType == DRW::MTEXT) {
373 const DRW_Text *text = static_cast<const DRW_Text *>(e);
374 alignH = text->alignH;
375 alignV = text->alignV;
376 textHeight = text->height;
377 textAngle = text->angle;
378 // I have no idea why, but works
379 if(alignH == DRW_Text::HMiddle) {
380 alignV = DRW_Text::VMiddle;
381 }
382 }
383
384 // Unique identifier based on style properties.
385 std::string id = "@dxf";
386 if(lw != DRW_LW_Conv::widthDefault)
387 id += ssprintf("-w%.4g", width);
388 if(lineType != "CONTINUOUS")
389 id += ssprintf("-%s", lineType.c_str());
390 if(c.red != 0 || c.green != 0 || c.blue != 0)
391 id += ssprintf("-#%02x%02x%02x", c.red, c.green, c.blue);
392 if(textHeight != Style::DefaultTextHeight())
393 id += ssprintf("-h%.4g", textHeight);
394 if(textAngle != 0.0)
395 id += ssprintf("-a%.5g", textAngle);
396 if(alignH != DRW_Text::HLeft)
397 id += ssprintf("-oh%d", alignH);
398 if(alignV != DRW_Text::VBaseLine)
399 id += ssprintf("-ov%d", alignV);
400
401 auto si = styles.find(id);
402 if(si != styles.end()) {
403 return si->second;
404 }
405
406 hStyle hs = { Style::CreateCustomStyle(/*rememberForUndo=*/false) };
407 Style *s = Style::Get(hs);
408 if(lw != DRW_LW_Conv::widthDefault) {
409 s->widthAs = Style::UNITS_AS_MM;
410 s->width = width;
411 s->stippleScale = 1.0 + width * 2.0;
412 }
413 s->name = id;
414 s->stippleType = stipple;
415 if(c.red != 0 || c.green != 0 || c.blue != 0) s->color = c;
416 s->textHeightAs = Style::UNITS_AS_MM;
417 s->textHeight = textHeight;
418 s->textAngle = textAngle;
419 s->textOrigin = dxfAlignToOrigin(alignH, alignV);
420
421 styles.emplace(id, hs);
422 return hs;
423 }
424
setStyle(hRequest hr,hStyle hs)425 void setStyle(hRequest hr, hStyle hs) {
426 Request *r = SK.GetRequest(hr);
427 r->style = hs;
428 }
429
430 struct VectorHash {
operator ()SolveSpace::DxfReadInterface::VectorHash431 size_t operator()(const Vector &v) const {
432 static const size_t size = std::numeric_limits<size_t>::max() / 2 - 1;
433 static const double eps = (4.0 * LENGTH_EPS);
434
435 double x = fabs(v.x) / eps;
436 double y = fabs(v.y) / eps;
437
438 size_t xs = size_t(fmod(x, double(size)));
439 size_t ys = size_t(fmod(y, double(size)));
440
441 return ys * size + xs;
442 }
443 };
444
445 struct VectorPred {
operator ()SolveSpace::DxfReadInterface::VectorPred446 bool operator()(Vector a, Vector b) const {
447 return a.Equals(b, LENGTH_EPS);
448 }
449 };
450
451 std::unordered_map<Vector, hEntity, VectorHash, VectorPred> points;
452
processPoint(hEntity he,bool constrain=true)453 void processPoint(hEntity he, bool constrain = true) {
454 Entity *e = SK.GetEntity(he);
455 Vector pos = e->PointGetNum();
456 hEntity p = findPoint(pos);
457 if(p.v == he.v) return;
458 if(p.v != Entity::NO_ENTITY.v) {
459 if(constrain) {
460 Constraint::ConstrainCoincident(he, p);
461 }
462 // We don't add point because we already
463 // have point in this position
464 return;
465 }
466 points.emplace(pos, he);
467 }
468
findPoint(const Vector & p)469 hEntity findPoint(const Vector &p) {
470 auto it = points.find(p);
471 if(it == points.end()) return Entity::NO_ENTITY;
472 return it->second;
473 }
474
createOrGetPoint(const Vector & p)475 hEntity createOrGetPoint(const Vector &p) {
476 hEntity he = findPoint(p);
477 if(he.v != Entity::NO_ENTITY.v) return he;
478
479 hRequest hr = SS.GW.AddRequest(Request::DATUM_POINT, false);
480 he = hr.entity(0);
481 SK.GetEntity(he)->PointForceTo(p);
482 points.emplace(p, he);
483 return he;
484 }
485
createLine(Vector p0,Vector p1,uint32_t style,bool constrainHV=false)486 hEntity createLine(Vector p0, Vector p1, uint32_t style, bool constrainHV = false) {
487 if(p0.Equals(p1)) return Entity::NO_ENTITY;
488 hRequest hr = SS.GW.AddRequest(Request::LINE_SEGMENT, false);
489 SK.GetEntity(hr.entity(1))->PointForceTo(p0);
490 SK.GetEntity(hr.entity(2))->PointForceTo(p1);
491 processPoint(hr.entity(1));
492 processPoint(hr.entity(2));
493
494 if(constrainHV) {
495 int cType = -1;
496 if(fabs(p0.x - p1.x) < LENGTH_EPS) {
497 cType = Constraint::VERTICAL;
498 }
499 else if(fabs(p0.y - p1.y) < LENGTH_EPS) {
500 cType = Constraint::HORIZONTAL;
501 }
502 if(cType != -1) {
503 Constraint::Constrain(
504 cType,
505 Entity::NO_ENTITY,
506 Entity::NO_ENTITY,
507 hr.entity(0)
508 );
509 }
510 }
511
512 if(style != 0) {
513 Request *r = SK.GetRequest(hr);
514 r->style = hStyle{ style };
515 }
516 return hr.entity(0);
517 }
518
createCircle(const Vector & c,double r,uint32_t style)519 hEntity createCircle(const Vector &c, double r, uint32_t style) {
520 hRequest hr = SS.GW.AddRequest(Request::CIRCLE, false);
521 SK.GetEntity(hr.entity(1))->PointForceTo(c);
522 processPoint(hr.entity(1));
523 SK.GetEntity(hr.entity(64))->DistanceForceTo(r);
524 if(style != 0) {
525 Request *r = SK.GetRequest(hr);
526 r->style = hStyle{ style };
527 }
528 return hr.entity(0);
529 }
530
addLayer(const DRW_Layer & data)531 virtual void addLayer(const DRW_Layer &data) {
532 layers.emplace(data.name, data);
533 }
534
addBlock(const DRW_Block & data)535 virtual void addBlock(const DRW_Block &data) {
536 readBlock = &blocks[data.name];
537 readBlock->data = data;
538 }
539
endBlock()540 virtual void endBlock() {
541 readBlock = NULL;
542 }
543
addPoint(const DRW_Point & data)544 virtual void addPoint(const DRW_Point &data) {
545 if(data.space != DRW::ModelSpace) return;
546 if(addPendingBlockEntity<DRW_Point>(data)) return;
547
548 hRequest hr = SS.GW.AddRequest(Request::DATUM_POINT, false);
549 SK.GetEntity(hr.entity(0))->PointForceTo(toVector(data.basePoint));
550 processPoint(hr.entity(0));
551 }
552
addLine(const DRW_Line & data)553 virtual void addLine(const DRW_Line &data) {
554 if(data.space != DRW::ModelSpace) return;
555 if(addPendingBlockEntity<DRW_Line>(data)) return;
556
557 createLine(toVector(data.basePoint), toVector(data.secPoint), styleFor(&data).v, true);
558 }
559
addArc(const DRW_Arc & data)560 virtual void addArc(const DRW_Arc &data) {
561 if(data.space != DRW::ModelSpace) return;
562 if(addPendingBlockEntity<DRW_Arc>(data)) return;
563
564 hRequest hr = SS.GW.AddRequest(Request::ARC_OF_CIRCLE, false);
565 double r = data.radious;
566 double sa = data.staangle;
567 double ea = data.endangle;
568 Vector c = Vector::From(data.basePoint.x, data.basePoint.y, 0.0);
569 Vector rvs = Vector::From(r * cos(sa), r * sin(sa), data.basePoint.z).Plus(c);
570 Vector rve = Vector::From(r * cos(ea), r * sin(ea), data.basePoint.z).Plus(c);
571
572 if(data.extPoint.z == -1.0) {
573 c.x = -c.x;
574 rvs.x = - rvs.x;
575 rve.x = - rve.x;
576 std::swap(rvs, rve);
577 }
578
579 blockTransformArc(&c, &rvs, &rve);
580
581 SK.GetEntity(hr.entity(1))->PointForceTo(c);
582 SK.GetEntity(hr.entity(2))->PointForceTo(rvs);
583 SK.GetEntity(hr.entity(3))->PointForceTo(rve);
584 processPoint(hr.entity(1));
585 processPoint(hr.entity(2));
586 processPoint(hr.entity(3));
587 setStyle(hr, styleFor(&data));
588 }
589
addCircle(const DRW_Circle & data)590 virtual void addCircle(const DRW_Circle &data) {
591 if(data.space != DRW::ModelSpace) return;
592 if(addPendingBlockEntity<DRW_Circle>(data)) return;
593
594 createCircle(toVector(data.basePoint), data.radious, styleFor(&data).v);
595 }
596
addLWPolyline(const DRW_LWPolyline & data)597 virtual void addLWPolyline(const DRW_LWPolyline &data) {
598 if(data.space != DRW::ModelSpace) return;
599 if(addPendingBlockEntity<DRW_LWPolyline>(data)) return;
600
601 size_t vNum = data.vertlist.size();
602
603 // Check for closed polyline.
604 if((data.flags & 1) != 1) vNum--;
605
606 // Correct coordinate system for the case where z=-1, as described in
607 // http://paulbourke.net/dataformats/dxf/dxf10.html.
608 bool needSwapX = data.extPoint.z == -1.0;
609
610 for(size_t i = 0; i < vNum; i++) {
611 DRW_Vertex2D c0 = *data.vertlist[i];
612 DRW_Vertex2D c1 = *data.vertlist[(i + 1) % data.vertlist.size()];
613
614 if(needSwapX) {
615 c0.x = -c0.x;
616 c1.x = -c1.x;
617 c0.bulge = -c0.bulge;
618 }
619
620 Vector p0 = Vector::From(c0.x, c0.y, 0.0);
621 Vector p1 = Vector::From(c1.x, c1.y, 0.0);
622 hStyle hs = styleFor(&data);
623
624 if(EXACT(data.vertlist[i]->bulge == 0.0)) {
625 createLine(blockTransform(p0), blockTransform(p1), hs.v, true);
626 } else {
627 hRequest hr = createBulge(p0, p1, c0.bulge);
628 setStyle(hr, hs);
629 }
630 }
631 }
632
addPolyline(const DRW_Polyline & data)633 virtual void addPolyline(const DRW_Polyline &data) {
634 if(data.space != DRW::ModelSpace) return;
635 if(addPendingBlockEntity<DRW_Polyline>(data)) return;
636
637 int vNum = data.vertlist.size();
638
639 // Check for closed polyline.
640 if((data.flags & 1) != 1) vNum--;
641
642 // Correct coordinate system for the case where z=-1, as described in
643 // http://paulbourke.net/dataformats/dxf/dxf10.html.
644 bool needSwapX = data.extPoint.z == -1.0;
645
646 for(int i = 0; i < vNum; i++) {
647 DRW_Coord c0 = data.vertlist[i]->basePoint;
648 DRW_Coord c1 = data.vertlist[(i + 1) % data.vertlist.size()]->basePoint;
649
650 double bulge = data.vertlist[i]->bulge;
651 if(needSwapX) {
652 c0.x = -c0.x;
653 c1.x = -c1.x;
654 bulge = -bulge;
655 }
656
657 Vector p0 = Vector::From(c0.x, c0.y, 0.0);
658 Vector p1 = Vector::From(c1.x, c1.y, 0.0);
659 hStyle hs = styleFor(&data);
660
661 if(EXACT(bulge == 0.0)) {
662 createLine(blockTransform(p0), blockTransform(p1), hs.v, true);
663 } else {
664 hRequest hr = createBulge(p0, p1, bulge);
665 setStyle(hr, hs);
666 }
667 }
668 }
669
addSpline(const DRW_Spline * data)670 virtual void addSpline(const DRW_Spline *data) {
671 if(data->space != DRW::ModelSpace) return;
672 if(data->degree != 3) return;
673 if(addPendingBlockEntity<DRW_Spline>(*data)) return;
674
675 hRequest hr = SS.GW.AddRequest(Request::CUBIC, false);
676 for(int i = 0; i < 4; i++) {
677 SK.GetEntity(hr.entity(i + 1))->PointForceTo(toVector(*data->controllist[i]));
678 processPoint(hr.entity(i + 1));
679 }
680 setStyle(hr, styleFor(data));
681 }
682
addInsert(const DRW_Insert & data)683 virtual void addInsert(const DRW_Insert &data) {
684 if(data.space != DRW::ModelSpace) return;
685 if(addPendingBlockEntity<DRW_Insert>(data)) return;
686
687 auto bi = blocks.find(data.name);
688 if(bi == blocks.end()) oops();
689 Block *block = &bi->second;
690
691 // Push transform.
692 Vector x = blockX;
693 Vector y = blockY;
694 Vector t = blockT;
695
696 const DRW_Insert *oldInsert = insertInsert;
697 insertInsert = &data;
698
699 if(data.extPoint.z == -1.0) invertXTransform();
700 multBlockTransform(data.basePoint.x, data.basePoint.y, data.xscale, data.yscale, data.angle);
701 for(auto &e : block->entities) {
702 addEntity(&*e);
703 }
704
705 insertInsert = oldInsert;
706
707 // Pop transform.
708 blockX = x;
709 blockY = y;
710 blockT = t;
711 }
712
addMText(const DRW_MText & data)713 virtual void addMText(const DRW_MText &data) {
714 if(data.space != DRW::ModelSpace) return;
715 if(addPendingBlockEntity<DRW_MText>(data)) return;
716
717 DRW_MText text = data;
718 text.secPoint = text.basePoint;
719 addText(text);
720 }
721
addText(const DRW_Text & data)722 virtual void addText(const DRW_Text &data) {
723 if(data.space != DRW::ModelSpace) return;
724 if(addPendingBlockEntity<DRW_Text>(data)) return;
725
726 Constraint c = {};
727 c.group = SS.GW.activeGroup;
728 c.workplane = SS.GW.ActiveWorkplane();
729 c.type = Constraint::COMMENT;
730 if(data.alignH == DRW_Text::HLeft && data.alignV == DRW_Text::VBaseLine) {
731 c.disp.offset = toVector(data.basePoint);
732 } else {
733 c.disp.offset = toVector(data.secPoint);
734 }
735 c.comment = data.text;
736 c.disp.style = styleFor(&data);
737 Constraint::AddConstraint(&c, false);
738 }
739
addDimAlign(const DRW_DimAligned * data)740 virtual void addDimAlign(const DRW_DimAligned *data) {
741 if(data->space != DRW::ModelSpace) return;
742 if(addPendingBlockEntity<DRW_DimAligned>(*data)) return;
743
744 Vector p0 = toVector(data->getDef1Point());
745 Vector p1 = toVector(data->getDef2Point());
746 Vector p2 = toVector(data->getTextPoint());
747 hConstraint hc = Constraint::Constrain(
748 Constraint::PT_PT_DISTANCE,
749 createOrGetPoint(p0),
750 createOrGetPoint(p1),
751 Entity::NO_ENTITY
752 );
753
754 Constraint *c = SK.GetConstraint(hc);
755 if(data->hasActualMeasurement()) {
756 c->valA = data->getActualMeasurement();
757 } else {
758 c->ModifyToSatisfy();
759 }
760 c->disp.offset = p2.Minus(p0.Plus(p1).ScaledBy(0.5));
761 }
762
addDimLinear(const DRW_DimLinear * data)763 virtual void addDimLinear(const DRW_DimLinear *data) {
764 if(data->space != DRW::ModelSpace) return;
765 if(addPendingBlockEntity<DRW_DimLinear>(*data)) return;
766
767 Vector p0 = toVector(data->getDef1Point(), false);
768 Vector p1 = toVector(data->getDef2Point(), false);
769 Vector p2 = toVector(data->getTextPoint(), false);
770
771 double angle = data->getAngle() * PI / 180.0;
772 Vector dir = Vector::From(cos(angle), sin(angle), 0.0);
773 Vector p3 = p1.Minus(p1.ClosestPointOnLine(p2, dir)).Plus(p1);
774 if(p1.Minus(p3).Magnitude() < LENGTH_EPS) {
775 p3 = p0.Minus(p0.ClosestPointOnLine(p2, dir)).Plus(p1);
776 }
777
778 Vector p4 = p0.ClosestPointOnLine(p1, p3.Minus(p1)).Plus(p0).ScaledBy(0.5);
779
780 p0 = blockTransform(p0);
781 p1 = blockTransform(p1);
782 p2 = blockTransform(p2);
783 p3 = blockTransform(p3);
784 p4 = blockTransform(p4);
785
786 hConstraint hc = Constraint::Constrain(
787 Constraint::PT_LINE_DISTANCE,
788 createOrGetPoint(p0),
789 Entity::NO_ENTITY,
790 createLine(p1, p3, invisibleStyle().v)
791 );
792
793 Constraint *c = SK.GetConstraint(hc);
794 if(data->hasActualMeasurement()) {
795 c->valA = data->getActualMeasurement();
796 } else {
797 c->ModifyToSatisfy();
798 }
799 c->disp.offset = p2.Minus(p4);
800 }
801
addDimAngular(const DRW_DimAngular * data)802 virtual void addDimAngular(const DRW_DimAngular *data) {
803 if(data->space != DRW::ModelSpace) return;
804 if(addPendingBlockEntity<DRW_DimAngular>(*data)) return;
805
806 Vector l0p0 = toVector(data->getFirstLine1());
807 Vector l0p1 = toVector(data->getFirstLine2());
808 Vector l1p0 = toVector(data->getSecondLine1());
809 Vector l1p1 = toVector(data->getSecondLine2());
810
811 hConstraint hc = Constraint::Constrain(
812 Constraint::ANGLE,
813 Entity::NO_ENTITY,
814 Entity::NO_ENTITY,
815 createLine(l0p0, l0p1, invisibleStyle().v),
816 createLine(l1p1, l1p0, invisibleStyle().v),
817 /*other=*/false,
818 /*other2=*/false
819 );
820
821 Constraint *c = SK.GetConstraint(hc);
822 c->ModifyToSatisfy();
823 if(data->hasActualMeasurement()) {
824 double actual = data->getActualMeasurement() / PI * 180.0;
825 if(fabs(180.0 - actual - c->valA) < fabs(actual - c->valA)) {
826 c->other = true;
827 }
828 c->valA = actual;
829 }
830
831 bool skew = false;
832 Vector pi = Vector::AtIntersectionOfLines(l0p0, l0p1, l1p0, l1p1, &skew);
833 if(!skew) {
834 c->disp.offset = toVector(data->getTextPoint()).Minus(pi);
835 }
836 }
837
createDiametric(Vector cp,double r,Vector tp,double actual,bool asRadius=false)838 hConstraint createDiametric(Vector cp, double r, Vector tp, double actual, bool asRadius = false) {
839 hEntity he = createCircle(cp, r, invisibleStyle().v);
840
841 hConstraint hc = Constraint::Constrain(
842 Constraint::DIAMETER,
843 Entity::NO_ENTITY,
844 Entity::NO_ENTITY,
845 he
846 );
847
848 Constraint *c = SK.GetConstraint(hc);
849 if(actual > 0.0) {
850 c->valA = asRadius ? actual * 2.0 : actual;
851 } else {
852 c->ModifyToSatisfy();
853 }
854 c->disp.offset = tp.Minus(cp);
855 if(asRadius) c->other = true;
856 return hc;
857 }
858
addDimRadial(const DRW_DimRadial * data)859 virtual void addDimRadial(const DRW_DimRadial *data) {
860 if(data->space != DRW::ModelSpace) return;
861 if(addPendingBlockEntity<DRW_DimRadial>(*data)) return;
862
863 Vector cp = toVector(data->getCenterPoint());
864 Vector dp = toVector(data->getDiameterPoint());
865 Vector tp = toVector(data->getTextPoint());
866 double actual = -1.0;
867 if(data->hasActualMeasurement()) {
868 actual = data->getActualMeasurement();
869 }
870
871 createDiametric(cp, cp.Minus(dp).Magnitude(), tp, actual, /*asRadius=*/true);
872 }
873
addDimDiametric(const DRW_DimDiametric * data)874 virtual void addDimDiametric(const DRW_DimDiametric *data) {
875 if(data->space != DRW::ModelSpace) return;
876 if(addPendingBlockEntity<DRW_DimRadial>(*data)) return;
877
878 Vector dp1 = toVector(data->getDiameter1Point());
879 Vector dp2 = toVector(data->getDiameter2Point());
880
881 Vector cp = dp1.Plus(dp2).ScaledBy(0.5);
882 Vector tp = toVector(data->getTextPoint());
883 double actual = -1.0;
884 if(data->hasActualMeasurement()) {
885 actual = data->getActualMeasurement();
886 }
887
888 createDiametric(cp, cp.Minus(dp1).Magnitude(), tp, actual, /*asRadius=*/false);
889 }
890
addDimAngular3P(const DRW_DimAngular3p * data)891 virtual void addDimAngular3P(const DRW_DimAngular3p *data) {
892 if(data->space != DRW::ModelSpace) return;
893 if(addPendingBlockEntity<DRW_DimAngular3p>(*data)) return;
894
895 DRW_DimAngular dim = *static_cast<const DRW_Dimension *>(data);
896 dim.setFirstLine1(data->getVertexPoint());
897 dim.setFirstLine2(data->getFirstLine());
898 dim.setSecondLine1(data->getVertexPoint());
899 dim.setSecondLine2(data->getSecondLine());
900 addDimAngular(&dim);
901 }
902 };
903
ImportDxf(const std::string & filename)904 void ImportDxf(const std::string &filename) {
905 DxfReadInterface interface;
906 interface.clearBlockTransform();
907
908 std::string data;
909 if(!ReadFile(filename, &data)) {
910 Error("Couldn't read from '%s'", filename.c_str());
911 return;
912 }
913
914 SS.UndoRemember();
915 std::stringstream stream(data);
916 if(!dxfRW().read(stream, &interface, /*ext=*/false)) {
917 Error("Corrupted DXF file.");
918 }
919
920 if(interface.unknownEntities > 0) {
921 Message(ssprintf("%u DXF entities of unknown type were ignored.",
922 interface.unknownEntities).c_str());
923 }
924 }
925
ImportDwg(const std::string & filename)926 void ImportDwg(const std::string &filename) {
927 DxfReadInterface interface;
928 interface.clearBlockTransform();
929
930 std::string data;
931 if(!ReadFile(filename, &data)) {
932 Error("Couldn't read from '%s'", filename.c_str());
933 return;
934 }
935
936 SS.UndoRemember();
937 std::stringstream stream(data);
938 if(!dwgR().read(stream, &interface, /*ext=*/false)) {
939 Error("Corrupted DWG file.");
940 }
941
942 if(interface.unknownEntities > 0) {
943 Message(ssprintf("%u DWG entities of unknown type were ignored.",
944 interface.unknownEntities).c_str());
945 }
946 }
947
948 }
949