auto: 2026-09-03 18:31 (ESD_LAPTOP)
This commit is contained in:
@@ -323,20 +323,55 @@ function circlePoints(center: XY, radius: number): XY[] {
|
||||
return points;
|
||||
}
|
||||
|
||||
/**
|
||||
* `rect` → 닫힌 네 모서리 점열(회전 transform 적용).
|
||||
*
|
||||
* 돌쌓기 돌·돌망태 칸(`B06_Section_UI_Cross_Wall_Hatch.cell()`)은 `rect` 하나에
|
||||
* `rotate(벽기울기 cx cy)` 를 걸어 그린다. 수확기가 `rect` 를 안 보던 때는 형태 해칭
|
||||
* 80개 중 **49개(돌·칸 전부)가 CAD 에 안 실렸다**(2026-09-03 실측). 모서리 반경(`rx`)은
|
||||
* 무시한다 — 도면에서는 각진 칸으로 충분하다.
|
||||
*/
|
||||
function rectPoints(element: SVGElement): XY[] {
|
||||
const x = attr(element, "x");
|
||||
const y = attr(element, "y");
|
||||
const width = attr(element, "width");
|
||||
const height = attr(element, "height");
|
||||
const corners: XY[] = [
|
||||
[x, y],
|
||||
[x + width, y],
|
||||
[x + width, y + height],
|
||||
[x, y + height],
|
||||
[x, y],
|
||||
];
|
||||
const rotate = /rotate\(\s*(-?[\d.]+)[\s,]+(-?[\d.]+)[\s,]+(-?[\d.]+)\s*\)/.exec(
|
||||
element.getAttribute("transform") ?? "",
|
||||
);
|
||||
if (!rotate) return corners.map(([cx, cy]) => flip(cx, cy));
|
||||
const angle = (Number(rotate[1]) * Math.PI) / 180;
|
||||
const [ox, oy] = [Number(rotate[2]), Number(rotate[3])];
|
||||
const cos = Math.cos(angle);
|
||||
const sin = Math.sin(angle);
|
||||
return corners.map(([cx, cy]) => {
|
||||
const dx = cx - ox;
|
||||
const dy = cy - oy;
|
||||
return flip(ox + dx * cos - dy * sin, oy + dx * sin + dy * cos);
|
||||
});
|
||||
}
|
||||
|
||||
/** 오프스크린 SVG에 그려진 도형을 CAD 엔티티로 옮긴다 (블록 테두리 안으로 자른다). */
|
||||
function harvest(root: SVGElement, style: Style, frame: number[]): Entity[] {
|
||||
const [fx0, , fx1] = frame;
|
||||
const entities: Entity[] = [];
|
||||
const segments: XY[][] = [];
|
||||
const inside = (px: number): boolean => px >= fx0 && px <= fx1;
|
||||
const nodes = root.querySelectorAll<SVGElement>("polygon, polyline, line, circle, text");
|
||||
const nodes = root.querySelectorAll<SVGElement>("polygon, polyline, line, circle, rect, text");
|
||||
for (const element of Array.from(nodes)) {
|
||||
if (element.closest(SKIP_SELECTOR)) continue;
|
||||
const tag = element.tagName.toLowerCase();
|
||||
// 클립 그룹 안의 해칭은 경계로 **잘라서** 싣는다 — CAD 에는 클립이 없다.
|
||||
const clip = clipPolygonOf(element);
|
||||
if (tag === "polygon" || tag === "polyline") {
|
||||
const points = parsePoints(element);
|
||||
if (tag === "polygon" || tag === "polyline" || tag === "rect") {
|
||||
const points = tag === "rect" ? rectPoints(element) : parsePoints(element);
|
||||
if (tag === "polygon" && points.length > 2) points.push(points[0]);
|
||||
const runs = clip ? clipPointsToPolygon(points, clip) : [points];
|
||||
for (const run of runs) {
|
||||
|
||||
Reference in New Issue
Block a user