36 lines
2.3 KiB
TypeScript
36 lines
2.3 KiB
TypeScript
import type { Entity, Point, ViewBreak } from './types';
|
|
const id=(p:Point)=>`${Math.round(p[0]*1000)},${Math.round(p[1]*1000)}`;
|
|
export function hatchGeometry(entities:Entity[],scale:number):Entity[] {
|
|
const out:Entity[]=[],groups=new Map<string,Extract<Entity,{kind:'line'}>[]>();
|
|
for(const e of entities){
|
|
if(!['STRUCTURE','BEARING'].includes(e.layer))continue;
|
|
if(e.kind==='polyline'&&e.closed)out.push({kind:'hatch',points:e.points,pattern:e.source.member==='pile'?'ANSI31':'SOLID',angle:45,spacing:2*scale,color:e.source.member==='blinding'?'#e7e9ec':'#cccccc',source:e.source,layer:'HATCH'});
|
|
if(e.kind==='circle'&&e.source.member==='column')out.push({kind:'hatch',points:Array.from({length:48},(_,i)=>[e.center[0]+e.radius*Math.cos(i*Math.PI/24),e.center[1]+e.radius*Math.sin(i*Math.PI/24)] as Point),pattern:'SOLID',angle:45,spacing:2*scale,color:'#cccccc',source:e.source,layer:'HATCH'});
|
|
if(e.kind==='line'){const key=`${e.source.member}:${e.source.index}`;if(!groups.has(key))groups.set(key,[]);groups.get(key)!.push(e);}
|
|
}
|
|
for(const group of groups.values()){
|
|
const unused=new Set(group);
|
|
while(unused.size){const first=unused.values().next().value!;unused.delete(first);const points=[first.a,first.b];
|
|
while(id(points[points.length-1])!==id(points[0])){
|
|
const last=id(points[points.length-1]),next=[...unused].find(e=>id(e.a)===last||id(e.b)===last);
|
|
if(!next)break;unused.delete(next);points.push(id(next.a)===last?next.b:next.a);
|
|
}
|
|
if(points.length>3&&id(points[0])===id(points[points.length-1]))out.push({kind:'hatch',points:points.slice(0,-1),pattern:first.source.member==='blinding'?'ANSI31':'SOLID',spacing:2*scale,angle:45,color:'#cccccc',layer:'HATCH',source:first.source});
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
const clipY=(points:Point[],y:number,above:boolean):Point[]=>{
|
|
const out:Point[]=[];
|
|
for(let i=0;i<points.length;i++){
|
|
const a=points[i],b=points[(i+1)%points.length],da=(a[1]-y)*(above?1:-1),db=(b[1]-y)*(above?1:-1);
|
|
if(da>=0)out.push(a);
|
|
if((da>=0)!==(db>=0)){const t=(y-a[1])/(b[1]-a[1]);out.push([a[0]+(b[0]-a[0])*t,y]);}
|
|
}return out;
|
|
};
|
|
export function cutHatch(points:Point[],cuts:readonly ViewBreak[]):Point[][] {
|
|
let polygons=[points];
|
|
for(const cut of cuts)polygons=polygons.flatMap(p=>[clipY(p,cut.from,false),clipY(p,cut.to,true)]).filter(p=>p.length>2);
|
|
return polygons;
|
|
}
|