diff --git a/extlib/libdxfrw b/extlib/libdxfrw index a6f7c0a..a05d16e 160000 --- a/extlib/libdxfrw +++ b/extlib/libdxfrw @@ -1 +1 @@ -Subproject commit a6f7c0a9ff7b9dd847a1c673f7c414c3e10c4022 +Subproject commit a05d16eaa85c69d662d3b596ca82cbae56443295 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a112f02..9e15e96 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -284,6 +284,7 @@ set(solvespace_SOURCES graphicswin.cpp group.cpp groupmesh.cpp + importdxf.cpp mesh.cpp modify.cpp mouse.cpp diff --git a/src/dsc.h b/src/dsc.h index ade8ce7..c61bbf5 100644 --- a/src/dsc.h +++ b/src/dsc.h @@ -492,13 +492,22 @@ public: (int)(255.1f * a)); } - static RgbaColor FromPackedInt(uint32_t bgra) { + static RgbaColor FromPackedInt(uint32_t rgba) { + return From( + (int)((rgba) & 0xff), + (int)((rgba >> 8) & 0xff), + (int)((rgba >> 16) & 0xff), + (int)(255 - ((rgba >> 24) & 0xff))); + } + + static RgbaColor FromPackedIntBGRA(uint32_t bgra) { return From( - (int)((bgra) & 0xff), - (int)((bgra >> 8) & 0xff), (int)((bgra >> 16) & 0xff), + (int)((bgra >> 8) & 0xff), + (int)((bgra) & 0xff), (int)(255 - ((bgra >> 24) & 0xff))); } + }; class BBox { diff --git a/src/exportvector.cpp b/src/exportvector.cpp index 7b318f3..0f301ad 100644 --- a/src/exportvector.cpp +++ b/src/exportvector.cpp @@ -195,27 +195,12 @@ public: } } - const char *lineTypeName(int stippleType) { - switch(stippleType) { - case Style::STIPPLE_CONTINUOUS: return "CONTINUOUS"; - case Style::STIPPLE_DASH: return "DASHED"; - case Style::STIPPLE_LONG_DASH: return "DASHEDX2"; - case Style::STIPPLE_DASH_DOT: return "DASHDOT"; - case Style::STIPPLE_DASH_DOT_DOT: return "DIVIDE"; - case Style::STIPPLE_DOT: return "DOT"; - case Style::STIPPLE_FREEHAND: return "CONTINUOUS"; - case Style::STIPPLE_ZIGZAG: return "CONTINUOUS"; - } - - return "CONTINUOUS"; - } - virtual void writeLTypes() { for(int i = 0; i <= Style::LAST_STIPPLE; i++) { DRW_LType type; // LibreCAD requires the line type to have one of these exact names, // or otherwise it overwrites it with its own (continuous) style. - type.name = lineTypeName(i); + type.name = DxfFileWriter::lineTypeName(i); double sw = 1.0; switch(i) { case Style::STIPPLE_CONTINUOUS: @@ -421,7 +406,7 @@ public: Style *s = Style::Get(hs); entity->color24 = s->Color(hs, true).ToPackedIntBGRA(); entity->layer = s->DescriptionString(); - entity->lineType = lineTypeName(s->stippleType); + entity->lineType = DxfFileWriter::lineTypeName(s->stippleType); entity->ltypeScale = Style::StippleScaleMm(s->h); entity->setWidthMm(Style::WidthMm(hs.v)); } @@ -671,6 +656,21 @@ bool DxfFileWriter::NeedToOutput(Constraint *c) { return false; } +const char *DxfFileWriter::lineTypeName(int stippleType) { + switch(stippleType) { + case Style::STIPPLE_CONTINUOUS: return "CONTINUOUS"; + case Style::STIPPLE_DASH: return "DASHED"; + case Style::STIPPLE_LONG_DASH: return "DASHEDX2"; + case Style::STIPPLE_DASH_DOT: return "DASHDOT"; + case Style::STIPPLE_DASH_DOT_DOT: return "DIVIDE"; + case Style::STIPPLE_DOT: return "DOT"; + case Style::STIPPLE_FREEHAND: return "CONTINUOUS"; + case Style::STIPPLE_ZIGZAG: return "CONTINUOUS"; + } + + return "CONTINUOUS"; +} + //----------------------------------------------------------------------------- // Routines for EPS output //----------------------------------------------------------------------------- diff --git a/src/graphicswin.cpp b/src/graphicswin.cpp index 83eeb3b..fa655ab 100644 --- a/src/graphicswin.cpp +++ b/src/graphicswin.cpp @@ -40,6 +40,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { { 1, "Export 3d &Wireframe...", MNU_EXPORT_WIREFRAME, 0, TN, mFile }, { 1, "Export Triangle &Mesh...", MNU_EXPORT_MESH, 0, TN, mFile }, { 1, "Export &Surfaces...", MNU_EXPORT_SURFACES,0, TN, mFile }, +{ 1, "Im&port...", MNU_IMPORT ,0, TN, mFile }, #ifndef __APPLE__ { 1, NULL, 0, 0, TN, NULL }, { 1, "E&xit", MNU_EXIT, C|'Q', TN, mFile }, diff --git a/src/importdxf.cpp b/src/importdxf.cpp new file mode 100644 index 0000000..c9ec7cc --- /dev/null +++ b/src/importdxf.cpp @@ -0,0 +1,626 @@ +#include "solvespace.h" +#include "libdxfrw.h" + +#ifdef WIN32 +// Conflicts with DRW::TEXT. +# undef TEXT +#endif + +namespace SolveSpace { + +static std::string ToUpper(std::string str) { + std::transform(str.begin(), str.end(), str.begin(), ::toupper); + return str; +} + +class DxfReadInterface : public DRW_Interface { +public: + Vector blockX; + Vector blockY; + Vector blockT; + + void invertXTransform() { + blockX.x = -blockX.x; + blockY.x = -blockY.x; + blockT.x = -blockT.x; + } + + void multBlockTransform(double x, double y, double sx, double sy, double angle) { + Vector oldX = blockX; + Vector oldY = blockY; + Vector oldT = blockT; + + Vector newX = Vector::From(sx, 0.0, 0.0).RotatedAbout(Vector::From(0.0, 0.0, 1.0), angle); + Vector newY = Vector::From(0.0, sy, 0.0).RotatedAbout(Vector::From(0.0, 0.0, 1.0), angle); + Vector newT = Vector::From(x, y, 0.0); + + blockX = oldX.ScaledBy(newX.x).Plus( + oldY.ScaledBy(newX.y)); + + blockY = oldX.ScaledBy(newY.x).Plus( + oldY.ScaledBy(newY.y)); + + blockT = oldX.ScaledBy(newT.x).Plus( + oldY.ScaledBy(newT.y)).Plus(oldT); + } + + void clearBlockTransform() { + blockX = Vector::From(1.0, 0.0, 0.0); + blockY = Vector::From(0.0, 1.0, 0.0); + blockT = Vector::From(0.0, 0.0, 0.0); + } + + Vector blockTransform(Vector v) { + Vector r = blockT; + r = r.Plus(blockX.ScaledBy(v.x)); + r = r.Plus(blockY.ScaledBy(v.y)); + return r; + } + + void blockTransformArc(Vector *c, Vector *p0, Vector *p1) { + bool oldSign = p0->Minus(*c).Cross(p1->Minus(*c)).z > 0.0; + + *c = blockTransform(*c); + *p0 = blockTransform(*p0); + *p1 = blockTransform(*p1); + + bool newSign = p0->Minus(*c).Cross(p1->Minus(*c)).z > 0.0; + if(oldSign != newSign) std::swap(*p0, *p1); + } + + Vector toVector(const DRW_Coord &c) { + Vector result = Vector::From(c.x, c.y, 0.0); + return blockTransform(result); + } + + Vector toVector(const DRW_Vertex2D &c) { + Vector result = Vector::From(c.x, c.y, 0.0); + return blockTransform(result); + } + + Vector toVector(const DRW_Vertex &c) { + Vector result = Vector::From(c.basePoint.x, c.basePoint.y, 0.0); + return blockTransform(result); + } + + double angleTo(Vector v0, Vector v1) { + Vector d = v1.Minus(v0); + double a = atan2(d.y, d.x); + return M_PI + remainder(a - M_PI, 2 * M_PI); + } + + Vector polar(double radius, double angle) { + return Vector::From(radius * cos(angle), radius * sin(angle), 0.0); + } + + hRequest createBulge(Vector p0, Vector p1, double bulge) { + bool reversed = bulge < 0.0; + double alpha = atan(bulge) * 4.0; + + Vector middle = p1.Plus(p0).ScaledBy(0.5); + double dist = p1.Minus(p0).Magnitude() / 2.0; + double angle = angleTo(p0, p1); + + // alpha can't be 0.0 at this point + double radius = fabs(dist / sin(alpha / 2.0)); + double wu = fabs(radius * radius - dist * dist); + double h = sqrt(wu); + + if(bulge > 0.0) { + angle += M_PI_2; + } else { + angle -= M_PI_2; + } + + if (fabs(alpha) > M_PI) { + h *= -1.0; + } + + Vector center = polar(h, angle); + center = center.Plus(middle); + + if(reversed) std::swap(p0, p1); + blockTransformArc(¢er, &p0, &p1); + + hRequest hr = SS.GW.AddRequest(Request::ARC_OF_CIRCLE, false); + SK.GetEntity(hr.entity(1))->PointForceTo(center); + SK.GetEntity(hr.entity(2))->PointForceTo(p0); + SK.GetEntity(hr.entity(3))->PointForceTo(p1); + return hr; + } + + struct Block { + std::vector<std::unique_ptr<DRW_Entity>> entities; + DRW_Block data; + }; + + unsigned unknownEntities = 0; + std::map<std::string, hStyle> styles; + std::map<std::string, Block> blocks; + std::map<std::string, DRW_Layer> layers; + Block *readBlock = NULL; + const DRW_Insert *insertInsert = NULL; + + template<class T> + bool addPendingBlockEntity(const T &e) { + if(readBlock == NULL) return false; + readBlock->entities.emplace_back(new T(e)); + return true; + } + + void addEntity(DRW_Entity *e) { + switch(e->eType) { + case DRW::POINT: + addPoint(*static_cast<DRW_Point *>(e)); + break; + case DRW::LINE: + addLine(*static_cast<DRW_Line *>(e)); + break; + case DRW::ARC: + addArc(*static_cast<DRW_Arc *>(e)); + break; + case DRW::CIRCLE: + addCircle(*static_cast<DRW_Circle *>(e)); + break; + case DRW::POLYLINE: + addPolyline(*static_cast<DRW_Polyline *>(e)); + break; + case DRW::LWPOLYLINE: + addLWPolyline(*static_cast<DRW_LWPolyline *>(e)); + break; + case DRW::SPLINE: + addSpline(static_cast<DRW_Spline *>(e)); + break; + case DRW::INSERT: + addInsert(*static_cast<DRW_Insert *>(e)); + break; + case DRW::TEXT: + addText(*static_cast<DRW_Text *>(e)); + break; + case DRW::MTEXT: + addMText(*static_cast<DRW_MText *>(e)); + break; + default: + unknownEntities++; + } + } + + int dxfAlignToOrigin(DRW_Text::HAlign alignH, DRW_Text::VAlign alignV) { + int origin = 0; + switch(alignH) { + case DRW_Text::HLeft: + origin |= Style::ORIGIN_LEFT; + break; + + case DRW_Text::HMiddle: + case DRW_Text::HCenter: + break; + + case DRW_Text::HRight: + origin |= Style::ORIGIN_RIGHT; + break; + + case DRW_Text::HAligned: + case DRW_Text::HFit: + default: + origin |= Style::ORIGIN_LEFT; + break; + } + + switch(alignV) { + case DRW_Text::VBaseLine: + case DRW_Text::VBottom: + origin |= Style::ORIGIN_BOT; + break; + + case DRW_Text::VMiddle: + break; + + case DRW_Text::VTop: + origin |= Style::ORIGIN_TOP; + break; + + default: + origin |= Style::ORIGIN_BOT; + break; + } + + return origin; + } + + DRW_Layer *getSourceLayer(const DRW_Entity *e) { + DRW_Layer *layer = NULL; + if(insertInsert != NULL) { + std::string l = insertInsert->layer; + auto bi = layers.find(l); + if(bi != layers.end()) layer = &bi->second; + } else { + std::string l = e->layer; + auto bi = layers.find(l); + if(bi != layers.end()) layer = &bi->second; + } + return layer; + } + + int getColor(const DRW_Entity *e) { + int col = e->color; + if(col == DRW::ColorByBlock) { + if(insertInsert != NULL) { + col = insertInsert->color; + } else { + col = 7; + } + } + if(col == DRW::ColorByLayer) { + DRW_Layer *layer = getSourceLayer(e); + if(layer != NULL) { + col = layer->color; + } else { + col = 7; + } + } + return col; + } + + DRW_LW_Conv::lineWidth getLineWidth(const DRW_Entity *e) { + DRW_LW_Conv::lineWidth result = e->lWeight; + if(result == DRW_LW_Conv::widthByBlock) { + if(insertInsert != NULL) { + result = insertInsert->lWeight; + } else { + result = DRW_LW_Conv::widthDefault; + } + } + if(result == DRW_LW_Conv::widthByLayer) { + DRW_Layer *layer = getSourceLayer(e); + if(layer != NULL) { + result = layer->lWeight; + } else { + result = DRW_LW_Conv::widthDefault; + } + } + return result; + } + + std::string getLineType(const DRW_Entity *e) { + std::string result = e->lineType; + if(result == "BYBLOCK") { + if(insertInsert != NULL) { + result = ToUpper(insertInsert->lineType); + } else { + result = "CONTINUOUS"; + } + } + if(result == "BYLAYER") { + DRW_Layer *layer = getSourceLayer(e); + if(layer != NULL) { + result = ToUpper(layer->lineType); + } else { + result = "CONTINUOUS"; + } + } + return result; + } + + hStyle styleFor(const DRW_Entity *e) { + DRW_Layer *layer = NULL; + auto bi = layers.find(e->layer); + if(bi != layers.end()) layer = &bi->second; + + // Color. + // TODO: which color to choose: index or RGB one? + int col = getColor(e); + RgbaColor c = RgbaColor::From(DRW::dxfColors[col][0], + DRW::dxfColors[col][1], + DRW::dxfColors[col][2]); + + // Line width. + DRW_LW_Conv::lineWidth lw = getLineWidth(e); + double width = DRW_LW_Conv::lineWidth2dxfInt(e->lWeight) / 100.0; + if(width < 0.0) width = 1.0; + + // Line stipple. + // TODO: Probably, we can load default autocad patterns and match it with ours. + std::string lineType = getLineType(e); + int stipple = Style::STIPPLE_CONTINUOUS; + for(int i = 0; i <= Style::LAST_STIPPLE; i++) { + if(lineType == DxfFileWriter::lineTypeName(i)) { + stipple = i; + break; + } + } + + // Text properties. + DRW_Text::HAlign alignH = DRW_Text::HLeft; + DRW_Text::VAlign alignV = DRW_Text::VBaseLine; + double textAngle = 0.0; + double textHeight = Style::DefaultTextHeight(); + + if(e->eType == DRW::TEXT || e->eType == DRW::MTEXT) { + const DRW_Text *text = static_cast<const DRW_Text *>(e); + alignH = text->alignH; + alignV = text->alignV; + textHeight = text->height; + textAngle = text->angle; + // I have no idea why, but works + if(alignH == DRW_Text::HMiddle) { + alignV = DRW_Text::VMiddle; + } + } + + // Unique identifier based on style properties. + std::string id = "@dxf"; + if(lw != DRW_LW_Conv::widthDefault) + id += ssprintf("-w%.4g", width); + if(lineType != "CONTINUOUS") + id += ssprintf("-%s", lineType.c_str()); + if(c.red != 0 || c.green != 0 || c.blue != 0) + id += ssprintf("-#%02x%02x%02x", c.red, c.green, c.blue); + if(textHeight != Style::DefaultTextHeight()) + id += ssprintf("-h%.4g", textHeight); + if(textAngle != 0.0) + id += ssprintf("-a%.5g", textAngle); + if(alignH != DRW_Text::HLeft) + id += ssprintf("-oh%d", alignH); + if(alignV != DRW_Text::VBaseLine) + id += ssprintf("-ov%d", alignV); + + auto si = styles.find(id); + if(si != styles.end()) { + return si->second; + } + + hStyle hs = { Style::CreateCustomStyle(/*rememberForUndo=*/false) }; + Style *s = Style::Get(hs); + if(lw != DRW_LW_Conv::widthDefault) { + s->widthAs = Style::UNITS_AS_MM; + s->width = width; + s->stippleScale = 1.0 + width * 2.0; + } + s->name = id; + s->stippleType = stipple; + if(c.red != 0 || c.green != 0 || c.blue != 0) s->color = c; + s->textHeightAs = Style::UNITS_AS_MM; + s->textHeight = textHeight; + s->textAngle = textAngle; + s->textOrigin = dxfAlignToOrigin(alignH, alignV); + + styles.emplace(id, hs); + return hs; + } + + void setStyle(hRequest hr, hStyle hs) { + Request *r = SK.GetRequest(hr); + r->style = hs; + } + + virtual void addLayer(const DRW_Layer &data) { + layers.emplace(data.name, data); + } + + virtual void addBlock(const DRW_Block &data) { + blocks.emplace(data.name, Block()); + readBlock = &blocks[data.name]; + readBlock->data = data; + } + + virtual void endBlock() { + readBlock = NULL; + } + + virtual void addPoint(const DRW_Point &data) { + if(data.space != DRW::ModelSpace) return; + if(addPendingBlockEntity<DRW_Point>(data)) return; + + hRequest hr = SS.GW.AddRequest(Request::DATUM_POINT, false); + SK.GetEntity(hr.entity(0))->PointForceTo(toVector(data.basePoint)); + } + + virtual void addLine(const DRW_Line &data) { + if(data.space != DRW::ModelSpace) return; + if(addPendingBlockEntity<DRW_Line>(data)) return; + + hRequest hr = SS.GW.AddRequest(Request::LINE_SEGMENT, false); + SK.GetEntity(hr.entity(1))->PointForceTo(toVector(data.basePoint)); + SK.GetEntity(hr.entity(2))->PointForceTo(toVector(data.secPoint)); + setStyle(hr, styleFor(&data)); + } + + virtual void addArc(const DRW_Arc &data) { + if(data.space != DRW::ModelSpace) return; + if(addPendingBlockEntity<DRW_Arc>(data)) return; + + hRequest hr = SS.GW.AddRequest(Request::ARC_OF_CIRCLE, false); + double r = data.radious; + double sa = data.staangle; + double ea = data.endangle; + Vector c = Vector::From(data.basePoint.x, data.basePoint.y, 0.0); + Vector rvs = Vector::From(r * cos(sa), r * sin(sa), data.basePoint.z).Plus(c); + Vector rve = Vector::From(r * cos(ea), r * sin(ea), data.basePoint.z).Plus(c); + + if(data.extPoint.z == -1.0) { + c.x = -c.x; + rvs.x = - rvs.x; + rve.x = - rve.x; + std::swap(rvs, rve); + } + + blockTransformArc(&c, &rvs, &rve); + + SK.GetEntity(hr.entity(1))->PointForceTo(c); + SK.GetEntity(hr.entity(2))->PointForceTo(rvs); + SK.GetEntity(hr.entity(3))->PointForceTo(rve); + setStyle(hr, styleFor(&data)); + } + + virtual void addCircle(const DRW_Circle &data) { + if(data.space != DRW::ModelSpace) return; + if(addPendingBlockEntity<DRW_Circle>(data)) return; + + hRequest hr = SS.GW.AddRequest(Request::CIRCLE, false); + SK.GetEntity(hr.entity(1))->PointForceTo(toVector(data.basePoint)); + SK.GetEntity(hr.entity(64))->DistanceForceTo(data.radious); + setStyle(hr, styleFor(&data)); + } + + virtual void addLWPolyline(const DRW_LWPolyline &data) { + if(data.space != DRW::ModelSpace) return; + if(addPendingBlockEntity<DRW_LWPolyline>(data)) return; + + size_t vNum = data.vertlist.size(); + + // Check for closed polyline. + if((data.flags & 1) != 1) vNum--; + + // Correct coordinate system for the case where z=-1, as described in + // http://paulbourke.net/dataformats/dxf/dxf10.html. + bool needSwapX = data.extPoint.z == -1.0; + + for(size_t i = 0; i < vNum; i++) { + DRW_Vertex2D c0 = *data.vertlist[i]; + DRW_Vertex2D c1 = *data.vertlist[(i + 1) % data.vertlist.size()]; + + if(needSwapX) { + c0.x = -c0.x; + c1.x = -c1.x; + c0.bulge = -c0.bulge; + } + + Vector p0 = Vector::From(c0.x, c0.y, 0.0); + Vector p1 = Vector::From(c1.x, c1.y, 0.0); + hStyle hs = styleFor(&data); + + if(EXACT(data.vertlist[i]->bulge == 0.0)) { + hRequest hr = SS.GW.AddRequest(Request::LINE_SEGMENT, false); + SK.GetEntity(hr.entity(1))->PointForceTo(blockTransform(p0)); + SK.GetEntity(hr.entity(2))->PointForceTo(blockTransform(p1)); + setStyle(hr, hs); + } else { + hRequest hr = createBulge(p0, p1, c0.bulge); + setStyle(hr, hs); + } + } + } + + virtual void addPolyline(const DRW_Polyline &data) { + if(data.space != DRW::ModelSpace) return; + if(addPendingBlockEntity<DRW_Polyline>(data)) return; + + int vNum = data.vertlist.size(); + + // Check for closed polyline. + if((data.flags & 1) != 1) vNum--; + + // Correct coordinate system for the case where z=-1, as described in + // http://paulbourke.net/dataformats/dxf/dxf10.html. + bool needSwapX = data.extPoint.z == -1.0; + + for(int i = 0; i < vNum; i++) { + DRW_Coord c0 = data.vertlist[i]->basePoint; + DRW_Coord c1 = data.vertlist[(i + 1) % data.vertlist.size()]->basePoint; + + double bulge = data.vertlist[i]->bulge; + if(needSwapX) { + c0.x = -c0.x; + c1.x = -c1.x; + bulge = -bulge; + } + + Vector p0 = Vector::From(c0.x, c0.y, 0.0); + Vector p1 = Vector::From(c1.x, c1.y, 0.0); + hStyle hs = styleFor(&data); + + if(EXACT(bulge == 0.0)) { + hRequest hr = SS.GW.AddRequest(Request::LINE_SEGMENT, false); + SK.GetEntity(hr.entity(1))->PointForceTo(blockTransform(p0)); + SK.GetEntity(hr.entity(2))->PointForceTo(blockTransform(p1)); + setStyle(hr, hs); + } else { + hRequest hr = createBulge(p0, p1, bulge); + setStyle(hr, hs); + } + } + } + + virtual void addSpline(const DRW_Spline *data) { + if(data->space != DRW::ModelSpace) return; + if(data->degree != 3) return; + if(addPendingBlockEntity<DRW_Spline>(*data)) return; + + hRequest hr = SS.GW.AddRequest(Request::CUBIC, false); + for(int i = 0; i < 4; i++) { + SK.GetEntity(hr.entity(i + 1))->PointForceTo(toVector(*data->controllist[i])); + } + setStyle(hr, styleFor(data)); + } + + virtual void addInsert(const DRW_Insert &data) { + if(data.space != DRW::ModelSpace) return; + if(addPendingBlockEntity<DRW_Insert>(data)) return; + + auto bi = blocks.find(data.name); + if(bi == blocks.end()) oops(); + Block *block = &bi->second; + + // Push transform. + Vector x = blockX; + Vector y = blockY; + Vector t = blockT; + + const DRW_Insert *oldInsert = insertInsert; + insertInsert = &data; + + if(data.extPoint.z == -1.0) invertXTransform(); + multBlockTransform(data.basePoint.x, data.basePoint.y, data.xscale, data.yscale, data.angle); + for(auto &e : block->entities) { + addEntity(&*e); + } + + insertInsert = oldInsert; + + // Pop transform. + blockX = x; + blockY = y; + blockT = t; + } + + virtual void addMText(const DRW_MText &data) { + if(data.space != DRW::ModelSpace) return; + if(addPendingBlockEntity<DRW_MText>(data)) return; + + DRW_MText text = data; + text.secPoint = text.basePoint; + addText(text); + } + + virtual void addText(const DRW_Text &data) { + if(data.space != DRW::ModelSpace) return; + if(addPendingBlockEntity<DRW_Text>(data)) return; + + Constraint c = {}; + c.group = SS.GW.activeGroup; + c.workplane = SS.GW.ActiveWorkplane(); + c.type = Constraint::COMMENT; + if(data.alignH == DRW_Text::HLeft && data.alignV == DRW_Text::VBaseLine) { + c.disp.offset = toVector(data.basePoint); + } else { + c.disp.offset = toVector(data.secPoint); + } + c.comment = data.text; + c.disp.style = styleFor(&data); + Constraint::AddConstraint(&c, false); + } +}; + +void ImportDxf(const std::string &filename) { + dxfRW dxf(filename.c_str()); + DxfReadInterface interface; + interface.clearBlockTransform(); + dxf.read(&interface, false); + if(interface.unknownEntities > 0) { + Message(ssprintf("%u DXF entities of unknown type were ignored.", + interface.unknownEntities).c_str()); + } +} + +} diff --git a/src/sketch.h b/src/sketch.h index d39e476..38c16d5 100644 --- a/src/sketch.h +++ b/src/sketch.h @@ -830,7 +830,7 @@ public: static void LoadFactoryDefaults(void); static void AssignSelectionToStyle(uint32_t v); - static uint32_t CreateCustomStyle(void); + static uint32_t CreateCustomStyle(bool rememberForUndo = true); static RgbaColor RewriteColor(RgbaColor rgb); diff --git a/src/solvespace.cpp b/src/solvespace.cpp index 139970c..12acc28 100644 --- a/src/solvespace.cpp +++ b/src/solvespace.cpp @@ -541,6 +541,16 @@ void SolveSpaceUI::MenuFile(int id) { break; } + case GraphicsWindow::MNU_IMPORT: { + std::string importFile; + if(!GetOpenFile(&importFile, CnfThawString("", "ImportFormat"), + ImportableFileFilter)) break; + CnfFreezeString(Extension(importFile), "ImportFormat"); + + ImportDxf(importFile); + break; + } + case GraphicsWindow::MNU_EXIT: if(!SS.OkayToStartNewFile()) break; SS.Exit(); diff --git a/src/solvespace.h b/src/solvespace.h index 757c3ff..46c597f 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -19,6 +19,7 @@ #include <algorithm> #include <memory> #include <string> +#include <locale> #include <vector> #include <unordered_map> #include <map> @@ -195,6 +196,11 @@ const FileFilter Vector3dFileFilter[] = { { "DXF file (AutoCAD 2007)", { "dxf" } }, { NULL } }; +// All Importable formats +const FileFilter ImportableFileFilter[] = { + { "AutoCAD DXF and DWG files", { "dxf", "dwg" } }, + { NULL } +}; // Comma-separated value, like a spreadsheet would use const FileFilter CsvFileFilter[] = { { "CSV", { "csv" } }, @@ -534,6 +540,9 @@ public: void FinishAndCloseFile(void); bool HasCanvasSize(void) { return false; } bool NeedToOutput(Constraint *c); + + static const char *lineTypeName(int stippleType); + }; class EpsFileWriter : public VectorFileWriter { public: @@ -942,6 +951,8 @@ public: } }; +void ImportDxf(const std::string &file); + extern SolveSpaceUI SS; extern Sketch SK; diff --git a/src/style.cpp b/src/style.cpp index 75abffb..91caaea 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -122,8 +122,8 @@ void Style::FreezeDefaultStyles(void) { } } -uint32_t Style::CreateCustomStyle(void) { - SS.UndoRemember(); +uint32_t Style::CreateCustomStyle(bool rememberForUndo) { + if(rememberForUndo) SS.UndoRemember(); uint32_t vs = max((uint32_t)Style::FIRST_CUSTOM, SK.style.MaximumId() + 1); hStyle hs = { vs }; (void)Style::Get(hs); diff --git a/src/ui.h b/src/ui.h index 15f64dd..08c32e7 100644 --- a/src/ui.h +++ b/src/ui.h @@ -348,6 +348,7 @@ public: MNU_EXPORT_VIEW, MNU_EXPORT_SECTION, MNU_EXPORT_WIREFRAME, + MNU_IMPORT, MNU_EXIT, // View MNU_ZOOM_IN,