DXF: export constraints with labels as DXF constraints, not pwl.

Specifically, the following constraint types:
  * pt-pt-distance
  * pt-line-distance
  * diameter
  * angle
  * comment
This commit is contained in:
EvilSpirit 2016-01-06 18:40:17 +06:00 committed by whitequark
parent e377eb8851
commit f87152e8c0
5 changed files with 292 additions and 30 deletions

View File

@ -76,6 +76,22 @@ Vector EntityBase::VectorGetRefPoint(void) {
}
}
Vector EntityBase::VectorGetStartPoint(void) {
switch(type) {
case LINE_SEGMENT:
return SK.GetEntity(point[1])->PointGetNum();
case NORMAL_IN_3D:
case NORMAL_IN_2D:
case NORMAL_N_COPY:
case NORMAL_N_ROT:
case NORMAL_N_ROT_AA:
return SK.GetEntity(point[0])->PointGetNum();
default: oops();
}
}
bool EntityBase::IsCircle(void) {
return (type == CIRCLE) || (type == ARC_OF_CIRCLE);
}

View File

@ -112,6 +112,9 @@ void SolveSpaceUI::ExportViewOrWireframeTo(const std::string &filename, bool wir
SEdgeList edges = {};
SBezierList beziers = {};
VectorFileWriter *out = VectorFileWriter::ForFile(filename);
if(!out) return;
SS.exportMode = true;
GenerateAll(GENERATE_ALL);
@ -153,31 +156,41 @@ void SolveSpaceUI::ExportViewOrWireframeTo(const std::string &filename, bool wir
}
if(SS.GW.showConstraints) {
Constraint *c;
for(c = SK.constraint.First(); c; c = SK.constraint.NextAfter(c)) {
c->GetEdges(&edges);
if(!out->OutputConstraints(&SK.constraint)) {
// The output format cannot represent constraints directly,
// so convert them to edges.
Constraint *c;
for(c = SK.constraint.First(); c; c = SK.constraint.NextAfter(c)) {
c->GetEdges(&edges);
}
}
}
if(wireframe) {
VectorFileWriter *out = VectorFileWriter::ForFile(filename);
if(out) {
ExportWireframeCurves(&edges, &beziers, out);
}
Vector u = Vector::From(1.0, 0.0, 0.0),
v = Vector::From(0.0, 1.0, 0.0),
n = Vector::From(0.0, 0.0, 1.0),
origin = Vector::From(0.0, 0.0, 0.0);
double cameraTan = 0.0,
scale = 1.0;
out->SetModelviewProjection(u, v, n, origin, cameraTan, scale);
ExportWireframeCurves(&edges, &beziers, out);
} else {
Vector u = SS.GW.projRight,
v = SS.GW.projUp,
n = u.Cross(v),
origin = SS.GW.offset.ScaledBy(-1);
VectorFileWriter *out = VectorFileWriter::ForFile(filename);
if(out) {
ExportLinesAndMesh(&edges, &beziers, sm,
u, v, n, origin, SS.CameraTangent()*SS.GW.scale,
out);
}
out->SetModelviewProjection(u, v, n, origin,
SS.CameraTangent()*SS.GW.scale, SS.exportScale);
if(out && !out->HasCanvasSize()) {
ExportLinesAndMesh(&edges, &beziers, sm,
u, v, n, origin, SS.CameraTangent()*SS.GW.scale,
out);
if(!out->HasCanvasSize()) {
// These file formats don't have a canvas size, so they just
// get exported in the raw coordinate system. So indicate what
// that was on-screen.
@ -215,7 +228,7 @@ void SolveSpaceUI::ExportWireframeCurves(SEdgeList *sel, SBezierList *sbl,
sblss.AddOpenPath(sb);
}
out->Output(&sblss, NULL);
out->OutputLinesAndMesh(&sblss, NULL);
sblss.Clear();
}
@ -381,7 +394,7 @@ void SolveSpaceUI::ExportLinesAndMesh(SEdgeList *sel, SBezierList *sbl, SMesh *s
}
// Now write the lines and triangles to the output file
out->Output(&sblss, &sms);
out->OutputLinesAndMesh(&sblss, &sms);
leftovers.Clear();
spxyz.Clear();
@ -441,7 +454,22 @@ VectorFileWriter *VectorFileWriter::ForFile(const std::string &filename) {
return ret;
}
void VectorFileWriter::Output(SBezierLoopSetSet *sblss, SMesh *sm) {
void VectorFileWriter::SetModelviewProjection(const Vector &u, const Vector &v, const Vector &n,
const Vector &origin, double cameraTan,
double scale) {
this->u = u;
this->v = v;
this->n = n;
this->origin = origin;
this->cameraTan = cameraTan;
this->scale = scale;
}
Vector VectorFileWriter::Transform(Vector &pos) const {
return pos.InPerspective(u, v, n, origin, cameraTan).ScaledBy(1.0 / scale);
}
void VectorFileWriter::OutputLinesAndMesh(SBezierLoopSetSet *sblss, SMesh *sm) {
STriangle *tr;
SBezier *b;

View File

@ -6,7 +6,7 @@
#include <libdxfrw.h>
#include "solvespace.h"
void VectorFileWriter::Dummy(void) {
VectorFileWriter::~VectorFileWriter() {
// This out-of-line virtual method definition quells the following warning
// from Clang++: "'VectorFileWriter' has no out-of-line virtual method
// definitions; its vtable will be emitted in every translation unit
@ -22,10 +22,25 @@ class DxfWriteInterface : public DRW_Interface {
int currentColor;
double currentWidth;
static DRW_Coord toCoord(const Vector &v) {
return DRW_Coord(v.x, v.y, v.z);
}
Vector xfrm(Vector v) {
return writer->Transform(v);
}
public:
DxfWriteInterface(DxfFileWriter *w, dxfRW *dxfrw) :
writer(w), dxf(dxfrw) {}
virtual void writeTextstyles() {
DRW_Textstyle ts;
ts.name = "unicode";
ts.font = "unicode";
dxf->writeTextstyle(&ts);
}
virtual void writeEntities() {
for(DxfFileWriter::BezierPath &path : writer->paths) {
currentColor = path.color;
@ -34,6 +49,110 @@ public:
writeBezier(sb);
}
}
if(writer->constraint) {
Constraint *c;
for(c = writer->constraint->First(); c; c = writer->constraint->NextAfter(c)) {
switch(c->type) {
case Constraint::PT_PT_DISTANCE: {
Vector ap = SK.GetEntity(c->ptA)->PointGetNum();
Vector bp = SK.GetEntity(c->ptB)->PointGetNum();
Vector ref = ((ap.Plus(bp)).ScaledBy(0.5)).Plus(c->disp.offset);
writeAlignedDimension(xfrm(ap), xfrm(bp), xfrm(ref),
xfrm(ref), c->Label());
break;
}
case Constraint::PT_LINE_DISTANCE: {
Vector pt = SK.GetEntity(c->ptA)->PointGetNum();
Entity *line = SK.GetEntity(c->entityA);
Vector lA = SK.GetEntity(line->point[0])->PointGetNum();
Vector lB = SK.GetEntity(line->point[1])->PointGetNum();
Vector dl = lB.Minus(lA);
Vector closest = pt.ClosestPointOnLine(lA, dl);
if(pt.Equals(closest)) break;
Vector ref = ((closest.Plus(pt)).ScaledBy(0.5)).Plus(c->disp.offset);
Vector refClosest = ref.ClosestPointOnLine(lA, dl);
double ddl = dl.Dot(dl);
if(fabs(ddl) > LENGTH_EPS * LENGTH_EPS) {
double t = refClosest.Minus(lA).Dot(dl) / ddl;
if(t < 0.0) {
refClosest = lA;
} else if(t > 1.0) {
refClosest = lB;
}
}
Vector xdl = xfrm(lB).Minus(xfrm(lA));
writeLinearDimension(xfrm(pt), xfrm(refClosest), xfrm(ref),
xfrm(ref), c->Label(),
atan2(xdl.y, xdl.x) / PI * 180.0 + 90.0, 0.0);
break;
}
case Constraint::DIAMETER: {
Entity *circle = SK.GetEntity(c->entityA);
Vector center = SK.GetEntity(circle->point[0])->PointGetNum();
Quaternion q = SK.GetEntity(circle->normal)->NormalGetNum();
Vector n = q.RotationN().WithMagnitude(1);
double r = circle->CircleGetRadiusNum();
Vector ref = center.Plus(c->disp.offset);
// Force the label into the same plane as the circle.
ref = ref.Minus(n.ScaledBy(n.Dot(ref) - n.Dot(center)));
Vector rad = ref.Minus(center).WithMagnitude(r);
if(/*isRadius*/c->other) {
writeRadialDimension(
xfrm(center), xfrm(center.Plus(rad)),
xfrm(ref), c->Label());
} else {
writeDiametricDimension(
xfrm(center.Minus(rad)), xfrm(center.Plus(rad)),
xfrm(ref), c->Label());
}
break;
}
case Constraint::ANGLE: {
Entity *a = SK.GetEntity(c->entityA);
Entity *b = SK.GetEntity(c->entityB);
Vector a0 = a->VectorGetStartPoint();
Vector b0 = b->VectorGetStartPoint();
Vector da = a->VectorGetNum();
Vector db = b->VectorGetNum();
if(/*otherAngle*/c->other) {
a0 = a0.Plus(da);
da = da.ScaledBy(-1);
}
bool skew = false;
Vector ref = c->disp.offset;
Vector pi = Vector::AtIntersectionOfLines(a0, a0.Plus(da), b0, b0.Plus(db),
&skew);
if(!skew) ref = pi.Plus(c->disp.offset);
writeAngularDimension(
xfrm(a0), xfrm(a0.Plus(da)), xfrm(b0), xfrm(b0.Plus(db)), xfrm(ref),
xfrm(ref), c->Label());
break;
}
case Constraint::COMMENT: {
Style *st = Style::Get(c->disp.style);
writeText(xfrm(c->disp.offset), c->Label(),
Style::TextHeight(c->disp.style) / SS.GW.scale,
st->textAngle, st->textOrigin);
break;
}
}
}
}
}
void assignEntityDefaults(DRW_Entity *entity) {
@ -44,8 +163,8 @@ public:
void writeLine(const Vector &p0, const Vector &p1) {
DRW_Line line;
assignEntityDefaults(&line);
line.basePoint = DRW_Coord(p0.x, p0.y, 0.0);
line.secPoint = DRW_Coord(p1.x, p1.y, 0.0);
line.basePoint = toCoord(p0);
line.secPoint = toCoord(p1);
dxf->writeLine(&line);
}
@ -53,7 +172,7 @@ public:
DRW_Arc arc;
assignEntityDefaults(&arc);
arc.radious = r;
arc.basePoint = DRW_Coord(c.x, c.y, 0.0);
arc.basePoint = toCoord(c);
arc.staangle = sa;
arc.endangle = ea;
dxf->writeArc(&arc);
@ -154,8 +273,95 @@ public:
polyline.vertlist.push_back(vertex);
}
}
void writeAlignedDimension(Vector def1, Vector def2, Vector dimp,
Vector textp, const std::string &text) {
DRW_DimAligned dim;
dim.setDef1Point(toCoord(def1));
dim.setDef2Point(toCoord(def2));
dim.setDimPoint(toCoord(dimp));
dim.setTextPoint(toCoord(textp));
dim.setText(text);
dxf->writeDimension(&dim);
}
void writeLinearDimension(Vector def1, Vector def2, Vector dimp,
Vector textp, const std::string &text,
double angle, double oblique) {
DRW_DimLinear dim;
dim.setDef1Point(toCoord(def1));
dim.setDef2Point(toCoord(def2));
dim.setDimPoint(toCoord(dimp));
dim.setTextPoint(toCoord(textp));
dim.setText(text);
dim.setAngle(angle);
dim.setOblique(oblique);
dxf->writeDimension(&dim);
}
void writeRadialDimension(Vector center, Vector radius,
Vector textp, const std::string &text) {
DRW_DimRadial dim;
dim.setCenterPoint(toCoord(center));
dim.setDiameterPoint(toCoord(radius));
dim.setTextPoint(toCoord(textp));
dim.setText(text);
dxf->writeDimension(&dim);
}
void writeDiametricDimension(Vector def1, Vector def2,
Vector textp, const std::string &text) {
DRW_DimDiametric dim;
dim.setDiameter1Point(toCoord(def1));
dim.setDiameter2Point(toCoord(def2));
dim.setTextPoint(toCoord(textp));
dim.setText(text);
dxf->writeDimension(&dim);
}
void writeAngularDimension(Vector fl1, Vector fl2, Vector sl1, Vector sl2, Vector dimp,
Vector textp, const std::string &text) {
DRW_DimAngular dim;
dim.setFirstLine1(toCoord(fl1));
dim.setFirstLine2(toCoord(fl2));
dim.setSecondLine1(toCoord(sl1));
dim.setSecondLine2(toCoord(sl2));
dim.setDimPoint(toCoord(dimp));
dim.setTextPoint(toCoord(textp));
dim.setText(text);
dxf->writeDimension(&dim);
}
void writeText(Vector textp, const std::string &text,
double height, double angle, int origin) {
DRW_Text txt;
txt.style = "unicode";
txt.basePoint = toCoord(textp);
txt.secPoint = txt.basePoint;
txt.text = text;
txt.height = height;
txt.angle = angle;
txt.alignH = DRW_Text::HCenter;
if(origin & Style::ORIGIN_LEFT) {
txt.alignH = DRW_Text::HLeft;
} else if(origin & Style::ORIGIN_RIGHT) {
txt.alignH = DRW_Text::HRight;
}
txt.alignV = DRW_Text::VMiddle;
if(origin & Style::ORIGIN_TOP) {
txt.alignV = DRW_Text::VTop;
} else if(origin & Style::ORIGIN_BOT) {
txt.alignV = DRW_Text::VBaseLine;
}
dxf->writeText(&txt);
}
};
bool DxfFileWriter::OutputConstraints(IdList<Constraint,hConstraint> *constraint) {
this->constraint = constraint;
return true;
}
void DxfFileWriter::StartFile(void) {
paths.clear();
}
@ -183,8 +389,9 @@ void DxfFileWriter::Bezier(SBezier *sb) {
void DxfFileWriter::FinishAndCloseFile(void) {
dxfRW dxf(filename.c_str());
DxfWriteInterface interface(this, &dxf);
dxf.write(&interface, DRW::AC1018, false);
dxf.write(&interface, DRW::AC1021, false);
paths.clear();
constraint = NULL;
}
//-----------------------------------------------------------------------------

View File

@ -383,6 +383,7 @@ public:
ExprVector VectorGetExprs(void);
Vector VectorGetNum(void);
Vector VectorGetRefPoint(void);
Vector VectorGetStartPoint(void);
// For distances
bool IsDistance(void);

View File

@ -490,24 +490,33 @@ public:
};
class VectorFileWriter {
protected:
Vector u, v, n, origin;
double cameraTan, scale;
public:
FILE *f;
std::string filename;
Vector ptMin, ptMax;
// This quells the Clang++ warning "'VectorFileWriter' has virtual
// functions but non-virtual destructor"
virtual ~VectorFileWriter() {}
static double MmToPts(double mm);
static VectorFileWriter *ForFile(const std::string &filename);
void Output(SBezierLoopSetSet *sblss, SMesh *sm);
~VectorFileWriter();
void SetModelviewProjection(const Vector &u, const Vector &v, const Vector &n,
const Vector &origin, double cameraTan, double scale);
Vector Transform(Vector &pos) const;
void OutputLinesAndMesh(SBezierLoopSetSet *sblss, SMesh *sm);
void BezierAsPwl(SBezier *sb);
void BezierAsNonrationalCubic(SBezier *sb, int depth=0);
virtual bool OutputConstraints(IdList<Constraint,hConstraint> *constraint)
{ return false; }
virtual void StartPath( RgbaColor strokeRgb, double lineWidth,
bool filled, RgbaColor fillRgb) = 0;
virtual void FinishPath(RgbaColor strokeRgb, double lineWidth,
@ -517,8 +526,6 @@ public:
virtual void StartFile(void) = 0;
virtual void FinishAndCloseFile(void) = 0;
virtual bool HasCanvasSize(void) = 0;
virtual void Dummy(void);
};
class DxfFileWriter : public VectorFileWriter {
public:
@ -528,7 +535,10 @@ public:
double width;
};
std::vector<BezierPath> paths;
std::vector<BezierPath> paths;
IdList<Constraint,hConstraint> *constraint;
bool OutputConstraints(IdList<Constraint,hConstraint> *constraint);
void StartPath( RgbaColor strokeRgb, double lineWidth,
bool filled, RgbaColor fillRgb);