Improve drawing export and foundation quantity views

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
CopilotandCopilot committed 2026-11-06 15:35:56 +09:00
1 parent a0ec74b09b
commit d22c5008f0
72 files changed
+24346 -12

No files matched your search

+36
View File
@@ -1,4 +1,6 @@
import { Vector3 } from 'three';
import type { PierInput } from '../src/core/types';
import { entityBounds } from './projection';
import type { PierModel } from '../src/core/geometry';
import { modelPrimitives, projectPoint, projectModel } from './projection';
import { modelBreaks, shortenedY } from './breaks';
@@ -61,3 +63,37 @@ export function keyplanEntities(models:readonly PierModel[],selected:PierModel,s
{kind:'polyline',points:[[tip[0]-north[0]*2*scale+north[1]*scale,tip[1]-north[1]*2*scale-north[0]*scale],tip,[tip[0]-north[0]*2*scale-north[1]*scale,tip[1]-north[1]*2*scale+north[0]*scale]],closed:false,layer:'TEXT',source});
return entities;
}
/** Actual projected model points anchor all isometric dimensions and EL leaders. */
export function isometricInfo(model:PierModel,input:PierInput,geometry:Entity[],scale:number,direction=0,dimensions=true):Entity[]{
const bounds=entityBounds(geometry),out:Entity[]=[],primitives=modelPrimitives(model);
const datum=Math.min(...model.columns.map(c=>c.bottom),...model.piles.map(c=>c.bottom),...model.footings.map(c=>c.bottom))*1000,theta=direction*Math.PI/2;
const project=(p:Vector3):Point=>{const [s,n]=projectPoint(model,p,'top'),a=s*Math.cos(theta)-n*Math.sin(theta),b=s*Math.sin(theta)+n*Math.cos(theta);return [(a-b)*Math.sqrt(3)/2,p.y*1000-datum+(a+b)*.5];};
const source={pier:model.name,member:'iso-info',index:0};
const text=(p:Point,value:string)=>out.push({kind:'text',point:p,text:value,height:2.5*scale,layer:'ELEVATION',source,align:'left'});
const line=(a:Point,b:Point)=>out.push({kind:'line',a,b,layer:'ELEVATION',source});
const rows:{point:Point;name:string;el:number}[]=[];
const column=primitives.cylinders.find(c=>c.source.member==='column');
if(column){
const bottom=project(column.center.clone().setY(column.bottom)),top=project(column.center.clone().setY(column.top));
if(dimensions)out.push({kind:'dimension',a:bottom,b:top,position:bounds.minX-4*scale,axis:'y',height:2.5*scale,value:(column.top-column.bottom)*1000,label:`H=${((column.top-column.bottom)*1000).toFixed(0)}`,source,layer:'DIMENSION'});
if(Number.isFinite(input.groundEl))rows.push({point:project(column.center.clone().setY(input.groundEl)),name:'지반고',el:input.groundEl});
}
const pile=primitives.cylinders.find(c=>c.source.member==='pile');
if(pile)rows.push({point:project(pile.center.clone().setY(pile.bottom)),name:'말뚝 하단',el:pile.bottom});
const footing=primitives.solids.find(s=>s.source.member==='footing');
if(footing){const points=footing.faces.flat(),el=Math.min(...points.map(p=>p.y)),p=points.find(p=>Math.abs(p.y-el)<1e-7)!;rows.push({point:project(p),name:'기초 하단',el});}
for(const [member,name,field] of [['block','교좌면','top'],['pad','몰탈 상면','padTop']] as const){
const solid=primitives.solids.find(s=>s.source.member===member);if(!solid)continue;
const block=model.blocks[solid.source.index];if(!block)continue;const el=block[field],points=solid.faces.flat(),p=points.reduce((a,b)=>Math.abs(a.y-el)<Math.abs(b.y-el)?a:b);
rows.push({point:project(p),name,el});
}
rows.sort((a,b)=>a.point[1]-b.point[1]);let last=-Infinity;
for(const row of rows){
const y=Math.max(row.point[1],last+8*scale);last=y;const x=bounds.maxX+3*scale;
line(row.point,[x-scale,y]);line([x-scale,y],[x+13*scale,y]);
out.push({kind:'polyline',points:[[row.point[0]+scale,row.point[1]+.6*scale],row.point,[row.point[0]+scale,row.point[1]-.6*scale]],closed:false,layer:'ELEVATION',source});
text([x,y+3.3*scale],row.name);text([x,y],`EL. ${row.el.toFixed(3)}`);
}
return out;
}