Add eps, hpgl, and svg output (simple, all just for polylines). And
fix convergence tolerance so that points projected into a rational polynomial surface end up much closer than LENGTH_EPS. [git-p4: depot-paths = "//depot/solvespace/": change = 1906]
This commit is contained in:
parent
07ddd62a3a
commit
95bded27ee
165
export.cpp
165
export.cpp
|
@ -162,18 +162,7 @@ void SolveSpace::ExportPolygon(SPolygon *sp,
|
||||||
|
|
||||||
// Now begin the entities, which are just line segments reproduced from
|
// Now begin the entities, which are just line segments reproduced from
|
||||||
// our piecewise linear curves.
|
// our piecewise linear curves.
|
||||||
out->StartFile();
|
out->OutputPolygon(sp);
|
||||||
for(i = 0; i < sp->l.n; i++) {
|
|
||||||
SContour *sc = &(sp->l.elem[i]);
|
|
||||||
|
|
||||||
for(j = 1; j < sc->l.n; j++) {
|
|
||||||
Vector p0 = sc->l.elem[j-1].p,
|
|
||||||
p1 = sc->l.elem[j].p;
|
|
||||||
|
|
||||||
out->LineSegment(p0.x, p0.y, p1.x, p1.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out->FinishAndCloseFile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VectorFileWriter::StringEndsIn(char *str, char *ending) {
|
bool VectorFileWriter::StringEndsIn(char *str, char *ending) {
|
||||||
|
@ -194,8 +183,18 @@ VectorFileWriter *VectorFileWriter::ForFile(char *filename) {
|
||||||
if(StringEndsIn(filename, ".dxf")) {
|
if(StringEndsIn(filename, ".dxf")) {
|
||||||
static DxfFileWriter DxfWriter;
|
static DxfFileWriter DxfWriter;
|
||||||
ret = &DxfWriter;
|
ret = &DxfWriter;
|
||||||
|
} else if(StringEndsIn(filename, ".ps") || StringEndsIn(filename, ".eps")) {
|
||||||
|
static EpsFileWriter EpsWriter;
|
||||||
|
ret = &EpsWriter;
|
||||||
|
} else if(StringEndsIn(filename, ".svg")) {
|
||||||
|
static SvgFileWriter SvgWriter;
|
||||||
|
ret = &SvgWriter;
|
||||||
|
} else if(StringEndsIn(filename, ".plt")||StringEndsIn(filename, ".hpgl")) {
|
||||||
|
static HpglFileWriter HpglWriter;
|
||||||
|
ret = &HpglWriter;
|
||||||
} else {
|
} else {
|
||||||
Error("Can't identify output file type from file extension.");
|
Error("Can't identify output file type from file extension of "
|
||||||
|
"filename '%s'; try .dxf, .svg, .plt, .hpgl, .eps, or .ps.", filename);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,6 +207,36 @@ VectorFileWriter *VectorFileWriter::ForFile(char *filename) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VectorFileWriter::OutputPolygon(SPolygon *sp) {
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
// First calculate the bounding box.
|
||||||
|
ptMin = Vector::From(VERY_POSITIVE, VERY_POSITIVE, VERY_POSITIVE);
|
||||||
|
ptMax = Vector::From(VERY_NEGATIVE, VERY_NEGATIVE, VERY_NEGATIVE);
|
||||||
|
for(i = 0; i < sp->l.n; i++) {
|
||||||
|
SContour *sc = &(sp->l.elem[i]);
|
||||||
|
for(j = 0; j < sc->l.n; j++) {
|
||||||
|
(sc->l.elem[j].p).MakeMaxMin(&ptMax, &ptMin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StartFile();
|
||||||
|
for(i = 0; i < sp->l.n; i++) {
|
||||||
|
SContour *sc = &(sp->l.elem[i]);
|
||||||
|
|
||||||
|
for(j = 1; j < sc->l.n; j++) {
|
||||||
|
Vector p0 = sc->l.elem[j-1].p,
|
||||||
|
p1 = sc->l.elem[j].p;
|
||||||
|
|
||||||
|
LineSegment(p0.x, p0.y, p1.x, p1.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FinishAndCloseFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Routines for DXF export
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
void DxfFileWriter::StartFile(void) {
|
void DxfFileWriter::StartFile(void) {
|
||||||
// Some software, like Adobe Illustrator, insists on a header.
|
// Some software, like Adobe Illustrator, insists on a header.
|
||||||
fprintf(f,
|
fprintf(f,
|
||||||
|
@ -252,9 +281,6 @@ void DxfFileWriter::StartFile(void) {
|
||||||
"ENTITIES\r\n");
|
"ENTITIES\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DxfFileWriter::SetLineWidth(double mm) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void DxfFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
void DxfFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
||||||
fprintf(f,
|
fprintf(f,
|
||||||
" 0\r\n"
|
" 0\r\n"
|
||||||
|
@ -287,6 +313,109 @@ void DxfFileWriter::FinishAndCloseFile(void) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Routines for EPS output
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
double EpsFileWriter::MmToPoints(double mm) {
|
||||||
|
// 72 points in an inch
|
||||||
|
return (mm/25.4)*72;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EpsFileWriter::StartFile(void) {
|
||||||
|
fprintf(f,
|
||||||
|
"%%!PS-Adobe-2.0\r\n"
|
||||||
|
"%%%%Creator: SolveSpace\r\n"
|
||||||
|
"%%%%Title: title\r\n"
|
||||||
|
"%%%%Pages: 0\r\n"
|
||||||
|
"%%%%PageOrder: Ascend\r\n"
|
||||||
|
"%%%%BoundingBox: 0 0 %d %d\r\n"
|
||||||
|
"%%%%HiResBoundingBox: 0 0 %.3f %.3f\r\n"
|
||||||
|
"%%%%EndComments\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"gsave\r\n"
|
||||||
|
"\r\n",
|
||||||
|
(int)ceil(MmToPoints(ptMax.x - ptMin.x)),
|
||||||
|
(int)ceil(MmToPoints(ptMax.y - ptMin.y)),
|
||||||
|
MmToPoints(ptMax.x - ptMin.x),
|
||||||
|
MmToPoints(ptMax.y - ptMin.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EpsFileWriter::LineSegment(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"
|
||||||
|
"stroke\r\n",
|
||||||
|
MmToPoints(x0 - ptMin.x), MmToPoints(y0 - ptMin.y),
|
||||||
|
MmToPoints(x1 - ptMin.x), MmToPoints(y1 - ptMin.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EpsFileWriter::FinishAndCloseFile(void) {
|
||||||
|
fprintf(f,
|
||||||
|
"\r\n"
|
||||||
|
"grestore\r\n"
|
||||||
|
"\r\n");
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Routines for SVG output
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void SvgFileWriter::StartFile(void) {
|
||||||
|
fprintf(f,
|
||||||
|
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" "
|
||||||
|
"\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\r\n"
|
||||||
|
"<svg xmlns=\"http://www.w3.org/2000/svg\" "
|
||||||
|
"xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
|
||||||
|
"width='%.3fmm' height='%.3fmm' "
|
||||||
|
"viewBox=\"0 0 %.3f %.3f\">\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"<title>Exported SVG</title>\r\n"
|
||||||
|
"\r\n",
|
||||||
|
ptMax.x - ptMin.x, ptMax.y - ptMin.y,
|
||||||
|
ptMax.x - ptMin.x, ptMax.y - ptMin.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SvgFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
||||||
|
fprintf(f,
|
||||||
|
"<polyline points='%.3f %.3f, %.3f %.3f' "
|
||||||
|
"stroke-width='1' stroke='black' style='fill: none;' />\r\n",
|
||||||
|
(x0 - ptMin.x), (y0 - ptMin.y),
|
||||||
|
(x1 - ptMin.x), (y1 - ptMin.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SvgFileWriter::FinishAndCloseFile(void) {
|
||||||
|
fprintf(f, "\r\n</svg>\r\n");
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Routines for HPGL output
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
double HpglFileWriter::MmToHpglUnits(double mm) {
|
||||||
|
return mm*40;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HpglFileWriter::StartFile(void) {
|
||||||
|
fprintf(f, "IN;\r\n");
|
||||||
|
fprintf(f, "SP1;\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void HpglFileWriter::LineSegment(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));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HpglFileWriter::FinishAndCloseFile(void) {
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Export the mesh as an STL file; it should always be vertex-to-vertex and
|
||||||
|
// not self-intersecting, so not much to do.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
void SolveSpace::ExportMeshTo(char *filename) {
|
void SolveSpace::ExportMeshTo(char *filename) {
|
||||||
SMesh *m = &(SS.GetGroup(SS.GW.activeGroup)->runningMesh);
|
SMesh *m = &(SS.GetGroup(SS.GW.activeGroup)->runningMesh);
|
||||||
if(m->l.n == 0) {
|
if(m->l.n == 0) {
|
||||||
|
@ -332,6 +461,10 @@ void SolveSpace::ExportMeshTo(char *filename) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Export a view of the model as an image; we just take a screenshot, by
|
||||||
|
// rendering the view in the usual way and then copying the pixels.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
void SolveSpace::ExportAsPngTo(char *filename) {
|
void SolveSpace::ExportAsPngTo(char *filename) {
|
||||||
int w = (int)SS.GW.width, h = (int)SS.GW.height;
|
int w = (int)SS.GW.width, h = (int)SS.GW.height;
|
||||||
// No guarantee that the back buffer contains anything valid right now,
|
// No guarantee that the back buffer contains anything valid right now,
|
||||||
|
|
|
@ -339,14 +339,14 @@ void SolveSpace::MenuFile(int id) {
|
||||||
|
|
||||||
case GraphicsWindow::MNU_EXPORT_VIEW: {
|
case GraphicsWindow::MNU_EXPORT_VIEW: {
|
||||||
char exportFile[MAX_PATH] = "";
|
char exportFile[MAX_PATH] = "";
|
||||||
if(!GetSaveFile(exportFile, DXF_EXT, DXF_PATTERN)) break;
|
if(!GetSaveFile(exportFile, VEC_EXT, VEC_PATTERN)) break;
|
||||||
SS.ExportViewTo(exportFile);
|
SS.ExportViewTo(exportFile);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case GraphicsWindow::MNU_EXPORT_SECTION: {
|
case GraphicsWindow::MNU_EXPORT_SECTION: {
|
||||||
char exportFile[MAX_PATH] = "";
|
char exportFile[MAX_PATH] = "";
|
||||||
if(!GetSaveFile(exportFile, DXF_EXT, DXF_PATTERN)) break;
|
if(!GetSaveFile(exportFile, VEC_EXT, VEC_PATTERN)) break;
|
||||||
SS.ExportSectionTo(exportFile);
|
SS.ExportSectionTo(exportFile);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
37
solvespace.h
37
solvespace.h
|
@ -32,7 +32,9 @@ inline double WRAP_NOT_0(double v, double n) {
|
||||||
#define ZERO(v) memset((v), 0, sizeof(*(v)))
|
#define ZERO(v) memset((v), 0, sizeof(*(v)))
|
||||||
#define CO(v) (v).x, (v).y, (v).z
|
#define CO(v) (v).x, (v).y, (v).z
|
||||||
|
|
||||||
#define LENGTH_EPS (1e-7)
|
#define LENGTH_EPS (1e-7)
|
||||||
|
#define VERY_POSITIVE (1e10)
|
||||||
|
#define VERY_NEGATIVE (-1e10)
|
||||||
|
|
||||||
#define isforname(c) (isalnum(c) || (c) == '_' || (c) == '-' || (c) == '#')
|
#define isforname(c) (isalnum(c) || (c) == '_' || (c) == '-' || (c) == '#')
|
||||||
|
|
||||||
|
@ -68,8 +70,12 @@ int SaveFileYesNoCancel(void);
|
||||||
#define PNG_EXT "png"
|
#define PNG_EXT "png"
|
||||||
#define STL_PATTERN "STL Mesh (*.stl)\0*.stl\0All Files (*)\0*\0\0"
|
#define STL_PATTERN "STL Mesh (*.stl)\0*.stl\0All Files (*)\0*\0\0"
|
||||||
#define STL_EXT "stl"
|
#define STL_EXT "stl"
|
||||||
#define DXF_PATTERN "DXF File (*.dxf)\0*.dxf\0All Files (*)\0*\0\0"
|
#define VEC_PATTERN "DXF File (*.dxf)\0*.dxf\0" \
|
||||||
#define DXF_EXT "dxf"
|
"Encapsulated PostScript (*.eps;*.ps)\0*.eps;*.ps\0" \
|
||||||
|
"Scalable Vector Graphics (*.svg)\0*.svg\0" \
|
||||||
|
"HPGL File (*.plt;*.hpgl)\0*.plt;*.hpgl\0" \
|
||||||
|
"All Files (*)\0*\0\0"
|
||||||
|
#define VEC_EXT "dxf"
|
||||||
#define CSV_PATTERN "CSV File (*.csv)\0*.csv\0All Files (*)\0*\0\0"
|
#define CSV_PATTERN "CSV File (*.csv)\0*.csv\0All Files (*)\0*\0\0"
|
||||||
#define CSV_EXT "csv"
|
#define CSV_EXT "csv"
|
||||||
#define LICENSE_PATTERN \
|
#define LICENSE_PATTERN \
|
||||||
|
@ -331,18 +337,39 @@ public:
|
||||||
class VectorFileWriter {
|
class VectorFileWriter {
|
||||||
public:
|
public:
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
Vector ptMin, ptMax;
|
||||||
|
|
||||||
static bool StringEndsIn(char *str, char *ending);
|
static bool StringEndsIn(char *str, char *ending);
|
||||||
static VectorFileWriter *ForFile(char *file);
|
static VectorFileWriter *ForFile(char *file);
|
||||||
|
|
||||||
virtual void SetLineWidth(double mm) = 0;
|
void OutputPolygon(SPolygon *sp);
|
||||||
|
|
||||||
virtual void LineSegment(double x0, double y0, double x1, double y1) = 0;
|
virtual void LineSegment(double x0, double y0, double x1, double y1) = 0;
|
||||||
virtual void StartFile(void) = 0;
|
virtual void StartFile(void) = 0;
|
||||||
virtual void FinishAndCloseFile(void) = 0;
|
virtual void FinishAndCloseFile(void) = 0;
|
||||||
};
|
};
|
||||||
class DxfFileWriter : public VectorFileWriter {
|
class DxfFileWriter : public VectorFileWriter {
|
||||||
public:
|
public:
|
||||||
void SetLineWidth(double mm);
|
void LineSegment(double x0, double y0, double x1, double y1);
|
||||||
|
void StartFile(void);
|
||||||
|
void FinishAndCloseFile(void);
|
||||||
|
};
|
||||||
|
class EpsFileWriter : public VectorFileWriter {
|
||||||
|
public:
|
||||||
|
static double MmToPoints(double mm);
|
||||||
|
void LineSegment(double x0, double y0, double x1, double y1);
|
||||||
|
void StartFile(void);
|
||||||
|
void FinishAndCloseFile(void);
|
||||||
|
};
|
||||||
|
class SvgFileWriter : public VectorFileWriter {
|
||||||
|
public:
|
||||||
|
void LineSegment(double x0, double y0, double x1, double y1);
|
||||||
|
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(double x0, double y0, double x1, double y1);
|
||||||
void StartFile(void);
|
void StartFile(void);
|
||||||
void FinishAndCloseFile(void);
|
void FinishAndCloseFile(void);
|
||||||
|
|
|
@ -518,7 +518,11 @@ void SSurface::ClosestPointTo(Vector p, double *u, double *v) {
|
||||||
Vector p0;
|
Vector p0;
|
||||||
for(i = 0; i < 50; i++) {
|
for(i = 0; i < 50; i++) {
|
||||||
p0 = PointAt(*u, *v);
|
p0 = PointAt(*u, *v);
|
||||||
if(p0.Equals(p)) {
|
// Converge it to better than LENGTH_EPS; we want two points, each
|
||||||
|
// independently projected into uv and back, to end up equal with
|
||||||
|
// the LENGTH_EPS. Best case that requires LENGTH_EPS/2, but more
|
||||||
|
// is better and convergence should be fast by now.
|
||||||
|
if(p0.Equals(p, LENGTH_EPS/100)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user