DXF: implement import.
This commit is contained in:
parent
a8465cbc8a
commit
70d84b30e8
|
@ -1 +1 @@
|
|||
Subproject commit a6f7c0a9ff7b9dd847a1c673f7c414c3e10c4022
|
||||
Subproject commit a05d16eaa85c69d662d3b596ca82cbae56443295
|
|
@ -284,6 +284,7 @@ set(solvespace_SOURCES
|
|||
graphicswin.cpp
|
||||
group.cpp
|
||||
groupmesh.cpp
|
||||
importdxf.cpp
|
||||
mesh.cpp
|
||||
modify.cpp
|
||||
mouse.cpp
|
||||
|
|
15
src/dsc.h
15
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 {
|
||||
|
|
|
@ -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
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -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 },
|
||||
|
|
626
src/importdxf.cpp
Normal file
626
src/importdxf.cpp
Normal file
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user