Solvespace
1199 строк · 39.0 Кб
1#include "solvespace.h"2#include "libdxfrw.h"3#include "libdwgr.h"4
5namespace SolveSpace {6
7static std::string ToUpper(std::string str) {8std::transform(str.begin(), str.end(), str.begin(), ::toupper);9return str;10}
11
12static Quaternion NormalFromExtPoint(Vector extPoint) {13// DXF arbitrary axis algorithm for transforming a Z-vector into a rotated14// coordinate system15Vector ax, ay;16Vector az = extPoint.WithMagnitude(1.0);17
18if ((fabs(az.x) < 1/64.) && (fabs(az.y) < 1/64.)) {19ax = Vector::From(0, 1, 0).Cross(az).WithMagnitude(1.0);20} else {21ax = Vector::From(0, 0, 1).Cross(az).WithMagnitude(1.0);22}23ay = az.Cross(ax).WithMagnitude(1.0);24return Quaternion::From(ax, ay);25}
26
27class DxfImport : public DRW_Interface {28public:29Vector blockX;30Vector blockY;31Vector blockZ;32Vector blockT;33
34void invertXTransform() {35blockX.x = -blockX.x;36blockY.x = -blockY.x;37blockT.x = -blockT.x;38}39
40void multBlockTransform(double x, double y, double sx, double sy, double angle) {41Vector oldX = blockX;42Vector oldY = blockY;43Vector oldT = blockT;44
45Vector newX = Vector::From(sx, 0.0, 0.0).RotatedAbout(Vector::From(0.0, 0.0, 1.0), angle);46Vector newY = Vector::From(0.0, sy, 0.0).RotatedAbout(Vector::From(0.0, 0.0, 1.0), angle);47Vector newT = Vector::From(x, y, 0.0);48
49blockX = oldX.ScaledBy(newX.x).Plus(50oldY.ScaledBy(newX.y));51
52blockY = oldX.ScaledBy(newY.x).Plus(53oldY.ScaledBy(newY.y));54
55blockT = oldX.ScaledBy(newT.x).Plus(56oldY.ScaledBy(newT.y)).Plus(oldT);57}58
59void clearBlockTransform() {60blockX = Vector::From(1.0, 0.0, 0.0);61blockY = Vector::From(0.0, 1.0, 0.0);62blockZ = Vector::From(0.0, 0.0, 1.0);63blockT = Vector::From(0.0, 0.0, 0.0);64}65
66Vector blockTransform(Vector v) {67Vector r = blockT;68r = r.Plus(blockX.ScaledBy(v.x));69r = r.Plus(blockY.ScaledBy(v.y));70r = r.Plus(blockZ.ScaledBy(v.z));71return r;72}73
74void blockTransformArc(Vector *c, Vector *p0, Vector *p1) {75bool 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
81bool newSign = p0->Minus(*c).Cross(p1->Minus(*c)).z > 0.0;82if(oldSign != newSign) std::swap(*p0, *p1);83}84
85Vector toVector(const DRW_Coord &c, bool transform = true) {86Vector result = Vector::From(c.x, c.y, c.z);87if(transform) return blockTransform(result);88return result;89}90
91Vector toVector(const DRW_Vertex2D &c) {92Vector result = Vector::From(c.x, c.y, 0.0);93return blockTransform(result);94}95
96Vector toVector(const DRW_Vertex &c) {97Vector result = Vector::From(c.basePoint.x, c.basePoint.y, c.basePoint.z);98return blockTransform(result);99}100
101double angleTo(Vector v0, Vector v1) {102Vector d = v1.Minus(v0);103double a = atan2(d.y, d.x);104return M_PI + remainder(a - M_PI, 2 * M_PI);105}106
107Vector polar(double radius, double angle) {108return Vector::From(radius * cos(angle), radius * sin(angle), 0.0);109}110
111hRequest createBulge(Vector p0, Vector p1, double bulge) {112bool reversed = bulge < 0.0;113double alpha = atan(bulge) * 4.0;114
115Vector middle = p1.Plus(p0).ScaledBy(0.5);116double dist = p1.Minus(p0).Magnitude() / 2.0;117double angle = angleTo(p0, p1);118
119// alpha can't be 0.0 at this point120double radius = fabs(dist / sin(alpha / 2.0));121double wu = fabs(radius * radius - dist * dist);122double h = sqrt(wu);123
124if(bulge > 0.0) {125angle += M_PI_2;126} else {127angle -= M_PI_2;128}129
130if (fabs(alpha) > M_PI) {131h *= -1.0;132}133
134Vector center = polar(h, angle);135center = center.Plus(middle);136
137if(reversed) std::swap(p0, p1);138blockTransformArc(¢er, &p0, &p1);139
140hRequest hr = SS.GW.AddRequest(Request::Type::ARC_OF_CIRCLE, /*rememberForUndo=*/false);141SK.GetEntity(hr.entity(1))->PointForceTo(center);142SK.GetEntity(hr.entity(2))->PointForceTo(p0);143SK.GetEntity(hr.entity(3))->PointForceTo(p1);144processPoint(hr.entity(1));145processPoint(hr.entity(2));146processPoint(hr.entity(3));147return hr;148}149
150struct Block {151std::vector<std::unique_ptr<DRW_Entity>> entities;152DRW_Block data;153};154
155bool asConstruction = false;156unsigned unknownEntities = 0;157std::map<std::string, hStyle> styles;158std::map<std::string, Block> blocks;159std::map<std::string, DRW_Layer> layers;160Block *readBlock = NULL;161const DRW_Insert *insertInsert = NULL;162
163template<class T>164bool addPendingBlockEntity(const T &e) {165if(readBlock == NULL) return false;166readBlock->entities.emplace_back(new T(e));167return true;168}169
170void addEntity(DRW_Entity *e) {171switch(e->eType) {172case DRW::POINT:173addPoint(*static_cast<DRW_Point *>(e));174break;175case DRW::LINE:176addLine(*static_cast<DRW_Line *>(e));177break;178case DRW::ARC:179addArc(*static_cast<DRW_Arc *>(e));180break;181case DRW::CIRCLE:182addCircle(*static_cast<DRW_Circle *>(e));183break;184case DRW::POLYLINE:185addPolyline(*static_cast<DRW_Polyline *>(e));186break;187case DRW::LWPOLYLINE:188addLWPolyline(*static_cast<DRW_LWPolyline *>(e));189break;190case DRW::SPLINE:191addSpline(static_cast<DRW_Spline *>(e));192break;193case DRW::INSERT:194addInsert(*static_cast<DRW_Insert *>(e));195break;196case DRW::TEXT:197addText(*static_cast<DRW_Text *>(e));198break;199case DRW::MTEXT:200addMText(*static_cast<DRW_MText *>(e));201break;202case DRW::DIMALIGNED:203addDimAlign(static_cast<DRW_DimAligned *>(e));204break;205case DRW::DIMLINEAR:206addDimLinear(static_cast<DRW_DimLinear *>(e));207break;208case DRW::DIMRADIAL:209addDimRadial(static_cast<DRW_DimRadial *>(e));210break;211case DRW::DIMDIAMETRIC:212addDimDiametric(static_cast<DRW_DimDiametric *>(e));213break;214case DRW::DIMANGULAR:215addDimAngular(static_cast<DRW_DimAngular *>(e));216break;217default:218unknownEntities++;219}220}221
222Style::TextOrigin dxfAlignToOrigin(DRW_Text::HAlign alignH, DRW_Text::VAlign alignV) {223uint32_t origin = 0;224switch(alignH) {225case DRW_Text::HLeft:226origin |= (uint32_t)Style::TextOrigin::LEFT;227break;228
229case DRW_Text::HMiddle:230case DRW_Text::HCenter:231break;232
233case DRW_Text::HRight:234origin |= (uint32_t)Style::TextOrigin::RIGHT;235break;236
237case DRW_Text::HAligned:238case DRW_Text::HFit:239default:240origin |= (uint32_t)Style::TextOrigin::LEFT;241break;242}243
244switch(alignV) {245case DRW_Text::VBaseLine:246case DRW_Text::VBottom:247origin |= (uint32_t)Style::TextOrigin::BOT;248break;249
250case DRW_Text::VMiddle:251break;252
253case DRW_Text::VTop:254origin |= (uint32_t)Style::TextOrigin::TOP;255break;256
257default:258origin |= (uint32_t)Style::TextOrigin::BOT;259break;260}261
262return (Style::TextOrigin)origin;263}264
265DRW_Layer *getSourceLayer(const DRW_Entity *e) {266DRW_Layer *layer = NULL;267if(insertInsert != NULL) {268std::string l = insertInsert->layer;269auto bi = layers.find(l);270if(bi != layers.end()) layer = &bi->second;271} else {272std::string l = e->layer;273auto bi = layers.find(l);274if(bi != layers.end()) layer = &bi->second;275}276return layer;277}278
279int getColor(const DRW_Entity *e) {280int col = e->color;281if(col == DRW::ColorByBlock) {282if(insertInsert != NULL) {283col = insertInsert->color;284} else {285col = 7;286}287}288if(col == DRW::ColorByLayer) {289DRW_Layer *layer = getSourceLayer(e);290if(layer != NULL) {291col = layer->color;292} else {293col = 7;294}295}296return col;297}298
299DRW_LW_Conv::lineWidth getLineWidth(const DRW_Entity *e) {300DRW_LW_Conv::lineWidth result = e->lWeight;301if(result == DRW_LW_Conv::widthByBlock) {302if(insertInsert != NULL) {303result = insertInsert->lWeight;304} else {305result = DRW_LW_Conv::widthDefault;306}307}308if(result == DRW_LW_Conv::widthByLayer) {309DRW_Layer *layer = getSourceLayer(e);310if(layer != NULL) {311result = layer->lWeight;312} else {313result = DRW_LW_Conv::widthDefault;314}315}316return result;317}318
319std::string getLineType(const DRW_Entity *e) {320std::string result = e->lineType;321if(result == "BYBLOCK") {322if(insertInsert != NULL) {323result = ToUpper(insertInsert->lineType);324} else {325result = "CONTINUOUS";326}327}328if(result == "BYLAYER") {329DRW_Layer *layer = getSourceLayer(e);330if(layer != NULL) {331result = ToUpper(layer->lineType);332} else {333result = "CONTINUOUS";334}335}336return result;337}338
339hStyle invisibleStyle() {340std::string id = "@dxf-invisible";341
342auto si = styles.find(id);343if(si != styles.end()) {344return si->second;345}346
347hStyle hs = { Style::CreateCustomStyle(/*rememberForUndo=*/false) };348Style *s = Style::Get(hs);349s->name = id;350s->visible = false;351
352styles.emplace(id, hs);353return hs;354}355
356hStyle styleFor(const DRW_Entity *e) {357// Color.358//! @todo which color to choose: index or RGB one?359int col = getColor(e);360RgbaColor c = RgbaColor::From(DRW::dxfColors[col][0],361DRW::dxfColors[col][1],362DRW::dxfColors[col][2]);363
364// Line width.365DRW_LW_Conv::lineWidth lw = getLineWidth(e);366double width = DRW_LW_Conv::lineWidth2dxfInt(e->lWeight) / 100.0;367if(width < 0.0) width = 1.0;368
369// Line stipple.370//! @todo Probably, we can load default autocad patterns and match it with ours.371std::string lineType = getLineType(e);372StipplePattern stipple = StipplePattern::CONTINUOUS;373for(uint32_t i = 0; i <= (uint32_t)StipplePattern::LAST; i++) {374StipplePattern st = (StipplePattern)i;375if(lineType == DxfFileWriter::lineTypeName(st)) {376stipple = st;377break;378}379}380
381// Text properties.382DRW_Text::HAlign alignH = DRW_Text::HLeft;383DRW_Text::VAlign alignV = DRW_Text::VBaseLine;384double textAngle = 0.0;385double textHeight = Style::DefaultTextHeight();386
387if(e->eType == DRW::TEXT || e->eType == DRW::MTEXT) {388const DRW_Text *text = static_cast<const DRW_Text *>(e);389alignH = text->alignH;390alignV = text->alignV;391textHeight = text->height;392textAngle = text->angle;393// I have no idea why, but works394if(alignH == DRW_Text::HMiddle) {395alignV = DRW_Text::VMiddle;396}397}398
399// Unique identifier based on style properties.400std::string id = "@dxf";401if(lw != DRW_LW_Conv::widthDefault)402id += ssprintf("-w%.4g", width);403if(lineType != "CONTINUOUS")404id += ssprintf("-%s", lineType.c_str());405if(c.red != 0 || c.green != 0 || c.blue != 0)406id += ssprintf("-#%02x%02x%02x", c.red, c.green, c.blue);407if(textHeight != Style::DefaultTextHeight())408id += ssprintf("-h%.4g", textHeight);409if(textAngle != 0.0)410id += ssprintf("-a%.5g", textAngle);411if(alignH != DRW_Text::HLeft)412id += ssprintf("-oh%d", alignH);413if(alignV != DRW_Text::VBaseLine)414id += ssprintf("-ov%d", alignV);415
416auto si = styles.find(id);417if(si != styles.end()) {418return si->second;419}420
421hStyle hs = { Style::CreateCustomStyle(/*rememberForUndo=*/false) };422Style *s = Style::Get(hs);423if(lw != DRW_LW_Conv::widthDefault) {424s->widthAs = Style::UnitsAs::MM;425s->width = width;426s->stippleScale = 1.0 + width * 2.0;427}428s->name = id;429s->stippleType = stipple;430if(c.red != 0 || c.green != 0 || c.blue != 0) s->color = c;431s->textHeightAs = Style::UnitsAs::MM;432s->textHeight = textHeight;433s->textAngle = textAngle;434s->textOrigin = dxfAlignToOrigin(alignH, alignV);435
436styles.emplace(id, hs);437return hs;438}439
440void configureRequest(hRequest hr, hStyle hs) {441Request *r = SK.GetRequest(hr);442r->construction = asConstruction;443r->style = hs;444}445
446struct VectorHash {447size_t operator()(const Vector &v) const {448static const size_t size = std::numeric_limits<size_t>::max() / 2 - 1;449static const double eps = (4.0 * LENGTH_EPS);450
451double x = fabs(v.x) / eps;452double y = fabs(v.y) / eps;453
454size_t xs = size_t(fmod(x, double(size)));455size_t ys = size_t(fmod(y, double(size)));456
457return ys * size + xs;458}459};460
461struct VectorPred {462bool operator()(Vector a, Vector b) const {463return a.Equals(b, LENGTH_EPS);464}465};466
467std::unordered_map<Vector, hEntity, VectorHash, VectorPred> points;468
469void processPoint(hEntity he, bool constrain = true) {470Entity *e = SK.GetEntity(he);471Vector pos = e->PointGetNum();472hEntity p = findPoint(pos);473if(p == he) return;474if(p != Entity::NO_ENTITY) {475if(constrain) {476Constraint::ConstrainCoincident(he, p);477}478// We don't add point because we already479// have point in this position480return;481}482points.emplace(pos, he);483}484
485hEntity findPoint(const Vector &p) {486auto it = points.find(p);487if(it == points.end()) return Entity::NO_ENTITY;488return it->second;489}490
491hEntity createOrGetPoint(const Vector &p) {492hEntity he = findPoint(p);493if(he != Entity::NO_ENTITY) return he;494
495hRequest hr = SS.GW.AddRequest(Request::Type::DATUM_POINT, /*rememberForUndo=*/false);496he = hr.entity(0);497SK.GetEntity(he)->PointForceTo(p);498points.emplace(p, he);499return he;500}501
502hEntity createLine(Vector p0, Vector p1, hStyle style, bool constrainHV = false) {503if(p0.Equals(p1)) return Entity::NO_ENTITY;504hRequest hr = SS.GW.AddRequest(Request::Type::LINE_SEGMENT, /*rememberForUndo=*/false);505SK.GetEntity(hr.entity(1))->PointForceTo(p0);506SK.GetEntity(hr.entity(2))->PointForceTo(p1);507processPoint(hr.entity(1));508processPoint(hr.entity(2));509
510if(constrainHV && SS.GW.LockedInWorkplane()) {511bool hasConstraint = false;512Constraint::Type cType;513if(fabs(p0.x - p1.x) < LENGTH_EPS) {514hasConstraint = true;515cType = Constraint::Type::VERTICAL;516} else if(fabs(p0.y - p1.y) < LENGTH_EPS) {517hasConstraint = true;518cType = Constraint::Type::HORIZONTAL;519}520if(hasConstraint) {521Constraint::Constrain(522cType,523Entity::NO_ENTITY,524Entity::NO_ENTITY,525hr.entity(0)526);527}528}529
530configureRequest(hr, style);531return hr.entity(0);532}533
534hEntity createWorkplane(const Vector &p, const Quaternion &q) {535hRequest hr = SS.GW.AddRequest(Request::Type::WORKPLANE, /*rememberForUndo=*/false);536SK.GetEntity(hr.entity(1))->PointForceTo(p);537processPoint(hr.entity(1));538SK.GetEntity(hr.entity(32))->NormalForceTo(q);539return hr.entity(0);540}541
542hEntity findOrCreateWorkplane(const Vector &p, const Quaternion &q) {543Vector z = q.RotationN();544for(auto &r : SK.request) {545if((r.type == Request::Type::WORKPLANE) && (r.group == SS.GW.activeGroup)) {546Vector wp = SK.GetEntity(r.h.entity(1))->PointGetNum();547Vector wz = SK.GetEntity(r.h.entity(32))->NormalN();548
549if ((p.DistanceToPlane(wz, wp) < LENGTH_EPS) && z.Equals(wz)) {550return r.h.entity(0);551}552}553}554
555return createWorkplane(p, q);556}557
558static void activateWorkplane(hEntity he) {559Group *g = SK.GetGroup(SS.GW.activeGroup);560g->activeWorkplane = he;561}562
563hEntity createCircle(const Vector &c, const Quaternion &q, double r, hStyle style) {564hRequest hr = SS.GW.AddRequest(Request::Type::CIRCLE, /*rememberForUndo=*/false);565SK.GetEntity(hr.entity(1))->PointForceTo(c);566processPoint(hr.entity(1));567SK.GetEntity(hr.entity(32))->NormalForceTo(q);568SK.GetEntity(hr.entity(64))->DistanceForceTo(r);569configureRequest(hr, style);570return hr.entity(0);571}572
573void addLayer(const DRW_Layer &data) override {574layers.emplace(data.name, data);575}576
577void addBlock(const DRW_Block &data) override {578readBlock = &blocks[data.name];579readBlock->data = data;580}581
582void endBlock() override {583readBlock = NULL;584}585
586void addPoint(const DRW_Point &data) override {587if(data.space != DRW::ModelSpace) return;588if(addPendingBlockEntity<DRW_Point>(data)) return;589
590hRequest hr = SS.GW.AddRequest(Request::Type::DATUM_POINT, /*rememberForUndo=*/false);591SK.GetEntity(hr.entity(0))->PointForceTo(toVector(data.basePoint));592processPoint(hr.entity(0));593}594
595void addLine(const DRW_Line &data) override {596if(data.space != DRW::ModelSpace) return;597if(addPendingBlockEntity<DRW_Line>(data)) return;598
599createLine(toVector(data.basePoint), toVector(data.secPoint), styleFor(&data),600/*constrainHV=*/true);601}602
603void addArc(const DRW_Arc &data) override {604if(data.space != DRW::ModelSpace) return;605if(addPendingBlockEntity<DRW_Arc>(data)) return;606
607double r = data.radious;608double sa = data.staangle;609double ea = data.endangle;610Vector c = toVector(data.basePoint);611Vector nz = toVector(data.extPoint);612Quaternion q = NormalFromExtPoint(nz);613
614bool planar = q.RotationN().Equals(Vector::From(0, 0, 1));615bool onPlane = c.z < LENGTH_EPS;616
617hEntity oldWorkplane = SS.GW.ActiveWorkplane();618if (!planar || !onPlane) {619activateWorkplane(findOrCreateWorkplane(c, q));620}621
622hRequest hr = SS.GW.AddRequest(Request::Type::ARC_OF_CIRCLE, /*rememberForUndo=*/false);623Vector u = q.RotationU(), v = q.RotationV();624Vector rvs = c.Plus(u.ScaledBy(r * cos(sa))).Plus(v.ScaledBy(r * sin(sa)));625Vector rve = c.Plus(u.ScaledBy(r * cos(ea))).Plus(v.ScaledBy(r * sin(ea)));626
627if(data.extPoint.z == -1.0) {628c.x = -c.x;629rvs.x = - rvs.x;630rve.x = - rve.x;631std::swap(rvs, rve);632}633
634blockTransformArc(&c, &rvs, &rve);635
636SK.GetEntity(hr.entity(1))->PointForceTo(c);637SK.GetEntity(hr.entity(2))->PointForceTo(rvs);638SK.GetEntity(hr.entity(3))->PointForceTo(rve);639processPoint(hr.entity(1));640processPoint(hr.entity(2));641processPoint(hr.entity(3));642configureRequest(hr, styleFor(&data));643activateWorkplane(oldWorkplane);644}645
646void addCircle(const DRW_Circle &data) override {647if(data.space != DRW::ModelSpace) return;648if(addPendingBlockEntity<DRW_Circle>(data)) return;649
650Vector nz = toVector(data.extPoint);651Quaternion normal = NormalFromExtPoint(nz);652createCircle(toVector(data.basePoint), normal, data.radious, styleFor(&data));653}654
655void addLWPolyline(const DRW_LWPolyline &data) override {656if(data.space != DRW::ModelSpace) return;657if(addPendingBlockEntity<DRW_LWPolyline>(data)) return;658
659size_t vNum = data.vertlist.size();660
661// Check for closed polyline.662if((data.flags & 1) != 1) vNum--;663
664// Correct coordinate system for the case where z=-1, as described in665// http://paulbourke.net/dataformats/dxf/dxf10.html.666bool needSwapX = data.extPoint.z == -1.0;667
668for(size_t i = 0; i < vNum; i++) {669DRW_Vertex2D c0 = *data.vertlist[i];670DRW_Vertex2D c1 = *data.vertlist[(i + 1) % data.vertlist.size()];671
672if(needSwapX) {673c0.x = -c0.x;674c1.x = -c1.x;675c0.bulge = -c0.bulge;676}677
678Vector p0 = Vector::From(c0.x, c0.y, 0.0);679Vector p1 = Vector::From(c1.x, c1.y, 0.0);680hStyle hs = styleFor(&data);681
682if(EXACT(data.vertlist[i]->bulge == 0.0)) {683createLine(blockTransform(p0), blockTransform(p1), hs, /*constrainHV=*/true);684} else {685hRequest hr = createBulge(p0, p1, c0.bulge);686configureRequest(hr, hs);687}688}689}690
691void addPolyline(const DRW_Polyline &data) override {692if(data.space != DRW::ModelSpace) return;693if(addPendingBlockEntity<DRW_Polyline>(data)) return;694
695size_t vNum = data.vertlist.size();696
697// Check for closed polyline.698if((data.flags & 1) != 1) vNum--;699
700// Correct coordinate system for the case where z=-1, as described in701// http://paulbourke.net/dataformats/dxf/dxf10.html.702bool needSwapX = (data.extPoint.z == -1.0);703
704for(size_t i = 0; i < vNum; i++) {705DRW_Coord c0 = data.vertlist[i]->basePoint;706DRW_Coord c1 = data.vertlist[(i + 1) % data.vertlist.size()]->basePoint;707
708double bulge = data.vertlist[i]->bulge;709if(needSwapX) {710c0.x = -c0.x;711c1.x = -c1.x;712bulge = -bulge;713}714
715Vector p0 = Vector::From(c0.x, c0.y, c0.z);716Vector p1 = Vector::From(c1.x, c1.y, c1.z);717hStyle hs = styleFor(&data);718
719if(EXACT(bulge == 0.0)) {720createLine(blockTransform(p0), blockTransform(p1), hs, /*constrainHV=*/true);721} else {722hRequest hr = createBulge(p0, p1, bulge);723configureRequest(hr, hs);724}725}726}727
728void addSpline(const DRW_Spline *data) override {729if(data->space != DRW::ModelSpace) return;730if(data->degree != 3) return;731if(addPendingBlockEntity<DRW_Spline>(*data)) return;732
733hRequest hr = SS.GW.AddRequest(Request::Type::CUBIC, /*rememberForUndo=*/false);734for(int i = 0; i < 4; i++) {735SK.GetEntity(hr.entity(i + 1))->PointForceTo(toVector(*data->controllist[i]));736processPoint(hr.entity(i + 1));737}738configureRequest(hr, styleFor(data));739}740
741void addInsert(const DRW_Insert &data) override {742if(data.space != DRW::ModelSpace) return;743if(addPendingBlockEntity<DRW_Insert>(data)) return;744
745auto bi = blocks.find(data.name);746ssassert(bi != blocks.end(), "Inserted block does not exist");747Block *block = &bi->second;748
749// Push transform.750Vector x = blockX;751Vector y = blockY;752Vector t = blockT;753
754const DRW_Insert *oldInsert = insertInsert;755insertInsert = &data;756
757if(data.extPoint.z == -1.0) invertXTransform();758multBlockTransform(data.basePoint.x, data.basePoint.y, data.xscale, data.yscale,759data.angle);760for(auto &e : block->entities) {761addEntity(&*e);762}763
764insertInsert = oldInsert;765
766// Pop transform.767blockX = x;768blockY = y;769blockT = t;770}771
772void addMText(const DRW_MText &data) override {773if(data.space != DRW::ModelSpace) return;774if(addPendingBlockEntity<DRW_MText>(data)) return;775
776DRW_MText text = data;777text.secPoint = text.basePoint;778addText(text);779}780
781void addText(const DRW_Text &data) override {782if(data.space != DRW::ModelSpace) return;783if(addPendingBlockEntity<DRW_Text>(data)) return;784
785Constraint c = {};786c.group = SS.GW.activeGroup;787c.workplane = SS.GW.ActiveWorkplane();788c.type = Constraint::Type::COMMENT;789if(data.alignH == DRW_Text::HLeft && data.alignV == DRW_Text::VBaseLine) {790c.disp.offset = toVector(data.basePoint);791} else {792c.disp.offset = toVector(data.secPoint);793}794c.comment = data.text;795c.disp.style = styleFor(&data);796Constraint::AddConstraint(&c, /*rememberForUndo=*/false);797}798
799void addDimAlign(const DRW_DimAligned *data) override {800if(data->space != DRW::ModelSpace) return;801if(addPendingBlockEntity<DRW_DimAligned>(*data)) return;802
803Vector p0 = toVector(data->getDef1Point());804Vector p1 = toVector(data->getDef2Point());805Vector p2 = toVector(data->getTextPoint());806hConstraint hc = Constraint::Constrain(807Constraint::Type::PT_PT_DISTANCE,808createOrGetPoint(p0),809createOrGetPoint(p1),810Entity::NO_ENTITY811);812
813Constraint *c = SK.GetConstraint(hc);814if(data->hasActualMeasurement()) {815c->valA = data->getActualMeasurement();816} else {817c->ModifyToSatisfy();818}819c->disp.offset = p2.Minus(p0.Plus(p1).ScaledBy(0.5));820}821
822void addDimLinear(const DRW_DimLinear *data) override {823if(data->space != DRW::ModelSpace) return;824if(addPendingBlockEntity<DRW_DimLinear>(*data)) return;825
826Vector p0 = toVector(data->getDef1Point(), /*transform=*/false);827Vector p1 = toVector(data->getDef2Point(), /*transform=*/false);828Vector p2 = toVector(data->getTextPoint(), /*transform=*/false);829
830double angle = data->getAngle() * PI / 180.0;831Vector dir = Vector::From(cos(angle), sin(angle), 0.0);832Vector p3 = p1.Minus(p1.ClosestPointOnLine(p2, dir)).Plus(p1);833if(p1.Minus(p3).Magnitude() < LENGTH_EPS) {834p3 = p0.Minus(p0.ClosestPointOnLine(p2, dir)).Plus(p1);835}836
837Vector p4 = p0.ClosestPointOnLine(p1, p3.Minus(p1)).Plus(p0).ScaledBy(0.5);838
839p0 = blockTransform(p0);840p1 = blockTransform(p1);841p2 = blockTransform(p2);842p3 = blockTransform(p3);843p4 = blockTransform(p4);844
845hConstraint hc = Constraint::Constrain(846Constraint::Type::PT_LINE_DISTANCE,847createOrGetPoint(p0),848Entity::NO_ENTITY,849createLine(p1, p3, invisibleStyle())850);851
852Constraint *c = SK.GetConstraint(hc);853if(data->hasActualMeasurement()) {854c->valA = data->getActualMeasurement();855} else {856c->ModifyToSatisfy();857}858c->disp.offset = p2.Minus(p4);859}860
861void addDimAngular(const DRW_DimAngular *data) override {862if(data->space != DRW::ModelSpace) return;863if(addPendingBlockEntity<DRW_DimAngular>(*data)) return;864
865Vector l0p0 = toVector(data->getFirstLine1());866Vector l0p1 = toVector(data->getFirstLine2());867Vector l1p0 = toVector(data->getSecondLine1());868Vector l1p1 = toVector(data->getSecondLine2());869
870hConstraint hc = Constraint::Constrain(871Constraint::Type::ANGLE,872Entity::NO_ENTITY,873Entity::NO_ENTITY,874createLine(l0p0, l0p1, invisibleStyle()),875createLine(l1p1, l1p0, invisibleStyle()),876/*other=*/false,877/*other2=*/false878);879
880Constraint *c = SK.GetConstraint(hc);881c->ModifyToSatisfy();882if(data->hasActualMeasurement()) {883double actual = data->getActualMeasurement() / PI * 180.0;884if(fabs(180.0 - actual - c->valA) < fabs(actual - c->valA)) {885c->other = true;886}887c->valA = actual;888}889
890bool skew = false;891Vector pi = Vector::AtIntersectionOfLines(l0p0, l0p1, l1p0, l1p1, &skew);892if(!skew) {893c->disp.offset = toVector(data->getTextPoint()).Minus(pi);894}895}896
897hConstraint createDiametric(Vector cp, Quaternion q, double r, Vector tp,898double actual, bool asRadius = false) {899hEntity he = createCircle(cp, q, r, invisibleStyle());900
901hConstraint hc = Constraint::Constrain(902Constraint::Type::DIAMETER,903Entity::NO_ENTITY,904Entity::NO_ENTITY,905he
906);907
908Constraint *c = SK.GetConstraint(hc);909if(actual > 0.0) {910c->valA = asRadius ? actual * 2.0 : actual;911} else {912c->ModifyToSatisfy();913}914c->disp.offset = tp.Minus(cp);915if(asRadius) c->other = true;916return hc;917}918
919void addDimRadial(const DRW_DimRadial *data) override {920if(data->space != DRW::ModelSpace) return;921if(addPendingBlockEntity<DRW_DimRadial>(*data)) return;922
923Vector cp = toVector(data->getCenterPoint());924Vector dp = toVector(data->getDiameterPoint());925Vector tp = toVector(data->getTextPoint());926double actual = -1.0;927if(data->hasActualMeasurement()) {928actual = data->getActualMeasurement();929}930
931Vector nz = toVector(data->getExtrusion());932Quaternion q = NormalFromExtPoint(nz);933createDiametric(cp, q, cp.Minus(dp).Magnitude(), tp, actual, /*asRadius=*/true);934}935
936void addDimDiametric(const DRW_DimDiametric *data) override {937if(data->space != DRW::ModelSpace) return;938if(addPendingBlockEntity<DRW_DimRadial>(*data)) return;939
940Vector dp1 = toVector(data->getDiameter1Point());941Vector dp2 = toVector(data->getDiameter2Point());942
943Vector cp = dp1.Plus(dp2).ScaledBy(0.5);944Vector tp = toVector(data->getTextPoint());945double actual = -1.0;946if(data->hasActualMeasurement()) {947actual = data->getActualMeasurement();948}949
950Vector nz = toVector(data->getExtrusion());951Quaternion q = NormalFromExtPoint(nz);952createDiametric(cp, q, cp.Minus(dp1).Magnitude(), tp, actual, /*asRadius=*/false);953}954
955void addDimAngular3P(const DRW_DimAngular3p *data) override {956if(data->space != DRW::ModelSpace) return;957if(addPendingBlockEntity<DRW_DimAngular3p>(*data)) return;958
959DRW_DimAngular dim = *static_cast<const DRW_Dimension *>(data);960dim.setFirstLine1(data->getVertexPoint());961dim.setFirstLine2(data->getFirstLine());962dim.setSecondLine1(data->getVertexPoint());963dim.setSecondLine2(data->getSecondLine());964addDimAngular(&dim);965}966};967
968class DxfCheck3D : public DRW_Interface {969public:970bool is3d;971
972void addEntity(DRW_Entity *e) {973switch(e->eType) {974case DRW::POINT:975addPoint(*static_cast<DRW_Point *>(e));976break;977case DRW::LINE:978addLine(*static_cast<DRW_Line *>(e));979break;980case DRW::ARC:981addArc(*static_cast<DRW_Arc *>(e));982break;983case DRW::CIRCLE:984addCircle(*static_cast<DRW_Circle *>(e));985break;986case DRW::POLYLINE:987addPolyline(*static_cast<DRW_Polyline *>(e));988break;989case DRW::LWPOLYLINE:990addLWPolyline(*static_cast<DRW_LWPolyline *>(e));991break;992case DRW::SPLINE:993addSpline(static_cast<DRW_Spline *>(e));994break;995case DRW::INSERT:996addInsert(*static_cast<DRW_Insert *>(e));997break;998case DRW::TEXT:999addText(*static_cast<DRW_Text *>(e));1000break;1001case DRW::MTEXT:1002addMText(*static_cast<DRW_MText *>(e));1003break;1004case DRW::DIMALIGNED:1005addDimAlign(static_cast<DRW_DimAligned *>(e));1006break;1007case DRW::DIMLINEAR:1008addDimLinear(static_cast<DRW_DimLinear *>(e));1009break;1010case DRW::DIMRADIAL:1011addDimRadial(static_cast<DRW_DimRadial *>(e));1012break;1013case DRW::DIMDIAMETRIC:1014addDimDiametric(static_cast<DRW_DimDiametric *>(e));1015break;1016case DRW::DIMANGULAR:1017addDimAngular(static_cast<DRW_DimAngular *>(e));1018break;1019default:1020break;1021}1022}1023
1024void addPoint(const DRW_Point &data) override {1025if(data.space != DRW::ModelSpace) return;1026checkCoord(data.basePoint);1027}1028
1029void addLine(const DRW_Line &data) override {1030if(data.space != DRW::ModelSpace) return;1031checkCoord(data.basePoint);1032checkCoord(data.secPoint);1033}1034
1035void addArc(const DRW_Arc &data) override {1036if(data.space != DRW::ModelSpace) return;1037checkCoord(data.basePoint);1038checkExt(data.extPoint);1039}1040
1041void addCircle(const DRW_Circle &data) override {1042if(data.space != DRW::ModelSpace) return;1043checkCoord(data.basePoint);1044checkExt(data.extPoint);1045}1046
1047void addPolyline(const DRW_Polyline &data) override {1048if(data.space != DRW::ModelSpace) return;1049for(size_t i = 0; i < data.vertlist.size(); i++) {1050checkCoord(data.vertlist[i]->basePoint);1051}1052}1053
1054void addSpline(const DRW_Spline *data) override {1055if(data->space != DRW::ModelSpace) return;1056if(data->degree != 3) return;1057for(int i = 0; i < 4; i++) {1058checkCoord(*data->controllist[i]);1059}1060}1061
1062void addInsert(const DRW_Insert &data) override {1063if(data.space != DRW::ModelSpace) return;1064checkCoord(data.basePoint);1065}1066
1067void addMText(const DRW_MText &data) override {1068if(data.space != DRW::ModelSpace) return;1069
1070DRW_MText text = data;1071text.secPoint = text.basePoint;1072addText(text);1073}1074
1075void addText(const DRW_Text &data) override {1076if(data.space != DRW::ModelSpace) return;1077checkCoord(data.basePoint);1078checkCoord(data.secPoint);1079}1080
1081void addDimAlign(const DRW_DimAligned *data) override {1082if(data->space != DRW::ModelSpace) return;1083checkCoord(data->getDef1Point());1084checkCoord(data->getDef2Point());1085checkCoord(data->getTextPoint());1086}1087
1088void addDimLinear(const DRW_DimLinear *data) override {1089if(data->space != DRW::ModelSpace) return;1090checkCoord(data->getDef1Point());1091checkCoord(data->getDef2Point());1092checkCoord(data->getTextPoint());1093}1094
1095void addDimAngular(const DRW_DimAngular *data) override {1096if(data->space != DRW::ModelSpace) return;1097checkCoord(data->getFirstLine1());1098checkCoord(data->getFirstLine2());1099checkCoord(data->getSecondLine1());1100checkCoord(data->getSecondLine2());1101checkCoord(data->getTextPoint());1102}1103
1104void addDimRadial(const DRW_DimRadial *data) override {1105if(data->space != DRW::ModelSpace) return;1106checkCoord(data->getCenterPoint());1107checkCoord(data->getDiameterPoint());1108checkCoord(data->getTextPoint());1109checkExt(data->getExtrusion());1110}1111
1112void addDimDiametric(const DRW_DimDiametric *data) override {1113if(data->space != DRW::ModelSpace) return;1114checkCoord(data->getDiameter1Point());1115checkCoord(data->getDiameter2Point());1116checkCoord(data->getTextPoint());1117checkExt(data->getExtrusion());1118}1119
1120void addDimAngular3P(const DRW_DimAngular3p *data) override {1121if(data->space != DRW::ModelSpace) return;1122DRW_DimAngular dim = *static_cast<const DRW_Dimension *>(data);1123
1124dim.setFirstLine1(data->getVertexPoint());1125dim.setFirstLine2(data->getFirstLine());1126dim.setSecondLine1(data->getVertexPoint());1127dim.setSecondLine2(data->getSecondLine());1128addDimAngular(&dim);1129}1130
1131void checkCoord(const DRW_Coord &coord) {1132if(fabs(coord.z) > LENGTH_EPS) {1133is3d = true;1134}1135}1136
1137void checkExt(const DRW_Coord &coord) {1138if ((fabs(coord.x) > 1/64.) || (fabs(coord.y) > 1/64.)) {1139is3d = true;1140}1141}1142};1143
1144static void1145ImportDwgDxf(const Platform::Path &filename,1146const std::function<bool(const std::string &data, DRW_Interface *intf)> &read) {1147std::string fileType = ToUpper(filename.Extension());1148
1149std::string data;1150if(!ReadFile(filename, &data)) {1151Error("Couldn't read from '%s'", filename.raw.c_str());1152return;1153}1154
1155bool asConstruction = true;1156if(SS.GW.LockedInWorkplane()) {1157DxfCheck3D checker = {};1158read(data, &checker);1159if(checker.is3d) {1160Message("This %s file contains entities with non-zero Z coordinate; "1161"the entire file will be imported as construction entities in 3d.",1162fileType.c_str());1163SS.GW.SetWorkplaneFreeIn3d();1164SS.GW.EnsureValidActives();1165} else {1166asConstruction = false;1167}1168}1169
1170SS.UndoRemember();1171
1172DxfImport importer = {};1173importer.asConstruction = asConstruction;1174importer.clearBlockTransform();1175if(!read(data, &importer)) {1176Error("Corrupted %s file.", fileType.c_str());1177return;1178}1179if(importer.unknownEntities > 0) {1180Message("%u %s entities of unknown type were ignored.",1181importer.unknownEntities, fileType.c_str());1182}1183}
1184
1185void ImportDxf(const Platform::Path &filename) {1186ImportDwgDxf(filename, [](const std::string &data, DRW_Interface *intf) {1187std::stringstream stream(data);1188return dxfRW().read(stream, intf, /*ext=*/true);1189});1190}
1191
1192void ImportDwg(const Platform::Path &filename) {1193ImportDwgDxf(filename, [](const std::string &data, DRW_Interface *intf) {1194std::stringstream stream(data);1195return dwgR().read(stream, intf, /*ext=*/true);1196});1197}
1198
1199}
1200