Initial commit

Made-with: Cursor
This commit is contained in:
lyf
2026-03-12 17:51:30 +08:00
commit 79102a18fb
1507 changed files with 480854 additions and 0 deletions

View 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", &center))
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", &center);
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]);
}