几何算法
使用
通过 vjmap3d.loadPluginAlgorithm 加载几何算法插件库
或 通过 vjmap3d.Plugins.loadPlugin("algorithm") 加载
let amLib = await vjmap3d.loadPluginAlgorithm();
let len = 1;
const brush1 = new amLib.Brush( new THREE.SphereGeometry(len) );
brush1.material.color = new THREE.Color("#0f0")
//
brush1.position.set(0, 0, 2)
brush1.updateMatrixWorld();
//
const brush2 = new amLib.Brush( new THREE.BoxGeometry(len, len, len) );
brush2.position.set(0, 0.5, 2)
//
brush2.material.color = new THREE.Color("#f00")
brush2.updateMatrixWorld();
// // 在球的表面挖去立方体的表面
const evaluator = new amLib.Evaluator();
const result = evaluator.evaluate( brush1, brush2, amLib.HOLLOW_SUBTRACTION );
app.scene.add(result)
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
scene: {
gridHelper: { visible: true } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
}
})
let amLib = await vjmap3d.loadPluginAlgorithm();
let len = 1;
const brush1 = new amLib.Brush( new THREE.SphereGeometry(len) );
brush1.material.color = new THREE.Color("#0f0")
//
brush1.position.set(0, 0, 2)
brush1.updateMatrixWorld();
//
const brush2 = new amLib.Brush( new THREE.BoxGeometry(len, len, len) );
brush2.position.set(0, 0.5, 2)
//
brush2.material.color = new THREE.Color("#f00")
brush2.updateMatrixWorld();
//
const evaluator = new amLib.Evaluator();
const result = evaluator.evaluate( brush1, brush2, amLib.HOLLOW_SUBTRACTION );
app.scene.add(result)
根据三维模型生成二维CAD图示例
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
scene: {
gridHelper: { visible: true } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
},
control: {
initState: {
cameraTarget: new THREE.Vector3(0.1, 0, 2),
cameraPosition: new THREE.Vector3(-2 ,2, 0),
}
}
})
let amLib = await vjmap3d.loadPluginAlgorithm();
let silhouette = new THREE.Mesh( new THREE.BufferGeometry(), new THREE.MeshBasicMaterial( {
color: '#eee',
polygonOffset: true,
polygonOffsetFactor: 3,
polygonOffsetUnits: 3,
side: THREE.DoubleSide,
} ) );
let outlines = new THREE.LineSegments( new THREE.BufferGeometry(), new THREE.LineBasicMaterial( { color: 0x030303 } ) );
app.scene.add( outlines, silhouette );
let ent = await vjmap3d.ResManager.loadModel(env.assetsPath + "models/soldier.glb", {
splitSubEntity: true,
position: [0, 1, 0],
rotation: [Math.PI / 2, 0, 0]
});
ent.addTo(app);
//
app.logInfo("正在根据三维模型生成二维平面图... (生成完成后可的右上角导出成dwg图)", 10000)
let model = ent.node;
let task = amLib.createProjectionTask({
model,
silhouette,
outlines,
updateProgressCb: (name, progress) => console.log(name, progress),
updateVisible: undefined,
ANGLE_THRESHOLD: 50
});
await task.promise();
//
let positions = outlines.geometry.attributes.position.array;
let entitys = []
for(let n = 0; n < positions.length; n+=6) {
// vjmap3d 约定 CAD/地图的 y 对应世界坐标的 -z,导出 DWG 时 z 要取反,否则图形上下镜像
let start = [positions[n], -positions[n + 2]];
let end = [positions[n + 3], -positions[n + 5]];
if (vjmap3d.approxArrayEquals(start, end)) continue; // 两点重合(默认容差 1e-5;第三参 error 可放宽,如 0.01)
entitys.push({
typename: "DbLine",
start: start,
end: end,
})
}
console.log(entitys)
let doc = app.svc.toDbDoc({
entitys
})
//console.log(doc)
let control = new vjmap3d.ButtonGroupControl({
buttons: [
{
id: "export",
html: "导出成CAD图",
title: "把生成的平面图导出成cad图",
style: {
width: "130px"
},
onclick: async () => {
let res = await app.svc.updateMap({
mapid: "silhouette_demo",
filedoc: doc,
mapopenway: vjmap3d.MapOpenWay.Memory,
style: {
backcolor: 0 // 如果div背景色是浅色,则设置为oxFFFFFF
}
})
let href = `${app.svc.baseUrl()}_cloud/#/map/${res.mapid}?version=${res.version}&mapopenway=Memory&vector=false&isFitMap=true`
window.open(href)
}
}
]
});
app.addControl(control, "top-right");
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
scene: {
gridHelper: { visible: true } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
},
control: {
initState: {
cameraTarget: new THREE.Vector3(0.1, 0, 2),
cameraPosition: new THREE.Vector3(-2 ,2, 0),
}
}
})
let amLib = await vjmap3d.loadPluginAlgorithm();
let silhouette = new THREE.Mesh( new THREE.BufferGeometry(), new THREE.MeshBasicMaterial( {
color: '#eee',
polygonOffset: true,
polygonOffsetFactor: 3,
polygonOffsetUnits: 3,
side: THREE.DoubleSide,
} ) );
let outlines = new THREE.LineSegments( new THREE.BufferGeometry(), new THREE.LineBasicMaterial( { color: 0x030303 } ) );
app.scene.add( outlines, silhouette );
let ent = await vjmap3d.ResManager.loadModel(env.assetsPath + "models/soldier.glb", {
splitSubEntity: true,
position: [0, 1, 0],
rotation: [Math.PI / 2, 0, 0]
});
ent.addTo(app);
//
app.logInfo("正在根据三维模型生成二维平面图... (生成完成后可的右上角导出成dwg图)", 10000)
let model = ent.node;
let task = amLib.createProjectionTask({
model,
silhouette,
outlines,
updateProgressCb: (name, progress) => console.log(name, progress),
updateVisible: undefined,
ANGLE_THRESHOLD: 50
});
await task.promise();
//
let positions = outlines.geometry.attributes.position.array;
let entitys = []
for(let n = 0; n < positions.length; n+=6) {
// vjmap3d 约定 CAD/地图的 y 对应世界坐标的 -z,导出 DWG 时 z 要取反,否则图形上下镜像
let start = [positions[n], -positions[n + 2]];
let end = [positions[n + 3], -positions[n + 5]];
if (vjmap3d.approxArrayEquals(start, end)) continue; // 两点重合(默认容差 1e-5;第三参 error 可放宽,如 0.01)
entitys.push({
typename: "DbLine",
start: start,
end: end,
})
}
console.log(entitys)
let doc = app.svc.toDbDoc({
entitys
})
//console.log(doc)
let control = new vjmap3d.ButtonGroupControl({
buttons: [
{
id: "export",
html: "导出成CAD图",
title: "把生成的平面图导出成cad图",
style: {
width: "130px"
},
onclick: async () => {
let res = await app.svc.updateMap({
mapid: "silhouette_demo",
filedoc: doc,
mapopenway: vjmap3d.MapOpenWay.Memory,
style: {
backcolor: 0 // 如果div背景色是浅色,则设置为oxFFFFFF
}
})
let href = `${app.svc.baseUrl()}_cloud/#/map/${res.mapid}?version=${res.version}&mapopenway=Memory&vector=false&isFitMap=true`
window.open(href)
}
}
]
});
app.addControl(control, "top-right");
类型定义
import { BufferGeometry, Group, InstancedMesh, InterleavedBufferAttribute, Line, Line3, LineSegments, Mesh, MeshPhongMaterial, Plane, Points, Triangle, TrianglesDrawModes, Vector3 } from 'three';
import {Side, Material, Ray, Sphere, Matrix4, Color,
Intersection, Box3, Vector2, Raycaster, MeshBasicMaterial,
LineBasicMaterial, DataTexture, BufferAttribute, Object3D } from 'three';
export declare class Brush extends Mesh {
isBrush: boolean;
markUpdated(): void;
isDirty(): boolean;
prepareGeometry(): void;
disposeCacheData(): void;
}
export declare class TypedAttributeData {
groupAttributes: Object[];
groupCount: number;
getType( name: String ): string;
getTotalLength( name: String ): number;
getGroupSet( index?: number ): Object;
getGroupAttrArray( name: string, index?: number ): Array<number>;
initializeArray( name: string, type: string ): void;
clear(): void;
delete( key: string ): void;
reset(): void;
}
export declare enum CSGOperation{}
export declare const ADDITION: CSGOperation;
export declare const SUBTRACTION: CSGOperation;
export declare const REVERSE_SUBTRACTION: CSGOperation;
export declare const INTERSECTION: CSGOperation;
export declare const DIFFERENCE: CSGOperation;
export declare const HOLLOW_SUBTRACTION: CSGOperation;
export declare const HOLLOW_INTERSECTION: CSGOperation;
export declare class Evaluator {
attributes: String[];
useGroups: boolean;
consolidateGroups: boolean; // 运行时属性名(上游 d.ts 误写为 consolidateMaterials)
debug: OperationDebugData;
evaluate( a: Brush, b: Brush, operation: CSGOperation, targetBrush?: Brush ): Brush;
evaluate( a: Brush, b: Brush, operations: CSGOperation[], targetBrushes: Brush[] ): Brush[];
evaluateHierarchy( root: Operation, target?: Brush ): Brush;
}
export declare class Operation extends Brush {
isOperation: boolean;
// operation
markUpdated(): void;
isDirty(): boolean;
insertBefore( brush: Brush ): void;
insertAfter( brush: Brush ): void;
}
export declare class OperationGroup extends Group {
isOperationGroup: boolean; // 运行时属性名(上游 d.ts 误拼为 isOperatioinGroup)
markUpdated(): void;
isDirty(): boolean;
}
export declare class CullableTriangle extends Triangle {
initFrom( other: Triangle ): void;
updateSide( plane: Plane, triangle: Triangle, coplanarIndex: number ): void;
}
export declare class TrianglePool {
getTriangle(): Triangle;
clear(): void;
reset(): void;
}
export declare class TriangleSplitter {
trianglePool: TrianglePool;
triangles: Triangle[];
normal: Vector3;
initialize( tri: Triangle ): void;
splitByTriangle( triangle: Triangle ): void;
splitByPlane( plane: Plane, triangle: Triangle, coplanarIndex: number ): void;
reset(): void;
}
export declare class HalfEdgeMap {
constructor( geometry?: BufferGeometry );
getSiblingTriangleIndex( triIndex: number, edgeIndex: number ): number;
getSiblingEdgeIndex( triIndex: number, edgeIndex: number ): number;
updateFrom( geomtry: BufferGeometry ): void;
}
export declare class GridMaterial extends MeshPhongMaterial {
enableGrid: boolean;
}
// ⚠️ 注意:主包 `vjmap3d.GridMaterial` 与 `createGridMaterialGpu` 均未导出(undefined);
// 上面这个类由算法插件导出,用 `amLib.GridMaterial`(amLib = await vjmap3d.loadPluginAlgorithm())。
// 网格地面助手实际导出名是 `vjmap3d.Grid`:Grid({cellSize,...}) 返回 { mesh, update }。
export declare function getTriangleDefinitions( ...triangles: Triangle[] ): String[];
export declare function logTriangleDefinitions( ...triangles: Triangle[] ): void;
export declare function generateRandomTriangleColors( geometry: BufferGeometry ): void;
export declare class TriangleSetHelper extends Group {
constructor( triangles?: Triangle[] );
setTriangles( triangles: Triangle[] ): void;
}
export declare class EdgesHelper extends LineSegments {
constructor( edges?: Line3[] );
setEdges( edges: Line3[] ): void;
}
export declare class TriangleIntersectData {
intersects: Object;
triangle: Triangle;
constructor( tri: Triangle );
addTriangle( index: number, tri: Triangle ): void;
getIntersectArray(): Array<Triangle>;
}
export declare class TriangleIntersectionSets {
addTriangleIntersection( ia: number, tribA: Triangle, ib: number, triB: Triangle ): void;
getTrianglesAsArray( id?: number ): Array<Triangle>;
getTriangleIndices(): Array<number>;
getIntersectionIndices( id: number ): void;
getIntersectionsAsArray( id?: number, id2?: number ): Array<Triangle>;
}
export declare class OperationDebugData {
intersectionEdges: Line3[];
enabled: boolean;
addIntersectingTriangles( ia: number, triA: Triangle, ib: number, triB: Triangle ): void;
addEdge( edge: Line3 ): void;
reset(): void;
}
export declare class PointsHelper extends InstancedMesh {
constructor( count?: number, points?: Vector3[] );
setPoints( points: Vector3 ): void;
}
export declare class HalfEdgeHelper extends EdgesHelper {
constructor( geometry?: BufferGeometry, halfEdges?: HalfEdgeMap );
setHalfEdges( geometry: BufferGeometry, halfEdges: HalfEdgeMap ): void;
}
export declare function computeMeshVolume( mesh : Mesh | BufferGeometry ) : Number;
// ⚠️ 参数对象不能省略:createProjectionTask() 无参调用会抛 ReferenceError(默认值引用了未定义的 options)。
// ANGLE_THRESHOLD 只有显式传 null 才取 50;不传(undefined)时实际按 1° 处理,需要 50 请显式传 ANGLE_THRESHOLD: 50。
export declare function createProjectionTask({ model, silhouette, outlines, updateProgressCb, updateVisible, ANGLE_THRESHOLD }?: any): {
onUpdate: () => void;
cancel: () => boolean;
promise: (tm?: any) => Promise<any>;
}
export declare class ProjectionGenerator {
[key: string]: any;
}
export declare class SilhouetteGenerator {
[key: string]: any;
}
// Contants
export declare enum SplitStrategy {}
export declare const CENTER: SplitStrategy;
export declare const AVERAGE: SplitStrategy;
export declare const SAH: SplitStrategy;
export declare enum ShapecastIntersection {}
export declare const NOT_INTERSECTED: ShapecastIntersection;
export declare const INTERSECTED: ShapecastIntersection;
export declare const CONTAINED: ShapecastIntersection;
// MeshBVH
export declare interface HitPointInfo {
point: Vector3;
distance: number;
faceIndex: number;
}
export declare interface MeshBVHOptions {
strategy?: SplitStrategy;
maxDepth?: number;
maxLeafTris?: number;
setBoundingBox?: boolean;
useSharedArrayBuffer?: boolean;
verbose?: boolean;
onProgress?: ( progress: number ) => void;
}
export declare interface MeshBVHSerializeOptions {
cloneBuffers?: boolean;
}
export declare interface MeshBVHDeserializeOptions {
setIndex?: boolean;
}
export declare class MeshBVH {
readonly geometry: BufferGeometry;
static serialize( bvh: MeshBVH, options?: MeshBVHSerializeOptions ): SerializedBVH;
static deserialize(
data: SerializedBVH,
geometry: BufferGeometry,
options?: MeshBVHDeserializeOptions
): MeshBVH;
constructor( geometry: BufferGeometry, options?: MeshBVHOptions );
raycast( ray: Ray, materialOrSide: Side | Array<Material> | Material ): Array<Intersection>
raycastFirst( ray: Ray, materialOrSide: Side | Array<Material> | Material ): Intersection;
intersectsSphere( sphere: Sphere ): boolean;
intersectsBox( box: Box3, boxToMesh: Matrix4 ): boolean;
intersectsGeometry( geometry: BufferGeometry, geometryToBvh: Matrix4 ): boolean;
closestPointToPoint(
point: Vector3,
target?: HitPointInfo,
minThreshold?: number,
maxThreshold?: number
): HitPointInfo | null;
closestPointToGeometry(
geometry: BufferGeometry,
geometryToBvh: Matrix4,
target1?: HitPointInfo,
target2?: HitPointInfo,
minThreshold?: number,
maxThreshold?: number
): HitPointInfo | null;
// union types to enable at least one of two functions:
shapecast(
callbacks: {
intersectsBounds: (
box: Box3,
isLeaf: boolean,
score: number | undefined,
depth: number,
nodeIndex: number
) => ShapecastIntersection|boolean,
boundsTraverseOrder?: (
box: Box3
) => number,
} & ( {
intersectsRange: (
triangleOffset: number,
triangleCount: number,
contained: boolean,
depth: number,
nodeIndex: number,
box: Box3
) => boolean,
} | {
intersectsTriangle: (
triangle: ExtendedTriangle,
triangleIndex: number,
contained: boolean,
depth: number
) => boolean|void
} )
): boolean;
// union types to enable at least one of two functions:
bvhcast(
otherBVH: MeshBVH,
matrixToLocal: Matrix4,
callbacks: ( {
intersectsRanges: (
offset1: number,
count1: number,
offset2: number,
count2: number,
depth1: number,
index1: number,
depth2: number,
index2: number
) => boolean
} | {
intersectsTriangles: (
triangle1: ExtendedTriangle,
triangle2: ExtendedTriangle,
i1: number,
i2: number,
depth1: number,
index1: number,
depth2: number,
index2: number,
) => boolean,
} )
): boolean;
traverse(
callback: (
depth: number,
isLeaf: boolean,
boundingData: ArrayBuffer,
offsetOrSplit: number,
count: number
) => void,
rootIndex?: number
): void;
refit( nodeIndices?: Array<number> | Set<number> ): void;
getBoundingBox( target: Box3 ): Box3;
}
// SerializedBVH
export class SerializedBVH {
roots: Array<ArrayBuffer>;
index: ArrayBufferView;
}
// MeshBVHHelper
export declare class MeshBVHHelper extends Group {
opacity: number;
depth: number;
displayParents: boolean;
displayEdges: boolean;
edgeMaterial: LineBasicMaterial;
meshMaterial: MeshBasicMaterial;
constructor( mesh: Mesh, depth?: number );
update(): void;
get color(): Color;
}
// THREE.js Extensions
export declare function computeBoundsTree( options?: MeshBVHOptions ): MeshBVH;
export declare function disposeBoundsTree(): void;
export declare function acceleratedRaycast(
raycaster: Raycaster,
intersects: Array<Intersection>
): void;
// Debug functions
export declare function estimateMemoryInBytes( bvh: MeshBVH ): number;
export declare interface ExtremeInfo {
nodeCount: number;
leafNodeCount: number;
surfaceAreaScore: number;
depth: {min: number, max: number};
tris: {min: number, max: number};
splits: [number, number, number];
}
export declare function getBVHExtremes( bvh :MeshBVH ): Array<ExtremeInfo>;
export declare function validateBounds( bvh: MeshBVH ): boolean;
export interface TreeNode {
bounds: Box3;
count: number;
offset: number;
left?: TreeNode;
right?: TreeNode;
}
export declare function getJSONStructure( bvh: MeshBVH ): TreeNode;
// Triangle Utilities
export declare interface HitTriangleInfo {
face: {
a: number,
b: number,
c: number,
materialIndex: number,
normal: Vector3
},
uv: Vector2
}
export declare function getTriangleHitPointInfo(
point: Vector3,
geometry : BufferGeometry,
triangleIndex: number,
target?: HitTriangleInfo
): HitTriangleInfo
// Shader Utilities
declare class VertexAttributeTexture extends DataTexture {
overrideItemSize: number | null;
updateFrom( attribute: BufferAttribute ): void;
}
// export declare class FloatVertexAttributeTexture extends VertexAttributeTexture {}
// export declare class UIntVertexAttributeTexture extends VertexAttributeTexture {}
// export declare class IntVertexAttributeTexture extends VertexAttributeTexture {}
export declare class MeshBVHUniformStruct {
updateFrom( bvh: MeshBVH ): void;
dispose(): void;
}
export declare const shaderStructs: string;
export declare const shaderFunctions: string;
// Math classes
export declare class ExtendedTriangle extends Triangle {
needsUpdate : boolean;
intersectsTriangle( other : Triangle, target? : Line3 ) : boolean;
intersectsSphere( sphere : Sphere ) : boolean;
closestPointToSegment( segment : Line3, target1? : Vector3, target2? : Vector3 ) : number;
distanceToPoint( point : Vector3 ) : number;
distanceToTriangle( tri : Triangle ) : number;
}
export declare class OrientedBox {
min: Vector3;
max: Vector3;
matrix : Matrix4;
needsUpdate : boolean;
constructor( min : Vector3, max : Vector3 );
set( min : Vector3, max : Vector3, matrix : Matrix4 ) : OrientedBox;
intersectsBox( box : Box3 ) : boolean;
intersectsTriangle( tri : Triangle ) : boolean;
closestPointToPoint( point : Vector3, target? : Vector3 ) : number;
distanceToPoint( point : Vector3 ) : number;
distanceToBox( box : Box3, threshold? : number, target1? : Vector3, target2? : Vector3 ) : number;
}
export declare class StaticGeometryGenerator {
useGroups : boolean;
attributes : Array<string>;
applyWorldTransforms : boolean;
constructor( objects : Array<Object3D> | Object3D );
getMaterials() : Array<Material>;
generate( target? : BufferGeometry ) : BufferGeometry;
}
export declare function mergeGeometries(geometries: BufferGeometry[], useGroups?: boolean): BufferGeometry;
export declare function mergeAttributes(attributes: BufferAttribute[]): BufferAttribute;
export declare function interleaveAttributes(attributes: BufferAttribute[]): InterleavedBufferAttribute;
export declare function estimateBytesUsed(geometry: BufferGeometry): number;
export declare function mergeVertices(geometry: BufferGeometry, tolerance?: number): BufferGeometry;
export declare function toTrianglesDrawMode(geometry: BufferGeometry, drawMode: TrianglesDrawModes): BufferGeometry;
export declare function computeMorphedAttributes(object: Mesh | Line | Points): object;
export declare function computeMikkTSpaceTangents(
geometry: BufferGeometry,
MikkTSpace: unknown,
negateSign?: boolean,
): BufferGeometry;
export declare function mergeGroups(geometry: BufferGeometry): BufferGeometry;
/**
* Modifies the supplied geometry if it is non-indexed, otherwise creates a new, non-indexed geometry. Returns the
* geometry with smooth normals everywhere except faces that meet at an angle greater than the crease angle.
*
* @param geometry The input geometry.
* @param creaseAngle The crease angle in radians.
*/
export declare function toCreasedNormals(geometry: BufferGeometry, creaseAngle?: number): BufferGeometry;
export declare class Delatin {
data: number[];
width: number;
height: number;
coords: any[];
triangles: any[];
_halfedges: any[];
_candidates: any[];
_queueIndices: any[];
_queue: any[];
_errors: any[];
_rms: any[];
_pending: any[];
_pendingLen: number;
_rmsSum: number;
constructor(data: number[], width: number, height: number);
run(maxError?: number): void;
refine(): void;
getMaxError(): any;
getRMSD(): number;
heightAt(x: any, y: any): number;
}