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
|
||||
// our piecewise linear curves.
|
||||
out->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;
|
||||
|
||||
out->LineSegment(p0.x, p0.y, p1.x, p1.y);
|
||||
}
|
||||
}
|
||||
out->FinishAndCloseFile();
|
||||
out->OutputPolygon(sp);
|
||||
}
|
||||
|
||||
bool VectorFileWriter::StringEndsIn(char *str, char *ending) {
|
||||
|
@ -194,8 +183,18 @@ VectorFileWriter *VectorFileWriter::ForFile(char *filename) {
|
|||
if(StringEndsIn(filename, ".dxf")) {
|
||||
static DxfFileWriter 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 {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -208,6 +207,36 @@ VectorFileWriter *VectorFileWriter::ForFile(char *filename) {
|
|||
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) {
|
||||
// Some software, like Adobe Illustrator, insists on a header.
|
||||
fprintf(f,
|
||||
|
@ -252,9 +281,6 @@ void DxfFileWriter::StartFile(void) {
|
|||
"ENTITIES\r\n");
|
||||
}
|
||||
|
||||
void DxfFileWriter::SetLineWidth(double mm) {
|
||||
}
|
||||
|
||||
void DxfFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
||||
fprintf(f,
|
||||
" 0\r\n"
|
||||
|
@ -287,6 +313,109 @@ void DxfFileWriter::FinishAndCloseFile(void) {
|
|||
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) {
|
||||
SMesh *m = &(SS.GetGroup(SS.GW.activeGroup)->runningMesh);
|
||||
if(m->l.n == 0) {
|
||||
|
@ -332,6 +461,10 @@ void SolveSpace::ExportMeshTo(char *filename) {
|
|||
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) {
|
||||
int w = (int)SS.GW.width, h = (int)SS.GW.height;
|
||||
// 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: {
|
||||
char exportFile[MAX_PATH] = "";
|
||||
if(!GetSaveFile(exportFile, DXF_EXT, DXF_PATTERN)) break;
|
||||
if(!GetSaveFile(exportFile, VEC_EXT, VEC_PATTERN)) break;
|
||||
SS.ExportViewTo(exportFile);
|
||||
break;
|
||||
}
|
||||
|
||||
case GraphicsWindow::MNU_EXPORT_SECTION: {
|
||||
char exportFile[MAX_PATH] = "";
|
||||
if(!GetSaveFile(exportFile, DXF_EXT, DXF_PATTERN)) break;
|
||||
if(!GetSaveFile(exportFile, VEC_EXT, VEC_PATTERN)) break;
|
||||
SS.ExportSectionTo(exportFile);
|
||||
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 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) == '#')
|
||||
|
||||
|
@ -68,8 +70,12 @@ int SaveFileYesNoCancel(void);
|
|||
#define PNG_EXT "png"
|
||||
#define STL_PATTERN "STL Mesh (*.stl)\0*.stl\0All Files (*)\0*\0\0"
|
||||
#define STL_EXT "stl"
|
||||
#define DXF_PATTERN "DXF File (*.dxf)\0*.dxf\0All Files (*)\0*\0\0"
|
||||
#define DXF_EXT "dxf"
|
||||
#define VEC_PATTERN "DXF File (*.dxf)\0*.dxf\0" \
|
||||
"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_EXT "csv"
|
||||
#define LICENSE_PATTERN \
|
||||
|
@ -331,18 +337,39 @@ public:
|
|||
class VectorFileWriter {
|
||||
public:
|
||||
FILE *f;
|
||||
Vector ptMin, ptMax;
|
||||
|
||||
static bool StringEndsIn(char *str, char *ending);
|
||||
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 StartFile(void) = 0;
|
||||
virtual void FinishAndCloseFile(void) = 0;
|
||||
};
|
||||
class DxfFileWriter : public VectorFileWriter {
|
||||
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 StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
|
|
|
@ -518,7 +518,11 @@ void SSurface::ClosestPointTo(Vector p, double *u, double *v) {
|
|||
Vector p0;
|
||||
for(i = 0; i < 50; i++) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user