diff options
Diffstat (limited to 'app/bin/svgoutput.c')
| -rw-r--r-- | app/bin/svgoutput.c | 490 | 
1 files changed, 490 insertions, 0 deletions
diff --git a/app/bin/svgoutput.c b/app/bin/svgoutput.c new file mode 100644 index 0000000..e4ff66b --- /dev/null +++ b/app/bin/svgoutput.c @@ -0,0 +1,490 @@ +/** \file svgoutput.c + * Exporting SVG files +*/ + +/*  XTrkCad - Model Railroad CAD + *  Copyright (C) 2020 Martin Fischer + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdio.h> +#include <string.h> +#include <time.h> +#ifdef WINDOWS +#include <io.h> +#define UTFCONVERT +#else +#include <errno.h> +#endif + +#include <xtrkcad-config.h> +#include <locale.h> +#include <mxml.h> +#include <dynstring.h> + +#include "cselect.h" +#include "custom.h" +#include "draw.h" +#include "include/svgformat.h" +#include "fileio.h" +#include "i18n.h" +#include "layout.h" +#include "messages.h" +#include "paths.h" +#include "track.h" +#include "include/utf8convert.h" +#include "utility.h" +#include "wlib.h" + +static struct wFilSel_t * exportSVGFile_fs; +static coOrd roomSize; + +static int svgLineWidth[4] = {10, 10, 20, 30}; + +/** + * get line style for element + * + * \param  d drawCmd_p to process. + * + * \returns the line style + */ + +static unsigned +SvgDrawGetLineStyle(drawCmd_p d) +{ +	unsigned long notSolid = DC_NOTSOLIDLINE; +	unsigned long opt = d->options & notSolid; +	unsigned lineOpt; + +	switch (opt) { +	case DC_DASH: +		lineOpt = wDrawLineDash; +		break; +	case DC_DOT: +		lineOpt = wDrawLineDot; +		break; +	case DC_DASHDOT: +		lineOpt = wDrawLineDashDot; +		break; +	case DC_DASHDOTDOT: +		lineOpt = wDrawLineDashDotDot; +		break; +	case DC_CENTER: +		lineOpt = wDrawLineCenter; +		break; +	case DC_PHANTOM: +		lineOpt = wDrawLinePhantom; +		break; +	default: +		lineOpt = wDrawLineSolid; +		break; +	} + +	return (lineOpt); +} + +/** + * Svg draw line + * + * \param  d	 A drawCmd_p to process. + * \param  p0    The p 0. + * \param  p1    The first coOrd. + * \param  width The width. + * \param  color The color. + */ + +static void SvgDrawLine( +        drawCmd_p d, +        coOrd p0, +        coOrd p1, +        wDrawWidth width, +        wDrawColor color) +{ +	unsigned lineOpt = SvgDrawGetLineStyle(d); + +	width = (wDrawWidth)(width >= MINIMUMLINEWIDTH ? width : svgLineWidth[width]); + +	SvgLineCommand((SVGParent *)(d->d), +	               p0.x, roomSize.y - p0.y, +	               p1.x, roomSize.y - p1.y, +	               (double)width, +	               wDrawGetRGB(color), +	               lineOpt); +} + +/** + * Svg draw arc + * + * \param  d		  A drawCmd_p to process. + * \param  p		  A coOrd to process. + * \param  r		  A DIST_T to process. + * \param  angle0	  The angle 0. + * \param  angle1	  The first angle. + * \param  drawCenter The draw center. + * \param  width	  The width. + * \param  color	  The color. + */ + +static void SvgDrawArc( +        drawCmd_p d, +        coOrd p, +        DIST_T r, +        ANGLE_T angle0, +        ANGLE_T angle1, +        BOOL_T drawCenter, +        wDrawWidth width, +        wDrawColor color) +{ +	unsigned lineOpt = SvgDrawGetLineStyle(d); +	wDrawWidth w = (width >= MINIMUMLINEWIDTH ? width : svgLineWidth[width]); + +	if (angle1 >= 360.0) { +		SvgCircleCommand((SVGParent *)(d->d), +		                 p.x, +		                 roomSize.y - p.y, +		                 r, +		                 w, +		                 wDrawGetRGB(color), +		                 false, +		                 lineOpt); +	} else { +		SvgArcCommand((SVGParent *)(d->d), +		              p.x, +		              roomSize.y-p.y, +		              r, +		              angle0, +		              angle1, +		              drawCenter, +		              w, +		              wDrawGetRGB(color), +		              lineOpt); +	} + +} + +/** + * Svg draw string. Perform conversion to UTF-8 if required. + * + * \param 		   d	    A drawCmd_p to process. + * \param 		   p	    position of text + * \param 		   a	    text angle + * \param [in,out] s	    the string + * \param 		   fp	    font definition (ignored) + * \param 		   fontSize Size of the font. + * \param 		   color    color. + */ + +static void SvgDrawString( +        drawCmd_p d, +        coOrd p, +        ANGLE_T a, +        char * s, +        wFont_p fp, +        FONTSIZE_T fontSize, +        wDrawColor color) +{ +	char *text = MyStrdup(s); + +#ifdef UTFCONVERT +	text = Convert2UTF8(text); +#endif // UTFCONVERT + +	SvgTextCommand((SVGParent *)(d->d), +	               p.x, +	               roomSize.y - p.y, +	               fontSize, +	               wDrawGetRGB(color), +	               text); + +	MyFree(text); +} + +/** + * Svg draw bitmap + * + * \param  d	 A drawCmd_p to process. + * \param  p	 A coOrd to process. + * \param  bm    The bm. + * \param  color The color. + */ + +static void SvgDrawBitmap( +        drawCmd_p d, +        coOrd p, +        wDrawBitMap_p bm, +        wDrawColor color) +{ +} + +/** + * Svg draw fill polygon + * + * \param 		   d		 A drawCmd_p to process. + * \param 		   cnt		 Number of points in polyline. + * \param [in,out] pts		 the coordinates + * \param [in,out] pointer   If non-null, the pointer. + * \param 		   color	 color. + * \param 		   width	 line width. + * \param 		   fillStyle fill style. + */ + +static void SvgDrawFillPoly( +        drawCmd_p d, +        int cnt, +        coOrd * pts, +        int * pointer, +        wDrawColor color, wDrawWidth width, drawFill_e fillStyle) +{ +	int i; +	double *points = malloc((cnt + 1) * 2 * sizeof(double)); +	CHECK( points ); + +	unsigned lineOpt = SvgDrawGetLineStyle(d); + +	for (i = 0; i < cnt; i++) { +		points[i * 2] = pts[i].x; +		points[i * 2 + 1] = roomSize.y - pts[i].y; +	} + +	if (fillStyle == DRAW_CLOSED || fillStyle == DRAW_FILL) { +		points[i * 2] = points[0]; +		points[i * 2 + 1] = points[1]; +		cnt++; +	} + +	width = (wDrawWidth)(width >= MINIMUMLINEWIDTH ? width : svgLineWidth[width]); +	SvgPolyLineCommand((SVGParent *)(d->d), cnt, points,  wDrawGetRGB(color), +	                   (double)width, fillStyle == DRAW_FILL, lineOpt); + +	free(points); +} + +/** + * Svg draw filled circle + * + * \param  d	  A drawCmd_p to process. + * \param  center The center. + * \param  radius The radius. + * \param  color  The fill color. + */ + +static void SvgDrawFillCircle(drawCmd_p d, coOrd center, DIST_T radius, +                              wDrawColor color) +{ +	SvgCircleCommand((SVGParent *)(d->d), +	                 center.x, +	                 roomSize.y - center.y, +	                 radius, +	                 0, +	                 wDrawGetRGB(color), +	                 true, +	                 0); +} + +/** + * Svg draw rectangle + * + * \param  d	   A drawCmd_p to process. + * \param  corner1 The first corner. + * \param  corner2 The second corner. + * \param  color   The color. + * \param  pattern Specifies the pattern. + */ + +static void +SvgDrawRectangle(drawCmd_p d, coOrd corner1, coOrd corner2, wDrawColor color, +                 drawFill_e fillOpt) +{ +	SvgRectCommand((SVGParent *)(d->d), +	               corner1.x, roomSize.y - corner1.y, +	               corner2.x, roomSize.y - corner2.y, +	               wDrawGetRGB(color), +	               fillOpt); +} + +static drawFuncs_t svgDrawFuncs = { +	SvgDrawLine, +	SvgDrawArc, +	SvgDrawString, +	SvgDrawBitmap, +	SvgDrawFillPoly, +	SvgDrawFillCircle, +	SvgDrawRectangle +}; + +static drawCmd_t svgD = { +	NULL, &svgDrawFuncs, 0, 1.0, 0.0, {0.0,0.0}, {0.0,0.0}, Pix2CoOrd, CoOrd2Pix, 100.0 +}; + +/** + * Creates valid identifier from a string. Whitespaces are removed + * and characters are prepended to make sure the i starts with + * valid chars. + * https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/id + * + * \param [in,out] base the base for the id. + * + * \returns Null if it fails, else the new valid identifier. + */ + +static char * +CreateValidId(char *base) +{ +	const char *idHead = "id"; +	char *out = MyMalloc(strlen(idHead) + strlen(base) + 1); +	char *tmp; +	int j; + +	strcpy(out, idHead); +	j = strlen(out); + +	for (unsigned int i = 0; i < strlen(base); i++) { +		if (isblank(base[i])) { +			i++; +		} else { +			out[j++] = base[i]; +		} +	} + +	out[j] = '\0'; + +	// strip off the extension +	tmp = strchr(out, '.'); +	if (tmp) { +		*tmp = '\0'; +	} +	return (out); +} + +/** + * get a valid identifier for SVG export + * + * \returns Null if it fails, else a pointer to a char. + */ + +static char * SvgGetId(void) +{ +	char *fileName = GetLayoutFilename(); +	char *id = NULL; + +	if (fileName) { +		id = CreateValidId(fileName); +#ifdef UTFCONVERT +		id = Convert2UTF8(id); +#endif +	} + +	return (id); +} + +/** + * Set title for SVG file + * The first title line of the design is used and stored in the SVG file + * + * \param  d A drawCmd_p to process. + */ + +static void SvgSetTitle(drawCmd_p d) +{ +	char *tmp = GetLayoutTitle(); +	char *title; + +	if (tmp) { +		title = MyStrdup(tmp); +#ifdef UTFCONVERT +		title = Convert2UTF8(title); +#endif +		SvgAddTitle((SVGParent *)(d->d), title); +		MyFree(title); +	} + +} + +/** + * Executes the export tracks to SVG operation + * + * \param 		   cnt	    Number of filenames, has to be 1 + * \param [in]     fileName filename of the export file. + * \param [in]     data	    If non-null, the data. + * + * \returns TRUE on success, FALSE on failure + */ + +static int DoExportSVGTracks( +        int cnt, +        char ** fileName, +        void * data) +{ +	DynString command = NaS; +	SVGDocument *svg; +	SVGParent *svgData; +	BOOL_T all = (selectedTrackCount == 0); +	char *id; + +	CHECK(fileName != NULL); +	CHECK(cnt == 1); + +	SetCLocale(); +	GetLayoutRoomSize(&roomSize); + +	SetCurrentPath(SVGPATHKEY, fileName[ 0 ]); + +	svg = SvgCreateDocument(); +	id = SvgGetId(); +	svgData = SvgPrologue(svg, id, 0, 0.0, 0.0, roomSize.x, roomSize.y); +	MyFree(id); + +	wSetCursor(mainD.d, wCursorWait); +//    time(&clock); + +	svgD.d = (wDraw_p)svgData; + +	DrawSelectedTracks(&svgD,all); +	SvgAddCSSStyle((SVGParent *)svgD.d); +	SvgSetTitle(&svgD);						// make sure this is the last element + +	if (!SvgSaveFile(svg, fileName[0])) { +		NoticeMessage(MSG_OPEN_FAIL, _("Cancel"), NULL, "SVG", fileName[0], +		              strerror(errno)); + +		SvgDestroyDocument(svg); +		wSetCursor(mainD.d, wCursorNormal); +		SetUserLocale(); +		return FALSE; +	} +	SvgDestroyDocument(svg); +	Reset();	/**<TODO: was tut das? */ +	wSetCursor(mainD.d, wCursorNormal); +	SetUserLocale(); +	return TRUE; +} + +/** + * Create and show the dialog for selecting the DXF export filename + */ + +void DoExportSVG(void * unused) +{ +	// CHECK(selectedTrackCount > 0); + +	if (exportSVGFile_fs == NULL) +		exportSVGFile_fs = wFilSelCreate(mainW, FS_SAVE, 0, _("Export to SVG"), +		                                 sSVGFilePattern, DoExportSVGTracks, NULL); + +	wFilSelect(exportSVGFile_fs, GetCurrentPath(SVGPATHKEY)); +} + +  | 
