当前位置:首页 » 《休闲阅读》 » 正文

(WEB在线CAD)在线CAD如何实现图形识别功能

20 人参与  2024年12月03日 16:01  分类 : 《休闲阅读》  评论

点击全文阅读


前言

CAD图形识别功能可帮助用户快速识别和提取CAD图纸中的各种图形,从而加速设计过程。可应用在识别与分类阶段,自动识别图纸中的不同元素,通过特定特征进行区分,减少了手动分类的工作量;也可应用在数量统计阶段,统计图纸中各种构件的数量用于预算;还可运用在图纸定位和应用阶段,快速定位图纸上的特定元素,便于快速查找和修改。

mxcad 为用户提供了图形识别功能和API,用户可根据自身需求对该功能进行拓展或二次开发,更多开发文档关注公众号:梦想云图网页CAD。

图形识别步骤

1. 打开mxcad在线示例demo:demo.mxdraw3d.com:3000/mxcad/。

2. 点击【工具(A)】菜单栏,找到图形识别功能,选择【图形识别】按钮,如下图:(WEB在线CAD)在线CAD如何实现图形识别功能_webcad

3.根据命令行提示,点击鼠标左键点选图元或拉框选择需要识别的图形(图形识别功能目前支持识别直线类、多段线类、弧线类、圆类,以及块这五类图元),如下图:

(WEB在线CAD)在线CAD如何实现图形识别功能_网页CAD_02

4.点击右键结束选择后,在弹出的图形识别框内设置查找图形详情,设置图形名称可方便后续查找已识别图形;设置重新选择图形时,会覆盖当前选中图形;设置区域查找时,需要用户框选查找范围,若未框选范围则会默认为全图纸查找图形,如下图:

(WEB在线CAD)在线CAD如何实现图形识别功能_webcad_03

5. 在图形识别框内点击【开始识别】按钮,开始在目标范围内查找图形,并将查找结果展示在图形识别列表中。点击图形识别列表下的坐标对应的【查看】按钮会自动定位到对应的图形位置,并圈选出目标图形,如下图:(WEB在线CAD)在线CAD如何实现图形识别功能_在线CAD_04

6. 当识别多个图形后,可点击目标图形统计表格对应的操作列中的【详情】按钮查看识别详情,图形坐标列表将转换为该目标图形的识别结果,如下图:(WEB在线CAD)在线CAD如何实现图形识别功能_webcad_05

识别注意事项:

如果需要识别的图形较为复杂,为保证识别速度与精度,我们需尽可能查找图形中的特殊部分而不是选取整个图形(图形对象过多时可能会导致卡顿,影响用户使用效率)。

图形识别支持区域选择,用户可根据自身需求精确定位图形筛选区域。

功能开发

mxcad 图形识别功能中运用的核心思想是通过[McDbEntity]实体中每个实体的特征在图纸中进行查找,查找的实体中包括了[直线类]、[多段线类] 、[弧线类]、[圆类],以及[块]。

下列为基于mxcad 封装的图形识别类 SearchSamePattern 用户可根据该类的使用方法利用 mxcad 进行二次开发,代码如下:

登录后复制
import {    DxfCode, McCmColor, McDbArc, McDbBlockReference, McDbCircle, McDbLine, McDbPolyline, McDbWipeout, McGePoint3d,    McGePoint3dArray, McGeVector3d, MxCADResbuf, MxCADSelectionSet, MxCADUtility, MxCpp} from "mxcad";import { MxFun } from "mxdraw";export class SearchSamePattern {    /** 识别图元数 */    private objectCount: number = 0;    /** 选择图形集合 Map<className,[Ent]>*/    private selectObjects: any;    private dTol = 0.000001;    /**     * pt1:左下角     * pt2:右上角     * pt3:左上角     * pt4:右下角     */    private pt1: McGePoint3d;    private pt2: McGePoint3d;    private pt3: McGePoint3d;    private pt4: McGePoint3d;//包围盒大小    private pl: McDbPolyline;    /** 识别图形类名集合 [string] */    private classNames: any    /** 识别图形图片地址 */    private patternImgUrl: String    /** 识别对象详情  Map<ClassName,[{}]>*/    private objectsDetails: any = {};    // 下列为识别结果数据    /** 识别后的图形位置数组集合 */;    private graphBoxsPos: any[] = [];    private formPt: McGePoint3d;    private toPt: McGePoint3d;    /** 点精度值 */    private dTolPt: any;    /** 识别后图形列表 */    private patternList: any = {};    /** 选择的图形集合 */    public setSelectset(ss: MxCADSelectionSet): Promise<String> {        if (!ss?.count()) return;        const mxcad = MxCpp.getCurrentMxCAD();        // 获取当前图纸的空间块表记录包围盒        const { maxPt, minPt } = mxcad.getDatabase().currentSpace.getBoundingBox();        const currentDrawOrder = mxcad.getDatabase().currentSpace.getMinMaxDrawOrder()        const n = MxFun.screenCoordLong2Doc(Math.abs(maxPt.x - minPt.x));        minPt.x -= n; minPt.y -= n; maxPt.x += n; maxPt.y += n;        let points = new McGePoint3dArray();        points.append(minPt);        points.append(new McGePoint3d(minPt.x, maxPt.y, 0));        points.append(new McGePoint3d(maxPt.x, maxPt.y, 0));        points.append(new McGePoint3d(maxPt.x, minPt.y, 0));        this.objectCount = ss.count();        // 获取遮罩层drawOrder        let wipeout = new McDbWipeout        wipeout.setVertices(points);        const wipeoutId = mxcad.drawEntity(wipeout);        const e = wipeoutId.getMcDbEntity();        e.drawOrder = currentDrawOrder.maxDrawOrder + 1;        this.selectObjects = {};        const oldDrawOder = [];        ss.forEach(id => {            const ent = id.getMcDbEntity();            /** 记录识别图形的信息 */            if (!this.selectObjects[ent.objectName]) this.selectObjects[ent.objectName] = [];            this.selectObjects[ent.objectName].push(ent);            if (ent.objectName === 'McDbLine') {                if (!this.objectsDetails['McDbLine']) this.objectsDetails['McDbLine'] = [];                this.objectsDetails['McDbLine'].push({ entity: ent, length: (ent as McDbLine).getLength().val });            } else if (ent.objectName === 'McDbArc') {                if (!this.objectsDetails['McDbArc']) this.objectsDetails['McDbArc'] = [];                const length = (ent as McDbArc).getLength().val;                const { bugle } = this.getBugle((ent as McDbArc), length)                this.objectsDetails['McDbArc'].push({ entity: ent, length, bugle });            } else if (ent.objectName === 'McDbCircle') {                if (!this.objectsDetails['McDbCircle']) this.objectsDetails['McDbCircle'] = [];                const radius = (ent as McDbCircle).radius;                this.objectsDetails['McDbCircle'].push({ entity: ent, radius });            } else if (ent.objectName === 'McDbBlockReference') {                if (!this.objectsDetails['McDbBlockReference']) this.objectsDetails['McDbBlockReference'] = [];                const blkName = (ent as McDbBlockReference).blockName;                this.objectsDetails['McDbBlockReference'].push({ entity: ent, blkName });            } else if (ent.objectName === 'McDbPolyline') {                if (!this.objectsDetails['McDbPolyline']) this.objectsDetails['McDbPolyline'] = [];                const length = (ent as McDbPolyline).getLength().val;                this.objectsDetails['McDbPolyline'].push({ entity: ent, length });            }            /** 渲染顺序 */            oldDrawOder.push({ obj: ent, drawOrder: ent.drawOrder });            ent.drawOrder = e.drawOrder + 1;            const { maxPt, minPt } = ent.getBoundingBox();            if (!this.pt1 || !this.pt2) {                this.pt1 = minPt;                this.pt2 = maxPt;            } else {                if (minPt.x < this.pt1.x) this.pt1.x = minPt.x;                if (minPt.y < this.pt1.y) this.pt1.y = minPt.y;                if (maxPt.x > this.pt2.x) this.pt2.x = maxPt.x;                if (maxPt.y > this.pt2.y) this.pt2.y = maxPt.y;            }        });        this.classNames = Object.keys(this.selectObjects);        /**         * 计算包围盒其他两个角点         */        this.pt3 = new McGePoint3d(this.pt1.x, this.pt2.y);        this.pt4 = new McGePoint3d(this.pt2.x, this.pt1.y);        /** 绘制识别图形包围盒 */        this.pl = new McDbPolyline()        this.pl.addVertexAt(this.pt1);        this.pl.addVertexAt(this.pt3);        this.pl.addVertexAt(this.pt2);        this.pl.addVertexAt(this.pt4);        this.pl.isClosed = true;        const num = MxFun.screenCoordLong2Doc(10);        this.pt1.x -= num; this.pt1.y -= num; this.pt2.x += num; this.pt2.y += num;        // 生成预览图        let w = Math.abs(this.pt1.x - this.pt2.x);        let h = Math.abs(this.pt1.y - this.pt2.y);        if (w < 1 || h < 1) return;        let jpg_width = 300;        let jpg_height = 240;        return new Promise<String>((resolve, reject) => {            MxFun.getCurrentDraw().createCanvasImageData(                (imageData: String) => {                    this.patternImgUrl = imageData;                    // 恢复绘制顺序                    oldDrawOder.forEach(item => {                        item.obj.drawOrder = item.drawOrder;                    })                    wipeoutId.erase();                    resolve(imageData)                },                {                    width: jpg_width, // 图片宽                    height: jpg_height, // 图片高                    range_pt1: this.pt1.toVector3(), // 截图范围角点1                    range_pt2: this.pt2.toVector3(), // 截图范围角点2                }            );        });    };    // 开始识别图形    /**     * 1.查找初始包围盒     * 2.筛选符合条件的包围盒     * 3.比较包围盒内的每一个图元与需要识别的图元是否匹配     */    public identifyGraphics(corner1?: McGePoint3d, corner2?: McGePoint3d): any {        /** 记录图形缩略图 */        this.patternList.patternImgUrl = this.patternImgUrl;        /**初始化图形位置列表 */        this.graphBoxsPos.length = 0;        const mxcad = MxCpp.getCurrentMxCAD();        this.dTolPt = mxcad.mxdraw.viewCoordLong2Cad(0.5);// 设置精度值        if (!this.classNames) return;        const array = this.classNames.map(name => this.selectObjects[name].length);        const minIndex = array.findIndex(element => element === Math.min(...array));        const str = this.classNames[minIndex];        /** 识别块 */        if (str === 'McDbBlockReference') {            const refBlk = this.selectObjects['McDbBlockReference'][0].clone() as McDbBlockReference;            const blkName = refBlk.blockName; // 图块名            const { position } = this.getBlkMidPt(refBlk);            this.formPt = position;            const rotate = refBlk.rotation;            // 设置图块过滤器            const filter = new MxCADResbuf([DxfCode.kEntityType, "INSERT"])            const ss = new MxCADSelectionSet()            if (corner1 && corner2) {                // 局部选择                ss.crossingSelect(corner1.x, corner1.y, corner2.x, corner2.y, filter);            } else {                // 全局选择                ss.allSelect(filter);            };            // 筛选出符合条件的块            const boxs: any[] = [];            ss.forEach(id => {                const _blk = id.getMcDbEntity().clone() as McDbBlockReference;                /** 块名相等=》计算旋转角度=》计算包围盒大小 */                if (blkName === _blk.blockName) {                    const _rotate = _blk.rotation;                    const angle = rotate >= 0 ? _rotate - rotate : rotate - _rotate;                    const { position: _position, minPt, maxPt } = this.getBlkMidPt(_blk);                    if (this.classNames.length === 1) {                        this.toPt = _position;                        this.identificationBBox(minPt, maxPt, 0)                    } else {                        // 平移旋转初始包围盒。计算出最新包围盒的大小                        const _pl = this.pl.clone() as McDbPolyline;                        _pl.move(this.formPt, _position);                        _pl.rotate(_position, angle);                        let x = [], y = [];                        for (let i = 0; i < _pl.numVerts(); i++) {                            const pt = _pl.getPointAt(i).val;                            x.push(pt.x);                            y.push(pt.y);                        }                        const _minPt = new McGePoint3d(Math.min(...x) - 1, Math.min(...y) - 1);                        const _maxPt = new McGePoint3d(Math.max(...x) + 1, Math.max(...y) + 1);                        const res = boxs.filter(item => {                            let ret1 = _minPt.distanceTo(item.pt1) < this.dTolPt && _maxPt.distanceTo(item.pt2) < this.dTolPt                            let ret2 = _minPt.distanceTo(item.pt2) < this.dTolPt && _maxPt.distanceTo(item.pt1) < this.dTolPt                            return ret1 || ret2                        })                        if (!res.length) {                            boxs.push({ pt1: _minPt, pt2: _maxPt });                            this.toPt = _position;                            // MxCpp.getCurrentMxCAD().drawLine(_maxPt.x, _maxPt.y, _minPt.x, _minPt.y);                            this.identificationBBox(_minPt, _maxPt, angle);                        }                    }                }            });        }        /** 识别弧线 */        else if (str === 'McDbArc') {            // 识别直线            const refArc = this.selectObjects['McDbArc'][0].clone() as McDbArc;            const length = refArc.getLength().val; // 弧线线长度            // 圆弧凸度            const { bugle, midPt } = this.getBugle(refArc, length);            const center = refArc.center;            const vec = center.sub(midPt);            // 设置弧线过滤器            const filter = new MxCADResbuf([DxfCode.kEntityType, "ARC"])            const ss = new MxCADSelectionSet()            if (corner1 && corner2) {                // 局部选择                ss.crossingSelect(corner1.x, corner1.y, corner2.x, corner2.y, filter);            } else {                // 全局选择                ss.allSelect(filter);            };            // 筛选出符合条件的弧线            const boxs: any[] = [];            ss.forEach(id => {                const _arc = id.getMcDbEntity().clone() as McDbArc;                const _length = _arc.getLength().val;                const { bugle: _bugle, midPt: _midPt } = this.getBugle(_arc, _length);                /** 筛选出圆弧凸度与长度相同的弧线*/                if (Math.abs(_length - length) < this.dTol && Math.abs(_bugle - bugle) < this.dTol) {                    /** 分两种情况                     * 1.直接旋转平移得到                     * 2.镜像得到=》移动到目标位置+旋转角度+镜像翻转=》比较起始点位置                     */                    // 平移+旋转                    const _center = _arc.center;                    const _vec = _center.sub(_midPt);                    const angle = _vec.angleTo2(vec, McGeVector3d.kNegateZAxis);                    // 旋转平移初始包围盒。计算出最新包围盒的大小                    const _pl = this.pl.clone() as McDbPolyline;                    _pl.move(midPt, _midPt);                    _pl.rotate(_midPt, angle);                    let x = [], y = [];                    for (let i = 0; i < _pl.numVerts(); i++) {                        const pt = _pl.getPointAt(i).val;                        x.push(pt.x);                        y.push(pt.y);                    }                    const _minPt = new McGePoint3d(Math.min(...x) - 1, Math.min(...y) - 1);                    const _maxPt = new McGePoint3d(Math.max(...x) + 1, Math.max(...y) + 1);                    const res = boxs.filter(item => {                        let ret1 = _minPt.distanceTo(item.pt1) < this.dTolPt && _maxPt.distanceTo(item.pt2) < this.dTolPt                        let ret2 = _minPt.distanceTo(item.pt2) < this.dTolPt && _maxPt.distanceTo(item.pt1) < this.dTolPt                        let ret3 = _midPt.distanceTo(item.midPt) < this.dTolPt                        return (ret1 || ret2) && ret3                    })                    if (!res.length) {                        boxs.push({ pt1: _minPt, pt2: _maxPt, midPt: _midPt });                        this.toPt = _midPt;                        this.formPt = midPt;                        this.identificationBBox(_minPt, _maxPt, angle);                    }                }            });        }        /** 识别直线 */        else if (str === 'McDbLine') {            // 识别直线            const refLine = this.selectObjects['McDbLine'][0].clone() as McDbLine;            const length = refLine.getLength().val; // 直线长度            const vec = refLine.endPoint.sub(refLine.startPoint); // 直线角度            // 设置直线过滤器            const filter = new MxCADResbuf([DxfCode.kEntityType, "LINE"])            const ss = new MxCADSelectionSet()            if (corner1 && corner2) {                // 局部选择                ss.crossingSelect(corner1.x, corner1.y, corner2.x, corner2.y, filter);            } else {                // 全局选择                ss.allSelect(filter);            };            // 筛选出符合条件的直线            const lineArr: McDbLine[] = [];            ss.forEach(id => {                const line = id.getMcDbEntity().clone() as McDbLine;                const _length = line.getLength().val;                /**                 * 1.未旋转                 * 2.旋转过                 */                if (Math.abs(_length - length) < this.dTol) {                    lineArr.push(line);                }            });            // 筛选出符合条件的直线后,根据包围盒范围再次筛选出符合条件的直线组合            const boxs: any[] = [];            if (lineArr.length > 0) {                lineArr.forEach((item) => {                    /**                     * 将要识别的图形进行平移+旋转到目标位置                     */                    const ptArr = [item.startPoint, item.endPoint];                    ptArr.forEach((point, index) => {                        const _line = refLine.clone() as McDbLine;                        _line.move(refLine.startPoint, point);                        const _vec = ptArr[1 - index].sub(point);                        const angle = _vec.angleTo2(vec, McGeVector3d.kNegateZAxis);                        _line.rotate(point, angle)                        const pt = _line.endPoint;                        const _pl = this.pl.clone() as McDbPolyline;                        _pl.move(refLine.startPoint, point);                        _pl.rotate(point, angle);                        const _refBoxPt1 = _pl.getPointAt(0).val;                        const _refBoxPt2 = _pl.getPointAt(1).val;                        const refVec1 = _refBoxPt1.sub(_line.startPoint);                        const refVec2 = _refBoxPt2.sub(_line.startPoint);                        if (pt.distanceTo(ptArr[1 - index]) < this.dTolPt && refVec1.isEqualTo(_refBoxPt1.sub(point)) && refVec2.isEqualTo(_refBoxPt2.sub(point))) {                            let x = [], y = [];                            for (let i = 0; i < _pl.numVerts(); i++) {                                const pt = _pl.getPointAt(i).val;                                x.push(pt.x);                                y.push(pt.y);                            }                            const _minPt = new McGePoint3d(Math.min(...x) - 1, Math.min(...y) - 1);                            const _maxPt = new McGePoint3d(Math.max(...x) + 1, Math.max(...y) + 1);                            const res = boxs.filter(item => {                                let r1 = _minPt.distanceTo(item.pt1) < this.dTolPt && _maxPt.distanceTo(item.pt2) < this.dTolPt                                let r2 = _minPt.distanceTo(item.pt2) < this.dTolPt && _maxPt.distanceTo(item.pt1) < this.dTolPt                                return r1 || r2                            })                            if (!res.length) {                                boxs.push({ pt1: _minPt, pt2: _maxPt });                                this.toPt = point;                                this.formPt = refLine.startPoint;                                // MxCpp.getCurrentMxCAD().drawLine(_maxPt.x, _maxPt.y, _minPt.x, _minPt.y);                                this.identificationBBox(_minPt, _maxPt, angle);                            }                        }                    })                })            };        }        /** 识别圆 */        else if (str === 'McDbCircle') {            const refCricle = this.selectObjects['McDbCircle'][0].clone() as McDbCircle;            const radius = refCricle.radius; // 圆半径            // 设置圆过滤器            const filter = new MxCADResbuf([DxfCode.kEntityType, "CIRCLE"])            const ss = new MxCADSelectionSet()            if (corner1 && corner2) {                // 局部选择                ss.crossingSelect(corner1.x, corner1.y, corner2.x, corner2.y, filter);            } else {                // 全局选择                ss.allSelect(filter);            };            // 筛选出符合条件的圆            ss.forEach(id => {                const _circle = id.getMcDbEntity().clone() as McDbCircle;                const _radius = _circle.radius;                /** 筛选出圆半径相同的圆*/                if (Math.abs(_radius - radius) < this.dTol) {                    const _center = _circle.center;                    this.toPt = _center;                    this.formPt = refCricle.center;                    // 平移初始包围盒。计算出最新包围盒的大小                    const _pl = this.pl.clone() as McDbPolyline;                    _pl.move(this.formPt, this.toPt);                    let x = [], y = [];                    for (let i = 0; i < _pl.numVerts(); i++) {                        const pt = _pl.getPointAt(i).val;                        x.push(pt.x);                        y.push(pt.y);                    }                    const _minPt = new McGePoint3d(Math.min(...x) - 1, Math.min(...y) - 1);                    const _maxPt = new McGePoint3d(Math.max(...x) + 1, Math.max(...y) + 1);                    // MxCpp.getCurrentMxCAD().drawLine(_maxPt.x, _maxPt.y, _minPt.x, _minPt.y);                    this.identificationBBox(_minPt, _maxPt, 0);                }            });        }        /** 识别多段线 */        else if (str === 'McDbPolyline') {            /** 长度+顶点数+顶点对应的凸度相等=》旋转+平移后的顶点相等+有凸度线段的中点相等*/            const refPoly = this.selectObjects['McDbPolyline'][0].clone() as McDbPolyline;            const length = refPoly.getLength().val;            const { lengthArr, bugleArr, vertNum, vec, point } = this.getPlDetails(refPoly);            // 设置多段线过滤器            const filter = new MxCADResbuf([DxfCode.kEntityType, "LWPOLYLINE"])            const ss = new MxCADSelectionSet()            if (corner1 && corner2) {                // 局部选择                ss.crossingSelect(corner1.x, corner1.y, corner2.x, corner2.y, filter);            } else {                // 全局选择                ss.allSelect(filter);            };            // 筛选出符合条件的多段线            const boxs: any[] = [];            ss.forEach(id => {                const _poly = id.getMcDbEntity().clone() as McDbPolyline;                const _length = _poly.getLength().val;                /** 筛选 长度+顶点数+顶点对应的凸度 相同的多段线*/                if (Math.abs(_length - length) < this.dTol && _poly.isClosed === refPoly.isClosed) {                    const { lengthArr: _lengthArr, bugleArr: _bugleArr, vertNum: _vertNum, vec: _vec, point: _point } = this.getPlDetails(_poly);                    const revBugleArr = _bugleArr.map(item => item === 0 ? item : -item);                    // 全等                    const r1 = lengthArr.toString() === _lengthArr.toString() && bugleArr.toString() === _bugleArr.toString();                    let r2 = false;                    if (!r1) {                        // 反向                        r2 = lengthArr.toString() === [..._lengthArr].reverse().toString() && bugleArr.toString() === [...revBugleArr].reverse().toString();                    }                    const r3 = vertNum === _vertNum;                    // 镜像                    const r4 = lengthArr.toString() === _lengthArr.toString() && bugleArr.toString() === [...revBugleArr].reverse().toString();                    if ((r1 || r2 || r4) && r3) {                        const poly = refPoly.clone() as McDbPolyline;                        const angle1 = vec.angleTo2(McGeVector3d.kXAxis, McGeVector3d.kNegateZAxis);                        // 如果是反向则方向取反                        const angle2 = (r2 ? _vec.negate() : _vec).angleTo2(McGeVector3d.kXAxis, McGeVector3d.kNegateZAxis);                        const angle = angle2 - angle1;                        poly.move(point, _point);                        poly.rotate(_point, angle);                        poly.trueColor = new McCmColor(255, 0, 0);                        let num = 0;                        for (let i = 0; i < vertNum; i++) {                            const pt = poly.getPointAt(i).val;                            const width = poly.getWidthsAt(i);                            const _pt = r2 ? _poly.getPointAt(vertNum - 1 - i).val : _poly.getPointAt(i).val;                            const _width = r2 ? _poly.getWidthsAt(vertNum - 1 - i) : _poly.getWidthsAt(i);                            if (pt.distanceTo(_pt) < this.dTolPt && width.val1 === _width.val1 && width.val2 === _width.val2) {                                num += 1                            } else {                                // 两个点且反向的情况                                if (vertNum === 2 && i === 0) {                                    const _pt1 = _poly.getPointAt(0).val;                                    const _pt2 = _poly.getPointAt(1).val;                                    const pt2 = poly.getPointAt(1).val;                                    const _width = _poly.getWidthsAt(0);                                    if (pt2.distanceTo(_pt2) < this.dTolPt && pt.distanceTo(_pt1) < this.dTolPt && width.val1 === _width.val2 && width.val2 === _width.val1) {                                        num += 2;                                    }                                }                            }                        };                        if (num === vertNum) {                            // 旋转平移初始包围盒。计算出最新包围盒的大小                            const _pl = this.pl.clone() as McDbPolyline;                            _pl.move(point, _point);                            _pl.rotate(_point, angle);                            let x = [], y = [];                            for (let i = 0; i < _pl.numVerts(); i++) {                                const pt = _pl.getPointAt(i).val;                                x.push(pt.x);                                y.push(pt.y);                            }                            const _minPt = new McGePoint3d(Math.min(...x) - 1, Math.min(...y) - 1);                            const _maxPt = new McGePoint3d(Math.max(...x) + 1, Math.max(...y) + 1);                            const res = boxs.filter(item => {                                let ret1 = _minPt.distanceTo(item.pt1) < this.dTolPt && _maxPt.distanceTo(item.pt2) < this.dTolPt                                let ret2 = _minPt.distanceTo(item.pt2) < this.dTolPt && _maxPt.distanceTo(item.pt1) < this.dTolPt                                return ret1 || ret2                            })                            if (!res.length) {                                boxs.push({ pt1: _minPt, pt2: _maxPt });                                this.toPt = _point;                                this.formPt = point;                                // MxCpp.getCurrentMxCAD().drawLine(_maxPt.x, _maxPt.y, _minPt.x, _minPt.y);                                this.identificationBBox(_minPt, _maxPt, angle);                            }                        }                    }                }            });        }        /** 返回识别列表 */        return this.patternList;    }    // 计算块中心点    private getBlkMidPt = (blkRef: McDbBlockReference) => {        const { minPt, maxPt } = blkRef.getBoundingBox();        const pt = minPt.clone().addvec(maxPt.sub(minPt).normalize().mult(maxPt.distanceTo(minPt) / 2))        return { position: pt, minPt, maxPt }    }    // 计算凸度    private getBugle = (arc: McDbArc, length: number) => {        const midPt = arc.getPointAtDist(length / 2).val;        const bugle = MxCADUtility.calcBulge(arc.getPointAtDist(0).val, midPt, arc.getPointAtDist(length).val).val;        return { bugle, midPt }    }    // 计算多段线的每一段线的长度和凸度    private getPlDetails = (pl: McDbPolyline) => {        const vertNum = pl.numVerts();        const lengthArr: number[] = [];        const bugleArr: number[] = [];        let point1: McGePoint3d, point2: McGePoint3d;        for (let i = 0; i < vertNum; i++) {            if (i < vertNum - 1) {                const p1 = pl.getPointAt(i).val;                const p2 = pl.getPointAt(i + 1).val;                const length = pl.getDistAtPoint(p2).val - pl.getDistAtPoint(p1).val;                const bugle = pl.getBulgeAt(i);                lengthArr.push(Number(length.toFixed(6)));                bugleArr.push(Number(bugle.toFixed(6)));                if (i === 0) {                    point1 = p1;                }                if (i === vertNum - 2) {                    point2 = p2;                }            }        };        const vec = point2.sub(point1)// 多段线角度        const point = point1.clone().addvec(point2.sub(point1).normalize().mult(point2.distanceTo(point1) / 2))        return { lengthArr, bugleArr, vertNum, vec, point }    }    // 将找到的实体数组与需要识别的实体数组比对    private comparisonPhysical = (objects: any, maxPt: McGePoint3d, minPt: McGePoint3d, angle: number): any => {        const calssNames = Object.keys(this.selectObjects);        if (!calssNames) return;        let num = 0;        if (calssNames.includes('McDbLine')) {            let ents = objects['McDbLine'];            const lineObjects = this.objectsDetails['McDbLine'];            for (let i = 0; i < lineObjects.length; i++) {                const element = lineObjects[i];                let _line = (element.entity as McDbLine).clone() as McDbLine;                _line.move(this.formPt, this.toPt);                _line.rotate(this.toPt, angle);                const indexArr: number[] = [];                const mLineArr = ents.filter((item: McDbLine, index: number) => {                    if (Math.abs(element.length - item.getLength().val) < this.dTol) {                        let r1 = item.startPoint.distanceTo(_line.startPoint) < this.dTolPt && item.endPoint.distanceTo(_line.endPoint) < this.dTolPt;                        let r2 = item.startPoint.distanceTo(_line.endPoint) < this.dTolPt && item.endPoint.distanceTo(_line.startPoint) < this.dTolPt;                        if (r1 || r2) indexArr.push(index);                        return r1 || r2;                    }                });                if (mLineArr.length > 0) {                    num += 1;                    ents.splice(indexArr[0], 1);                    ents = [...ents];                } else {                    break;                }            }        };        if (calssNames.includes('McDbArc')) {            let ents = objects['McDbArc'];            const arcObjects = this.objectsDetails['McDbArc'];            for (let i = 0; i < arcObjects.length; i++) {                const element = arcObjects[i];                let _arc = (element.entity as McDbArc).clone() as McDbArc;                _arc.move(this.formPt, this.toPt);                _arc.rotate(this.toPt, angle);                const startPoint = _arc.getPointAtDist(0).val;                const endPoint = _arc.getPointAtDist(element.length).val;                const indexArr: number[] = [];                const mArcArr = ents.filter((item: McDbArc, index: number) => {                    const _length = item.getLength().val;                    const { bugle: _bugle } = this.getBugle(item, _length)                    if (Math.abs(element.length - item.getLength().val) < this.dTol && Math.abs(_bugle - element.bugle) < this.dTol) {                        const _startPoint = item.getPointAtDist(0).val;                        const _endPoint = item.getPointAtDist(_length).val;                        let r1 = startPoint.distanceTo(_startPoint) < this.dTolPt && endPoint.distanceTo(_endPoint) < this.dTolPt;                        let r2 = startPoint.distanceTo(_endPoint) < this.dTolPt && endPoint.distanceTo(_startPoint) < this.dTolPt;                        if (r1 || r2) {                            indexArr.push(index);                        }                        return r1 || r2;                    }                });                if (mArcArr.length > 0) {                    num += 1;                    ents.splice(indexArr[0], 1);                    ents = [...ents];                } else {                    break;                }            }        };        if (calssNames.includes('McDbCircle')) {            let ents = objects['McDbCircle'];            const circleObjects = this.objectsDetails['McDbCircle'];            for (let i = 0; i < circleObjects.length; i++) {                const element = circleObjects[i];                let _circle = (element.entity as McDbCircle).clone() as McDbCircle;                _circle.move(this.formPt, this.toPt);                _circle.rotate(this.toPt, angle);                const center = _circle.center;                const radius = _circle.radius;                const indexArr: number[] = [];                const mCiecleArr = ents.filter((item: McDbCircle, index: number) => {                    const _center = item.center;                    const _radius = item.radius;                    const r = Math.abs(_radius - radius) < this.dTol && center.distanceTo(_center) < this.dTolPt;                    if (r) {                        indexArr.push(index)                    }                    return r;                });                if (mCiecleArr.length > 0) {                    num += 1;                    ents.splice(indexArr[0], 1);                    ents = [...ents];                } else {                    break;                }            }        };        if (calssNames.includes('McDbBlockReference')) {            /** 平移+旋转=>比对包围盒大小+块名字 */            let ents = objects['McDbBlockReference'];            const blkObjects = this.objectsDetails['McDbBlockReference'];            for (let i = 0; i < blkObjects.length; i++) {                const element = blkObjects[i];                let _blk = (element.entity as McDbBlockReference).clone() as McDbBlockReference;                _blk.move(this.formPt, this.toPt);                _blk.rotate(this.toPt, angle);                const blkName = _blk.blockName;                const { minPt: blkMinPt, maxPt: blkMaxPt } = this.getBlkMidPt(_blk);                const indexArr: number[] = [];               const mArcArr = ents.filter((item: McDbBlockReference, index: number) => {                    const _blkName = item.blockName;                    if (_blkName === blkName) {                        if (this.classNames.length === 1) {                            indexArr.push(index);                            return true                        } else {                            const { minPt: _blkMinPt, maxPt: _blkMaxPt } = this.getBlkMidPt(item);                            let r1 = blkMinPt.distanceTo(_blkMinPt) < this.dTolPt && blkMaxPt.distanceTo(_blkMaxPt) < this.dTolPt;                            if (r1) {                                indexArr.push(index);                            }                            return r1                        }                    }                });                if (mArcArr.length > 0) {                    num += 1;                    ents.splice(indexArr[0], 1);                    ents = [...ents];                } else {                    return;                }            }        }        if (calssNames.includes('McDbPolyline')) {            /** 平移+旋转=>比对凸度+点位置 */            let ents = objects['McDbPolyline'];            const plObjects = this.objectsDetails['McDbPolyline'];            for (let i = 0; i < plObjects.length; i++) {                const element = plObjects[i];                let _poly = (element.entity as McDbPolyline).clone() as McDbPolyline;                _poly.move(this.formPt, this.toPt);                _poly.rotate(this.toPt, angle);                const { lengthArr, bugleArr, vertNum } = this.getPlDetails(_poly);                const indexArr: number[] = [];                const mPlArr = ents.filter((item: McDbPolyline, index: number) => {                    const _length = item.getLength().val;                    if (Math.abs(_length - element.length) < this.dTol && _poly.isClosed === _poly.isClosed) {                        const { lengthArr: _lengthArr, bugleArr: _bugleArr, vertNum: _vertNum } = this.getPlDetails(item);                        const revBugleArr = _bugleArr.map(item => item === 0 ? item : -item);                        const r1 = lengthArr.toString() === _lengthArr.toString() && bugleArr.toString() === _bugleArr.toString();                        let r2 = false;                        if (!r1) {                            r2 = lengthArr.toString() === [..._lengthArr].reverse().toString() && bugleArr.toString() === [...revBugleArr].reverse().toString();                        }                        const r3 = vertNum === _vertNum;                        if ((r1 || r2) && r3) {                            let _num = 0;                            for (let i = 0; i < vertNum; i++) {                                const pt = _poly.getPointAt(i).val;                                const width = _poly.getWidthsAt(i);                                const _pt = r2 ? item.getPointAt(vertNum - 1 - i).val : item.getPointAt(i).val;                                const _width = r2 ? item.getWidthsAt(vertNum - 1 - i) : item.getWidthsAt(i);                                if (pt.distanceTo(_pt) < this.dTolPt && width.val1 === _width.val1 && width.val2 === _width.val2) {                                    _num += 1                                } else {                                    // 两个点且反向的情况                                    if (vertNum === 2 && i === 0) {                                        const _pt1 = item.getPointAt(0).val;                                        const _pt2 = item.getPointAt(1).val;                                        const _width = item.getWidthsAt(0);                                        const pt2 = _poly.getPointAt(1).val;                                        if (pt2.distanceTo(_pt2) < this.dTolPt && pt.distanceTo(_pt1) < this.dTolPt && width.val1 === _width.val2 && width.val2 === _width.val1) {                                           _num += 2;                                        }                                    }                                }                            };                            if (_num === vertNum) {                                indexArr.push(index);                            }                            return _num === vertNum;                        }                    }                });                if (mPlArr.length > 0) {                    num += 1;                    ents.splice(indexArr[0], 1);                    ents = [...ents];                } else {                    break;                }            }        }        if (num === this.objectCount) {            // 匹配成功            const pt = minPt.clone().addvec(maxPt.clone().sub(minPt).normalize().mult(minPt.distanceTo(maxPt) / 2));            const res = this.graphBoxsPos.filter(point => pt.distanceTo(point) < this.dTolPt);            if (!res.length) {                this.graphBoxsPos.push(pt)            }        };        this.patternList.graphBoxsPos = [...this.graphBoxsPos];    }    // 识别包围盒是否符合要求    private identificationBBox = (minPt: McGePoint3d, maxPt: McGePoint3d, angle: number): any => {        const _ss = new MxCADSelectionSet()        _ss.crossingSelect(minPt.x, minPt.y, maxPt.x, maxPt.y);        const boxEntity = {};        _ss.forEach(id => {            const ent = id.getMcDbEntity();            if (!boxEntity[ent.objectName]) boxEntity[ent.objectName] = [];            boxEntity[ent.objectName].push(ent);        });        let r = this.classNames.filter(name => boxEntity[name] && this.selectObjects[name].length <= boxEntity[name].length);        if (r.length === this.classNames.length) {            this.comparisonPhysical(boxEntity, maxPt, minPt, angle);        }    }};
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.104.105.106.107.108.109.110.111.112.113.114.115.116.117.118.119.120.121.122.123.124.125.126.127.128.129.130.131.132.133.134.135.136.137.138.139.140.141.142.143.144.145.146.147.148.149.150.151.152.153.154.155.156.157.158.159.160.161.162.163.164.165.166.167.168.169.170.171.172.173.174.175.176.177.178.179.180.181.182.183.184.185.186.187.188.189.190.191.192.193.194.195.196.197.198.199.200.201.202.203.204.205.206.207.208.209.210.211.212.213.214.215.216.217.218.219.220.221.222.223.224.225.226.227.228.229.230.231.232.233.234.235.236.237.238.239.240.241.242.243.244.245.246.247.248.249.250.251.252.253.254.255.256.257.258.259.260.261.262.263.264.265.266.267.268.269.270.271.272.273.274.275.276.277.278.279.280.281.282.283.284.285.286.287.288.289.290.291.292.293.294.295.296.297.298.299.300.301.302.303.304.305.306.307.308.309.310.311.312.313.314.315.316.317.318.319.320.321.322.323.324.325.326.327.328.329.330.331.332.333.334.335.336.337.338.339.340.341.342.343.344.345.346.347.348.349.350.351.352.353.354.355.356.357.358.359.360.361.362.363.364.365.366.367.368.369.370.371.372.373.374.375.376.377.378.379.380.381.382.383.384.385.386.387.388.389.390.391.392.393.394.395.396.397.398.399.400.401.402.403.404.405.406.407.408.409.410.411.412.413.414.415.416.417.418.419.420.421.422.423.424.425.426.427.428.429.430.431.432.433.434.435.436.437.438.439.440.441.442.443.444.445.446.447.448.449.450.451.452.453.454.455.456.457.458.459.460.461.462.463.464.465.466.467.468.469.470.471.472.473.474.475.476.477.478.479.480.481.482.483.484.485.486.487.488.489.490.491.492.493.494.495.496.497.498.499.500.501.502.503.504.505.506.507.508.509.510.511.512.513.514.515.516.517.518.519.520.521.522.523.524.525.526.527.528.529.530.531.532.533.534.535.536.537.538.539.540.541.542.543.544.545.546.547.548.549.550.551.552.553.554.555.556.557.558.559.560.561.562.563.564.565.566.567.568.569.570.571.572.573.574.575.576.577.578.579.580.581.582.583.584.585.586.587.588.589.590.591.592.593.594.595.596.597.598.599.600.601.602.603.604.605.606.607.608.609.610.611.612.613.614.615.616.617.618.619.620.621.622.623.624.625.626.627.628.629.630.631.632.633.634.635.636.637.638.639.640.641.642.643.644.645.646.647.648.649.650.651.652.653.654.655.656.657.658.659.660.661.662.663.664.665.666.667.668.669.670.671.672.673.674.675.676.677.678.679.680.681.682.683.684.685.686.687.688.689.690.691.692.693.694.695.696.697.698.699.700.701.702.703.704.705.706.707.708.709.710.711.712.713.714.715.716.717.718.719.720.721.722.723.724.725.726.727.728.729.730.731.732.733.734.735.736.737.738.739.740.741.742.743.744.745.746.747.748.

调用 SearchSamePattern 类,实现图形识别功能,代码如下:

登录后复制
/** 获取需要识别的图形 */const getIdentificationPattern = async () => {    // 获取需要识别的图形    const ss = new MxCADSelectionSet();// 选择集    const filter = new MxCADResbuf([DxfCode.kEntityType, "LINE,ARC,CIRCLE,LWPOLYLINE,INSERT"])    if (!await ss.userSelect("请点击左键或拉框选择需要识别的图形:", filter)) return;    if (ss.count() == 0) return;    // 搜索图形    const searchPattern = new SearchSamePattern();    // 搜索图形简图地址    const patternImgUrl = await searchPattern.setSelectset(ss);    if (!patternImgUrl.value) return;    // 获取识别结果    const searchList = searchPattern.identifyGraphics();    console.log(searchList);}
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.

点击全文阅读


本文链接:http://zhangshiyu.com/post/196031.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1