Allow DXF import of 3D arcs and circles

Extrusion direction (normal) of arcs and circles were not taken into
account when importing.

- Add method for calculating a quaternion from extrusion direction
  according to DXF arbitrary axis algorithm
- Add required workplanes for arcs not on XY origin plane
- Adjust addDimRadial and addDimDiametric to include normal when
  creating associated circle request
This commit is contained in:
Johannes Rehnman 2020-06-06 18:32:46 +02:00 committed by phkahler
parent 6b7f114697
commit 3ce8c29982
2 changed files with 88 additions and 15 deletions

@ -1 +1 @@
Subproject commit 03fa5f30f1a1db7231a25653c9dd38044fe06640 Subproject commit 0b7b7b709d9299565db603f878214656ef5e9ddf

View File

@ -9,6 +9,21 @@ static std::string ToUpper(std::string str) {
return str; return str;
} }
static Quaternion NormalFromExtPoint(Vector extPoint) {
// DXF arbitrary axis algorithm for transforming a Z-vector into a rotated
// coordinate system
Vector ax, ay;
Vector az = extPoint.WithMagnitude(1.0);
if ((fabs(az.x) < 1/64.) && (fabs(az.y) < 1/64.)) {
ax = Vector::From(0, 1, 0).Cross(az).WithMagnitude(1.0);
} else {
ax = Vector::From(0, 0, 1).Cross(az).WithMagnitude(1.0);
}
ay = az.Cross(ax).WithMagnitude(1.0);
return Quaternion::From(ax, ay);
}
class DxfImport : public DRW_Interface { class DxfImport : public DRW_Interface {
public: public:
Vector blockX; Vector blockX;
@ -516,12 +531,41 @@ public:
return hr.entity(0); return hr.entity(0);
} }
hEntity createCircle(const Vector &c, double r, hStyle style) { hEntity createWorkplane(const Vector &p, const Quaternion &q) {
hRequest hr = SS.GW.AddRequest(Request::Type::WORKPLANE, /*rememberForUndo=*/false);
SK.GetEntity(hr.entity(1))->PointForceTo(p);
processPoint(hr.entity(1));
SK.GetEntity(hr.entity(32))->NormalForceTo(q);
return hr.entity(0);
}
hEntity findOrCreateWorkplane(const Vector &p, const Quaternion &q) {
Vector z = q.RotationN();
for(auto &r : SK.request) {
if((r.type == Request::Type::WORKPLANE) && (r.group == SS.GW.activeGroup)) {
Vector wp = SK.GetEntity(r.h.entity(1))->PointGetNum();
Vector wz = SK.GetEntity(r.h.entity(32))->NormalN();
if ((p.DistanceToPlane(wz, wp) < LENGTH_EPS) && z.Equals(wz)) {
return r.h.entity(0);
}
}
}
return createWorkplane(p, q);
}
static void activateWorkplane(hEntity he) {
Group *g = SK.GetGroup(SS.GW.activeGroup);
g->activeWorkplane = he;
}
hEntity createCircle(const Vector &c, const Quaternion &q, double r, hStyle style) {
hRequest hr = SS.GW.AddRequest(Request::Type::CIRCLE, /*rememberForUndo=*/false); hRequest hr = SS.GW.AddRequest(Request::Type::CIRCLE, /*rememberForUndo=*/false);
SK.GetEntity(hr.entity(1))->PointForceTo(c); SK.GetEntity(hr.entity(1))->PointForceTo(c);
processPoint(hr.entity(1)); processPoint(hr.entity(1));
SK.GetEntity(hr.entity(32))->NormalForceTo(q);
SK.GetEntity(hr.entity(64))->DistanceForceTo(r); SK.GetEntity(hr.entity(64))->DistanceForceTo(r);
configureRequest(hr, style); configureRequest(hr, style);
return hr.entity(0); return hr.entity(0);
} }
@ -560,13 +604,25 @@ public:
if(data.space != DRW::ModelSpace) return; if(data.space != DRW::ModelSpace) return;
if(addPendingBlockEntity<DRW_Arc>(data)) return; if(addPendingBlockEntity<DRW_Arc>(data)) return;
hRequest hr = SS.GW.AddRequest(Request::Type::ARC_OF_CIRCLE, /*rememberForUndo=*/false);
double r = data.radious; double r = data.radious;
double sa = data.staangle; double sa = data.staangle;
double ea = data.endangle; double ea = data.endangle;
Vector c = Vector::From(data.basePoint.x, data.basePoint.y, data.basePoint.z); Vector c = toVector(data.basePoint);
Vector rvs = Vector::From(r * cos(sa), r * sin(sa), data.basePoint.z).Plus(c); Vector nz = toVector(data.extPoint);
Vector rve = Vector::From(r * cos(ea), r * sin(ea), data.basePoint.z).Plus(c); Quaternion q = NormalFromExtPoint(nz);
bool planar = q.RotationN().Equals(Vector::From(0, 0, 1));
bool onPlane = c.z < LENGTH_EPS;
hEntity oldWorkplane = SS.GW.ActiveWorkplane();
if (!planar || !onPlane) {
activateWorkplane(findOrCreateWorkplane(c, q));
}
hRequest hr = SS.GW.AddRequest(Request::Type::ARC_OF_CIRCLE, /*rememberForUndo=*/false);
Vector u = q.RotationU(), v = q.RotationV();
Vector rvs = c.Plus(u.ScaledBy(r * cos(sa))).Plus(v.ScaledBy(r * sin(sa)));
Vector rve = c.Plus(u.ScaledBy(r * cos(ea))).Plus(v.ScaledBy(r * sin(ea)));
if(data.extPoint.z == -1.0) { if(data.extPoint.z == -1.0) {
c.x = -c.x; c.x = -c.x;
@ -584,13 +640,16 @@ public:
processPoint(hr.entity(2)); processPoint(hr.entity(2));
processPoint(hr.entity(3)); processPoint(hr.entity(3));
configureRequest(hr, styleFor(&data)); configureRequest(hr, styleFor(&data));
activateWorkplane(oldWorkplane);
} }
void addCircle(const DRW_Circle &data) override { void addCircle(const DRW_Circle &data) override {
if(data.space != DRW::ModelSpace) return; if(data.space != DRW::ModelSpace) return;
if(addPendingBlockEntity<DRW_Circle>(data)) return; if(addPendingBlockEntity<DRW_Circle>(data)) return;
createCircle(toVector(data.basePoint), data.radious, styleFor(&data)); Vector nz = toVector(data.extPoint);
Quaternion normal = NormalFromExtPoint(nz);
createCircle(toVector(data.basePoint), normal, data.radious, styleFor(&data));
} }
void addLWPolyline(const DRW_LWPolyline &data) override { void addLWPolyline(const DRW_LWPolyline &data) override {
@ -835,9 +894,9 @@ public:
} }
} }
hConstraint createDiametric(Vector cp, double r, Vector tp, double actual, hConstraint createDiametric(Vector cp, Quaternion q, double r, Vector tp,
bool asRadius = false) { double actual, bool asRadius = false) {
hEntity he = createCircle(cp, r, invisibleStyle()); hEntity he = createCircle(cp, q, r, invisibleStyle());
hConstraint hc = Constraint::Constrain( hConstraint hc = Constraint::Constrain(
Constraint::Type::DIAMETER, Constraint::Type::DIAMETER,
@ -869,7 +928,9 @@ public:
actual = data->getActualMeasurement(); actual = data->getActualMeasurement();
} }
createDiametric(cp, cp.Minus(dp).Magnitude(), tp, actual, /*asRadius=*/true); Vector nz = toVector(data->getExtrusion());
Quaternion q = NormalFromExtPoint(nz);
createDiametric(cp, q, cp.Minus(dp).Magnitude(), tp, actual, /*asRadius=*/true);
} }
void addDimDiametric(const DRW_DimDiametric *data) override { void addDimDiametric(const DRW_DimDiametric *data) override {
@ -886,7 +947,9 @@ public:
actual = data->getActualMeasurement(); actual = data->getActualMeasurement();
} }
createDiametric(cp, cp.Minus(dp1).Magnitude(), tp, actual, /*asRadius=*/false); Vector nz = toVector(data->getExtrusion());
Quaternion q = NormalFromExtPoint(nz);
createDiametric(cp, q, cp.Minus(dp1).Magnitude(), tp, actual, /*asRadius=*/false);
} }
void addDimAngular3P(const DRW_DimAngular3p *data) override { void addDimAngular3P(const DRW_DimAngular3p *data) override {
@ -972,11 +1035,13 @@ public:
void addArc(const DRW_Arc &data) override { void addArc(const DRW_Arc &data) override {
if(data.space != DRW::ModelSpace) return; if(data.space != DRW::ModelSpace) return;
checkCoord(data.basePoint); checkCoord(data.basePoint);
checkExt(data.extPoint);
} }
void addCircle(const DRW_Circle &data) override { void addCircle(const DRW_Circle &data) override {
if(data.space != DRW::ModelSpace) return; if(data.space != DRW::ModelSpace) return;
checkCoord(data.basePoint); checkCoord(data.basePoint);
checkExt(data.extPoint);
} }
void addPolyline(const DRW_Polyline &data) override { void addPolyline(const DRW_Polyline &data) override {
@ -1041,6 +1106,7 @@ public:
checkCoord(data->getCenterPoint()); checkCoord(data->getCenterPoint());
checkCoord(data->getDiameterPoint()); checkCoord(data->getDiameterPoint());
checkCoord(data->getTextPoint()); checkCoord(data->getTextPoint());
checkExt(data->getExtrusion());
} }
void addDimDiametric(const DRW_DimDiametric *data) override { void addDimDiametric(const DRW_DimDiametric *data) override {
@ -1048,6 +1114,7 @@ public:
checkCoord(data->getDiameter1Point()); checkCoord(data->getDiameter1Point());
checkCoord(data->getDiameter2Point()); checkCoord(data->getDiameter2Point());
checkCoord(data->getTextPoint()); checkCoord(data->getTextPoint());
checkExt(data->getExtrusion());
} }
void addDimAngular3P(const DRW_DimAngular3p *data) override { void addDimAngular3P(const DRW_DimAngular3p *data) override {
@ -1066,6 +1133,12 @@ public:
is3d = true; is3d = true;
} }
} }
void checkExt(const DRW_Coord &coord) {
if ((fabs(coord.x) > 1/64.) || (fabs(coord.y) > 1/64.)) {
is3d = true;
}
}
}; };
static void static void
@ -1112,14 +1185,14 @@ ImportDwgDxf(const Platform::Path &filename,
void ImportDxf(const Platform::Path &filename) { void ImportDxf(const Platform::Path &filename) {
ImportDwgDxf(filename, [](const std::string &data, DRW_Interface *intf) { ImportDwgDxf(filename, [](const std::string &data, DRW_Interface *intf) {
std::stringstream stream(data); std::stringstream stream(data);
return dxfRW().read(stream, intf, /*ext=*/false); return dxfRW().read(stream, intf, /*ext=*/true);
}); });
} }
void ImportDwg(const Platform::Path &filename) { void ImportDwg(const Platform::Path &filename) {
ImportDwgDxf(filename, [](const std::string &data, DRW_Interface *intf) { ImportDwgDxf(filename, [](const std::string &data, DRW_Interface *intf) {
std::stringstream stream(data); std::stringstream stream(data);
return dwgR().read(stream, intf, /*ext=*/false); return dwgR().read(stream, intf, /*ext=*/true);
}); });
} }