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