Initial commit
Made-with: Cursor
This commit is contained in:
531
astral-service/static/lib/libredwg/examples/dwg2svg2.c
Normal file
531
astral-service/static/lib/libredwg/examples/dwg2svg2.c
Normal file
@@ -0,0 +1,531 @@
|
||||
/*****************************************************************************/
|
||||
/* LibreDWG - free implementation of the DWG file format */
|
||||
/* */
|
||||
/* Copyright (C) 2013-2020,2023 Free Software Foundation, Inc. */
|
||||
/* */
|
||||
/* This library is free software, licensed under the terms of the GNU */
|
||||
/* General Public License as published by the Free Software Foundation, */
|
||||
/* either version 3 of the License, or (at your option) any later version. */
|
||||
/* You should have received a copy of the GNU General Public License */
|
||||
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* dwg2svg2.c: convert a DWG to SVG via the API.
|
||||
if there are paperspace entities, only output them. else all modelspace
|
||||
entities.
|
||||
* written by Gaganjyot Singh
|
||||
* modified by Reini Urban
|
||||
*/
|
||||
|
||||
#include "../src/config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#ifdef ENABLE_MIMALLOC
|
||||
# include <mimalloc-override.h>
|
||||
#endif
|
||||
|
||||
#include <dwg.h>
|
||||
#include <dwg_api.h>
|
||||
#include "geom.h"
|
||||
|
||||
static int opts = 0;
|
||||
static dwg_data g_dwg;
|
||||
static double model_xmin, model_ymin;
|
||||
static double page_width, page_height, scale;
|
||||
|
||||
static int
|
||||
usage (void)
|
||||
{
|
||||
printf ("\nUsage: dwg2svg2 [-v[0-9]] DWGFILE\n");
|
||||
return 1;
|
||||
}
|
||||
static int
|
||||
opt_version (void)
|
||||
{
|
||||
printf ("dwg2svg2 %s\n", PACKAGE_VERSION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
help (void)
|
||||
{
|
||||
printf ("\nUsage: dwg2svg2 [OPTION]... DWGFILE >file.svg\n");
|
||||
printf ("Example to use the DWG api\n"
|
||||
"\n");
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
printf (" -v[0-9], --verbose [0-9] verbosity\n");
|
||||
printf (" --help display this help and exit\n");
|
||||
printf (" --version output version information and exit\n"
|
||||
"\n");
|
||||
#else
|
||||
printf (" -v[0-9] verbosity\n");
|
||||
printf (" -h display this help and exit\n");
|
||||
printf (" -i output version information and exit\n"
|
||||
"\n");
|
||||
#endif
|
||||
printf ("GNU LibreDWG online manual: "
|
||||
"<https://www.gnu.org/software/libredwg/>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define log_if_error(msg) \
|
||||
if (error) \
|
||||
{ \
|
||||
fprintf (stderr, "ERROR: %s", msg); \
|
||||
exit (1); \
|
||||
}
|
||||
#define log_error(msg) \
|
||||
{ \
|
||||
fprintf (stderr, "ERROR: %s", msg); \
|
||||
exit (1); \
|
||||
}
|
||||
#define dynget(obj, name, field, var) \
|
||||
if (!dwg_dynapi_entity_value (obj, "" name, "" field, var, NULL)) \
|
||||
{ \
|
||||
fprintf (stderr, "ERROR: %s.%s", name, field); \
|
||||
exit (1); \
|
||||
}
|
||||
#define dynget_utf8(obj, name, field, var) \
|
||||
if (!dwg_dynapi_entity_utf8text (obj, "" name, "" field, var, &isnew, \
|
||||
NULL)) \
|
||||
{ \
|
||||
fprintf (stderr, "ERROR: %s.%s", name, field); \
|
||||
exit (1); \
|
||||
}
|
||||
|
||||
static double
|
||||
transform_X (double x)
|
||||
{
|
||||
return x - model_xmin;
|
||||
}
|
||||
|
||||
static double
|
||||
transform_Y (double y)
|
||||
{
|
||||
return page_height - (y - model_ymin);
|
||||
}
|
||||
|
||||
static void output_SVG (dwg_data *dwg);
|
||||
|
||||
static int
|
||||
test_SVG (char *filename)
|
||||
{
|
||||
int error;
|
||||
|
||||
memset (&g_dwg, 0, sizeof (dwg_data));
|
||||
g_dwg.opts = opts;
|
||||
error = dwg_read_file (filename, &g_dwg);
|
||||
if (error < DWG_ERR_CRITICAL)
|
||||
output_SVG (&g_dwg);
|
||||
|
||||
dwg_free (&g_dwg);
|
||||
/* This value is the return value for `main',
|
||||
so clamp it to either 0 or 1. */
|
||||
return error < DWG_ERR_CRITICAL ? 0 : 1;
|
||||
}
|
||||
|
||||
static void
|
||||
output_TEXT (dwg_object *obj)
|
||||
{
|
||||
int error, index;
|
||||
dwg_point_2d ins_pt;
|
||||
Dwg_Entity_TEXT *text;
|
||||
char *text_value;
|
||||
double fontsize;
|
||||
const Dwg_Version_Type dwg_version = obj->parent->header.version;
|
||||
int isnew = 0;
|
||||
|
||||
index = dwg_object_get_index (obj, &error);
|
||||
log_if_error ("object_get_index");
|
||||
text = dwg_object_to_TEXT (obj);
|
||||
if (!text)
|
||||
log_error ("dwg_object_to_TEXT");
|
||||
dynget_utf8 (text, "TEXT", "text_value", &text_value);
|
||||
dynget (text, "TEXT", "ins_pt", &ins_pt);
|
||||
dynget (text, "TEXT", "height", &fontsize);
|
||||
|
||||
printf ("\t<text id=\"dwg-object-%d\" x=\"%f\" y=\"%f\" "
|
||||
"font-family=\"Verdana\" font-size=\"%f\" fill=\"blue\">%s</text>\n",
|
||||
index, transform_X (ins_pt.x), transform_Y (ins_pt.y), fontsize,
|
||||
text_value);
|
||||
|
||||
if (text_value && isnew)
|
||||
free (text_value);
|
||||
}
|
||||
|
||||
static void
|
||||
output_LINE (dwg_object *obj)
|
||||
{
|
||||
int error, index;
|
||||
Dwg_Entity_LINE *line;
|
||||
dwg_point_3d start, end;
|
||||
|
||||
index = dwg_object_get_index (obj, &error);
|
||||
log_if_error ("object_get_index");
|
||||
line = dwg_object_to_LINE (obj);
|
||||
if (!line)
|
||||
log_error ("dwg_object_to_LINE");
|
||||
if (!dwg_get_LINE (line, "start", &start))
|
||||
log_error ("LINE.start");
|
||||
if (!dwg_get_LINE (line, "end", &end))
|
||||
log_error ("LINE.end");
|
||||
|
||||
printf ("\t<path id=\"dwg-object-%d\" d=\"M %f,%f %f,%f\" "
|
||||
"style=\"fill:none;stroke:blue;stroke-width:0.1px\" />\n",
|
||||
index, transform_X (start.x), transform_Y (start.y),
|
||||
transform_X (end.x), transform_Y (end.y));
|
||||
}
|
||||
|
||||
static void
|
||||
output_CIRCLE (dwg_object *obj)
|
||||
{
|
||||
Dwg_Entity_CIRCLE *circle;
|
||||
int error, index;
|
||||
double radius;
|
||||
dwg_point_3d center;
|
||||
|
||||
index = dwg_object_get_index (obj, &error);
|
||||
log_if_error ("object_get_index");
|
||||
circle = dwg_object_to_CIRCLE (obj);
|
||||
if (!circle)
|
||||
log_error ("dwg_object_to_CIRCLE");
|
||||
if (!dwg_get_CIRCLE (circle, "center", ¢er))
|
||||
log_error ("CIRCLE.center");
|
||||
if (!dwg_get_CIRCLE (circle, "radius", &radius))
|
||||
log_error ("CIRCLE.radius");
|
||||
|
||||
printf ("\t<circle id=\"dwg-object-%d\" cx=\"%f\" cy=\"%f\" r=\"%f\" "
|
||||
"fill=\"none\" stroke=\"blue\" stroke-width=\"0.1px\" />\n",
|
||||
index, transform_X (center.x), transform_Y (center.y), radius);
|
||||
}
|
||||
|
||||
static void
|
||||
output_ARC (dwg_object *obj)
|
||||
{
|
||||
Dwg_Entity_ARC *arc;
|
||||
int error, index;
|
||||
double radius, start_angle, end_angle;
|
||||
dwg_point_3d center;
|
||||
double x_start, y_start, x_end, y_end;
|
||||
int large_arc;
|
||||
|
||||
index = dwg_object_get_index (obj, &error);
|
||||
log_if_error ("object_get_index");
|
||||
arc = dwg_object_to_ARC (obj);
|
||||
if (!arc)
|
||||
log_error ("dwg_object_to_ARC");
|
||||
dynget (arc, "ARC", "radius", &radius);
|
||||
dynget (arc, "ARC", "center", ¢er);
|
||||
dynget (arc, "ARC", "start_angle", &start_angle);
|
||||
dynget (arc, "ARC", "end_angle", &end_angle);
|
||||
|
||||
x_start = center.x + radius * cos (start_angle);
|
||||
y_start = center.y + radius * sin (start_angle);
|
||||
x_end = center.x + radius * cos (end_angle);
|
||||
y_end = center.y + radius * sin (end_angle);
|
||||
// Assuming clockwise arcs.
|
||||
large_arc = (end_angle - start_angle < M_PI) ? 0 : 1;
|
||||
|
||||
printf ("\t<path id=\"dwg-object-%d\" d=\"M %f,%f A %f,%f 0 %d 0 %f,%f\" "
|
||||
"fill=\"none\" stroke=\"blue\" stroke-width=\"%f\" />\n",
|
||||
index, transform_X (x_start), transform_Y (y_start), radius, radius,
|
||||
large_arc, transform_X (x_end), transform_Y (y_end), 0.1);
|
||||
}
|
||||
|
||||
static void
|
||||
output_INSERT (dwg_object *obj)
|
||||
{
|
||||
int index, error;
|
||||
BITCODE_RL abs_ref;
|
||||
double rotation;
|
||||
dwg_ent_insert *insert;
|
||||
dwg_point_3d ins_pt, _scale;
|
||||
dwg_handle *obj_handle, *ins_handle;
|
||||
Dwg_Data *dwg;
|
||||
|
||||
insert = dwg_object_to_INSERT (obj);
|
||||
if (!insert)
|
||||
log_error ("dwg_object_to_INSERT");
|
||||
dwg = obj->parent;
|
||||
index = dwg_object_get_index (obj, &error);
|
||||
log_if_error ("object_get_index");
|
||||
dynget (insert, "INSERT", "rotation", &rotation);
|
||||
dynget (insert, "INSERT", "ins_pt", &ins_pt);
|
||||
dynget (insert, "INSERT", "scale", &_scale);
|
||||
obj_handle = dwg_object_get_handle (obj, &error);
|
||||
log_if_error ("get_handle");
|
||||
if (!insert->block_header)
|
||||
log_error ("insert->block_header");
|
||||
abs_ref = insert->block_header->absolute_ref;
|
||||
|
||||
if (insert->block_header->handleref.code == 5 || dwg->header.version < R_13)
|
||||
{
|
||||
printf ("\t<use id=\"dwg-object-%d\" transform=\"translate(%f %f) "
|
||||
"rotate(%f) scale(%f %f)\" xlink:href=\"#symbol-%X\" /><!-- "
|
||||
"block_header->handleref: " FORMAT_H " -->\n",
|
||||
index, transform_X (ins_pt.x), transform_Y (ins_pt.y),
|
||||
(180.0 / M_PI) * rotation, _scale.x, _scale.y, abs_ref,
|
||||
ARGS_H (*obj_handle));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("\n\n<!-- WRONG INSERT(" FORMAT_H ") -->\n",
|
||||
ARGS_H (*obj_handle));
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
output_object (dwg_object *obj)
|
||||
{
|
||||
int i = 0;
|
||||
if (!obj)
|
||||
{
|
||||
fprintf (stderr, "object is NULL\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dwg_object_get_fixedtype (obj) == DWG_TYPE_INSERT)
|
||||
{
|
||||
i++;
|
||||
output_INSERT (obj);
|
||||
}
|
||||
else if (dwg_object_get_fixedtype (obj) == DWG_TYPE_LINE)
|
||||
{
|
||||
i++;
|
||||
output_LINE (obj);
|
||||
}
|
||||
else if (dwg_object_get_fixedtype (obj) == DWG_TYPE_CIRCLE)
|
||||
{
|
||||
i++;
|
||||
output_CIRCLE (obj);
|
||||
}
|
||||
else if (dwg_object_get_fixedtype (obj) == DWG_TYPE_TEXT)
|
||||
{
|
||||
i++;
|
||||
output_TEXT (obj);
|
||||
}
|
||||
else if (dwg_object_get_fixedtype (obj) == DWG_TYPE_ARC)
|
||||
{
|
||||
i++;
|
||||
output_ARC (obj);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int
|
||||
output_BLOCK_HEADER (dwg_object_ref *ref)
|
||||
{
|
||||
dwg_object *hdr, *obj;
|
||||
dwg_obj_block_header *_hdr;
|
||||
int error;
|
||||
BITCODE_RL abs_ref;
|
||||
char *name;
|
||||
int i = 0;
|
||||
|
||||
if (!ref)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Empty BLOCK."
|
||||
" Could not output an SVG symbol for this BLOCK_HEADER\n");
|
||||
return 0;
|
||||
}
|
||||
hdr = dwg_ref_get_object (ref, &error);
|
||||
if (!hdr || error)
|
||||
{
|
||||
abs_ref = dwg_ref_get_absref (ref, &error);
|
||||
fprintf (stderr, "Failed to resolve BLOCK handle %X.\n",
|
||||
(unsigned)abs_ref);
|
||||
return 0;
|
||||
}
|
||||
abs_ref = dwg_ref_get_absref (ref, &error);
|
||||
|
||||
_hdr = dwg_object_to_BLOCK_HEADER (hdr);
|
||||
if (_hdr)
|
||||
{
|
||||
i++;
|
||||
dynget (_hdr, "BLOCK_HEADER", "name", &name);
|
||||
// name = dwg_obj_block_header_get_name (_hdr, &error);
|
||||
printf ("\t<g id=\"symbol-%X\" >\n\t\t<!-- %s -->\n",
|
||||
abs_ref ? abs_ref : 0, name ? name : "");
|
||||
if (name != NULL && name != _hdr->name
|
||||
&& hdr->parent->header.version >= R_2007)
|
||||
free (name);
|
||||
}
|
||||
else
|
||||
printf ("\t<g id=\"symbol-%X\" >\n\t\t<!-- ? -->\n",
|
||||
abs_ref ? abs_ref : 0);
|
||||
|
||||
obj = get_first_owned_entity (hdr);
|
||||
while (obj)
|
||||
{
|
||||
i += output_object (obj);
|
||||
obj = get_next_owned_entity (hdr, obj);
|
||||
}
|
||||
printf ("\t</g>\n");
|
||||
return i;
|
||||
}
|
||||
|
||||
static void
|
||||
output_SVG (dwg_data *dwg)
|
||||
{
|
||||
unsigned int i, num_hdr_objs;
|
||||
int error;
|
||||
dwg_obj_block_control *_ctrl;
|
||||
dwg_object_ref *hdr;
|
||||
dwg_object_ref **hdr_refs;
|
||||
dwg_object_ref *ms = dwg_model_space_ref (dwg);
|
||||
dwg_object_ref *ps = dwg_paper_space_ref (dwg);
|
||||
|
||||
double dx = dwg_model_x_max (dwg) - dwg_model_x_min (dwg);
|
||||
double dy = dwg_model_y_max (dwg) - dwg_model_y_min (dwg);
|
||||
double pdx = dwg->header_vars.PLIMMAX.x - dwg->header_vars.PLIMMIN.x;
|
||||
double pdy = dwg->header_vars.PLIMMAX.y - dwg->header_vars.PLIMMIN.y;
|
||||
double scale_x = dx / (pdx == 0.0 ? 1.0 : pdx);
|
||||
double scale_y = dy / (pdy == 0.0 ? 1.0 : pdy);
|
||||
scale = 25.4 / 72.0; // pt:mm TODO
|
||||
|
||||
model_xmin = dwg_model_x_min (dwg);
|
||||
model_ymin = dwg_model_y_min (dwg);
|
||||
page_width = dx;
|
||||
page_height = dy;
|
||||
scale *= (scale_x > scale_y ? scale_x : scale_y);
|
||||
|
||||
_ctrl = dwg_block_control (dwg);
|
||||
hdr_refs = dwg_obj_block_control_get_block_headers (_ctrl, &error);
|
||||
log_if_error ("block_control_get_block_headers");
|
||||
num_hdr_objs = dwg_obj_block_control_get_num_entries (_ctrl, &error);
|
||||
log_if_error ("block_control_get_num_entries");
|
||||
|
||||
printf ("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
|
||||
"<svg\n"
|
||||
" xmlns:svg=\"http://www.w3.org/2000/svg\"\n"
|
||||
" xmlns=\"http://www.w3.org/2000/svg\"\n"
|
||||
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
|
||||
" version=\"1.1\"\n"
|
||||
" width=\"%f\"\n"
|
||||
" height=\"%f\"\n"
|
||||
">\n",
|
||||
page_width, page_height);
|
||||
|
||||
printf ("\t<defs>\n");
|
||||
for (i = 0; i < num_hdr_objs; i++)
|
||||
{
|
||||
hdr = hdr_refs[i];
|
||||
if (hdr == ms || hdr == ps)
|
||||
continue;
|
||||
output_BLOCK_HEADER (hdr_refs[i]);
|
||||
}
|
||||
printf ("\t</defs>\n");
|
||||
|
||||
if (ps)
|
||||
i = output_BLOCK_HEADER (ps);
|
||||
if (!ps || !i)
|
||||
output_BLOCK_HEADER (ms);
|
||||
free (hdr_refs);
|
||||
|
||||
printf ("</svg>\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int i = 1;
|
||||
int c;
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
int option_index = 0;
|
||||
static struct option long_options[]
|
||||
= { { "verbose", 1, &opts, 1 }, // optional
|
||||
{ "help", 0, 0, 0 },
|
||||
{ "version", 0, 0, 0 },
|
||||
{ NULL, 0, NULL, 0 } };
|
||||
#endif
|
||||
|
||||
if (argc < 2)
|
||||
return usage ();
|
||||
|
||||
while
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
((c = getopt_long (argc, argv, ":v::h", long_options, &option_index))
|
||||
!= -1)
|
||||
#else
|
||||
((c = getopt (argc, argv, ":v::hi")) != -1)
|
||||
#endif
|
||||
{
|
||||
if (c == -1)
|
||||
break;
|
||||
switch (c)
|
||||
{
|
||||
case ':': // missing arg
|
||||
if (optarg && !strcmp (optarg, "v"))
|
||||
{
|
||||
opts = 1;
|
||||
break;
|
||||
}
|
||||
fprintf (stderr, "%s: option '-%c' requires an argument\n", argv[0],
|
||||
optopt);
|
||||
break;
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
case 0:
|
||||
/* This option sets a flag */
|
||||
if (!strcmp (long_options[option_index].name, "verbose"))
|
||||
{
|
||||
if (opts < 0 || opts > 9)
|
||||
return usage ();
|
||||
# if defined(USE_TRACING) && defined(HAVE_SETENV)
|
||||
{
|
||||
char v[2];
|
||||
*v = opts + '0';
|
||||
*(v + 1) = 0;
|
||||
setenv ("LIBREDWG_TRACE", v, 1);
|
||||
}
|
||||
# endif
|
||||
break;
|
||||
}
|
||||
if (!strcmp (long_options[option_index].name, "version"))
|
||||
return opt_version ();
|
||||
if (!strcmp (long_options[option_index].name, "help"))
|
||||
return help ();
|
||||
break;
|
||||
#else
|
||||
case 'i':
|
||||
return opt_version ();
|
||||
#endif
|
||||
case 'v': // support -v3 and -v
|
||||
i = (optind > 0 && optind < argc) ? optind - 1 : 1;
|
||||
if (!memcmp (argv[i], "-v", 2))
|
||||
{
|
||||
opts = argv[i][2] ? argv[i][2] - '0' : 1;
|
||||
}
|
||||
if (opts < 0 || opts > 9)
|
||||
return usage ();
|
||||
#if defined(USE_TRACING) && defined(HAVE_SETENV)
|
||||
{
|
||||
char v[2];
|
||||
*v = opts + '0';
|
||||
*(v + 1) = 0;
|
||||
setenv ("LIBREDWG_TRACE", v, 1);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 'h':
|
||||
return help ();
|
||||
case '?':
|
||||
fprintf (stderr, "%s: invalid option '-%c' ignored\n", argv[0],
|
||||
optopt);
|
||||
break;
|
||||
default:
|
||||
return usage ();
|
||||
}
|
||||
}
|
||||
i = optind;
|
||||
if (i >= argc)
|
||||
return usage ();
|
||||
|
||||
return test_SVG (argv[i]);
|
||||
}
|
||||
Reference in New Issue
Block a user