Skip to content
On this page

局部放大

下面我们将介绍如何利用 mxcad 插件实现在CAD图纸中局部放大的功能,该功能中用户可以自主选择需要放大的区域,并自定义放置放大后图形的位置。局部放大功能能够帮助用户更好的注意到图纸的细节或重点部分,提高快速获取图纸信息的速率。

功能实现

  1. 实现自定义局部放大标注类

为了方便后期管理与修改标注对象,我们可以通过继承 McDbCustomEntity 自定义实体类来扩展实现局部放大类。我们根据用户框选的放大区域在图纸中调用 MxCADSelectionSet.crossingSelect() 方法获取到目标区域内的所有实体,再通过调用 McDbBlockTableRecord.appendAcDbEntity() 方法将区域内的实体整合为块,然后调用 McDbSpatialFilter.setBoundary() 方法根据自身需求对块的外边框做剪裁。最后根据设置的比例因子对块做缩放。

ts
// 自定义局部放大类
class McDbTestEnlarge extends McDbCustomEntity {
    // 定义McDbTestReactArea内部的点对象 
    // 放大中心点
    private center: McGePoint3d = new McGePoint3d();
    // 放大范围
    private radius: number = 20;
    // 放大倍数
    private scale: number = 50;
    // 插入点
    private position: McGePoint3d = new McGePoint3d();
    // 构造函数
    constructor(imp?: any) {
        super(imp);
    }
    // 创建函数
    public create(imp: any) {
        return new McDbTestEnlarge(imp)
    }
    // 获取类名
    public getTypeName(): string {
        return "McDbTestEnlarge";
    }
    //设置或获取放大中心点
    public set enlargeCenter(val: McGePoint3d) {
        this.center = val;
    }
    public get enlargeCenter(): McGePoint3d {
        return this.center;
    }
    //设置或获取放大范围
    public set enlargeRadius(val: number) {
        this.radius = val;
    }
    public get enlargeRadius(): number {
        return this.radius;
    }
    //设置或获取放大倍数
    public set enlargeScale(val: number) {
        this.scale = val;
    }
    public get enlargeScale(): number {
        return this.scale;
    }
    // 读取自定义实体数据pt1、pt2
    public dwgInFields(filter: IMcDbDwgFiler): boolean {
        this.center = filter.readPoint("center").val;
        this.position = filter.readPoint("position").val;
        this.radius = filter.readDouble("radius").val;
        this.scale = filter.readDouble("scale").val;
        return true;
    }
    // 写入自定义实体数据pt1、pt2
    public dwgOutFields(filter: IMcDbDwgFiler): boolean {
        filter.writePoint("center", this.center);
        filter.writePoint("position", this.position);
        filter.writeDouble("radius", this.radius);
        filter.writeDouble("scale", this.scale);
        return true;
    }

    // 移动自定义对象的夹点
    public moveGripPointsAt(iIndex: number, dXOffset: number, dYOffset: number, dZOffset: number) {
        this.assertWrite();
        if (iIndex == 0) {
            this.center.x += dXOffset;
            this.center.y += dYOffset;
            this.center.z += dZOffset;
        }
        else if (iIndex == 1) {
            this.position.x += dXOffset;
            this.position.y += dYOffset;
            this.position.z += dZOffset;
        }
    };
    // 获取自定义对象的夹点
    public getGripPoints(): McGePoint3dArray {
        let ret = new McGePoint3dArray()
        ret.append(this.center);
        ret.append(this.position);
        return ret;
    };
    // 绘制实体
    public worldDraw(draw: MxCADWorldDraw): void {
        const circle = new McDbCircle();
        circle.center = this.center;
        circle.radius = this.radius;
        draw.drawEntity(circle);

        const { minPt, maxPt, ret } = circle.getBoundingBox();
        if (!ret) return;
        let ss = new MxCADSelectionSet();
        ss.crossingSelect(minPt.x, minPt.y, maxPt.x, maxPt.y)
        
        const mxcad = MxCpp.getCurrentMxCAD();
        let blkTable = mxcad.getDatabase().getBlockTable();
        let blkRec = new McDbBlockTableRecord();
        let blkRecId = blkTable.add(blkRec);
        let blkTableRecord: McDbBlockTableRecord = blkRecId.getMcDbBlockTableRecord() as any;
        if (blkTableRecord == null) return;

        ss.forEach((id) => {
            let ent = id.getMcDbEntity();
            if (!ent) return;
            let cent = ent.clone() as McDbEntity;
            blkTableRecord.appendAcDbEntity(cent);
        });
        // 设置图块的插入基点,在图形对象的中心位置。
        blkTableRecord.origin = new McGePoint3d(this.center.x, this.center.y, 0);
        let blkRef = new McDbBlockReference();
        blkRef.blockTableRecordId = blkRecId;
        blkRef.position = this.position;
        const blkRefId = mxcad.drawEntity(blkRef);
        blkRef = blkRefId.getMcDbEntity() as McDbBlockReference;

        // 设置一个圆做它的剪切边界.
        let samplePoints = circle.getSamplePoints(this.radius * 0.00001);
        let aryPoint = new McGePoint3dArray();
        samplePoints.forEach((val, _type, dxf) => {
            if (dxf === 1010) {
                const point = new McGePoint3d(val.x, val.y, val.z);
                aryPoint.append(point);
            }
        });
        blkRef.createSpatialFilter();
        blkRef.setScale(this.scale);
        let idSpatialFilter = blkRef.getSpatialFilterId();
        let blkFilter: McDbSpatialFilter = idSpatialFilter.getMcDbObject() as any;
        blkFilter.setBoundary(aryPoint);
        draw.drawEntity(blkRef);
        blkRefId.erase();

        const vec = this.position.sub(this.center).normalize();
        const pt1 = this.center.clone().addvec(vec.mult(this.radius));
        const pt2 = this.position.clone().subvec(vec.mult(this.scale));
        const line = new McDbLine(pt1, pt2);
        draw.drawEntity(line)
    }
    // 获取position
    public setPosition(pt: McGePoint3d) {
        this.assertWrite();
        this.position = pt.clone();
    }
    // 获取position
    public getPosition() {
        return this.position;
    }
}
  1. 注册自定义类信息
ts
new McDbTestEnlarge().rxInit();
  1. 编写方法,调用 McDbTestEnlarge 自定义局部放大标注类实现局部放大功能
  • 获取放大范围

我们可以利用取点对象 MxCADUiPrPoint() 获取放大范围的中心点,再调用 MxCADUiPrDist() 设置放大范围。

ts
// 设置放大中心点
const getPoint = new MxCADUiPrPoint();
getPoint.setMessage('请选择放大中心点');
const point = await getPoint.go();
if (!point) return;

// 设置放大范围
const getDist = new MxCADUiPrDist();
getDist.setMessage('请选择放大范围');
getDist.setBasePt(point);
getDist.setUserDraw((pt, pw) => {
    const radius = point.distanceTo(pt);
    const circle = new McDbCircle(point.x, point.y, point.z, radius);
    pw.drawMcDbEntity(circle);
});
const distVal = await getDist.go();
if (!distVal) return;
const dist = getDist.value();

const mxcad = MxCpp.getCurrentMxCAD();
const circle1 = new McDbCircle(point.x, point.y, point.z, dist);
  • 设置放大倍数
ts
// 设置放大倍数
const getAmplifyDist = new MxCADUiPrDist();
getAmplifyDist.setMessage('请设置放大倍数');
getAmplifyDist.setBasePt(point);
getAmplifyDist.setUserDraw((pt, pw) => {
    const radius = point.distanceTo(pt);
    const circle = new McDbCircle(point.x, point.y, point.z, radius);
    pw.drawMcDbEntity(circle);
    pw.drawMcDbEntity(circle1);
});
const aDistVal = await getAmplifyDist.go();
if (!aDistVal) return;
const aDist = getAmplifyDist.value();
const scale = aDist / dist
  • 指定放大图像位置,并绘制局部放大标注

我们可以利用 MxCADUiPrPoint 取点对象在页面中交互取点。在取点过程中,我们可以通过 MxCADUiPrPoint.setUserDraw() 方法动态绘制对象,使用户更加直观的观察到放大标注的位置变化。

ts
// 设置放大插入点
const getInsertPt = new MxCADUiPrPoint();
getInsertPt.setMessage('请选择放大插入点');
getInsertPt.setUserDraw((pt, pw) => {
    const circle = new McDbCircle(pt.x, pt.y, pt.z, aDist);
    pw.drawMcDbEntity(circle);
    pw.drawMcDbEntity(circle1);
})
const insertPt = await getInsertPt.go();
if (!insertPt) return;

const enlarge = new McDbTestEnlarge();
enlarge.enlargeCenter = point;
enlarge.enlargeRadius = dist;
enlarge.enlargeScale = scale;
enlarge.setPosition(insertPt);
mxcad.drawEntity(enlarge)

功能实践

实践效果如下:

  • 点击局部放大按钮,执行局部放大方法
  • 选中放大中心点,并确定放大范围
  • 设置放大倍数
  • 确定标注所在位置
  • 成功绘制局部放大标注