Solvespace

Форк
0
/
importdxf.cpp 
1199 строк · 39.0 Кб
1
#include "solvespace.h"
2
#include "libdxfrw.h"
3
#include "libdwgr.h"
4

5
namespace SolveSpace {
6

7
static std::string ToUpper(std::string str) {
8
    std::transform(str.begin(), str.end(), str.begin(), ::toupper);
9
    return str;
10
}
11

12
static Quaternion NormalFromExtPoint(Vector extPoint) {
13
    // DXF arbitrary axis algorithm for transforming a Z-vector into a rotated
14
    // coordinate system
15
    Vector ax, ay;
16
    Vector az = extPoint.WithMagnitude(1.0);
17

18
    if ((fabs(az.x) < 1/64.) && (fabs(az.y) < 1/64.)) {
19
        ax = Vector::From(0, 1, 0).Cross(az).WithMagnitude(1.0);
20
    } else {
21
        ax = Vector::From(0, 0, 1).Cross(az).WithMagnitude(1.0);
22
    }
23
    ay = az.Cross(ax).WithMagnitude(1.0);
24
    return Quaternion::From(ax, ay);
25
}
26

27
class DxfImport : public DRW_Interface {
28
public:
29
    Vector blockX;
30
    Vector blockY;
31
    Vector blockZ;
32
    Vector blockT;
33

34
    void invertXTransform() {
35
        blockX.x = -blockX.x;
36
        blockY.x = -blockY.x;
37
        blockT.x = -blockT.x;
38
    }
39

40
    void multBlockTransform(double x, double y, double sx, double sy, double angle) {
41
        Vector oldX = blockX;
42
        Vector oldY = blockY;
43
        Vector oldT = blockT;
44

45
        Vector newX = Vector::From(sx, 0.0, 0.0).RotatedAbout(Vector::From(0.0, 0.0, 1.0), angle);
46
        Vector newY = Vector::From(0.0, sy, 0.0).RotatedAbout(Vector::From(0.0, 0.0, 1.0), angle);
47
        Vector newT = Vector::From(x, y, 0.0);
48

49
        blockX = oldX.ScaledBy(newX.x).Plus(
50
                 oldY.ScaledBy(newX.y));
51

52
        blockY = oldX.ScaledBy(newY.x).Plus(
53
                 oldY.ScaledBy(newY.y));
54

55
        blockT = oldX.ScaledBy(newT.x).Plus(
56
                 oldY.ScaledBy(newT.y)).Plus(oldT);
57
    }
58

59
    void clearBlockTransform() {
60
        blockX = Vector::From(1.0, 0.0, 0.0);
61
        blockY = Vector::From(0.0, 1.0, 0.0);
62
        blockZ = Vector::From(0.0, 0.0, 1.0);
63
        blockT = Vector::From(0.0, 0.0, 0.0);
64
    }
65

66
    Vector blockTransform(Vector v) {
67
        Vector r = blockT;
68
        r = r.Plus(blockX.ScaledBy(v.x));
69
        r = r.Plus(blockY.ScaledBy(v.y));
70
        r = r.Plus(blockZ.ScaledBy(v.z));
71
        return r;
72
    }
73

74
    void blockTransformArc(Vector *c, Vector *p0, Vector *p1) {
75
        bool oldSign = p0->Minus(*c).Cross(p1->Minus(*c)).z > 0.0;
76

77
        *c = blockTransform(*c);
78
        *p0 = blockTransform(*p0);
79
        *p1 = blockTransform(*p1);
80

81
        bool newSign = p0->Minus(*c).Cross(p1->Minus(*c)).z > 0.0;
82
        if(oldSign != newSign) std::swap(*p0, *p1);
83
    }
84

85
    Vector toVector(const DRW_Coord &c, bool transform = true) {
86
        Vector result = Vector::From(c.x, c.y, c.z);
87
        if(transform) return blockTransform(result);
88
        return result;
89
    }
90

91
    Vector toVector(const DRW_Vertex2D &c) {
92
        Vector result = Vector::From(c.x, c.y, 0.0);
93
        return blockTransform(result);
94
    }
95

96
    Vector toVector(const DRW_Vertex &c) {
97
        Vector result = Vector::From(c.basePoint.x, c.basePoint.y, c.basePoint.z);
98
        return blockTransform(result);
99
    }
100

101
    double angleTo(Vector v0, Vector v1) {
102
        Vector d = v1.Minus(v0);
103
        double a = atan2(d.y, d.x);
104
        return M_PI + remainder(a - M_PI, 2 * M_PI);
105
    }
106

107
    Vector polar(double radius, double angle) {
108
        return Vector::From(radius * cos(angle), radius * sin(angle), 0.0);
109
    }
110

111
    hRequest createBulge(Vector p0, Vector p1, double bulge) {
112
        bool reversed = bulge < 0.0;
113
        double alpha = atan(bulge) * 4.0;
114

115
        Vector middle = p1.Plus(p0).ScaledBy(0.5);
116
        double dist = p1.Minus(p0).Magnitude() / 2.0;
117
        double angle = angleTo(p0, p1);
118

119
        // alpha can't be 0.0 at this point
120
        double radius = fabs(dist / sin(alpha / 2.0));
121
        double wu = fabs(radius * radius - dist * dist);
122
        double h = sqrt(wu);
123

124
        if(bulge > 0.0) {
125
            angle += M_PI_2;
126
        } else {
127
            angle -= M_PI_2;
128
        }
129

130
        if (fabs(alpha) > M_PI) {
131
            h *= -1.0;
132
        }
133

134
        Vector center = polar(h, angle);
135
        center = center.Plus(middle);
136

137
        if(reversed) std::swap(p0, p1);
138
        blockTransformArc(&center, &p0, &p1);
139

140
        hRequest hr = SS.GW.AddRequest(Request::Type::ARC_OF_CIRCLE, /*rememberForUndo=*/false);
141
        SK.GetEntity(hr.entity(1))->PointForceTo(center);
142
        SK.GetEntity(hr.entity(2))->PointForceTo(p0);
143
        SK.GetEntity(hr.entity(3))->PointForceTo(p1);
144
        processPoint(hr.entity(1));
145
        processPoint(hr.entity(2));
146
        processPoint(hr.entity(3));
147
        return hr;
148
    }
149

150
    struct Block {
151
        std::vector<std::unique_ptr<DRW_Entity>> entities;
152
        DRW_Block data;
153
    };
154

155
    bool asConstruction = false;
156
    unsigned unknownEntities = 0;
157
    std::map<std::string, hStyle> styles;
158
    std::map<std::string, Block> blocks;
159
    std::map<std::string, DRW_Layer> layers;
160
    Block *readBlock = NULL;
161
    const DRW_Insert *insertInsert = NULL;
162

163
    template<class T>
164
    bool addPendingBlockEntity(const T &e) {
165
        if(readBlock == NULL) return false;
166
        readBlock->entities.emplace_back(new T(e));
167
        return true;
168
    }
169

170
    void addEntity(DRW_Entity *e) {
171
        switch(e->eType) {
172
            case DRW::POINT:
173
                addPoint(*static_cast<DRW_Point *>(e));
174
                break;
175
            case DRW::LINE:
176
                addLine(*static_cast<DRW_Line *>(e));
177
                break;
178
            case DRW::ARC:
179
                addArc(*static_cast<DRW_Arc *>(e));
180
                break;
181
            case DRW::CIRCLE:
182
                addCircle(*static_cast<DRW_Circle *>(e));
183
                break;
184
            case DRW::POLYLINE:
185
                addPolyline(*static_cast<DRW_Polyline *>(e));
186
                break;
187
            case DRW::LWPOLYLINE:
188
                addLWPolyline(*static_cast<DRW_LWPolyline *>(e));
189
                break;
190
            case DRW::SPLINE:
191
                addSpline(static_cast<DRW_Spline *>(e));
192
                break;
193
            case DRW::INSERT:
194
                addInsert(*static_cast<DRW_Insert *>(e));
195
                break;
196
            case DRW::TEXT:
197
                addText(*static_cast<DRW_Text *>(e));
198
                break;
199
            case DRW::MTEXT:
200
                addMText(*static_cast<DRW_MText *>(e));
201
                break;
202
            case DRW::DIMALIGNED:
203
                addDimAlign(static_cast<DRW_DimAligned *>(e));
204
                break;
205
            case DRW::DIMLINEAR:
206
                addDimLinear(static_cast<DRW_DimLinear *>(e));
207
                break;
208
            case DRW::DIMRADIAL:
209
                addDimRadial(static_cast<DRW_DimRadial *>(e));
210
                break;
211
            case DRW::DIMDIAMETRIC:
212
                addDimDiametric(static_cast<DRW_DimDiametric *>(e));
213
                break;
214
            case DRW::DIMANGULAR:
215
                addDimAngular(static_cast<DRW_DimAngular *>(e));
216
                break;
217
            default:
218
                unknownEntities++;
219
        }
220
    }
221

222
    Style::TextOrigin dxfAlignToOrigin(DRW_Text::HAlign alignH, DRW_Text::VAlign alignV) {
223
        uint32_t origin = 0;
224
        switch(alignH) {
225
            case DRW_Text::HLeft:
226
                origin |= (uint32_t)Style::TextOrigin::LEFT;
227
                break;
228

229
            case DRW_Text::HMiddle:
230
            case DRW_Text::HCenter:
231
                break;
232

233
            case DRW_Text::HRight:
234
                origin |= (uint32_t)Style::TextOrigin::RIGHT;
235
                break;
236

237
            case DRW_Text::HAligned:
238
            case DRW_Text::HFit:
239
            default:
240
                origin |= (uint32_t)Style::TextOrigin::LEFT;
241
                break;
242
        }
243

244
        switch(alignV) {
245
            case DRW_Text::VBaseLine:
246
            case DRW_Text::VBottom:
247
                origin |= (uint32_t)Style::TextOrigin::BOT;
248
                break;
249

250
            case DRW_Text::VMiddle:
251
                break;
252

253
            case DRW_Text::VTop:
254
                origin |= (uint32_t)Style::TextOrigin::TOP;
255
                break;
256

257
            default:
258
                origin |= (uint32_t)Style::TextOrigin::BOT;
259
                break;
260
        }
261

262
        return (Style::TextOrigin)origin;
263
    }
264

265
    DRW_Layer *getSourceLayer(const DRW_Entity *e) {
266
        DRW_Layer *layer = NULL;
267
        if(insertInsert != NULL) {
268
            std::string l = insertInsert->layer;
269
            auto bi = layers.find(l);
270
            if(bi != layers.end()) layer = &bi->second;
271
        } else {
272
            std::string l = e->layer;
273
            auto bi = layers.find(l);
274
            if(bi != layers.end()) layer = &bi->second;
275
        }
276
        return layer;
277
    }
278

279
    int getColor(const DRW_Entity *e) {
280
        int col = e->color;
281
        if(col == DRW::ColorByBlock) {
282
            if(insertInsert != NULL) {
283
                col = insertInsert->color;
284
            } else {
285
                col = 7;
286
            }
287
        }
288
        if(col == DRW::ColorByLayer) {
289
            DRW_Layer *layer = getSourceLayer(e);
290
            if(layer != NULL) {
291
                col = layer->color;
292
            } else {
293
                col = 7;
294
            }
295
        }
296
        return col;
297
    }
298

299
    DRW_LW_Conv::lineWidth getLineWidth(const DRW_Entity *e) {
300
        DRW_LW_Conv::lineWidth result = e->lWeight;
301
        if(result == DRW_LW_Conv::widthByBlock) {
302
            if(insertInsert != NULL) {
303
                result = insertInsert->lWeight;
304
            } else {
305
                result = DRW_LW_Conv::widthDefault;
306
            }
307
        }
308
        if(result == DRW_LW_Conv::widthByLayer) {
309
            DRW_Layer *layer = getSourceLayer(e);
310
            if(layer != NULL) {
311
                result = layer->lWeight;
312
            } else {
313
                result = DRW_LW_Conv::widthDefault;
314
            }
315
        }
316
        return result;
317
    }
318

319
    std::string getLineType(const DRW_Entity *e) {
320
        std::string  result = e->lineType;
321
        if(result == "BYBLOCK") {
322
            if(insertInsert != NULL) {
323
                result = ToUpper(insertInsert->lineType);
324
            } else {
325
                result = "CONTINUOUS";
326
            }
327
        }
328
        if(result == "BYLAYER") {
329
            DRW_Layer *layer = getSourceLayer(e);
330
            if(layer != NULL) {
331
                result = ToUpper(layer->lineType);
332
            } else {
333
                result = "CONTINUOUS";
334
            }
335
        }
336
        return result;
337
    }
338

339
    hStyle invisibleStyle() {
340
        std::string id = "@dxf-invisible";
341

342
        auto si = styles.find(id);
343
        if(si != styles.end()) {
344
            return si->second;
345
        }
346

347
        hStyle hs = { Style::CreateCustomStyle(/*rememberForUndo=*/false) };
348
        Style *s = Style::Get(hs);
349
        s->name = id;
350
        s->visible = false;
351

352
        styles.emplace(id, hs);
353
        return hs;
354
    }
355

356
    hStyle styleFor(const DRW_Entity *e) {
357
        // Color.
358
        //! @todo which color to choose: index or RGB one?
359
        int col = getColor(e);
360
        RgbaColor c = RgbaColor::From(DRW::dxfColors[col][0],
361
                                      DRW::dxfColors[col][1],
362
                                      DRW::dxfColors[col][2]);
363

364
        // Line width.
365
        DRW_LW_Conv::lineWidth lw = getLineWidth(e);
366
        double width = DRW_LW_Conv::lineWidth2dxfInt(e->lWeight) / 100.0;
367
        if(width < 0.0) width = 1.0;
368

369
        // Line stipple.
370
        //! @todo Probably, we can load default autocad patterns and match it with ours.
371
        std::string lineType = getLineType(e);
372
        StipplePattern stipple = StipplePattern::CONTINUOUS;
373
        for(uint32_t i = 0; i <= (uint32_t)StipplePattern::LAST; i++) {
374
            StipplePattern st = (StipplePattern)i;
375
            if(lineType == DxfFileWriter::lineTypeName(st)) {
376
                stipple = st;
377
                break;
378
            }
379
        }
380

381
        // Text properties.
382
        DRW_Text::HAlign alignH = DRW_Text::HLeft;
383
        DRW_Text::VAlign alignV = DRW_Text::VBaseLine;
384
        double textAngle = 0.0;
385
        double textHeight = Style::DefaultTextHeight();
386

387
        if(e->eType == DRW::TEXT || e->eType == DRW::MTEXT) {
388
            const DRW_Text *text = static_cast<const DRW_Text *>(e);
389
            alignH = text->alignH;
390
            alignV = text->alignV;
391
            textHeight = text->height;
392
            textAngle = text->angle;
393
            // I have no idea why, but works
394
            if(alignH == DRW_Text::HMiddle) {
395
                alignV = DRW_Text::VMiddle;
396
            }
397
        }
398

399
        // Unique identifier based on style properties.
400
        std::string id = "@dxf";
401
        if(lw != DRW_LW_Conv::widthDefault)
402
            id += ssprintf("-w%.4g", width);
403
        if(lineType != "CONTINUOUS")
404
            id += ssprintf("-%s", lineType.c_str());
405
        if(c.red != 0 || c.green != 0 || c.blue != 0)
406
            id += ssprintf("-#%02x%02x%02x", c.red, c.green, c.blue);
407
        if(textHeight != Style::DefaultTextHeight())
408
            id += ssprintf("-h%.4g", textHeight);
409
        if(textAngle != 0.0)
410
            id += ssprintf("-a%.5g", textAngle);
411
        if(alignH != DRW_Text::HLeft)
412
            id += ssprintf("-oh%d", alignH);
413
        if(alignV != DRW_Text::VBaseLine)
414
            id += ssprintf("-ov%d", alignV);
415

416
        auto si = styles.find(id);
417
        if(si != styles.end()) {
418
            return si->second;
419
        }
420

421
        hStyle hs = { Style::CreateCustomStyle(/*rememberForUndo=*/false) };
422
        Style *s = Style::Get(hs);
423
        if(lw != DRW_LW_Conv::widthDefault) {
424
            s->widthAs = Style::UnitsAs::MM;
425
            s->width = width;
426
            s->stippleScale = 1.0 + width * 2.0;
427
        }
428
        s->name = id;
429
        s->stippleType = stipple;
430
        if(c.red != 0 || c.green != 0 || c.blue != 0) s->color = c;
431
        s->textHeightAs = Style::UnitsAs::MM;
432
        s->textHeight = textHeight;
433
        s->textAngle = textAngle;
434
        s->textOrigin = dxfAlignToOrigin(alignH, alignV);
435

436
        styles.emplace(id, hs);
437
        return hs;
438
    }
439

440
    void configureRequest(hRequest hr, hStyle hs) {
441
        Request *r = SK.GetRequest(hr);
442
        r->construction = asConstruction;
443
        r->style = hs;
444
    }
445

446
    struct VectorHash {
447
        size_t operator()(const Vector &v) const {
448
            static const size_t size = std::numeric_limits<size_t>::max() / 2 - 1;
449
            static const double eps = (4.0 * LENGTH_EPS);
450

451
            double x = fabs(v.x) / eps;
452
            double y = fabs(v.y) / eps;
453

454
            size_t xs = size_t(fmod(x, double(size)));
455
            size_t ys = size_t(fmod(y, double(size)));
456

457
            return ys * size + xs;
458
        }
459
    };
460

461
    struct VectorPred {
462
        bool operator()(Vector a, Vector b) const {
463
            return a.Equals(b, LENGTH_EPS);
464
        }
465
    };
466

467
    std::unordered_map<Vector, hEntity, VectorHash, VectorPred> points;
468

469
    void processPoint(hEntity he, bool constrain = true) {
470
        Entity *e = SK.GetEntity(he);
471
        Vector pos = e->PointGetNum();
472
        hEntity p = findPoint(pos);
473
        if(p == he) return;
474
        if(p != Entity::NO_ENTITY) {
475
            if(constrain) {
476
                Constraint::ConstrainCoincident(he, p);
477
            }
478
            // We don't add point because we already
479
            // have point in this position
480
            return;
481
        }
482
        points.emplace(pos, he);
483
    }
484

485
    hEntity findPoint(const Vector &p) {
486
        auto it = points.find(p);
487
        if(it == points.end()) return Entity::NO_ENTITY;
488
        return it->second;
489
    }
490

491
    hEntity createOrGetPoint(const Vector &p) {
492
        hEntity he = findPoint(p);
493
        if(he != Entity::NO_ENTITY) return he;
494

495
        hRequest hr = SS.GW.AddRequest(Request::Type::DATUM_POINT, /*rememberForUndo=*/false);
496
        he = hr.entity(0);
497
        SK.GetEntity(he)->PointForceTo(p);
498
        points.emplace(p, he);
499
        return he;
500
    }
501

502
    hEntity createLine(Vector p0, Vector p1, hStyle style, bool constrainHV = false) {
503
        if(p0.Equals(p1)) return Entity::NO_ENTITY;
504
        hRequest hr = SS.GW.AddRequest(Request::Type::LINE_SEGMENT, /*rememberForUndo=*/false);
505
        SK.GetEntity(hr.entity(1))->PointForceTo(p0);
506
        SK.GetEntity(hr.entity(2))->PointForceTo(p1);
507
        processPoint(hr.entity(1));
508
        processPoint(hr.entity(2));
509

510
        if(constrainHV && SS.GW.LockedInWorkplane()) {
511
            bool hasConstraint = false;
512
            Constraint::Type cType;
513
            if(fabs(p0.x - p1.x) < LENGTH_EPS) {
514
                hasConstraint = true;
515
                cType = Constraint::Type::VERTICAL;
516
            } else if(fabs(p0.y - p1.y) < LENGTH_EPS) {
517
                hasConstraint = true;
518
                cType = Constraint::Type::HORIZONTAL;
519
            }
520
            if(hasConstraint) {
521
                Constraint::Constrain(
522
                    cType,
523
                    Entity::NO_ENTITY,
524
                    Entity::NO_ENTITY,
525
                    hr.entity(0)
526
                );
527
            }
528
        }
529

530
        configureRequest(hr, style);
531
        return hr.entity(0);
532
    }
533

534
    hEntity createWorkplane(const Vector &p, const Quaternion &q) {
535
        hRequest hr = SS.GW.AddRequest(Request::Type::WORKPLANE, /*rememberForUndo=*/false);
536
        SK.GetEntity(hr.entity(1))->PointForceTo(p);
537
        processPoint(hr.entity(1));
538
        SK.GetEntity(hr.entity(32))->NormalForceTo(q);
539
        return hr.entity(0);
540
    }
541

542
    hEntity findOrCreateWorkplane(const Vector &p, const Quaternion &q) {
543
        Vector z = q.RotationN();
544
        for(auto &r : SK.request) {
545
            if((r.type == Request::Type::WORKPLANE) && (r.group == SS.GW.activeGroup)) {
546
                Vector wp = SK.GetEntity(r.h.entity(1))->PointGetNum();
547
                Vector wz = SK.GetEntity(r.h.entity(32))->NormalN();
548

549
                if ((p.DistanceToPlane(wz, wp) < LENGTH_EPS) && z.Equals(wz)) {
550
                   return r.h.entity(0);
551
                }
552
            }
553
        }
554

555
        return createWorkplane(p, q);
556
    }
557

558
    static void activateWorkplane(hEntity he) {
559
        Group *g = SK.GetGroup(SS.GW.activeGroup);
560
        g->activeWorkplane = he;
561
    }
562

563
    hEntity createCircle(const Vector &c, const Quaternion &q, double r, hStyle style) {
564
        hRequest hr = SS.GW.AddRequest(Request::Type::CIRCLE, /*rememberForUndo=*/false);
565
        SK.GetEntity(hr.entity(1))->PointForceTo(c);
566
        processPoint(hr.entity(1));
567
        SK.GetEntity(hr.entity(32))->NormalForceTo(q);
568
        SK.GetEntity(hr.entity(64))->DistanceForceTo(r);
569
        configureRequest(hr, style);
570
        return hr.entity(0);
571
    }
572

573
    void addLayer(const DRW_Layer &data) override {
574
        layers.emplace(data.name, data);
575
    }
576

577
    void addBlock(const DRW_Block &data) override {
578
        readBlock = &blocks[data.name];
579
        readBlock->data = data;
580
    }
581

582
    void endBlock() override {
583
        readBlock = NULL;
584
    }
585

586
    void addPoint(const DRW_Point &data) override {
587
        if(data.space != DRW::ModelSpace) return;
588
        if(addPendingBlockEntity<DRW_Point>(data)) return;
589

590
        hRequest hr = SS.GW.AddRequest(Request::Type::DATUM_POINT, /*rememberForUndo=*/false);
591
        SK.GetEntity(hr.entity(0))->PointForceTo(toVector(data.basePoint));
592
        processPoint(hr.entity(0));
593
    }
594

595
    void addLine(const DRW_Line &data) override {
596
        if(data.space != DRW::ModelSpace) return;
597
        if(addPendingBlockEntity<DRW_Line>(data)) return;
598

599
        createLine(toVector(data.basePoint), toVector(data.secPoint), styleFor(&data),
600
                   /*constrainHV=*/true);
601
    }
602

603
    void addArc(const DRW_Arc &data) override {
604
        if(data.space != DRW::ModelSpace) return;
605
        if(addPendingBlockEntity<DRW_Arc>(data)) return;
606

607
        double r = data.radious;
608
        double sa = data.staangle;
609
        double ea = data.endangle;
610
        Vector c = toVector(data.basePoint);
611
        Vector nz = toVector(data.extPoint);
612
        Quaternion q = NormalFromExtPoint(nz);
613

614
        bool planar = q.RotationN().Equals(Vector::From(0, 0, 1));
615
        bool onPlane = c.z < LENGTH_EPS;
616

617
        hEntity oldWorkplane = SS.GW.ActiveWorkplane();
618
        if (!planar || !onPlane) {
619
            activateWorkplane(findOrCreateWorkplane(c, q));
620
        }
621

622
        hRequest hr = SS.GW.AddRequest(Request::Type::ARC_OF_CIRCLE, /*rememberForUndo=*/false);
623
        Vector u = q.RotationU(), v = q.RotationV();
624
        Vector rvs = c.Plus(u.ScaledBy(r * cos(sa))).Plus(v.ScaledBy(r * sin(sa)));
625
        Vector rve = c.Plus(u.ScaledBy(r * cos(ea))).Plus(v.ScaledBy(r * sin(ea)));
626

627
        if(data.extPoint.z == -1.0) {
628
            c.x = -c.x;
629
            rvs.x = - rvs.x;
630
            rve.x = - rve.x;
631
            std::swap(rvs, rve);
632
        }
633

634
        blockTransformArc(&c, &rvs, &rve);
635

636
        SK.GetEntity(hr.entity(1))->PointForceTo(c);
637
        SK.GetEntity(hr.entity(2))->PointForceTo(rvs);
638
        SK.GetEntity(hr.entity(3))->PointForceTo(rve);
639
        processPoint(hr.entity(1));
640
        processPoint(hr.entity(2));
641
        processPoint(hr.entity(3));
642
        configureRequest(hr, styleFor(&data));
643
        activateWorkplane(oldWorkplane);
644
    }
645

646
    void addCircle(const DRW_Circle &data) override {
647
        if(data.space != DRW::ModelSpace) return;
648
        if(addPendingBlockEntity<DRW_Circle>(data)) return;
649

650
        Vector nz = toVector(data.extPoint);
651
        Quaternion normal = NormalFromExtPoint(nz);
652
        createCircle(toVector(data.basePoint), normal, data.radious, styleFor(&data));
653
    }
654

655
    void addLWPolyline(const DRW_LWPolyline &data)  override {
656
        if(data.space != DRW::ModelSpace) return;
657
        if(addPendingBlockEntity<DRW_LWPolyline>(data)) return;
658

659
        size_t vNum = data.vertlist.size();
660

661
        // Check for closed polyline.
662
        if((data.flags & 1) != 1) vNum--;
663

664
        // Correct coordinate system for the case where z=-1, as described in
665
        // http://paulbourke.net/dataformats/dxf/dxf10.html.
666
        bool needSwapX = data.extPoint.z == -1.0;
667

668
        for(size_t i = 0; i < vNum; i++) {
669
            DRW_Vertex2D c0 = *data.vertlist[i];
670
            DRW_Vertex2D c1 = *data.vertlist[(i + 1) % data.vertlist.size()];
671

672
            if(needSwapX) {
673
                c0.x = -c0.x;
674
                c1.x = -c1.x;
675
                c0.bulge = -c0.bulge;
676
            }
677

678
            Vector p0 = Vector::From(c0.x, c0.y, 0.0);
679
            Vector p1 = Vector::From(c1.x, c1.y, 0.0);
680
            hStyle hs = styleFor(&data);
681

682
            if(EXACT(data.vertlist[i]->bulge == 0.0)) {
683
                createLine(blockTransform(p0), blockTransform(p1), hs, /*constrainHV=*/true);
684
            } else {
685
                hRequest hr = createBulge(p0, p1, c0.bulge);
686
                configureRequest(hr, hs);
687
            }
688
        }
689
    }
690

691
    void addPolyline(const DRW_Polyline &data) override {
692
        if(data.space != DRW::ModelSpace) return;
693
        if(addPendingBlockEntity<DRW_Polyline>(data)) return;
694

695
        size_t vNum = data.vertlist.size();
696

697
        // Check for closed polyline.
698
        if((data.flags & 1) != 1) vNum--;
699

700
        // Correct coordinate system for the case where z=-1, as described in
701
        // http://paulbourke.net/dataformats/dxf/dxf10.html.
702
        bool needSwapX = (data.extPoint.z == -1.0);
703

704
        for(size_t i = 0; i < vNum; i++) {
705
            DRW_Coord c0 = data.vertlist[i]->basePoint;
706
            DRW_Coord c1 = data.vertlist[(i + 1) % data.vertlist.size()]->basePoint;
707

708
            double bulge = data.vertlist[i]->bulge;
709
            if(needSwapX) {
710
                c0.x = -c0.x;
711
                c1.x = -c1.x;
712
                bulge = -bulge;
713
            }
714

715
            Vector p0 = Vector::From(c0.x, c0.y, c0.z);
716
            Vector p1 = Vector::From(c1.x, c1.y, c1.z);
717
            hStyle hs = styleFor(&data);
718

719
            if(EXACT(bulge == 0.0)) {
720
                createLine(blockTransform(p0), blockTransform(p1), hs, /*constrainHV=*/true);
721
            } else {
722
                hRequest hr = createBulge(p0, p1, bulge);
723
                configureRequest(hr, hs);
724
            }
725
        }
726
    }
727

728
    void addSpline(const DRW_Spline *data) override {
729
        if(data->space != DRW::ModelSpace) return;
730
        if(data->degree != 3) return;
731
        if(addPendingBlockEntity<DRW_Spline>(*data)) return;
732

733
        hRequest hr = SS.GW.AddRequest(Request::Type::CUBIC, /*rememberForUndo=*/false);
734
        for(int i = 0; i < 4; i++) {
735
            SK.GetEntity(hr.entity(i + 1))->PointForceTo(toVector(*data->controllist[i]));
736
            processPoint(hr.entity(i + 1));
737
        }
738
        configureRequest(hr, styleFor(data));
739
    }
740

741
    void addInsert(const DRW_Insert &data) override {
742
        if(data.space != DRW::ModelSpace) return;
743
        if(addPendingBlockEntity<DRW_Insert>(data)) return;
744

745
        auto bi = blocks.find(data.name);
746
        ssassert(bi != blocks.end(), "Inserted block does not exist");
747
        Block *block = &bi->second;
748

749
        // Push transform.
750
        Vector x = blockX;
751
        Vector y = blockY;
752
        Vector t = blockT;
753

754
        const DRW_Insert *oldInsert = insertInsert;
755
        insertInsert = &data;
756

757
        if(data.extPoint.z == -1.0) invertXTransform();
758
        multBlockTransform(data.basePoint.x, data.basePoint.y, data.xscale, data.yscale,
759
                           data.angle);
760
        for(auto &e : block->entities) {
761
            addEntity(&*e);
762
        }
763

764
        insertInsert = oldInsert;
765

766
        // Pop transform.
767
        blockX = x;
768
        blockY = y;
769
        blockT = t;
770
    }
771

772
    void addMText(const DRW_MText &data) override {
773
        if(data.space != DRW::ModelSpace) return;
774
        if(addPendingBlockEntity<DRW_MText>(data)) return;
775

776
        DRW_MText text = data;
777
        text.secPoint = text.basePoint;
778
        addText(text);
779
    }
780

781
    void addText(const DRW_Text &data) override {
782
        if(data.space != DRW::ModelSpace) return;
783
        if(addPendingBlockEntity<DRW_Text>(data)) return;
784

785
        Constraint c = {};
786
        c.group         = SS.GW.activeGroup;
787
        c.workplane     = SS.GW.ActiveWorkplane();
788
        c.type          = Constraint::Type::COMMENT;
789
        if(data.alignH == DRW_Text::HLeft && data.alignV == DRW_Text::VBaseLine) {
790
            c.disp.offset   = toVector(data.basePoint);
791
        } else {
792
            c.disp.offset   = toVector(data.secPoint);
793
        }
794
        c.comment       = data.text;
795
        c.disp.style    = styleFor(&data);
796
        Constraint::AddConstraint(&c, /*rememberForUndo=*/false);
797
    }
798

799
    void addDimAlign(const DRW_DimAligned *data) override {
800
        if(data->space != DRW::ModelSpace) return;
801
        if(addPendingBlockEntity<DRW_DimAligned>(*data)) return;
802

803
        Vector p0 = toVector(data->getDef1Point());
804
        Vector p1 = toVector(data->getDef2Point());
805
        Vector p2 = toVector(data->getTextPoint());
806
        hConstraint hc = Constraint::Constrain(
807
            Constraint::Type::PT_PT_DISTANCE,
808
            createOrGetPoint(p0),
809
            createOrGetPoint(p1),
810
            Entity::NO_ENTITY
811
        );
812

813
        Constraint *c = SK.GetConstraint(hc);
814
        if(data->hasActualMeasurement()) {
815
            c->valA = data->getActualMeasurement();
816
        } else {
817
            c->ModifyToSatisfy();
818
        }
819
        c->disp.offset = p2.Minus(p0.Plus(p1).ScaledBy(0.5));
820
    }
821

822
    void addDimLinear(const DRW_DimLinear *data) override {
823
        if(data->space != DRW::ModelSpace) return;
824
        if(addPendingBlockEntity<DRW_DimLinear>(*data)) return;
825

826
        Vector p0 = toVector(data->getDef1Point(), /*transform=*/false);
827
        Vector p1 = toVector(data->getDef2Point(), /*transform=*/false);
828
        Vector p2 = toVector(data->getTextPoint(), /*transform=*/false);
829

830
        double angle = data->getAngle() * PI / 180.0;
831
        Vector dir = Vector::From(cos(angle), sin(angle), 0.0);
832
        Vector p3 = p1.Minus(p1.ClosestPointOnLine(p2, dir)).Plus(p1);
833
        if(p1.Minus(p3).Magnitude() < LENGTH_EPS) {
834
            p3 = p0.Minus(p0.ClosestPointOnLine(p2, dir)).Plus(p1);
835
        }
836

837
        Vector p4 = p0.ClosestPointOnLine(p1, p3.Minus(p1)).Plus(p0).ScaledBy(0.5);
838

839
        p0 = blockTransform(p0);
840
        p1 = blockTransform(p1);
841
        p2 = blockTransform(p2);
842
        p3 = blockTransform(p3);
843
        p4 = blockTransform(p4);
844

845
        hConstraint hc = Constraint::Constrain(
846
            Constraint::Type::PT_LINE_DISTANCE,
847
            createOrGetPoint(p0),
848
            Entity::NO_ENTITY,
849
            createLine(p1, p3, invisibleStyle())
850
        );
851

852
        Constraint *c = SK.GetConstraint(hc);
853
        if(data->hasActualMeasurement()) {
854
            c->valA = data->getActualMeasurement();
855
        } else {
856
            c->ModifyToSatisfy();
857
        }
858
        c->disp.offset = p2.Minus(p4);
859
    }
860

861
    void addDimAngular(const DRW_DimAngular *data) override {
862
        if(data->space != DRW::ModelSpace) return;
863
        if(addPendingBlockEntity<DRW_DimAngular>(*data)) return;
864

865
        Vector l0p0 = toVector(data->getFirstLine1());
866
        Vector l0p1 = toVector(data->getFirstLine2());
867
        Vector l1p0 = toVector(data->getSecondLine1());
868
        Vector l1p1 = toVector(data->getSecondLine2());
869

870
        hConstraint hc = Constraint::Constrain(
871
            Constraint::Type::ANGLE,
872
            Entity::NO_ENTITY,
873
            Entity::NO_ENTITY,
874
            createLine(l0p0, l0p1, invisibleStyle()),
875
            createLine(l1p1, l1p0, invisibleStyle()),
876
            /*other=*/false,
877
            /*other2=*/false
878
        );
879

880
        Constraint *c = SK.GetConstraint(hc);
881
        c->ModifyToSatisfy();
882
        if(data->hasActualMeasurement()) {
883
            double actual = data->getActualMeasurement() / PI * 180.0;
884
            if(fabs(180.0 - actual - c->valA) < fabs(actual - c->valA)) {
885
                c->other = true;
886
            }
887
            c->valA = actual;
888
        }
889

890
        bool skew = false;
891
        Vector pi = Vector::AtIntersectionOfLines(l0p0, l0p1, l1p0, l1p1, &skew);
892
        if(!skew) {
893
            c->disp.offset = toVector(data->getTextPoint()).Minus(pi);
894
        }
895
    }
896

897
    hConstraint createDiametric(Vector cp, Quaternion q, double r, Vector tp,
898
                                double actual, bool asRadius = false) {
899
        hEntity he = createCircle(cp, q, r, invisibleStyle());
900

901
        hConstraint hc = Constraint::Constrain(
902
            Constraint::Type::DIAMETER,
903
            Entity::NO_ENTITY,
904
            Entity::NO_ENTITY,
905
            he
906
        );
907

908
        Constraint *c = SK.GetConstraint(hc);
909
        if(actual > 0.0) {
910
            c->valA = asRadius ? actual * 2.0 : actual;
911
        } else {
912
            c->ModifyToSatisfy();
913
        }
914
        c->disp.offset = tp.Minus(cp);
915
        if(asRadius) c->other = true;
916
        return hc;
917
    }
918

919
    void addDimRadial(const DRW_DimRadial *data) override {
920
        if(data->space != DRW::ModelSpace) return;
921
        if(addPendingBlockEntity<DRW_DimRadial>(*data)) return;
922

923
        Vector cp = toVector(data->getCenterPoint());
924
        Vector dp = toVector(data->getDiameterPoint());
925
        Vector tp = toVector(data->getTextPoint());
926
        double actual = -1.0;
927
        if(data->hasActualMeasurement()) {
928
            actual = data->getActualMeasurement();
929
        }
930

931
        Vector nz = toVector(data->getExtrusion());
932
        Quaternion q = NormalFromExtPoint(nz);
933
        createDiametric(cp, q, cp.Minus(dp).Magnitude(), tp, actual, /*asRadius=*/true);
934
    }
935

936
    void addDimDiametric(const DRW_DimDiametric *data) override {
937
        if(data->space != DRW::ModelSpace) return;
938
        if(addPendingBlockEntity<DRW_DimRadial>(*data)) return;
939

940
        Vector dp1 = toVector(data->getDiameter1Point());
941
        Vector dp2 = toVector(data->getDiameter2Point());
942

943
        Vector cp = dp1.Plus(dp2).ScaledBy(0.5);
944
        Vector tp = toVector(data->getTextPoint());
945
        double actual = -1.0;
946
        if(data->hasActualMeasurement()) {
947
            actual = data->getActualMeasurement();
948
        }
949

950
        Vector nz = toVector(data->getExtrusion());
951
        Quaternion q = NormalFromExtPoint(nz);
952
        createDiametric(cp, q, cp.Minus(dp1).Magnitude(), tp, actual, /*asRadius=*/false);
953
    }
954

955
    void addDimAngular3P(const DRW_DimAngular3p *data) override {
956
        if(data->space != DRW::ModelSpace) return;
957
        if(addPendingBlockEntity<DRW_DimAngular3p>(*data)) return;
958

959
        DRW_DimAngular dim = *static_cast<const DRW_Dimension *>(data);
960
        dim.setFirstLine1(data->getVertexPoint());
961
        dim.setFirstLine2(data->getFirstLine());
962
        dim.setSecondLine1(data->getVertexPoint());
963
        dim.setSecondLine2(data->getSecondLine());
964
        addDimAngular(&dim);
965
    }
966
};
967

968
class DxfCheck3D : public DRW_Interface {
969
public:
970
    bool is3d;
971

972
    void addEntity(DRW_Entity *e) {
973
        switch(e->eType) {
974
            case DRW::POINT:
975
                addPoint(*static_cast<DRW_Point *>(e));
976
                break;
977
            case DRW::LINE:
978
                addLine(*static_cast<DRW_Line *>(e));
979
                break;
980
            case DRW::ARC:
981
                addArc(*static_cast<DRW_Arc *>(e));
982
                break;
983
            case DRW::CIRCLE:
984
                addCircle(*static_cast<DRW_Circle *>(e));
985
                break;
986
            case DRW::POLYLINE:
987
                addPolyline(*static_cast<DRW_Polyline *>(e));
988
                break;
989
            case DRW::LWPOLYLINE:
990
                addLWPolyline(*static_cast<DRW_LWPolyline *>(e));
991
                break;
992
            case DRW::SPLINE:
993
                addSpline(static_cast<DRW_Spline *>(e));
994
                break;
995
            case DRW::INSERT:
996
                addInsert(*static_cast<DRW_Insert *>(e));
997
                break;
998
            case DRW::TEXT:
999
                addText(*static_cast<DRW_Text *>(e));
1000
                break;
1001
            case DRW::MTEXT:
1002
                addMText(*static_cast<DRW_MText *>(e));
1003
                break;
1004
            case DRW::DIMALIGNED:
1005
                addDimAlign(static_cast<DRW_DimAligned *>(e));
1006
                break;
1007
            case DRW::DIMLINEAR:
1008
                addDimLinear(static_cast<DRW_DimLinear *>(e));
1009
                break;
1010
            case DRW::DIMRADIAL:
1011
                addDimRadial(static_cast<DRW_DimRadial *>(e));
1012
                break;
1013
            case DRW::DIMDIAMETRIC:
1014
                addDimDiametric(static_cast<DRW_DimDiametric *>(e));
1015
                break;
1016
            case DRW::DIMANGULAR:
1017
                addDimAngular(static_cast<DRW_DimAngular *>(e));
1018
                break;
1019
            default:
1020
                break;
1021
        }
1022
    }
1023

1024
    void addPoint(const DRW_Point &data) override {
1025
        if(data.space != DRW::ModelSpace) return;
1026
        checkCoord(data.basePoint);
1027
    }
1028

1029
    void addLine(const DRW_Line &data) override {
1030
        if(data.space != DRW::ModelSpace) return;
1031
        checkCoord(data.basePoint);
1032
        checkCoord(data.secPoint);
1033
    }
1034

1035
    void addArc(const DRW_Arc &data) override {
1036
        if(data.space != DRW::ModelSpace) return;
1037
        checkCoord(data.basePoint);
1038
        checkExt(data.extPoint);
1039
    }
1040

1041
    void addCircle(const DRW_Circle &data) override {
1042
        if(data.space != DRW::ModelSpace) return;
1043
        checkCoord(data.basePoint);
1044
        checkExt(data.extPoint);
1045
    }
1046

1047
    void addPolyline(const DRW_Polyline &data) override {
1048
        if(data.space != DRW::ModelSpace) return;
1049
        for(size_t i = 0; i < data.vertlist.size(); i++) {
1050
            checkCoord(data.vertlist[i]->basePoint);
1051
        }
1052
    }
1053

1054
    void addSpline(const DRW_Spline *data) override {
1055
        if(data->space != DRW::ModelSpace) return;
1056
        if(data->degree != 3) return;
1057
        for(int i = 0; i < 4; i++) {
1058
            checkCoord(*data->controllist[i]);
1059
        }
1060
    }
1061

1062
    void addInsert(const DRW_Insert &data) override {
1063
        if(data.space != DRW::ModelSpace) return;
1064
        checkCoord(data.basePoint);
1065
    }
1066

1067
    void addMText(const DRW_MText &data) override {
1068
        if(data.space != DRW::ModelSpace) return;
1069

1070
        DRW_MText text = data;
1071
        text.secPoint = text.basePoint;
1072
        addText(text);
1073
    }
1074

1075
    void addText(const DRW_Text &data) override {
1076
        if(data.space != DRW::ModelSpace) return;
1077
        checkCoord(data.basePoint);
1078
        checkCoord(data.secPoint);
1079
    }
1080

1081
    void addDimAlign(const DRW_DimAligned *data) override {
1082
        if(data->space != DRW::ModelSpace) return;
1083
        checkCoord(data->getDef1Point());
1084
        checkCoord(data->getDef2Point());
1085
        checkCoord(data->getTextPoint());
1086
    }
1087

1088
    void addDimLinear(const DRW_DimLinear *data) override {
1089
        if(data->space != DRW::ModelSpace) return;
1090
        checkCoord(data->getDef1Point());
1091
        checkCoord(data->getDef2Point());
1092
        checkCoord(data->getTextPoint());
1093
    }
1094

1095
    void addDimAngular(const DRW_DimAngular *data) override {
1096
        if(data->space != DRW::ModelSpace) return;
1097
        checkCoord(data->getFirstLine1());
1098
        checkCoord(data->getFirstLine2());
1099
        checkCoord(data->getSecondLine1());
1100
        checkCoord(data->getSecondLine2());
1101
        checkCoord(data->getTextPoint());
1102
    }
1103

1104
    void addDimRadial(const DRW_DimRadial *data) override {
1105
        if(data->space != DRW::ModelSpace) return;
1106
        checkCoord(data->getCenterPoint());
1107
        checkCoord(data->getDiameterPoint());
1108
        checkCoord(data->getTextPoint());
1109
        checkExt(data->getExtrusion());
1110
    }
1111

1112
    void addDimDiametric(const DRW_DimDiametric *data) override {
1113
        if(data->space != DRW::ModelSpace) return;
1114
        checkCoord(data->getDiameter1Point());
1115
        checkCoord(data->getDiameter2Point());
1116
        checkCoord(data->getTextPoint());
1117
        checkExt(data->getExtrusion());
1118
    }
1119

1120
    void addDimAngular3P(const DRW_DimAngular3p *data) override {
1121
        if(data->space != DRW::ModelSpace) return;
1122
        DRW_DimAngular dim = *static_cast<const DRW_Dimension *>(data);
1123

1124
        dim.setFirstLine1(data->getVertexPoint());
1125
        dim.setFirstLine2(data->getFirstLine());
1126
        dim.setSecondLine1(data->getVertexPoint());
1127
        dim.setSecondLine2(data->getSecondLine());
1128
        addDimAngular(&dim);
1129
    }
1130

1131
    void checkCoord(const DRW_Coord &coord) {
1132
        if(fabs(coord.z) > LENGTH_EPS) {
1133
            is3d = true;
1134
        }
1135
    }
1136

1137
    void checkExt(const DRW_Coord &coord) {
1138
        if ((fabs(coord.x) > 1/64.) || (fabs(coord.y) > 1/64.)) {
1139
            is3d = true;
1140
        }
1141
    }
1142
};
1143

1144
static void
1145
ImportDwgDxf(const Platform::Path &filename,
1146
             const std::function<bool(const std::string &data, DRW_Interface *intf)> &read) {
1147
    std::string fileType = ToUpper(filename.Extension());
1148

1149
    std::string data;
1150
    if(!ReadFile(filename, &data)) {
1151
        Error("Couldn't read from '%s'", filename.raw.c_str());
1152
        return;
1153
    }
1154

1155
    bool asConstruction = true;
1156
    if(SS.GW.LockedInWorkplane()) {
1157
        DxfCheck3D checker = {};
1158
        read(data, &checker);
1159
        if(checker.is3d) {
1160
            Message("This %s file contains entities with non-zero Z coordinate; "
1161
                    "the entire file will be imported as construction entities in 3d.",
1162
                    fileType.c_str());
1163
            SS.GW.SetWorkplaneFreeIn3d();
1164
            SS.GW.EnsureValidActives();
1165
        } else {
1166
            asConstruction = false;
1167
        }
1168
    }
1169

1170
    SS.UndoRemember();
1171

1172
    DxfImport importer = {};
1173
    importer.asConstruction = asConstruction;
1174
    importer.clearBlockTransform();
1175
    if(!read(data, &importer)) {
1176
        Error("Corrupted %s file.", fileType.c_str());
1177
        return;
1178
    }
1179
    if(importer.unknownEntities > 0) {
1180
        Message("%u %s entities of unknown type were ignored.",
1181
                importer.unknownEntities, fileType.c_str());
1182
    }
1183
}
1184

1185
void ImportDxf(const Platform::Path &filename) {
1186
    ImportDwgDxf(filename, [](const std::string &data, DRW_Interface *intf) {
1187
        std::stringstream stream(data);
1188
        return dxfRW().read(stream, intf, /*ext=*/true);
1189
    });
1190
}
1191

1192
void ImportDwg(const Platform::Path &filename) {
1193
    ImportDwgDxf(filename, [](const std::string &data, DRW_Interface *intf) {
1194
        std::stringstream stream(data);
1195
        return dwgR().read(stream, intf, /*ext=*/true);
1196
    });
1197
}
1198

1199
}
1200

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.