summaryrefslogtreecommitdiff
path: root/app/bin/dxfformat.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/bin/dxfformat.c')
-rw-r--r--app/bin/dxfformat.c368
1 files changed, 368 insertions, 0 deletions
diff --git a/app/bin/dxfformat.c b/app/bin/dxfformat.c
new file mode 100644
index 0000000..4e1c775
--- /dev/null
+++ b/app/bin/dxfformat.c
@@ -0,0 +1,368 @@
+/** \file dxfformat.c
+* Formating of DXF commands and parameters
+*/
+
+/* XTrkCad - Model Railroad CAD
+* Copyright (C)2017 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#include <dynstring.h>
+#include "dxfformat.h"
+
+extern char *sProdNameUpper;
+extern long units; /**< meaning is 0 = English, 1 = metric */
+
+static char *dxfDimensionDefaults[][3] = { /**< default values for dimensions, English, metric and DXF variable name */
+ { "1.0", "25.0", "$DIMTXT" },
+ { "0.8", "20.0", "$DIMASZ"}
+};
+
+/**
+* Build and format layer name. The name is created by appending the layer number
+* to the basic layer name.
+*
+* \param result OUT buffer for result
+* \param name IN base part of name
+* \param layer IN layer number
+*/
+
+void DxfLayerName(DynString *result, char *name, int layer)
+{
+ DynStringPrintf(result, DXF_INDENT "8\n%s%d\n", name, layer);
+}
+
+/**
+* Build and format a position. If it specifies a point the value
+* is assumed to be in inches and will be converted to millimeters
+* if the metric system is active.
+* If it is an angle (group codes 50 to 59) it is not converted.
+*
+* \param result OUT buffer for result
+* \param type IN type of position following DXF specs
+* \param value IN position
+*/
+
+void DxfFormatPosition(DynString *result, int type, double value)
+{
+ if (units == 1)
+ {
+ if( type < 50 || type > 58 )
+ value *= 25.4;
+ }
+
+ DynStringPrintf(result, DXF_INDENT "%d\n%0.6f\n", type, value);
+}
+
+/**
+* Build and format the line style definition
+*
+* \param result OUT buffer for result
+* \param type IN line style TRUE for dashed, FALSE for solid lines
+*/
+
+void DxfLineStyle(DynString *result, int isDashed)
+{
+ DynStringPrintf(result, DXF_INDENT "6\n%s\n",
+ (isDashed ? "DASHED" : "CONTINUOUS"));
+}
+
+/**
+* Build and format layer name. The name is created by appending the layer number
+* to the basic layer name. The result is appended to the existing result buffer.
+*
+* \param output OUT buffer for result
+* \param basename IN base part of name
+* \param layer IN layer number
+*/
+
+static void
+DxfAppendLayerName(DynString *output, int layer)
+{
+ DynString formatted = NaS;
+ DynStringMalloc(&formatted, 0);
+ DxfLayerName(&formatted, sProdNameUpper, layer);
+ DynStringCatStr(output, &formatted);
+ DynStringFree(&formatted);
+}
+
+/**
+* Build and format a position. The result is appended to the existing result buffer.
+*
+* \param output OUT buffer for result
+* \param type IN type of position following DXF specs
+* \param value IN position
+*/
+
+static void
+DxfAppendPosition(DynString *output, int type, double value)
+{
+ DynString formatted = NaS;
+ DynStringMalloc(&formatted, 0);
+ DxfFormatPosition(&formatted, type, value);
+ DynStringCatStr(output, &formatted);
+ DynStringFree(&formatted);
+}
+
+/**
+* Build and format the line style definition. The result is appended to the existing result buffer.
+*
+* \param result OUT buffer for result
+* \param type IN line style TRUE for dashed, FALSE for solid lines
+*/
+
+static void
+DxfAppendLineStyle(DynString *output, int style)
+{
+ DynString formatted = NaS;
+ DynStringMalloc(&formatted, 0);
+ DxfLineStyle(&formatted, style);
+ DynStringCatStr(output, &formatted);
+ DynStringFree(&formatted);
+}
+
+/**
+* Format a complete LINE command after DXF spec
+*
+* \param result OUT buffer for the completed command
+* \param layer IN number part of the layer
+* \param x0, y0 IN first endpoint
+* \param x1, y1 IN second endpoint
+* \param style IN line style, TRUE for dashed, FALSE for continuous
+*/
+
+void
+DxfLineCommand(DynString *result, int layer, double x0,
+ double y0, double x1, double y1, int style)
+{
+ DynStringCatCStr(result, DXF_INDENT "0\nLINE\n");
+ DxfAppendLayerName(result, layer);
+ DxfAppendPosition(result, 10, x0);
+ DxfAppendPosition(result, 20, y0);
+ DxfAppendPosition(result, 11, x1);
+ DxfAppendPosition(result, 21, y1);
+ DxfAppendLineStyle(result, style);
+}
+
+/**
+* Format a complete CIRCLE command after DXF spec
+*
+* \param result OUT buffer for the completed command
+* \param layer IN number part of the layer
+* \param x, y IN center point
+* \param r IN radius
+* \param style IN line style, TRUE for dashed, FALSE for continuous
+*/
+
+void
+DxfCircleCommand(DynString *result, int layer, double x,
+ double y, double r, int style)
+{
+ DynStringCatCStr(result, DXF_INDENT "0\nCIRCLE\n");
+ DxfAppendPosition(result, 10, x);
+ DxfAppendPosition(result, 20, y);
+ DxfAppendPosition(result, 40, r);
+ DxfAppendLayerName(result, layer);
+ DxfAppendLineStyle(result, style);
+}
+
+/**
+* Format a complete ARC command after DXF spec
+*
+* \param result OUT buffer for the completed command
+* \param layer IN number part of the layer
+* \param x, y IN center point
+* \param r IN radius
+* \param a0 IN starting angle
+* \param a1 IN ending angle
+* \param style IN line style, TRUE for dashed, FALSE for continuous
+*/
+
+void
+DxfArcCommand(DynString *result, int layer, double x, double y,
+ double r, double a0, double a1, int style)
+{
+ DynStringCatCStr(result, DXF_INDENT "0\nARC\n");
+ DxfAppendPosition(result, 10, x);
+ DxfAppendPosition(result, 20, y);
+ DxfAppendPosition(result, 40, r);
+ DxfAppendPosition(result, 50, a0);
+ DxfAppendPosition(result, 51, a0+a1);
+ DxfAppendLayerName(result, layer);
+ DxfAppendLineStyle(result, style);
+}
+
+/**
+* Format a complete TEXT command after DXF spec
+*
+* \param result OUT buffer for the completed command
+* \param layer IN number part of the layer
+* \param x, y IN text position
+* \param size IN font size
+* \param text IN text
+*/
+
+void
+DxfTextCommand(DynString *result, int layer, double x,
+ double y, double size, char *text)
+{
+ DynStringCatCStr(result, DXF_INDENT "0\nTEXT\n");
+ DynStringCatCStrs(result, DXF_INDENT "1\n", text, "\n", NULL);
+ DxfAppendPosition(result, 10, x);
+ DxfAppendPosition(result, 20, y);
+ DxfAppendPosition(result, 40, size/72.0);
+ DxfAppendLayerName(result, layer);
+}
+
+/**
+ * Append the header lines needed to define the measurement system. This includes the
+ * definition of the measurement system (metric or English) vie the $MEASUREMENT variable
+ * and the units i.e. inches for English and mm for metric.
+ *
+ * \PARAM result OUT buffer for the completed command
+ */
+
+void
+DxfUnits(DynString *result)
+{
+ char *value;
+ DynStringCatCStr(result, DXF_INDENT "9\n$MEASUREMENT\n 70\n");
+
+ if (units == 1) {
+ value = "1\n";
+ } else {
+ value = "0\n";
+ }
+
+ DynStringCatCStr(result, value);
+ DynStringCatCStr(result, DXF_INDENT "9\n$INSUNITS\n 70\n");
+
+ if (units == 1) {
+ value = "4\n";
+ } else {
+ value = "1\n";
+ }
+
+ DynStringCatCStr(result, value);
+}
+
+/**
+* Define a size of dimensions. The default values are taken from
+* static array dxfDimensionDefaults
+*
+* \PARAM result OUT the completed command is appended to this buffer
+* \PARAM dimension IN dimension variable to set
+*/
+
+void
+DxfDimensionSize(DynString *result, enum DXF_DIMENSIONS dimension )
+{
+ DynString formatted;
+ DynStringMalloc(&formatted, 0);
+
+ DynStringPrintf(&formatted,
+ DXF_INDENT "9\n%s\n 40\n%s\n",
+ dxfDimensionDefaults[dimension][2],
+ dxfDimensionDefaults[dimension][units]);
+
+ DynStringCatStr(result, &formatted);
+ DynStringFree(&formatted);
+}
+
+/**
+* Create the complete prologue for a DXF file. Includes the header section,
+* a table for line styles and a table for layers.
+*
+* \param result OUT buffer for the completed command
+* \param layerCount IN count of defined layers
+* \param x0, y0 IN minimum (left bottom) position
+* \param x1, y1 IN maximum (top right) position
+*/
+
+void
+DxfPrologue(DynString *result, int layerCount, double x0, double y0, double x1,
+ double y1)
+{
+ int i;
+ DynString layer = NaS;
+ DynStringMalloc(&layer, 0);
+ DynStringCatCStr(result, "\
+ 0\nSECTION\n\
+ 2\nHEADER\n\
+ 9\n$ACADVER\n 1\nAC1015\n");
+ DxfUnits(result);
+ DxfDimensionSize(result, DXF_DIMTEXTSIZE);
+ DxfDimensionSize(result, DXF_DIMARROWSIZE);
+
+ DynStringCatCStr(result, " 9\n$EXTMIN\n");
+ DxfAppendPosition(result, 10, x0);
+ DxfAppendPosition(result, 20, y0);
+ DynStringCatCStr(result, " 9\n$EXTMAX\n");
+ DxfAppendPosition(result, 10, x1);
+ DxfAppendPosition(result, 20, y1);
+ DynStringCatCStr(result, "\
+ 9\n$TEXTSTYLE\n 7\nSTANDARD\n\
+ 0\nENDSEC\n\
+ 0\nSECTION\n\
+ 2\nTABLES\n\
+ 0\nTABLE\n\
+ 2\nLTYPE\n\
+ 0\nLTYPE\n 2\nCONTINUOUS\n 70\n0\n\
+ 3\nSolid line\n\
+ 72\n65\n 73\n0\n 40\n0\n\
+ 0\nLTYPE\n 2\nDASHED\n 70\n0\n\
+ 3\n__ __ __ __ __ __ __ __ __ __ __ __ __ __ __\n\
+ 72\n65\n 73\n2\n 40\n0.15\n 49\n0.1\n 49\n-0.05\n\
+ 0\nLTYPE\n 2\nDOT\n 70\n0\n\
+ 3\n...............................................\n\
+ 72\n65\n 73\n2\n 40\n0.1\n 49\n0\n 49\n-0.05\n\
+ 0\nENDTAB\n\
+ 0\nTABLE\n\
+ 2\nLAYER\n\
+ 70\n0\n");
+
+ for (i = 0; i < layerCount; i++) {
+ DynStringPrintf(&layer,
+ DXF_INDENT"0\nLAYER\n 2\n%s%d\n 6\nCONTINUOUS\n 62\n7\n 70\n0\n",
+ sProdNameUpper, i + 1);
+ DynStringCatStr(result, &layer);
+ }
+
+ DynStringCatCStr(result, "\
+ 0\nENDTAB\n\
+ 0\nENDSEC\n\
+ 0\nSECTION\n\
+ 2\nENTITIES\n");
+}
+
+/**
+* Create the file footer for a DXF file. Closes the open section and places
+* an end-of-file marker
+*
+* \param result OUT buffer for the completed command
+*/
+
+void
+DxfEpilogue(DynString *result)
+{
+ DynStringCatCStr(result, DXF_INDENT "0\nENDSEC\n" DXF_INDENT "0\nEOF\n");
+}