第11章 - 实体与对象操作详解
第11章 - 实体与对象操作详解
11.1 实体分类
11.1.1 实体类型体系
LibreDWG中的实体按功能分类:
| 类别 | 实体类型 | 说明 |
|---|---|---|
| 基本几何 | LINE, POINT, CIRCLE, ARC, ELLIPSE | 简单几何图形 |
| 多段线 | POLYLINE_2D, POLYLINE_3D, LWPOLYLINE | 多顶点图形 |
| 曲线 | SPLINE, HELIX | 复杂曲线 |
| 文字 | TEXT, MTEXT, ATTRIB, ATTDEF | 文字标注 |
| 尺寸 | DIMENSION_* | 尺寸标注系列 |
| 填充 | HATCH, SOLID, TRACE | 填充图案 |
| 块引用 | INSERT, MINSERT | 块引用 |
| 三维 | 3DSOLID, BODY, REGION, MESH | 三维实体 |
| 图像 | IMAGE, WIPEOUT | 光栅图像 |
| 外部引用 | XREF | 外部引用 |
11.1.2 实体公共属性
所有实体共享的属性:
// 实体公共字段
typedef struct _dwg_object_entity {
// 拥有者和反应器
BITCODE_H ownerhandle;
BITCODE_BL num_reactors;
BITCODE_H *reactors;
// 扩展数据
BITCODE_H xdicobjhandle;
BITCODE_BL num_eed;
Dwg_Eed *eed;
// 图形属性
BITCODE_CMC color; // 颜色
BITCODE_BD ltype_scale; // 线型比例
BITCODE_RC lineweight; // 线宽
// 引用
BITCODE_H layer; // 图层
BITCODE_H ltype; // 线型
BITCODE_H plotstyle; // 打印样式
BITCODE_H material; // 材质
} Dwg_Object_Entity;
11.2 基本几何实体
11.2.1 LINE - 直线
#include <dwg.h>
#include <math.h>
// LINE结构
typedef struct _dwg_entity_LINE {
BITCODE_B z_is_zero; // Z坐标为零
BITCODE_3BD start; // 起点
BITCODE_3BD end; // 终点
BITCODE_BD thickness; // 厚度
BITCODE_BE extrusion; // 挤出方向
} Dwg_Entity_LINE;
// 操作函数
double line_length(Dwg_Entity_LINE *line)
{
double dx = line->end.x - line->start.x;
double dy = line->end.y - line->start.y;
double dz = line->end.z - line->start.z;
return sqrt(dx*dx + dy*dy + dz*dz);
}
double line_angle_2d(Dwg_Entity_LINE *line)
{
double dx = line->end.x - line->start.x;
double dy = line->end.y - line->start.y;
return atan2(dy, dx);
}
void line_midpoint(Dwg_Entity_LINE *line, BITCODE_3BD *mid)
{
mid->x = (line->start.x + line->end.x) / 2;
mid->y = (line->start.y + line->end.y) / 2;
mid->z = (line->start.z + line->end.z) / 2;
}
// 判断点是否在直线上
int point_on_line(Dwg_Entity_LINE *line, double px, double py, double tol)
{
double dx = line->end.x - line->start.x;
double dy = line->end.y - line->start.y;
double len = sqrt(dx*dx + dy*dy);
if (len < 1e-10) return 0;
// 点到直线的距离
double t = ((px - line->start.x) * dx + (py - line->start.y) * dy) / (len * len);
if (t < 0 || t > 1) return 0;
double dist_x = line->start.x + t * dx - px;
double dist_y = line->start.y + t * dy - py;
double dist = sqrt(dist_x*dist_x + dist_y*dist_y);
return dist <= tol;
}
11.2.2 CIRCLE - 圆
#include <dwg.h>
#include <math.h>
// CIRCLE结构
typedef struct _dwg_entity_CIRCLE {
BITCODE_3BD center; // 圆心
BITCODE_BD radius; // 半径
BITCODE_BD thickness; // 厚度
BITCODE_BE extrusion; // 挤出方向
} Dwg_Entity_CIRCLE;
// 操作函数
double circle_circumference(Dwg_Entity_CIRCLE *circle)
{
return 2 * M_PI * circle->radius;
}
double circle_area(Dwg_Entity_CIRCLE *circle)
{
return M_PI * circle->radius * circle->radius;
}
// 获取圆上的点(角度为弧度)
void circle_point_at_angle(Dwg_Entity_CIRCLE *circle, double angle,
BITCODE_3BD *point)
{
point->x = circle->center.x + circle->radius * cos(angle);
point->y = circle->center.y + circle->radius * sin(angle);
point->z = circle->center.z;
}
// 判断点是否在圆内
int point_in_circle(Dwg_Entity_CIRCLE *circle, double px, double py)
{
double dx = px - circle->center.x;
double dy = py - circle->center.y;
double dist = sqrt(dx*dx + dy*dy);
return dist <= circle->radius;
}
// 两圆相交判断
int circles_intersect(Dwg_Entity_CIRCLE *c1, Dwg_Entity_CIRCLE *c2)
{
double dx = c2->center.x - c1->center.x;
double dy = c2->center.y - c1->center.y;
double dist = sqrt(dx*dx + dy*dy);
double r_sum = c1->radius + c2->radius;
double r_diff = fabs(c1->radius - c2->radius);
return dist <= r_sum && dist >= r_diff;
}
11.2.3 ARC - 圆弧
#include <dwg.h>
#include <math.h>
// ARC结构
typedef struct _dwg_entity_ARC {
BITCODE_3BD center; // 圆心
BITCODE_BD radius; // 半径
BITCODE_BD thickness; // 厚度
BITCODE_BE extrusion; // 挤出方向
BITCODE_BD start_angle; // 起始角(弧度)
BITCODE_BD end_angle; // 终止角(弧度)
} Dwg_Entity_ARC;
// 操作函数
double arc_length(Dwg_Entity_ARC *arc)
{
double angle_span = arc->end_angle - arc->start_angle;
if (angle_span < 0) angle_span += 2 * M_PI;
return arc->radius * angle_span;
}
double arc_angle_span(Dwg_Entity_ARC *arc)
{
double span = arc->end_angle - arc->start_angle;
if (span < 0) span += 2 * M_PI;
return span;
}
// 获取起点
void arc_start_point(Dwg_Entity_ARC *arc, BITCODE_3BD *point)
{
point->x = arc->center.x + arc->radius * cos(arc->start_angle);
point->y = arc->center.y + arc->radius * sin(arc->start_angle);
point->z = arc->center.z;
}
// 获取终点
void arc_end_point(Dwg_Entity_ARC *arc, BITCODE_3BD *point)
{
point->x = arc->center.x + arc->radius * cos(arc->end_angle);
point->y = arc->center.y + arc->radius * sin(arc->end_angle);
point->z = arc->center.z;
}
// 获取中点
void arc_mid_point(Dwg_Entity_ARC *arc, BITCODE_3BD *point)
{
double mid_angle = (arc->start_angle + arc->end_angle) / 2;
if (arc->end_angle < arc->start_angle) {
mid_angle += M_PI;
}
point->x = arc->center.x + arc->radius * cos(mid_angle);
point->y = arc->center.y + arc->radius * sin(mid_angle);
point->z = arc->center.z;
}
// 判断角度是否在圆弧范围内
int angle_in_arc(Dwg_Entity_ARC *arc, double angle)
{
// 规范化角度到[0, 2π)
while (angle < 0) angle += 2 * M_PI;
while (angle >= 2 * M_PI) angle -= 2 * M_PI;
double start = arc->start_angle;
double end = arc->end_angle;
while (start < 0) start += 2 * M_PI;
while (end < 0) end += 2 * M_PI;
if (start <= end) {
return angle >= start && angle <= end;
} else {
return angle >= start || angle <= end;
}
}
11.2.4 ELLIPSE - 椭圆
#include <dwg.h>
#include <math.h>
// ELLIPSE结构
typedef struct _dwg_entity_ELLIPSE {
BITCODE_3BD center; // 圆心
BITCODE_3BD sm_axis; // 长轴向量
BITCODE_BE extrusion; // 挤出方向
BITCODE_BD axis_ratio; // 短轴/长轴比
BITCODE_BD start_angle; // 起始参数
BITCODE_BD end_angle; // 终止参数
} Dwg_Entity_ELLIPSE;
// 获取椭圆参数
void ellipse_get_axes(Dwg_Entity_ELLIPSE *ellipse,
double *major_axis, double *minor_axis)
{
*major_axis = sqrt(ellipse->sm_axis.x * ellipse->sm_axis.x +
ellipse->sm_axis.y * ellipse->sm_axis.y +
ellipse->sm_axis.z * ellipse->sm_axis.z);
*minor_axis = *major_axis * ellipse->axis_ratio;
}
// 椭圆上的点(参数t)
void ellipse_point_at_param(Dwg_Entity_ELLIPSE *ellipse, double t,
BITCODE_3BD *point)
{
double major, minor;
ellipse_get_axes(ellipse, &major, &minor);
// 简化2D计算
double angle = atan2(ellipse->sm_axis.y, ellipse->sm_axis.x);
double x = major * cos(t);
double y = minor * sin(t);
// 旋转
point->x = ellipse->center.x + x * cos(angle) - y * sin(angle);
point->y = ellipse->center.y + x * sin(angle) + y * cos(angle);
point->z = ellipse->center.z;
}
// 近似椭圆周长
double ellipse_circumference(Dwg_Entity_ELLIPSE *ellipse)
{
double a, b;
ellipse_get_axes(ellipse, &a, &b);
// 拉马努金近似公式
double h = pow((a - b) / (a + b), 2);
return M_PI * (a + b) * (1 + 3 * h / (10 + sqrt(4 - 3 * h)));
}
11.3 多段线实体
11.3.1 LWPOLYLINE - 轻量多段线
#include <dwg.h>
#include <math.h>
// LWPOLYLINE结构
typedef struct _dwg_entity_LWPOLYLINE {
BITCODE_BS flag; // 标志(1=闭合)
BITCODE_BD const_width; // 常量宽度
BITCODE_BD elevation; // 高程
BITCODE_BD thickness; // 厚度
BITCODE_BE extrusion; // 挤出方向
BITCODE_BL num_points; // 点数
BITCODE_2RD *points; // 点数组
BITCODE_BL num_bulges; // 凸度数量
BITCODE_BD *bulges; // 凸度数组
BITCODE_BL num_widths; // 宽度数量
Dwg_LWPOLYLINE_width *widths; // 宽度数组
} Dwg_Entity_LWPOLYLINE;
// 是否闭合
int lwpline_is_closed(Dwg_Entity_LWPOLYLINE *pline)
{
return (pline->flag & 1) != 0;
}
// 计算周长/总长
double lwpline_length(Dwg_Entity_LWPOLYLINE *pline)
{
double total = 0;
int n = pline->num_points;
int segments = lwpline_is_closed(pline) ? n : n - 1;
for (int i = 0; i < segments; i++) {
int j = (i + 1) % n;
double dx = pline->points[j].x - pline->points[i].x;
double dy = pline->points[j].y - pline->points[i].y;
double chord = sqrt(dx*dx + dy*dy);
// 检查凸度
double bulge = 0;
if (i < pline->num_bulges && pline->bulges) {
bulge = pline->bulges[i];
}
if (fabs(bulge) < 1e-10) {
total += chord;
} else {
// 圆弧长度
double theta = 4 * atan(fabs(bulge));
double radius = chord / (2 * sin(theta / 2));
total += radius * theta;
}
}
return total;
}
// 计算面积(仅对闭合多段线有效)
double lwpline_area(Dwg_Entity_LWPOLYLINE *pline)
{
if (!lwpline_is_closed(pline)) return 0;
double area = 0;
int n = pline->num_points;
// 使用鞋带公式
for (int i = 0; i < n; i++) {
int j = (i + 1) % n;
area += pline->points[i].x * pline->points[j].y;
area -= pline->points[j].x * pline->points[i].y;
}
return fabs(area) / 2;
}
// 获取边界框
void lwpline_bounds(Dwg_Entity_LWPOLYLINE *pline,
double *min_x, double *min_y,
double *max_x, double *max_y)
{
*min_x = *max_x = pline->points[0].x;
*min_y = *max_y = pline->points[0].y;
for (BITCODE_BL i = 1; i < pline->num_points; i++) {
if (pline->points[i].x < *min_x) *min_x = pline->points[i].x;
if (pline->points[i].x > *max_x) *max_x = pline->points[i].x;
if (pline->points[i].y < *min_y) *min_y = pline->points[i].y;
if (pline->points[i].y > *max_y) *max_y = pline->points[i].y;
}
}
// 点是否在闭合多段线内
int point_in_lwpline(Dwg_Entity_LWPOLYLINE *pline, double px, double py)
{
if (!lwpline_is_closed(pline)) return 0;
int inside = 0;
int n = pline->num_points;
for (int i = 0, j = n - 1; i < n; j = i++) {
double xi = pline->points[i].x, yi = pline->points[i].y;
double xj = pline->points[j].x, yj = pline->points[j].y;
if (((yi > py) != (yj > py)) &&
(px < (xj - xi) * (py - yi) / (yj - yi) + xi)) {
inside = !inside;
}
}
return inside;
}
11.4 文字实体
11.4.1 TEXT操作
#include <dwg.h>
#include <string.h>
// TEXT对齐方式
typedef enum {
TEXT_ALIGN_LEFT = 0,
TEXT_ALIGN_CENTER = 1,
TEXT_ALIGN_RIGHT = 2,
TEXT_ALIGN_ALIGNED = 3,
TEXT_ALIGN_MIDDLE = 4,
TEXT_ALIGN_FIT = 5
} TextHorizAlign;
typedef enum {
TEXT_VALIGN_BASELINE = 0,
TEXT_VALIGN_BOTTOM = 1,
TEXT_VALIGN_MIDDLE = 2,
TEXT_VALIGN_TOP = 3
} TextVertAlign;
// 获取文字边界框
void text_bounds(Dwg_Entity_TEXT *text,
double *min_x, double *min_y,
double *max_x, double *max_y)
{
double x = text->ins_pt.x;
double y = text->ins_pt.y;
double h = text->height;
double w = h * text->width_factor *
(text->text_value ? strlen(text->text_value) : 0);
// 简化计算,不考虑旋转
*min_x = x;
*min_y = y;
*max_x = x + w;
*max_y = y + h;
}
// 文字长度(字符数)
int text_length(Dwg_Entity_TEXT *text)
{
return text->text_value ? strlen(text->text_value) : 0;
}
11.4.2 MTEXT操作
#include <dwg.h>
#include <string.h>
#include <ctype.h>
// 清理MTEXT格式码
char* mtext_strip_formatting(const char *text)
{
if (!text) return NULL;
size_t len = strlen(text);
char *result = malloc(len + 1);
if (!result) return NULL;
const char *src = text;
char *dst = result;
while (*src) {
if (*src == '\\') {
src++;
if (*src == 'P' || *src == 'p') {
*dst++ = '\n';
src++;
} else if (strchr("LlOoKkUu", *src)) {
src++;
} else if (strchr("fFhHwWaAcCqQtT", *src)) {
while (*src && *src != ';') src++;
if (*src == ';') src++;
} else if (*src == '\\') {
*dst++ = '\\';
src++;
} else {
src++;
}
} else if (*src == '{' || *src == '}') {
src++;
} else {
*dst++ = *src++;
}
}
*dst = '\0';
return result;
}
// 计算MTEXT行数
int mtext_line_count(Dwg_Entity_MTEXT *mtext)
{
if (!mtext->text) return 0;
int lines = 1;
const char *p = mtext->text;
while (*p) {
if (*p == '\\' && (*(p+1) == 'P' || *(p+1) == 'p')) {
lines++;
p += 2;
} else {
p++;
}
}
return lines;
}
// 获取MTEXT边界框
void mtext_bounds(Dwg_Entity_MTEXT *mtext,
double *min_x, double *min_y,
double *max_x, double *max_y)
{
double x = mtext->ins_pt.x;
double y = mtext->ins_pt.y;
double w = mtext->rect_width;
double h = mtext->rect_height > 0 ? mtext->rect_height : mtext->extents_height;
// 根据附着点调整
switch (mtext->attachment) {
case 1: // 左上
*min_x = x;
*max_x = x + w;
*min_y = y - h;
*max_y = y;
break;
case 2: // 中上
*min_x = x - w/2;
*max_x = x + w/2;
*min_y = y - h;
*max_y = y;
break;
case 3: // 右上
*min_x = x - w;
*max_x = x;
*min_y = y - h;
*max_y = y;
break;
// ... 其他附着点
default:
*min_x = x;
*max_x = x + w;
*min_y = y;
*max_y = y + h;
}
}
11.5 块引用操作
11.5.1 INSERT - 块引用
#include <dwg.h>
// INSERT结构
typedef struct _dwg_entity_INSERT {
BITCODE_3BD ins_pt; // 插入点
BITCODE_BB scale_flag; // 缩放标志
BITCODE_3BD scale; // 缩放因子
BITCODE_BD rotation; // 旋转角度(弧度)
BITCODE_3BD extrusion; // 挤出方向
BITCODE_B has_attribs; // 有属性
BITCODE_BL num_owned; // 属性数量
BITCODE_H block_header; // 块定义句柄
BITCODE_H first_attrib; // 第一个属性
BITCODE_H last_attrib; // 最后一个属性
BITCODE_H *attribs; // 属性数组
BITCODE_H seqend; // SEQEND
} Dwg_Entity_INSERT;
// 获取块名
char* insert_get_block_name(Dwg_Data *dwg, Dwg_Entity_INSERT *insert)
{
if (!insert->block_header || !insert->block_header->obj) {
return NULL;
}
Dwg_Object *blk_obj = insert->block_header->obj;
if (blk_obj->fixedtype != DWG_TYPE_BLOCK_HEADER) {
return NULL;
}
Dwg_Object_BLOCK_HEADER *blk = blk_obj->tio.object->tio.BLOCK_HEADER;
return blk->name;
}
// 获取有效缩放因子
void insert_get_scale(Dwg_Entity_INSERT *insert, double *sx, double *sy, double *sz)
{
*sx = insert->scale.x != 0 ? insert->scale.x : 1.0;
*sy = insert->scale.y != 0 ? insert->scale.y : 1.0;
*sz = insert->scale.z != 0 ? insert->scale.z : 1.0;
}
// 变换点(块内坐标 -> 世界坐标)
void insert_transform_point(Dwg_Entity_INSERT *insert,
double bx, double by, double bz,
double *wx, double *wy, double *wz)
{
double sx, sy, sz;
insert_get_scale(insert, &sx, &sy, &sz);
double cos_r = cos(insert->rotation);
double sin_r = sin(insert->rotation);
// 缩放
double x = bx * sx;
double y = by * sy;
double z = bz * sz;
// 旋转(绕Z轴)
double rx = x * cos_r - y * sin_r;
double ry = x * sin_r + y * cos_r;
// 平移
*wx = rx + insert->ins_pt.x;
*wy = ry + insert->ins_pt.y;
*wz = z + insert->ins_pt.z;
}
// 遍历块引用的属性
void insert_iterate_attribs(Dwg_Data *dwg, Dwg_Object *insert_obj)
{
Dwg_Entity_INSERT *insert = insert_obj->tio.entity->tio.INSERT;
if (!insert->has_attribs || insert->num_owned == 0) {
return;
}
printf("块 '%s' 的属性:\n",
insert_get_block_name(dwg, insert));
for (BITCODE_BL i = 0; i < insert->num_owned; i++) {
if (!insert->attribs[i] || !insert->attribs[i]->obj) {
continue;
}
Dwg_Object *attr_obj = insert->attribs[i]->obj;
if (attr_obj->fixedtype != DWG_TYPE_ATTRIB) {
continue;
}
Dwg_Entity_ATTRIB *attrib = attr_obj->tio.entity->tio.ATTRIB;
printf(" %s = %s\n",
attrib->tag ? attrib->tag : "(无标签)",
attrib->text_value ? attrib->text_value : "(空)");
}
}
11.6 非图形对象
11.6.1 LAYER操作
#include <dwg.h>
// 查找图层
Dwg_Object_LAYER* find_layer(Dwg_Data *dwg, const char *name)
{
for (BITCODE_BL i = 0; i < dwg->num_objects; i++) {
Dwg_Object *obj = &dwg->object[i];
if (obj->fixedtype == DWG_TYPE_LAYER) {
Dwg_Object_LAYER *layer = obj->tio.object->tio.LAYER;
if (layer->name && strcasecmp(layer->name, name) == 0) {
return layer;
}
}
}
return NULL;
}
// 获取颜色名称
const char* color_name(int index)
{
static const char *names[] = {
"ByBlock", "Red", "Yellow", "Green",
"Cyan", "Blue", "Magenta", "White"
};
if (index >= 0 && index <= 7) {
return names[index];
} else if (index == 256) {
return "ByLayer";
}
return "Custom";
}
// 打印图层详细信息
void print_layer_info(Dwg_Object_LAYER *layer)
{
printf("图层: %s\n", layer->name);
printf(" 颜色: %d (%s)\n", layer->color.index,
color_name(layer->color.index));
printf(" 开启: %s\n", layer->on ? "是" : "否");
printf(" 冻结: %s\n", layer->frozen ? "是" : "否");
printf(" 锁定: %s\n", layer->locked ? "是" : "否");
printf(" 打印: %s\n", layer->plotflag ? "是" : "否");
printf(" 线宽: %d\n", layer->lineweight);
}
// 统计图层实体数量
int count_entities_on_layer(Dwg_Data *dwg, const char *layer_name)
{
int count = 0;
for (BITCODE_BL i = 0; i < dwg->num_objects; i++) {
Dwg_Object *obj = &dwg->object[i];
if (obj->supertype != DWG_SUPERTYPE_ENTITY) {
continue;
}
Dwg_Object_Entity *ent = obj->tio.entity;
if (ent->layer && ent->layer->obj) {
if (ent->layer->obj->fixedtype == DWG_TYPE_LAYER) {
Dwg_Object_LAYER *layer =
ent->layer->obj->tio.object->tio.LAYER;
if (layer->name &&
strcasecmp(layer->name, layer_name) == 0) {
count++;
}
}
}
}
return count;
}
11.7 本章小结
本章详细介绍了各种实体和对象的操作:
- 基本几何:LINE、CIRCLE、ARC、ELLIPSE的属性和计算
- 多段线:LWPOLYLINE的长度、面积、点包含判断
- 文字:TEXT和MTEXT的格式处理和边界计算
- 块引用:INSERT的变换和属性遍历
- 非图形对象:LAYER的查找和统计
下一章预告:第12章 - 二次开发实战案例 - 通过实际案例学习LibreDWG的应用开发。

浙公网安备 33010602011771号