Include custom styled entities in the same plane when exporting section.
parent
c44a471649
commit
7d181f0d0f
|
@ -46,6 +46,8 @@ New export/import features:
|
|||
exported. This format allows to easily hack on triangle mesh data created
|
||||
in SolveSpace, supports colour information and is more space efficient than
|
||||
most other formats.
|
||||
* Export 2d section: custom styled entities that lie in the same
|
||||
plane as the exported section are included.
|
||||
|
||||
New rendering features:
|
||||
* The "Show/hide hidden lines" button is now a tri-state button that allows
|
||||
|
|
|
@ -784,6 +784,47 @@ Vector EntityBase::EndpointFinish() const {
|
|||
return SK.GetEntity(point[2])->PointGetNum();
|
||||
} else ssassert(false, "Unexpected entity type");
|
||||
}
|
||||
static bool PointInPlane(hEntity h, Vector norm, double distance) {
|
||||
Vector p = SK.GetEntity(h)->PointGetNum();
|
||||
return (fabs(norm.Dot(p) - distance) < LENGTH_EPS);
|
||||
}
|
||||
bool EntityBase::IsInPlane(Vector norm, double distance) const {
|
||||
switch(type) {
|
||||
case Type::LINE_SEGMENT: {
|
||||
return PointInPlane(point[0], norm, distance)
|
||||
&& PointInPlane(point[1], norm, distance);
|
||||
}
|
||||
case Type::CUBIC:
|
||||
case Type::CUBIC_PERIODIC: {
|
||||
bool periodic = type == Type::CUBIC_PERIODIC;
|
||||
int n = periodic ? 3 + extraPoints : extraPoints;
|
||||
int i;
|
||||
for (i=0; i<n; i++) {
|
||||
if (!PointInPlane(point[i], norm, distance)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case Type::CIRCLE:
|
||||
case Type::ARC_OF_CIRCLE: {
|
||||
// If it is an (arc of) a circle, check whether the normals
|
||||
// are parallel and the mid point is in the plane.
|
||||
Vector n = Normal()->NormalN();
|
||||
if (!norm.Equals(n) && !norm.Equals(n.Negated())) return false;
|
||||
return PointInPlane(point[0], norm, distance);
|
||||
}
|
||||
|
||||
case Type::TTF_TEXT: {
|
||||
Vector n = Normal()->NormalN();
|
||||
if (!norm.Equals(n) && !norm.Equals(n.Negated())) return false;
|
||||
return PointInPlane(point[0], norm, distance)
|
||||
&& PointInPlane(point[1], norm, distance);
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityBase::RectGetPointsExprs(ExprVector *eb, ExprVector *ec) const {
|
||||
ssassert(type == Type::TTF_TEXT || type == Type::IMAGE,
|
||||
|
|
|
@ -78,9 +78,8 @@ void SolveSpaceUI::ExportSectionTo(const Platform::Path &filename) {
|
|||
g->runningMesh.MakeEdgesInPlaneInto(&el, n, d);
|
||||
|
||||
// If there's a shell, then grab the edges and possibly Beziers.
|
||||
g->runningShell.MakeSectionEdgesInto(n, d,
|
||||
&el,
|
||||
(SS.exportPwlCurves || fabs(SS.exportOffset) > LENGTH_EPS) ? NULL : &bl);
|
||||
bool export_as_pwl = SS.exportPwlCurves || fabs(SS.exportOffset) > LENGTH_EPS;
|
||||
g->runningShell.MakeSectionEdgesInto(n, d, &el, export_as_pwl ? NULL : &bl);
|
||||
|
||||
// All of these are solid model edges, so use the appropriate style.
|
||||
SEdge *se;
|
||||
|
@ -92,8 +91,28 @@ void SolveSpaceUI::ExportSectionTo(const Platform::Path &filename) {
|
|||
sb->auxA = Style::SOLID_EDGE;
|
||||
}
|
||||
|
||||
el.CullExtraneousEdges();
|
||||
bl.CullIdenticalBeziers();
|
||||
// Remove all overlapping edges/beziers to merge the areas they describe.
|
||||
el.CullExtraneousEdges(/*both=*/true);
|
||||
bl.CullIdenticalBeziers(/*both=*/true);
|
||||
|
||||
// Collect lines and beziers with custom style & export.
|
||||
int i;
|
||||
for(i = 0; i < SK.entity.n; i++) {
|
||||
Entity *e = &(SK.entity.elem[i]);
|
||||
if (!e->IsVisible()) continue;
|
||||
if (e->style.v < Style::FIRST_CUSTOM) continue;
|
||||
if (!Style::Exportable(e->style.v)) continue;
|
||||
if (!e->IsInPlane(n,d)) continue;
|
||||
if (export_as_pwl) {
|
||||
e->GenerateEdges(&el);
|
||||
} else {
|
||||
e->GenerateBezierCurves(&bl);
|
||||
}
|
||||
}
|
||||
|
||||
// Only remove half of the overlapping edges/beziers to support TTF Stick Fonts.
|
||||
el.CullExtraneousEdges(/*both=*/false);
|
||||
bl.CullIdenticalBeziers(/*both=*/false);
|
||||
|
||||
// And write the edges.
|
||||
VectorFileWriter *out = VectorFileWriter::ForFile(filename);
|
||||
|
@ -573,7 +592,7 @@ void SolveSpaceUI::ExportLinesAndMesh(SEdgeList *sel, SBezierList *sbl, SMesh *s
|
|||
// If possible, then we will assemble these output curves into loops. They
|
||||
// will then get exported as closed paths.
|
||||
SBezierLoopSetSet sblss = {};
|
||||
SBezierList leftovers = {};
|
||||
SBezierLoopSet leftovers = {};
|
||||
SSurface srf = SSurface::FromPlane(Vector::From(0, 0, 0),
|
||||
Vector::From(1, 0, 0),
|
||||
Vector::From(0, 1, 0));
|
||||
|
@ -586,14 +605,11 @@ void SolveSpaceUI::ExportLinesAndMesh(SEdgeList *sel, SBezierList *sbl, SMesh *s
|
|||
&allClosed, ¬ClosedAt,
|
||||
NULL, NULL,
|
||||
&leftovers);
|
||||
for(b = leftovers.l.First(); b; b = leftovers.l.NextAfter(b)) {
|
||||
sblss.AddOpenPath(b);
|
||||
}
|
||||
sblss.l.Add(&leftovers);
|
||||
|
||||
// Now write the lines and triangles to the output file
|
||||
out->OutputLinesAndMesh(&sblss, &sms);
|
||||
|
||||
leftovers.Clear();
|
||||
spxyz.Clear();
|
||||
sblss.Clear();
|
||||
smp.Clear();
|
||||
|
|
|
@ -327,10 +327,13 @@ bool SEdgeList::ContainsEdge(const SEdge *set) const {
|
|||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Remove unnecessary edges: if two are anti-parallel then remove both, and if
|
||||
// two are parallel then remove one.
|
||||
// Remove unnecessary edges:
|
||||
// - if two are anti-parallel then
|
||||
// if both=true, remove both
|
||||
// else remove only one.
|
||||
// - if two are parallel then remove one.
|
||||
//-----------------------------------------------------------------------------
|
||||
void SEdgeList::CullExtraneousEdges() {
|
||||
void SEdgeList::CullExtraneousEdges(bool both) {
|
||||
l.ClearTags();
|
||||
int i, j;
|
||||
for(i = 0; i < l.n; i++) {
|
||||
|
@ -342,8 +345,9 @@ void SEdgeList::CullExtraneousEdges() {
|
|||
set->tag = 1;
|
||||
}
|
||||
if((set->a).Equals(se->b) && (set->b).Equals(se->a)) {
|
||||
// Two anti-parallel edges exist; so keep neither.
|
||||
se->tag = 1;
|
||||
// Two anti-parallel edges exist; if both=true, keep neither,
|
||||
// otherwise keep only one.
|
||||
if (both) se->tag = 1;
|
||||
set->tag = 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ public:
|
|||
Vector *pi=NULL, SPointList *spl=NULL) const;
|
||||
bool ContainsEdgeFrom(const SEdgeList *sel) const;
|
||||
bool ContainsEdge(const SEdge *se) const;
|
||||
void CullExtraneousEdges();
|
||||
void CullExtraneousEdges(bool both=true);
|
||||
void MergeCollinearSegments(Vector a, Vector b);
|
||||
};
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ public:
|
|||
|
||||
SPolygon polyLoops;
|
||||
SBezierLoopSetSet bezierLoops;
|
||||
SBezierList bezierOpens;
|
||||
SBezierLoopSet bezierOpens;
|
||||
|
||||
struct {
|
||||
PolyError how;
|
||||
|
@ -483,6 +483,7 @@ public:
|
|||
bool HasEndpoints() const;
|
||||
Vector EndpointStart() const;
|
||||
Vector EndpointFinish() const;
|
||||
bool IsInPlane(Vector norm, double distance) const;
|
||||
|
||||
void RectGetPointsExprs(ExprVector *eap, ExprVector *ebp) const;
|
||||
|
||||
|
|
|
@ -231,9 +231,10 @@ void SBezierList::ScaleSelfBy(double s) {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
// If our list contains multiple identical Beziers (in either forward or
|
||||
// reverse order), then cull them.
|
||||
// reverse order), then cull them. If both is true, both beziers are removed.
|
||||
// Otherwise only one of them is removed.
|
||||
//-----------------------------------------------------------------------------
|
||||
void SBezierList::CullIdenticalBeziers() {
|
||||
void SBezierList::CullIdenticalBeziers(bool both) {
|
||||
int i, j;
|
||||
|
||||
l.ClearTags();
|
||||
|
@ -247,7 +248,7 @@ void SBezierList::CullIdenticalBeziers() {
|
|||
if(bj->Equals(bi) ||
|
||||
bj->Equals(&bir))
|
||||
{
|
||||
bi->tag = 1;
|
||||
if (both) bi->tag = 1;
|
||||
bj->tag = 1;
|
||||
}
|
||||
}
|
||||
|
@ -491,7 +492,7 @@ bool SBezierLoop::IsClosed() const {
|
|||
SBezierLoopSet SBezierLoopSet::From(SBezierList *sbl, SPolygon *poly,
|
||||
double chordTol,
|
||||
bool *allClosed, SEdge *errorAt,
|
||||
SBezierList *openContours)
|
||||
SBezierLoopSet *openContours)
|
||||
{
|
||||
SBezierLoopSet ret = {};
|
||||
|
||||
|
@ -504,12 +505,10 @@ SBezierLoopSet SBezierLoopSet::From(SBezierList *sbl, SPolygon *poly,
|
|||
// Record open loops in a separate list, if requested.
|
||||
*allClosed = false;
|
||||
if(openContours) {
|
||||
SBezier *sb;
|
||||
for(sb = loop.l.First(); sb; sb = loop.l.NextAfter(sb)) {
|
||||
openContours->l.Add(sb);
|
||||
}
|
||||
}
|
||||
openContours->l.Add(&loop);
|
||||
} else {
|
||||
loop.Clear();
|
||||
}
|
||||
} else {
|
||||
ret.l.Add(&loop);
|
||||
poly->AddEmptyContour();
|
||||
|
@ -576,7 +575,7 @@ void SBezierLoopSetSet::FindOuterFacesFrom(SBezierList *sbl, SPolygon *spxyz,
|
|||
double chordTol,
|
||||
bool *allClosed, SEdge *notClosedAt,
|
||||
bool *allCoplanar, Vector *notCoplanarAt,
|
||||
SBezierList *openContours)
|
||||
SBezierLoopSet *openContours)
|
||||
{
|
||||
SSurface srfPlane;
|
||||
if(!srfuv) {
|
||||
|
@ -589,7 +588,9 @@ void SBezierLoopSetSet::FindOuterFacesFrom(SBezierList *sbl, SPolygon *spxyz,
|
|||
if(openContours) {
|
||||
SBezier *sb;
|
||||
for(sb = sbl->l.First(); sb; sb = sbl->l.NextAfter(sb)) {
|
||||
openContours->l.Add(sb);
|
||||
SBezierLoop sbl={};
|
||||
sbl.l.Add(sb);
|
||||
openContours->l.Add(&sbl);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -705,12 +706,10 @@ void SBezierLoopSetSet::FindOuterFacesFrom(SBezierList *sbl, SPolygon *spxyz,
|
|||
if(loop->tag == USED_LOOP) continue;
|
||||
|
||||
if(openContours) {
|
||||
SBezier *sb;
|
||||
for(sb = loop->l.First(); sb; sb = loop->l.NextAfter(sb)) {
|
||||
openContours->l.Add(sb);
|
||||
}
|
||||
}
|
||||
openContours->l.Add(loop);
|
||||
} else {
|
||||
loop->Clear();
|
||||
}
|
||||
// but don't free the used loops, since we shallow-copied them to
|
||||
// ourself
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ public:
|
|||
|
||||
void Clear();
|
||||
void ScaleSelfBy(double s);
|
||||
void CullIdenticalBeziers();
|
||||
void CullIdenticalBeziers(bool both=true);
|
||||
void AllIntersectionsWith(SBezierList *sblb, SPointList *spl) const;
|
||||
bool GetPlaneContainingBeziers(Vector *p, Vector *u, Vector *v,
|
||||
Vector *notCoplanarAt) const;
|
||||
|
@ -156,7 +156,7 @@ public:
|
|||
static SBezierLoopSet From(SBezierList *spcl, SPolygon *poly,
|
||||
double chordTol,
|
||||
bool *allClosed, SEdge *errorAt,
|
||||
SBezierList *openContours);
|
||||
SBezierLoopSet *openContours);
|
||||
|
||||
void GetBoundingProjd(Vector u, Vector orig, double *umin, double *umax) const;
|
||||
double SignedArea();
|
||||
|
@ -172,7 +172,7 @@ public:
|
|||
double chordTol,
|
||||
bool *allClosed, SEdge *notClosedAt,
|
||||
bool *allCoplanar, Vector *notCoplanarAt,
|
||||
SBezierList *openContours);
|
||||
SBezierLoopSet *openContours);
|
||||
void AddOpenPath(SBezier *sb);
|
||||
void Clear();
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue