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 requestpull/727/head
parent
6b7f114697
commit
3ce8c29982
|
@ -1 +1 @@
|
|||
Subproject commit 03fa5f30f1a1db7231a25653c9dd38044fe06640
|
||||
Subproject commit 0b7b7b709d9299565db603f878214656ef5e9ddf
|
|
@ -9,6 +9,21 @@ static std::string ToUpper(std::string 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 {
|
||||
public:
|
||||
Vector blockX;
|
||||
|
@ -516,12 +531,41 @@ public:
|
|||
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);
|
||||
SK.GetEntity(hr.entity(1))->PointForceTo(c);
|
||||
processPoint(hr.entity(1));
|
||||
SK.GetEntity(hr.entity(32))->NormalForceTo(q);
|
||||
SK.GetEntity(hr.entity(64))->DistanceForceTo(r);
|
||||
|
||||
configureRequest(hr, style);
|
||||
return hr.entity(0);
|
||||
}
|
||||
|
@ -560,13 +604,25 @@ public:
|
|||
if(data.space != DRW::ModelSpace) return;
|
||||
if(addPendingBlockEntity<DRW_Arc>(data)) return;
|
||||
|
||||
hRequest hr = SS.GW.AddRequest(Request::Type::ARC_OF_CIRCLE, /*rememberForUndo=*/false);
|
||||
double r = data.radious;
|
||||
double sa = data.staangle;
|
||||
double ea = data.endangle;
|
||||
Vector c = Vector::From(data.basePoint.x, data.basePoint.y, data.basePoint.z);
|
||||
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);
|
||||
Vector c = toVector(data.basePoint);
|
||||
Vector nz = toVector(data.extPoint);
|
||||
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) {
|
||||
c.x = -c.x;
|
||||
|
@ -584,13 +640,16 @@ public:
|
|||
processPoint(hr.entity(2));
|
||||
processPoint(hr.entity(3));
|
||||
configureRequest(hr, styleFor(&data));
|
||||
activateWorkplane(oldWorkplane);
|
||||
}
|
||||
|
||||
void addCircle(const DRW_Circle &data) override {
|
||||
if(data.space != DRW::ModelSpace) 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 {
|
||||
|
@ -835,9 +894,9 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
hConstraint createDiametric(Vector cp, double r, Vector tp, double actual,
|
||||
bool asRadius = false) {
|
||||
hEntity he = createCircle(cp, r, invisibleStyle());
|
||||
hConstraint createDiametric(Vector cp, Quaternion q, double r, Vector tp,
|
||||
double actual, bool asRadius = false) {
|
||||
hEntity he = createCircle(cp, q, r, invisibleStyle());
|
||||
|
||||
hConstraint hc = Constraint::Constrain(
|
||||
Constraint::Type::DIAMETER,
|
||||
|
@ -869,7 +928,9 @@ public:
|
|||
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 {
|
||||
|
@ -886,7 +947,9 @@ public:
|
|||
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 {
|
||||
|
@ -972,11 +1035,13 @@ public:
|
|||
void addArc(const DRW_Arc &data) override {
|
||||
if(data.space != DRW::ModelSpace) return;
|
||||
checkCoord(data.basePoint);
|
||||
checkExt(data.extPoint);
|
||||
}
|
||||
|
||||
void addCircle(const DRW_Circle &data) override {
|
||||
if(data.space != DRW::ModelSpace) return;
|
||||
checkCoord(data.basePoint);
|
||||
checkExt(data.extPoint);
|
||||
}
|
||||
|
||||
void addPolyline(const DRW_Polyline &data) override {
|
||||
|
@ -1041,6 +1106,7 @@ public:
|
|||
checkCoord(data->getCenterPoint());
|
||||
checkCoord(data->getDiameterPoint());
|
||||
checkCoord(data->getTextPoint());
|
||||
checkExt(data->getExtrusion());
|
||||
}
|
||||
|
||||
void addDimDiametric(const DRW_DimDiametric *data) override {
|
||||
|
@ -1048,6 +1114,7 @@ public:
|
|||
checkCoord(data->getDiameter1Point());
|
||||
checkCoord(data->getDiameter2Point());
|
||||
checkCoord(data->getTextPoint());
|
||||
checkExt(data->getExtrusion());
|
||||
}
|
||||
|
||||
void addDimAngular3P(const DRW_DimAngular3p *data) override {
|
||||
|
@ -1066,6 +1133,12 @@ public:
|
|||
is3d = true;
|
||||
}
|
||||
}
|
||||
|
||||
void checkExt(const DRW_Coord &coord) {
|
||||
if ((fabs(coord.x) > 1/64.) || (fabs(coord.y) > 1/64.)) {
|
||||
is3d = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -1112,14 +1185,14 @@ ImportDwgDxf(const Platform::Path &filename,
|
|||
void ImportDxf(const Platform::Path &filename) {
|
||||
ImportDwgDxf(filename, [](const std::string &data, DRW_Interface *intf) {
|
||||
std::stringstream stream(data);
|
||||
return dxfRW().read(stream, intf, /*ext=*/false);
|
||||
return dxfRW().read(stream, intf, /*ext=*/true);
|
||||
});
|
||||
}
|
||||
|
||||
void ImportDwg(const Platform::Path &filename) {
|
||||
ImportDwgDxf(filename, [](const std::string &data, DRW_Interface *intf) {
|
||||
std::stringstream stream(data);
|
||||
return dwgR().read(stream, intf, /*ext=*/false);
|
||||
return dwgR().read(stream, intf, /*ext=*/true);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue