第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 本章小结

本章详细介绍了各种实体和对象的操作:

  1. 基本几何:LINE、CIRCLE、ARC、ELLIPSE的属性和计算
  2. 多段线:LWPOLYLINE的长度、面积、点包含判断
  3. 文字:TEXT和MTEXT的格式处理和边界计算
  4. 块引用:INSERT的变换和属性遍历
  5. 非图形对象:LAYER的查找和统计

下一章预告第12章 - 二次开发实战案例 - 通过实际案例学习LibreDWG的应用开发。

posted @ 2026-01-11 00:40  我才是银古  阅读(2)  评论(0)    收藏  举报