cili3d笔记20 正交投影3d重建笔记1

发布于:2025-06-21 ⋅ 阅读:(14) ⋅ 点赞:(0)

正交视图转3d

       mostFrequentCluster.lines.forEach(line => {
                const [x1, y1, x2, y2] = line;
                let xhat={x1,x2};
                let yhat={y1,y2};

                
              });

 没考虑到侧视图

   const clusters = clusterLines(inputlines, 5);
                const lines3d:[number,number,number,number,number,number][]=[]
                const { mostMinX, mostMinY } = getMostFrequentMinXY(clusters);
                const mostFrequentClusters = clusters.filter(cluster => {
    return cluster.min_x === mostMinX.value && cluster.min_y === mostMinY.value;
});
const topclusters = clusters.filter(cluster => {
    return cluster.min_x === mostMinX.value && cluster.min_y > mostMinY.value;
});
;
const rightclusters = clusters.filter(cluster => {
    return cluster.min_x > mostMinX.value && cluster.min_y === mostMinY.value;
});
const bottomclusters = clusters.filter(cluster => {
    return cluster.min_x === mostMinX.value && cluster.min_y < mostMinY.value;
});
const leftclusters = clusters.filter(cluster => {
    return cluster.min_x < mostMinX.value && cluster.min_y === mostMinY.value;
});
              const mostFrequentCluster= mostFrequentClusters[0];
               const topcluauster= topclusters[0];
               const rightcluster= rightclusters[0];
               const bottomcluster= bottomclusters[0];
               const leftcluster= leftclusters[0];
              mostFrequentCluster.lines.forEach(line => {
                const [x1, y1, x2, y2] = line;
             const seen = new Set<string>(); // 用于记录已经添加过的线段

function addUniqueLine(x1: number, y1: number, z1: number, x2: number, y2: number, z2: number) {
    const key = `${x1},${y1},${z1},${x2},${y2},${z2}`;
    if (!seen.has(key)) {
        seen.add(key);
        lines3d.push([x1, y1, z1, x2, y2, z2]);
    }
}
               
               topcluauster.lines.forEach(line => {
                const [tx1, ty1, tx2, ty2] = line;
                const clusterminy=topcluauster.min_y;
            if (tx1 <x1 && tx2 > x2) {
     addUniqueLine(x1, y1, ty1-clusterminy, x2, y2, ty1-clusterminy);
addUniqueLine(x1, y1, ty2-clusterminy, x2, y2, ty2-clusterminy);


            }
             rightcluster.lines.forEach(line => {
                const [rx1, ry1, rx2, ry2] = line;
                const clusterminx=rightcluster.min_x;
                if (ry1 <y1 && ry2 > y2) {
     addUniqueLine(x1, y1, rx1-clusterminx, x2, y2, rx1-clusterminx);
addUniqueLine(x1, y1, rx2-clusterminx, x2, y2, rx2-clusterminx);

                }
             });
         

              });
                
              });
Logger.info(`lines3d completed with ${lines3d.length} lines3d`);
                 lines3d.forEach(line => {

                PubSub.default.pub("njsgcs_makeline", line[0], line[1],  line[2], line[3], line[4], line[5],1); 
             })

第3 视角0是在外侧

材质全是红色说明侧视图读取可有可无

           topcluauster.lines.forEach(line => {
                const [tx1, ty1, tx2, ty2] = line;
                const clusterminy=topcluauster.min_y;
            if (tx1 <=x1 && tx2 >= x2) {
     addUniqueLine(x1, y1, ty1-clusterminy, x2, y2, ty1-clusterminy,1);
addUniqueLine(x1, y1, ty2-clusterminy, x2, y2, ty2-clusterminy,1);
addUniqueLine(x1, y1, ty1-clusterminy, x2, y2, ty2-clusterminy,1);

            }

.............

        topcluauster.lines.forEach(line => {
                const [tx1, ty1, tx2, ty2] = line;
                const clusterminy=topcluauster.min_y;
            if (tx1 <=x1 && tx2 >= x2) {
     addUniqueLine(x1, y1, ty1-clusterminy, x2, y2, ty1-clusterminy,1);
addUniqueLine(x1, y1, ty2-clusterminy, x2, y2, ty2-clusterminy,1);
addUniqueLine(x1, y1, ty1-clusterminy, x2, y2, ty2-clusterminy,1);
addUniqueLine(x1, y1, ty2-clusterminy, x2, y2, ty1-clusterminy,1);

            }

               
               topcluauster.lines.forEach(line => {
                const [tx1, ty1, tx2, ty2] = line;
                const clusterminy=topcluauster.min_y;
            if (tx1 <=x1 && tx2 >= x2) {
     addUniqueLine(x1, y1, ty1-clusterminy, x2, y2, ty1-clusterminy,1);
addUniqueLine(x1, y1, ty2-clusterminy, x2, y2, ty2-clusterminy,1);

if(ty1!=ty2){
addUniqueLine(x1, y1, ty1-clusterminy, x1, y1, ty2-clusterminy,1);
addUniqueLine(x2, y2, ty1-clusterminy, x2, y2, ty2-clusterminy,1);

}

旧版本合并会吃线条,不然是可以手动转为实体的

import { Logger, PubSub } from "chili-core";
import DxfParser, { ILineEntity } from 'dxf-parser';
class Cluster {
    lines: [number, number, number, number][];
    min_x: number;
    max_x: number;
    min_y: number;
    max_y: number;

    constructor(lines: [number, number, number, number][] = []) {
        this.lines = [...lines];
        this.min_x = Infinity;
        this.max_x = -Infinity;
        this.min_y = Infinity;
        this.max_y = -Infinity;

        if (lines.length > 0) {
            this.updateBounds();
        }
    }

    updateBounds(): void {
        this.min_x = Math.min(...this.lines.flatMap(line => [line[0], line[2]]));
        this.max_x = Math.max(...this.lines.flatMap(line => [line[0], line[2]]));
        this.min_y = Math.min(...this.lines.flatMap(line => [line[1], line[3]]));
        this.max_y = Math.max(...this.lines.flatMap(line => [line[1], line[3]]));
    }

    get lengthX(): number {
        return parseFloat((this.max_x - this.min_x).toFixed(1));
    }

    get lengthY(): number {
        return parseFloat((this.max_y - this.min_y).toFixed(1));
    }
}
function clusterLines(lines: [number, number, number, number][], expandDistance: number = 5): Cluster[] {
    const clusters: Cluster[] = [];
    const remainingLines = [...lines];

    while (remainingLines.length > 0) {
        const seed = remainingLines.shift()!;
        const currentCluster = new Cluster([seed]);
        currentCluster.updateBounds();

        let changed = true;

        while (changed) {
            changed = false;
            const expandedMinX = currentCluster.min_x - expandDistance;
            const expandedMaxX = currentCluster.max_x + expandDistance;
            const expandedMinY = currentCluster.min_y - expandDistance;
            const expandedMaxY = currentCluster.max_y + expandDistance;

            const toAdd: [number, number, number, number][] = [];

            for (const line of [...remainingLines]) {
                const [x1, y1, x2, y2] = line;
                const inBound =
                    (x1 >= expandedMinX && x1 <= expandedMaxX && y1 >= expandedMinY && y1 <= expandedMaxY) ||
                    (x2 >= expandedMinX && x2 <= expandedMaxX && y2 >= expandedMinY && y2 <= expandedMaxY);

                if (inBound) {
                    toAdd.push(line);
                    changed = true;
                }
            }

            for (const line of toAdd) {
                currentCluster.lines.push(line);
                remainingLines.splice(remainingLines.indexOf(line), 1);
            }

            currentCluster.updateBounds();
        }

        // 合并完全覆盖的聚类
        for (let i = 0; i < clusters.length; i++) {
            const cluster = clusters[i];
            if (
                currentCluster.min_x <= cluster.min_x &&
                currentCluster.min_y <= cluster.min_y &&
                currentCluster.max_x >= cluster.max_x &&
                currentCluster.max_y >= cluster.max_y
            ) {
                currentCluster.lines.push(...cluster.lines);
                clusters.splice(i, 1);
                break;
            }
        }

        clusters.push(currentCluster);
    }

    return clusters;
}
export function rebuild3D(document: Document) {
    const fileInput = document.createElement("input");
    fileInput.type = "file";
    fileInput.accept = ".dxf";
    fileInput.style.display = "none";

    fileInput.addEventListener("change", async (event) => {
        const target = event.target as HTMLInputElement;

        if (!target.files || target.files.length === 0) return;

        const file = target.files[0];
        Logger.info(`Selected file: ${file.name}`);

        try {
            const reader = new FileReader();
            reader.onload = () => {
                const dxfText = reader.result as string;
                const parser = new DxfParser();
                const dxf = parser.parseSync(dxfText);

                const inputlines: [number, number, number, number][] = [];

                if (dxf && dxf.entities) {
                    dxf.entities.forEach(entity => {
                        if (entity.type === 'LINE') {
                            const lineEntity = entity as ILineEntity;
                            const start = lineEntity.vertices[0];
                            const end = lineEntity.vertices[1];

                            if (start && end) {
                                inputlines.push([start.x, start.y, end.x, end.y]);
                            }
                        }
                    });
                }

                // 执行聚类
                const clusters = clusterLines(inputlines, 5);
                const lines3d:[number,number,number,number,number,number,number][]=[]
                const { mostMinX, mostMinY } = getMostFrequentMinXY(clusters);
                const mostFrequentClusters = clusters.filter(cluster => {
    return cluster.min_x === mostMinX.value && cluster.min_y === mostMinY.value;
});
const topclusters = clusters.filter(cluster => {
    return cluster.min_x === mostMinX.value && cluster.min_y > mostMinY.value;
});
;
const rightclusters = clusters.filter(cluster => {
    return cluster.min_x > mostMinX.value && cluster.min_y === mostMinY.value;
});
const bottomclusters = clusters.filter(cluster => {
    return cluster.min_x === mostMinX.value && cluster.min_y < mostMinY.value;
});
const leftclusters = clusters.filter(cluster => {
    return cluster.min_x < mostMinX.value && cluster.min_y === mostMinY.value;
});
              const mostFrequentCluster= mostFrequentClusters[0];
               const topcluauster= topclusters[0];
               const rightcluster= rightclusters[0];
               const bottomcluster= bottomclusters[0];
               const leftcluster= leftclusters[0];
                  const seen = new Set<string>(); // 用于记录已经添加过的线段
               function addUniqueLine(x1: number, y1: number, z1: number, x2: number, y2: number, z2: number,color:number) {
    const key = `${x1},${y1},${z1},${x2},${y2},${z2}`;
    if (!seen.has(key)) {
        seen.add(key);
        lines3d.push([x1, y1, z1, x2, y2, z2,color]);
    }
} const topview3dpoints = [];
              mostFrequentCluster.lines.forEach(line => {
                const [x1, y1, x2, y2] = line;
          


               
               topcluauster.lines.forEach(line => {
                const [tx1, ty1, tx2, ty2] = line;
                const clusterminy=topcluauster.min_y;
            if (tx1 <=x1 || tx2 >= x2) {
     addUniqueLine(x1, y1, ty1-clusterminy, x2, y2, ty1-clusterminy,1);
addUniqueLine(x1, y1, ty2-clusterminy, x2, y2, ty2-clusterminy,1);

if(ty1!=ty2){
addUniqueLine(x1, y1, ty1-clusterminy, x1, y1, ty2-clusterminy,1);
addUniqueLine(x2, y2, ty1-clusterminy, x2, y2, ty2-clusterminy,1);

}
    

            }
           
         

              });
                
              });
Logger.info(`lines3d completed with ${lines3d.length} lines3d`);
                 lines3d.forEach(line => {

                PubSub.default.pub("njsgcs_makeline", line[0], line[1],  line[2], line[3], line[4], line[5],1); 
             })
             ///
                // let i =0;
                // // 发送每个线段给 njsgcs_makeline
                // clusters.forEach(cluster => {
                //     i++;
                //     cluster.lines.forEach(line => {
                //         const [x1, y1, x2, y2] = line;
                //         PubSub.default.pub("njsgcs_makeline", x1, y1, 0, x2, y2, 0,i); // z=0 假设为俯视图
                //     });
                // });
  ///
                Logger.info(`Clustering completed with ${clusters.length} clusters`);
            };

            reader.readAsText(file);
        } catch (error) {
            Logger.error("Error reading file:", error);
        }
    });

    fileInput.click();
}
function getMostFrequentMinXY(clusters: Cluster[]) {
    const minXCounts: Record<number, number> = {};
    const minYCounts: Record<number, number> = {};

    let maxXCount = 0, mostX = clusters[0]?.min_x;
    let maxYCount = 0, mostY = clusters[0]?.min_y;

    for (const cluster of clusters) {
        const x = cluster.min_x;
        const y = cluster.min_y;

        minXCounts[x] = (minXCounts[x] || 0) + 1;
        if (minXCounts[x] > maxXCount) {
            maxXCount = minXCounts[x];
            mostX = x;
        }

        minYCounts[y] = (minYCounts[y] || 0) + 1;
        if (minYCounts[y] > maxYCount) {
            maxYCount = minYCounts[y];
            mostY = y;
        }
    }

    return {
        mostMinX: { value: mostX, count: maxXCount },
        mostMinY: { value: mostY, count: maxYCount }
    };
}

 

 里面开槽会多线


网站公告

今日签到

点亮在社区的每一天
去签到