Now actually export the line styles, for PDF, EPS, and SVG file
formats, with the proper color and width. This may need a bit of cleanup for stuff like the hidden line removal, which currently loses the style. Also fix a bug in the test for arcs of a circle. A second-order Bezier with collinear control points really is an arc, but it's an arc with infinite radius so stuff tends to blow up. So return false for that one. [git-p4: depot-paths = "//depot/solvespace/": change = 2030]
This commit is contained in:
parent
517c5edbfa
commit
9b8f32dad7
@ -20,7 +20,7 @@ bool Constraint::HasLabel(void) {
|
||||
void Constraint::LineDrawOrGetDistance(Vector a, Vector b) {
|
||||
if(dogd.drawing) {
|
||||
if(dogd.sel) {
|
||||
dogd.sel->AddEdge(a, b);
|
||||
dogd.sel->AddEdge(a, b, Style::CONSTRAINT);
|
||||
} else {
|
||||
glBegin(GL_LINE_STRIP);
|
||||
glxVertex3v(a);
|
||||
|
@ -179,7 +179,7 @@ void Entity::GenerateEdges(SEdgeList *el, bool includingConstruction) {
|
||||
ZERO(&lv);
|
||||
sb->MakePwlInto(&lv);
|
||||
for(j = 1; j < lv.n; j++) {
|
||||
el->AddEdge(lv.elem[j-1], lv.elem[j]);
|
||||
el->AddEdge(lv.elem[j-1], lv.elem[j], style.v);
|
||||
}
|
||||
lv.Clear();
|
||||
}
|
||||
@ -230,6 +230,11 @@ bool Entity::IsVisible(void) {
|
||||
}
|
||||
}
|
||||
|
||||
if(style.v) {
|
||||
Style *s = Style::Get(style);
|
||||
if(!s->visible) return false;
|
||||
}
|
||||
|
||||
if(forceHidden) return false;
|
||||
|
||||
return true;
|
||||
@ -259,9 +264,11 @@ bool Entity::PointIsFromReferences(void) {
|
||||
return h.request().IsFromReferences();
|
||||
}
|
||||
|
||||
void Entity::GenerateBezierCurves(SBezierList *sbl) {
|
||||
void Entity::GenerateBezierCurves(SBezierList *sbl) {
|
||||
SBezier sb;
|
||||
|
||||
int i = sbl->l.n;
|
||||
|
||||
switch(type) {
|
||||
case LINE_SEGMENT: {
|
||||
Vector a = SK.GetEntity(point[0])->PointGetNum();
|
||||
@ -357,6 +364,11 @@ void Entity::GenerateBezierCurves(SBezierList *sbl) {
|
||||
// Not a problem, points and normals and such don't generate curves
|
||||
break;
|
||||
}
|
||||
|
||||
// Record our style for all of the Beziers that we just created.
|
||||
for(; i < sbl->l.n; i++) {
|
||||
sbl->l.elem[i].auxA = style.v;
|
||||
}
|
||||
}
|
||||
|
||||
void Entity::DrawOrGetDistance(void) {
|
||||
|
40
export.cpp
40
export.cpp
@ -82,6 +82,16 @@ void SolveSpace::ExportSectionTo(char *filename) {
|
||||
&el,
|
||||
(SS.exportPwlCurves || fabs(SS.exportOffset) > LENGTH_EPS) ? NULL : &bl);
|
||||
|
||||
// All of these are solid model edges, so use the appropriate style.
|
||||
SEdge *se;
|
||||
for(se = el.l.First(); se; se = el.l.NextAfter(se)) {
|
||||
se->auxA = Style::SOLID_EDGE;
|
||||
}
|
||||
SBezier *sb;
|
||||
for(sb = bl.l.First(); sb; sb = bl.l.NextAfter(sb)) {
|
||||
sb->auxA = Style::SOLID_EDGE;
|
||||
}
|
||||
|
||||
el.CullExtraneousEdges();
|
||||
bl.CullIdenticalBeziers();
|
||||
|
||||
@ -137,7 +147,7 @@ void SolveSpace::ExportViewTo(char *filename) {
|
||||
SEdgeList *selr = &(g->displayEdges);
|
||||
SEdge *se;
|
||||
for(se = selr->l.First(); se; se = selr->l.NextAfter(se)) {
|
||||
edges.AddEdge(se->a, se->b);
|
||||
edges.AddEdge(se->a, se->b, Style::SOLID_EDGE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -406,30 +416,40 @@ void VectorFileWriter::Output(SEdgeList *sel, SBezierList *sbl, SMesh *sm) {
|
||||
}
|
||||
if(sel) {
|
||||
for(e = sel->l.First(); e; e = sel->l.NextAfter(e)) {
|
||||
LineSegment(e->a.x, e->a.y, e->b.x, e->b.y);
|
||||
if(!Style::Exportable(e->auxA)) continue;
|
||||
|
||||
DWORD rgb = Style::Color (e->auxA, true);
|
||||
double w = Style::WidthMm(e->auxA);
|
||||
LineSegment(rgb, w, e->a.x, e->a.y, e->b.x, e->b.y);
|
||||
}
|
||||
}
|
||||
if(sbl) {
|
||||
for(b = sbl->l.First(); b; b = sbl->l.NextAfter(b)) {
|
||||
Bezier(b);
|
||||
if(!Style::Exportable(b->auxA)) continue;
|
||||
|
||||
DWORD rgb = Style::Color (b->auxA, true);
|
||||
double w = Style::WidthMm(b->auxA);
|
||||
Bezier(rgb, w, b);
|
||||
}
|
||||
}
|
||||
FinishAndCloseFile();
|
||||
}
|
||||
|
||||
void VectorFileWriter::BezierAsPwl(SBezier *sb) {
|
||||
void VectorFileWriter::BezierAsPwl(DWORD rgb, double width, SBezier *sb) {
|
||||
List<Vector> lv;
|
||||
ZERO(&lv);
|
||||
sb->MakePwlInto(&lv);
|
||||
int i;
|
||||
for(i = 1; i < lv.n; i++) {
|
||||
LineSegment(lv.elem[i-1].x, lv.elem[i-1].y,
|
||||
lv.elem[i ].x, lv.elem[i ].y);
|
||||
LineSegment(rgb, width, lv.elem[i-1].x, lv.elem[i-1].y,
|
||||
lv.elem[i ].x, lv.elem[i ].y);
|
||||
}
|
||||
lv.Clear();
|
||||
}
|
||||
|
||||
void VectorFileWriter::BezierAsNonrationalCubic(SBezier *sb, int depth) {
|
||||
void VectorFileWriter::BezierAsNonrationalCubic(DWORD rgb, double width,
|
||||
SBezier *sb, int depth)
|
||||
{
|
||||
Vector t0 = sb->TangentAt(0), t1 = sb->TangentAt(1);
|
||||
// The curve is correct, and the first derivatives are correct, at the
|
||||
// endpoints.
|
||||
@ -457,12 +477,12 @@ void VectorFileWriter::BezierAsNonrationalCubic(SBezier *sb, int depth) {
|
||||
}
|
||||
|
||||
if(closeEnough || depth > 3) {
|
||||
Bezier(&bnr);
|
||||
Bezier(rgb, width, &bnr);
|
||||
} else {
|
||||
SBezier bef, aft;
|
||||
sb->SplitAt(0.5, &bef, &aft);
|
||||
BezierAsNonrationalCubic(&bef, depth+1);
|
||||
BezierAsNonrationalCubic(&aft, depth+1);
|
||||
BezierAsNonrationalCubic(rgb, width, &bef, depth+1);
|
||||
BezierAsNonrationalCubic(rgb, width, &aft, depth+1);
|
||||
}
|
||||
}
|
||||
|
||||
|
118
exportvector.cpp
118
exportvector.cpp
@ -62,7 +62,9 @@ void DxfFileWriter::StartFile(void) {
|
||||
"ENTITIES\r\n");
|
||||
}
|
||||
|
||||
void DxfFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
||||
void DxfFileWriter::LineSegment(DWORD rgb, double w,
|
||||
double x0, double y0, double x1, double y1)
|
||||
{
|
||||
fprintf(f,
|
||||
" 0\r\n"
|
||||
"LINE\r\n"
|
||||
@ -88,7 +90,7 @@ void DxfFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
||||
void DxfFileWriter::Triangle(STriangle *tr) {
|
||||
}
|
||||
|
||||
void DxfFileWriter::Bezier(SBezier *sb) {
|
||||
void DxfFileWriter::Bezier(DWORD rgb, double w, SBezier *sb) {
|
||||
Vector c, n = Vector::From(0, 0, 1);
|
||||
double r;
|
||||
if(sb->IsCircle(n, &c, &r)) {
|
||||
@ -121,7 +123,7 @@ void DxfFileWriter::Bezier(SBezier *sb) {
|
||||
r,
|
||||
theta0*180/PI, theta1*180/PI);
|
||||
} else {
|
||||
BezierAsPwl(sb);
|
||||
BezierAsPwl(rgb, w, sb);
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,6 +139,17 @@ void DxfFileWriter::FinishAndCloseFile(void) {
|
||||
//-----------------------------------------------------------------------------
|
||||
// Routines for EPS output
|
||||
//-----------------------------------------------------------------------------
|
||||
char *EpsFileWriter::StyleString(DWORD rgb, double w) {
|
||||
static char ret[300];
|
||||
sprintf(ret, " %.3f setlinewidth\r\n"
|
||||
" %.3f %.3f %.3f setrgbcolor\r\n"
|
||||
" 1 setlinejoin\r\n" // rounded
|
||||
" 1 setlinecap\r\n", // rounded
|
||||
MmToPts(w),
|
||||
REDf(rgb), GREENf(rgb), BLUEf(rgb));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void EpsFileWriter::StartFile(void) {
|
||||
fprintf(f,
|
||||
"%%!PS-Adobe-2.0\r\n"
|
||||
@ -156,16 +169,18 @@ void EpsFileWriter::StartFile(void) {
|
||||
MmToPts(ptMax.y - ptMin.y));
|
||||
}
|
||||
|
||||
void EpsFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
||||
void EpsFileWriter::LineSegment(DWORD rgb, double w,
|
||||
double x0, double y0, double x1, double y1)
|
||||
{
|
||||
fprintf(f,
|
||||
"newpath\r\n"
|
||||
" %.3f %.3f moveto\r\n"
|
||||
" %.3f %.3f lineto\r\n"
|
||||
" 1 setlinewidth\r\n"
|
||||
" 0 setgray\r\n"
|
||||
"%s"
|
||||
"stroke\r\n",
|
||||
MmToPts(x0 - ptMin.x), MmToPts(y0 - ptMin.y),
|
||||
MmToPts(x1 - ptMin.x), MmToPts(y1 - ptMin.y));
|
||||
MmToPts(x1 - ptMin.x), MmToPts(y1 - ptMin.y),
|
||||
StyleString(rgb, w));
|
||||
}
|
||||
|
||||
void EpsFileWriter::Triangle(STriangle *tr) {
|
||||
@ -200,7 +215,7 @@ void EpsFileWriter::Triangle(STriangle *tr) {
|
||||
MmToPts(tr->c.x - ptMin.x), MmToPts(tr->c.y - ptMin.y));
|
||||
}
|
||||
|
||||
void EpsFileWriter::Bezier(SBezier *sb) {
|
||||
void EpsFileWriter::Bezier(DWORD rgb, double w, SBezier *sb) {
|
||||
Vector c, n = Vector::From(0, 0, 1);
|
||||
double r;
|
||||
if(sb->IsCircle(n, &c, &r)) {
|
||||
@ -216,27 +231,27 @@ void EpsFileWriter::Bezier(SBezier *sb) {
|
||||
"newpath\r\n"
|
||||
" %.3f %.3f moveto\r\n"
|
||||
" %.3f %.3f %.3f %.3f %.3f arc\r\n"
|
||||
" 1 setlinewidth\r\n"
|
||||
" 0 setgray\r\n"
|
||||
"%s"
|
||||
"stroke\r\n",
|
||||
MmToPts(p0.x - ptMin.x), MmToPts(p0.y - ptMin.y),
|
||||
MmToPts(c.x - ptMin.x), MmToPts(c.y - ptMin.y),
|
||||
MmToPts(r),
|
||||
theta0*180/PI, theta1*180/PI);
|
||||
theta0*180/PI, theta1*180/PI,
|
||||
StyleString(rgb, w));
|
||||
} else if(sb->deg == 3 && !sb->IsRational()) {
|
||||
fprintf(f,
|
||||
"newpath\r\n"
|
||||
" %.3f %.3f moveto\r\n"
|
||||
" %.3f %.3f %.3f %.3f %.3f %.3f curveto\r\n"
|
||||
" 1 setlinewidth\r\n"
|
||||
" 0 setgray\r\n"
|
||||
"%s"
|
||||
"stroke\r\n",
|
||||
MmToPts(sb->ctrl[0].x - ptMin.x), MmToPts(sb->ctrl[0].y - ptMin.y),
|
||||
MmToPts(sb->ctrl[1].x - ptMin.x), MmToPts(sb->ctrl[1].y - ptMin.y),
|
||||
MmToPts(sb->ctrl[2].x - ptMin.x), MmToPts(sb->ctrl[2].y - ptMin.y),
|
||||
MmToPts(sb->ctrl[3].x - ptMin.x), MmToPts(sb->ctrl[3].y - ptMin.y));
|
||||
MmToPts(sb->ctrl[3].x - ptMin.x), MmToPts(sb->ctrl[3].y - ptMin.y),
|
||||
StyleString(rgb, w));
|
||||
} else {
|
||||
BezierAsNonrationalCubic(sb);
|
||||
BezierAsNonrationalCubic(rgb, w, sb);
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,6 +267,16 @@ void EpsFileWriter::FinishAndCloseFile(void) {
|
||||
// Routines for PDF output, some extra complexity because we have to generate
|
||||
// a correct xref table.
|
||||
//-----------------------------------------------------------------------------
|
||||
char *PdfFileWriter::StyleString(DWORD rgb, double w) {
|
||||
static char ret[300];
|
||||
sprintf(ret, "1 J 1 j " // round endcaps and joins
|
||||
"%.3f w "
|
||||
"%.3f %.3f %.3f RG\r\n",
|
||||
MmToPts(w),
|
||||
REDf(rgb), GREENf(rgb), BLUEf(rgb));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PdfFileWriter::StartFile(void) {
|
||||
fprintf(f,
|
||||
"%%PDF-1.1\r\n"
|
||||
@ -371,12 +396,15 @@ void PdfFileWriter::FinishAndCloseFile(void) {
|
||||
|
||||
}
|
||||
|
||||
void PdfFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
||||
void PdfFileWriter::LineSegment(DWORD rgb, double w,
|
||||
double x0, double y0, double x1, double y1)
|
||||
{
|
||||
fprintf(f,
|
||||
"1 w 0 0 0 RG\r\n"
|
||||
"%s"
|
||||
"%.3f %.3f m\r\n"
|
||||
"%.3f %.3f l\r\n"
|
||||
"S\r\n",
|
||||
StyleString(rgb, w),
|
||||
MmToPts(x0 - ptMin.x), MmToPts(y0 - ptMin.y),
|
||||
MmToPts(x1 - ptMin.x), MmToPts(y1 - ptMin.y));
|
||||
}
|
||||
@ -400,29 +428,34 @@ void PdfFileWriter::Triangle(STriangle *tr) {
|
||||
MmToPts(tr->c.x - ptMin.x), MmToPts(tr->c.y - ptMin.y));
|
||||
}
|
||||
|
||||
void PdfFileWriter::Bezier(SBezier *sb) {
|
||||
void PdfFileWriter::Bezier(DWORD rgb, double w, SBezier *sb) {
|
||||
if(sb->deg == 3 && !sb->IsRational()) {
|
||||
fprintf(f,
|
||||
"1 w 0 0 0 RG\r\n"
|
||||
"%s"
|
||||
"%.3f %.3f m\r\n"
|
||||
"%.3f %.3f %.3f %.3f %.3f %.3f c\r\n"
|
||||
"S\r\n",
|
||||
StyleString(rgb, w),
|
||||
MmToPts(sb->ctrl[0].x - ptMin.x), MmToPts(sb->ctrl[0].y - ptMin.y),
|
||||
MmToPts(sb->ctrl[1].x - ptMin.x), MmToPts(sb->ctrl[1].y - ptMin.y),
|
||||
MmToPts(sb->ctrl[2].x - ptMin.x), MmToPts(sb->ctrl[2].y - ptMin.y),
|
||||
MmToPts(sb->ctrl[3].x - ptMin.x), MmToPts(sb->ctrl[3].y - ptMin.y));
|
||||
} else {
|
||||
BezierAsNonrationalCubic(sb);
|
||||
BezierAsNonrationalCubic(rgb, w, sb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Routines for SVG output
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const char *SvgFileWriter::SVG_STYLE =
|
||||
"stroke-width='0.1' stroke='black' style='fill: none;'";
|
||||
char *SvgFileWriter::StyleString(DWORD rgb, double w) {
|
||||
static char ret[200];
|
||||
sprintf(ret, "stroke-width='%.3f' stroke='#%02x%02x%02x' "
|
||||
"style='fill: none;' "
|
||||
"stroke-linecap='round' stroke-linejoin='round' ",
|
||||
w, RED(rgb), GREEN(rgb), BLUE(rgb));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SvgFileWriter::StartFile(void) {
|
||||
fprintf(f,
|
||||
@ -440,13 +473,15 @@ void SvgFileWriter::StartFile(void) {
|
||||
// A little bit of extra space for the stroke width.
|
||||
}
|
||||
|
||||
void SvgFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
||||
void SvgFileWriter::LineSegment(DWORD rgb, double w,
|
||||
double x0, double y0, double x1, double y1)
|
||||
{
|
||||
// SVG uses a coordinate system with the origin at top left, +y down
|
||||
fprintf(f,
|
||||
"<polyline points='%.3f,%.3f %.3f,%.3f' %s />\r\n",
|
||||
(x0 - ptMin.x), (ptMax.y - y0),
|
||||
(x1 - ptMin.x), (ptMax.y - y1),
|
||||
SVG_STYLE);
|
||||
StyleString(rgb, w));
|
||||
}
|
||||
|
||||
void SvgFileWriter::Triangle(STriangle *tr) {
|
||||
@ -466,7 +501,7 @@ void SvgFileWriter::Triangle(STriangle *tr) {
|
||||
RED(tr->meta.color), GREEN(tr->meta.color), BLUE(tr->meta.color));
|
||||
}
|
||||
|
||||
void SvgFileWriter::Bezier(SBezier *sb) {
|
||||
void SvgFileWriter::Bezier(DWORD rgb, double w, SBezier *sb) {
|
||||
Vector c, n = Vector::From(0, 0, 1);
|
||||
double r;
|
||||
if(sb->IsCircle(n, &c, &r)) {
|
||||
@ -487,11 +522,11 @@ void SvgFileWriter::Bezier(SBezier *sb) {
|
||||
p0.x - ptMin.x, ptMax.y - p0.y,
|
||||
r, r,
|
||||
p1.x - ptMin.x, ptMax.y - p1.y,
|
||||
SVG_STYLE);
|
||||
StyleString(rgb, w));
|
||||
} else if(!sb->IsRational()) {
|
||||
if(sb->deg == 1) {
|
||||
LineSegment(sb->ctrl[0].x, sb->ctrl[0].y,
|
||||
sb->ctrl[1].x, sb->ctrl[1].y);
|
||||
LineSegment(rgb, w, sb->ctrl[0].x, sb->ctrl[0].y,
|
||||
sb->ctrl[1].x, sb->ctrl[1].y);
|
||||
} else if(sb->deg == 2) {
|
||||
fprintf(f,
|
||||
"<path d='M%.3f,%.3f "
|
||||
@ -499,7 +534,7 @@ void SvgFileWriter::Bezier(SBezier *sb) {
|
||||
sb->ctrl[0].x - ptMin.x, ptMax.y - sb->ctrl[0].y,
|
||||
sb->ctrl[1].x - ptMin.x, ptMax.y - sb->ctrl[1].y,
|
||||
sb->ctrl[2].x - ptMin.x, ptMax.y - sb->ctrl[2].y,
|
||||
SVG_STYLE);
|
||||
StyleString(rgb, w));
|
||||
} else if(sb->deg == 3) {
|
||||
fprintf(f,
|
||||
"<path d='M%.3f,%.3f "
|
||||
@ -508,11 +543,10 @@ void SvgFileWriter::Bezier(SBezier *sb) {
|
||||
sb->ctrl[1].x - ptMin.x, ptMax.y - sb->ctrl[1].y,
|
||||
sb->ctrl[2].x - ptMin.x, ptMax.y - sb->ctrl[2].y,
|
||||
sb->ctrl[3].x - ptMin.x, ptMax.y - sb->ctrl[3].y,
|
||||
SVG_STYLE);
|
||||
StyleString(rgb, w));
|
||||
}
|
||||
} else {
|
||||
BezierAsNonrationalCubic(sb);
|
||||
|
||||
BezierAsNonrationalCubic(rgb, w, sb);
|
||||
}
|
||||
}
|
||||
|
||||
@ -533,7 +567,9 @@ void HpglFileWriter::StartFile(void) {
|
||||
fprintf(f, "SP1;\r\n");
|
||||
}
|
||||
|
||||
void HpglFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
||||
void HpglFileWriter::LineSegment(DWORD rgb, double w,
|
||||
double x0, double y0, double x1, double y1)
|
||||
{
|
||||
fprintf(f, "PU%d,%d;\r\n", (int)MmToHpglUnits(x0), (int)MmToHpglUnits(y0));
|
||||
fprintf(f, "PD%d,%d;\r\n", (int)MmToHpglUnits(x1), (int)MmToHpglUnits(y1));
|
||||
}
|
||||
@ -541,8 +577,8 @@ void HpglFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
||||
void HpglFileWriter::Triangle(STriangle *tr) {
|
||||
}
|
||||
|
||||
void HpglFileWriter::Bezier(SBezier *sb) {
|
||||
BezierAsPwl(sb);
|
||||
void HpglFileWriter::Bezier(DWORD rgb, double w, SBezier *sb) {
|
||||
BezierAsPwl(rgb, w, sb);
|
||||
}
|
||||
|
||||
void HpglFileWriter::FinishAndCloseFile(void) {
|
||||
@ -562,13 +598,15 @@ void Step2dFileWriter::StartFile(void) {
|
||||
void Step2dFileWriter::Triangle(STriangle *tr) {
|
||||
}
|
||||
|
||||
void Step2dFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
||||
void Step2dFileWriter::LineSegment(DWORD rgb, double w,
|
||||
double x0, double y0, double x1, double y1)
|
||||
{
|
||||
SBezier sb = SBezier::From(Vector::From(x0, y0, 0),
|
||||
Vector::From(x1, y1, 0));
|
||||
Bezier(&sb);
|
||||
Bezier(rgb, w, &sb);
|
||||
}
|
||||
|
||||
void Step2dFileWriter::Bezier(SBezier *sb) {
|
||||
void Step2dFileWriter::Bezier(DWORD rgb, double w, SBezier *sb) {
|
||||
int c = sfw.ExportCurve(sb);
|
||||
sfw.curves.Add(&c);
|
||||
}
|
||||
|
@ -579,6 +579,8 @@ void Group::MakeExtrusionLines(IdList<Entity,hEntity> *el, hEntity in) {
|
||||
en.point[0] = Remap(ep->h, REMAP_TOP);
|
||||
en.point[1] = Remap(ep->h, REMAP_BOTTOM);
|
||||
en.group = h;
|
||||
en.construction = ep->construction;
|
||||
en.style = ep->style;
|
||||
en.h = Remap(ep->h, REMAP_PT_TO_LINE);
|
||||
en.type = Entity::LINE_SEGMENT;
|
||||
el->Add(&en);
|
||||
@ -596,6 +598,8 @@ void Group::MakeExtrusionLines(IdList<Entity,hEntity> *el, hEntity in) {
|
||||
en.numNormal = Quaternion::From(0, ab.x, ab.y, ab.z);
|
||||
|
||||
en.group = h;
|
||||
en.construction = ep->construction;
|
||||
en.style = ep->style;
|
||||
en.h = Remap(ep->h, REMAP_LINE_TO_FACE);
|
||||
en.type = Entity::FACE_XPROD;
|
||||
el->Add(&en);
|
||||
@ -636,6 +640,7 @@ void Group::CopyEntity(IdList<Entity,hEntity> *el,
|
||||
en.timesApplied = timesApplied;
|
||||
en.group = h;
|
||||
en.construction = ep->construction;
|
||||
en.style = ep->style;
|
||||
|
||||
switch(ep->type) {
|
||||
case Entity::WORKPLANE:
|
||||
|
@ -353,12 +353,8 @@ void SContour::AddPoint(Vector p) {
|
||||
|
||||
void SContour::MakeEdgesInto(SEdgeList *el) {
|
||||
int i;
|
||||
for(i = 0; i < (l.n-1); i++) {
|
||||
SEdge e;
|
||||
e.tag = 0;
|
||||
e.a = l.elem[i].p;
|
||||
e.b = l.elem[i+1].p;
|
||||
el->l.Add(&e);
|
||||
for(i = 0; i < (l.n - 1); i++) {
|
||||
el->AddEdge(l.elem[i].p, l.elem[i+1].p);
|
||||
}
|
||||
}
|
||||
|
||||
|
2
sketch.h
2
sketch.h
@ -659,6 +659,8 @@ public:
|
||||
static float Width(hStyle hs);
|
||||
static DWORD Color(int hs, bool forExport=false);
|
||||
static float Width(int hs);
|
||||
static double WidthMm(int hs);
|
||||
static bool Exportable(int hs);
|
||||
static hStyle ForEntity(hEntity he);
|
||||
|
||||
char *DescriptionString(void);
|
||||
|
@ -68,6 +68,8 @@ void SolveSpace::Init(char *cmdLine) {
|
||||
exportScale = CnfThawFloat(1.0f, "ExportScale");
|
||||
// Export offset (cutter radius comp)
|
||||
exportOffset = CnfThawFloat(0.0f, "ExportOffset");
|
||||
// Rewrite exported colors close to white into black (assuming white bg)
|
||||
fixExportColors = CnfThawDWORD(1, "FixExportColors");
|
||||
// Draw back faces of triangles (when mesh is leaky/self-intersecting)
|
||||
drawBackFaces = CnfThawDWORD(1, "DrawBackFaces");
|
||||
// Export shaded triangles in a 2d view
|
||||
@ -152,6 +154,8 @@ void SolveSpace::Exit(void) {
|
||||
CnfFreezeFloat(exportScale, "ExportScale");
|
||||
// Export offset (cutter radius comp)
|
||||
CnfFreezeFloat(exportOffset, "ExportOffset");
|
||||
// Rewrite exported colors close to white into black (assuming white bg)
|
||||
CnfFreezeDWORD(fixExportColors, "FixExportColors");
|
||||
// Draw back faces of triangles (when mesh is leaky/self-intersecting)
|
||||
CnfFreezeDWORD(drawBackFaces, "DrawBackFaces");
|
||||
// Export shaded triangles in a 2d view
|
||||
|
46
solvespace.h
46
solvespace.h
@ -395,28 +395,34 @@ public:
|
||||
static VectorFileWriter *ForFile(char *file);
|
||||
|
||||
void Output(SEdgeList *sel, SBezierList *sbl, SMesh *sm);
|
||||
void BezierAsPwl(SBezier *sb);
|
||||
void BezierAsNonrationalCubic(SBezier *sb, int depth=0);
|
||||
|
||||
virtual void Bezier(SBezier *sb) = 0;
|
||||
virtual void LineSegment(double x0, double y0, double x1, double y1) = 0;
|
||||
void BezierAsPwl(DWORD rgb, double width, SBezier *sb);
|
||||
void BezierAsNonrationalCubic(DWORD rgb, double width,
|
||||
SBezier *sb, int depth=0);
|
||||
|
||||
virtual void Bezier(DWORD rgb, double width, SBezier *sb) = 0;
|
||||
virtual void LineSegment(DWORD rgb, double width,
|
||||
double x0, double y0, double x1, double y1) = 0;
|
||||
virtual void Triangle(STriangle *tr) = 0;
|
||||
virtual void StartFile(void) = 0;
|
||||
virtual void FinishAndCloseFile(void) = 0;
|
||||
};
|
||||
class DxfFileWriter : public VectorFileWriter {
|
||||
public:
|
||||
void LineSegment(double x0, double y0, double x1, double y1);
|
||||
void LineSegment(DWORD rgb, double width,
|
||||
double x0, double y0, double x1, double y1);
|
||||
void Triangle(STriangle *tr);
|
||||
void Bezier(SBezier *sb);
|
||||
void Bezier(DWORD rgb, double width, SBezier *sb);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
class EpsFileWriter : public VectorFileWriter {
|
||||
public:
|
||||
void LineSegment(double x0, double y0, double x1, double y1);
|
||||
static char *StyleString(DWORD rgb, double width);
|
||||
void LineSegment(DWORD rgb, double width,
|
||||
double x0, double y0, double x1, double y1);
|
||||
void Triangle(STriangle *tr);
|
||||
void Bezier(SBezier *sb);
|
||||
void Bezier(DWORD rgb, double width, SBezier *sb);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
@ -425,35 +431,40 @@ public:
|
||||
DWORD xref[10];
|
||||
DWORD bodyStart;
|
||||
|
||||
void LineSegment(double x0, double y0, double x1, double y1);
|
||||
static char *StyleString(DWORD rgb, double width);
|
||||
void LineSegment(DWORD rgb, double width,
|
||||
double x0, double y0, double x1, double y1);
|
||||
void Triangle(STriangle *tr);
|
||||
void Bezier(SBezier *sb);
|
||||
void Bezier(DWORD rgb, double width, SBezier *sb);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
class SvgFileWriter : public VectorFileWriter {
|
||||
public:
|
||||
static const char *SVG_STYLE;
|
||||
void LineSegment(double x0, double y0, double x1, double y1);
|
||||
static char *StyleString(DWORD rgb, double width);
|
||||
void LineSegment(DWORD rgb, double width,
|
||||
double x0, double y0, double x1, double y1);
|
||||
void Triangle(STriangle *tr);
|
||||
void Bezier(SBezier *sb);
|
||||
void Bezier(DWORD rgb, double width, SBezier *sb);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
class HpglFileWriter : public VectorFileWriter {
|
||||
public:
|
||||
static double MmToHpglUnits(double mm);
|
||||
void LineSegment(double x0, double y0, double x1, double y1);
|
||||
void LineSegment(DWORD rgb, double width,
|
||||
double x0, double y0, double x1, double y1);
|
||||
void Triangle(STriangle *tr);
|
||||
void Bezier(SBezier *sb);
|
||||
void Bezier(DWORD rgb, double width, SBezier *sb);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
class Step2dFileWriter : public VectorFileWriter {
|
||||
StepFileWriter sfw;
|
||||
void LineSegment(double x0, double y0, double x1, double y1);
|
||||
void LineSegment(DWORD rgb, double width,
|
||||
double x0, double y0, double x1, double y1);
|
||||
void Triangle(STriangle *tr);
|
||||
void Bezier(SBezier *sb);
|
||||
void Bezier(DWORD rgb, double width, SBezier *sb);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
@ -530,6 +541,7 @@ public:
|
||||
double cameraTangent;
|
||||
float exportScale;
|
||||
float exportOffset;
|
||||
int fixExportColors;
|
||||
int drawBackFaces;
|
||||
int showToolbar;
|
||||
DWORD backgroundColor;
|
||||
|
@ -104,6 +104,13 @@ SBezier SBezier::TransformedBy(Vector t, Quaternion q) {
|
||||
bool SBezier::IsCircle(Vector axis, Vector *center, double *r) {
|
||||
if(deg != 2) return false;
|
||||
|
||||
if(ctrl[1].DistanceToLine(ctrl[0], ctrl[2].Minus(ctrl[0])) < LENGTH_EPS) {
|
||||
// This is almost a line segment. So it's a circle with very large
|
||||
// radius, which is likely to make code that tries to handle circles
|
||||
// blow up. So return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector t0 = (ctrl[0]).Minus(ctrl[1]),
|
||||
t2 = (ctrl[2]).Minus(ctrl[1]),
|
||||
r0 = axis.Cross(t0),
|
||||
|
@ -62,6 +62,8 @@ public:
|
||||
class SBezier {
|
||||
public:
|
||||
int tag;
|
||||
int auxA, auxB;
|
||||
|
||||
int deg;
|
||||
Vector ctrl[4];
|
||||
double weight[4];
|
||||
|
66
style.cpp
66
style.cpp
@ -111,6 +111,8 @@ void Style::FreezeDefaultStyles(void) {
|
||||
// the style, according to our table of default styles.
|
||||
//-----------------------------------------------------------------------------
|
||||
Style *Style::Get(hStyle h) {
|
||||
if(h.v == 0) h.v = ACTIVE_GRP;
|
||||
|
||||
Style *s = SK.style.FindByIdNoOops(h);
|
||||
if(s) {
|
||||
// It exists, good.
|
||||
@ -140,6 +142,19 @@ float Style::Width(int s) {
|
||||
//-----------------------------------------------------------------------------
|
||||
DWORD Style::Color(hStyle h, bool forExport) {
|
||||
Style *s = Get(h);
|
||||
if(forExport) {
|
||||
Vector rgb = Vector::From(REDf(s->color),
|
||||
GREENf(s->color),
|
||||
BLUEf(s->color));
|
||||
rgb = rgb.Minus(Vector::From(1, 1, 1));
|
||||
if(rgb.Magnitude() < 0.4 && SS.fixExportColors) {
|
||||
// This is an almost-white color in a default style, which is
|
||||
// good for the default on-screen view (black bg) but probably
|
||||
// not desired in the exported files, which typically are shown
|
||||
// against white backgrounds.
|
||||
return RGB(0, 0, 0);
|
||||
}
|
||||
}
|
||||
return s->color;
|
||||
}
|
||||
|
||||
@ -158,6 +173,24 @@ float Style::Width(hStyle h) {
|
||||
return (float)r;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Return the width associated with our style in millimeters..
|
||||
//-----------------------------------------------------------------------------
|
||||
double Style::WidthMm(int hs) {
|
||||
double widthpx = Width(hs);
|
||||
return widthpx / SS.GW.scale;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Should lines and curves from this style appear in the output file? Only
|
||||
// if it's both shown and exportable.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Style::Exportable(int si) {
|
||||
hStyle hs = { si };
|
||||
Style *s = Get(hs);
|
||||
return (s->exportable) && (s->visible);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Return the appropriate style for our entity. If the entity has a style
|
||||
// explicitly assigned, then it's that style. Otherwise it's the appropriate
|
||||
@ -432,6 +465,39 @@ void TextWindow::ShowStyleInfo(void) {
|
||||
s->h.v, &ScreenChangeStyleYesNo,
|
||||
(!s->exportable ? "" : "no"),
|
||||
(!s->exportable ? "no" : ""));
|
||||
|
||||
Printf(false, "");
|
||||
Printf(false, "To assign lines or curves to this style,");
|
||||
Printf(false, "select them on the drawing. Then commit");
|
||||
Printf(false, "by clicking the link at the bottom of");
|
||||
Printf(false, "this window.");
|
||||
}
|
||||
}
|
||||
|
||||
void TextWindow::ScreenAssignSelectionToStyle(int link, DWORD v) {
|
||||
bool showError = false;
|
||||
SS.GW.GroupSelection();
|
||||
|
||||
SS.UndoRemember();
|
||||
for(int i = 0; i < SS.GW.gs.entities; i++) {
|
||||
hEntity he = SS.GW.gs.entity[i];
|
||||
if(!he.isFromRequest()) {
|
||||
showError = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
hRequest hr = he.request();
|
||||
Request *r = SK.GetRequest(hr);
|
||||
r->style.v = v;
|
||||
SS.later.generateAll = true;
|
||||
}
|
||||
|
||||
if(showError) {
|
||||
Error("Can't assign style to an entity that's derived from another "
|
||||
"entity; try assigning a style to this entity's parent.");
|
||||
}
|
||||
|
||||
SS.GW.ClearSelection();
|
||||
InvalidateGraphics();
|
||||
}
|
||||
|
||||
|
@ -636,6 +636,9 @@ void TextWindow::ScreenChangeExportOffset(int link, DWORD v) {
|
||||
ShowTextEditControl(57, 3, SS.MmToString(SS.exportOffset));
|
||||
SS.TW.edit.meaning = EDIT_EXPORT_OFFSET;
|
||||
}
|
||||
void TextWindow::ScreenChangeFixExportColors(int link, DWORD v) {
|
||||
SS.fixExportColors = !SS.fixExportColors;
|
||||
}
|
||||
void TextWindow::ScreenChangeBackFaces(int link, DWORD v) {
|
||||
SS.drawBackFaces = !SS.drawBackFaces;
|
||||
InvalidateGraphics();
|
||||
@ -786,7 +789,14 @@ void TextWindow::ShowConfiguration(void) {
|
||||
}
|
||||
|
||||
Printf(false, "");
|
||||
Printf(false, "%Ft draw back faces: "
|
||||
Printf(false, "%Ft fix white exported lines: "
|
||||
"%Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E",
|
||||
&ScreenChangeFixExportColors,
|
||||
( SS.fixExportColors ? "" : "yes"), ( SS.fixExportColors ? "yes" : ""),
|
||||
&ScreenChangeFixExportColors,
|
||||
(!SS.fixExportColors ? "" : "no"), (!SS.fixExportColors ? "no" : ""));
|
||||
|
||||
Printf(false, "%Ft draw triangle back faces: "
|
||||
"%Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E",
|
||||
&ScreenChangeBackFaces,
|
||||
(SS.drawBackFaces ? "" : "yes"), (SS.drawBackFaces ? "yes" : ""),
|
||||
|
31
textwin.cpp
31
textwin.cpp
@ -414,6 +414,12 @@ void TextWindow::DescribeSelection(void) {
|
||||
Entity *w = SK.GetEntity(e->workplane);
|
||||
Printf(false, "%FtIN WORKPLANE%E %s", w->DescriptionString());
|
||||
}
|
||||
if(e->style.v) {
|
||||
Style *s = Style::Get(e->style);
|
||||
Printf(false, "%FtIN STYLE%E %s", s->DescriptionString());
|
||||
} else {
|
||||
Printf(false, "%FtIN STYLE%E none");
|
||||
}
|
||||
} else if(gs.n == 2 && gs.points == 2) {
|
||||
Printf(false, "%FtTWO POINTS");
|
||||
Vector p0 = SK.GetEntity(gs.point[0])->PointGetNum();
|
||||
@ -481,6 +487,31 @@ void TextWindow::DescribeSelection(void) {
|
||||
Printf(true, "%FtSELECTED:%E %d item%s", gs.n, gs.n == 1 ? "" : "s");
|
||||
}
|
||||
|
||||
if(shown.screen == SCREEN_STYLE_INFO &&
|
||||
shown.style.v >= Style::FIRST_CUSTOM)
|
||||
{
|
||||
// If we are showing a screen for a particular style, then offer the
|
||||
// option to assign our selected entities to that style.
|
||||
Style *s = Style::Get(shown.style);
|
||||
Printf(true, "%Fl%D%f%Ll(assign to style %s)%E",
|
||||
shown.style.v,
|
||||
&ScreenAssignSelectionToStyle,
|
||||
s->DescriptionString());
|
||||
}
|
||||
// If any of the selected entities have an assigned style, then offer
|
||||
// the option to remove that style.
|
||||
for(i = 0; i < gs.entities; i++) {
|
||||
Entity *e = SK.GetEntity(gs.entity[i]);
|
||||
if(e->style.v != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i < gs.entities) {
|
||||
Printf(true, "%Fl%D%f%Ll(remove assigned style)%E",
|
||||
0,
|
||||
&ScreenAssignSelectionToStyle);
|
||||
}
|
||||
|
||||
Printf(true, "%Fl%f%Ll(unselect all)%E", &TextWindow::ScreenUnselectAll);
|
||||
}
|
||||
|
||||
|
2
ui.h
2
ui.h
@ -159,10 +159,12 @@ public:
|
||||
static void ScreenChangeStyleYesNo(int link, DWORD v);
|
||||
static void ScreenCreateCustomStyle(int link, DWORD v);
|
||||
static void ScreenLoadFactoryDefaultStyles(int link, DWORD v);
|
||||
static void ScreenAssignSelectionToStyle(int link, DWORD v);
|
||||
|
||||
static void ScreenShowConfiguration(int link, DWORD v);
|
||||
static void ScreenGoToWebsite(int link, DWORD v);
|
||||
|
||||
static void ScreenChangeFixExportColors(int link, DWORD v);
|
||||
static void ScreenChangeBackFaces(int link, DWORD v);
|
||||
static void ScreenChangePwlCurves(int link, DWORD v);
|
||||
static void ScreenChangeCanvasSizeAuto(int link, DWORD v);
|
||||
|
@ -1,8 +1,7 @@
|
||||
|
||||
grid
|
||||
line styles (color, thickness)
|
||||
background color setting
|
||||
better text
|
||||
right-click menu
|
||||
faster triangulation
|
||||
interpolating splines
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user