import { useEffect } from 'react' import { useRecoilState } from 'recoil' import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import Big from 'big.js' import { isSamePoint, toGeoJSON } from '@/util/qpolygon-utils' import { SkeletonBuilder } from '@/lib/skeletons' import { preprocessPolygonCoordinates, findOppositeLine, createOrderedBasePoints, createInnerLinesFromSkeleton } from '@/util/skeleton-utils' export default function useSkeleton(canvas, roofId, textMode = false) { // 2. 스켈레톤 생성 및 그리기 //처마 if (!canvas) { console.warn('Canvas is not available'); return; } let roof = canvas?.getObjects().find((object) => object.id === roofId) if (!roof) { console.warn(`Roof with id ${roofId} not found`); return; } if (!roof.points || roof.points.length < 3) { console.warn('Roof points are invalid'); return; } const eavesType = [LINE_TYPE.WALLLINE.EAVES, LINE_TYPE.WALLLINE.HIPANDGABLE] const gableType = [LINE_TYPE.WALLLINE.GABLE, LINE_TYPE.WALLLINE.JERKINHEAD] /** 외벽선 */ const wall = canvas.getObjects().find((object) => object.name === POLYGON_TYPE.WALL && object.attributes.roofId === roofId) //const baseLines = wall.baseLines.filter((line) => line.attributes.planeSize > 0) const baseLines = canvas.getObjects().filter((object) => object.name === 'baseLine' && object.parentId === roofId) || []; const baseLinePoints = baseLines.map((line) => ({x:line.left, y:line.top})); const outerLines = canvas.getObjects().filter((object) => object.name === 'outerLinePoint') || []; const outerLinePoints = outerLines.map((line) => ({x:line.left, y:line.top})) const hipLines = canvas.getObjects().filter((object) => object.name === 'hip' && object.parentId === roofId) || []; const ridgeLines = canvas.getObjects().filter((object) => object.name === 'ridge' && object.parentId === roofId) || []; //const skeletonLines = []; // 1. 지붕 폴리곤 좌표 전처리 const coordinates = preprocessPolygonCoordinates(roof.points); if (coordinates.length < 3) { console.warn("Polygon has less than 3 unique points. Cannot generate skeleton."); return; } const moveFlowLine = roof.moveFlowLine || 0; // Provide a default value const moveUpDown = roof.moveUpDown || 0; // Provide a default value let points = roof.points; //마루이동 if (moveFlowLine !== 0 || moveUpDown !== 0) { const movingLineFromSkeleton = (roofId, canvas) => { if (!canvas) { console.warn('Canvas is not available in movingLineFromSkeleton'); return null; } let roof = canvas?.getObjects().find((object) => object.id === roofId) if (!roof) { console.warn(`Roof with id ${roofId} not found in movingLineFromSkeleton`); return null; } let moveDirection = roof.moveDirect; let moveFlowLine = roof.moveFlowLine??0; let moveUpDown = roof.moveUpDown??0; const getSelectLine = () => roof.moveSelectLine; const selectLine = getSelectLine(); if (!selectLine || !selectLine.startPoint || !selectLine.endPoint) { console.warn('SelectLine is not available'); return null; } let movePosition = roof.movePosition; const startPoint = selectLine.startPoint const endPoint = selectLine.endPoint const orgRoofPoints = roof.points; // orgPoint를 orgPoints로 변경 if (!canvas.skeleton || !canvas.skeleton.Edges) { console.warn('Skeleton edges are not available'); return null; } const oldPoints = canvas?.skeleton.lastPoints ?? orgRoofPoints // 여기도 변경 const oppositeLine = findOppositeLine(canvas.skeleton.Edges, startPoint, endPoint, oldPoints); const wall = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.WALL && obj.attributes.roofId === roofId) if (!wall || !wall.baseLines) { console.warn('Wall or baseLines are not available'); return null; } const baseLines = wall.baseLines roof.basePoints = createOrderedBasePoints(roof.points, baseLines) const skeletonPolygon = canvas.getObjects().filter((object) => object.skeletonType === 'polygon' && object.parentId === roofId) const skeletonLines = canvas.getObjects().filter((object) => object.skeletonType === 'line' && object.parentId === roofId) if (oppositeLine) { console.log('Opposite line found:', oppositeLine); } else { console.log('No opposite line found'); } if(moveFlowLine !== 0) { return oldPoints.map((point, index) => { console.log('Point:', point); const newPoint = { ...point }; const absMove = Big(moveFlowLine).times(2).div(10); console.log('skeletonBuilder moveDirection:', moveDirection); switch (moveDirection) { case 'left': // Move left: decrease X if (moveFlowLine !== 0) { for (const line of oppositeLine) { if (line.position === 'left') { if (isSamePoint(newPoint, line.start)) { newPoint.x = Big(line.start.x).plus(absMove).toNumber(); } else if (isSamePoint(newPoint, line.end)) { newPoint.x = Big(line.end.x).plus(absMove).toNumber(); } break; } } } else if (moveUpDown !== 0) { } break; case 'right': for (const line of oppositeLine) { if (line.position === 'right') { if (isSamePoint(newPoint, line.start)) { newPoint.x = Big(line.start.x).minus(absMove).toNumber(); } else if (isSamePoint(newPoint, line.end)) { newPoint.x = Big(line.end.x).minus(absMove).toNumber(); } break } } break; case 'up': // Move up: decrease Y (toward top of screen) for (const line of oppositeLine) { if (line.position === 'top') { if (isSamePoint(newPoint, line.start)) { newPoint.y = Big(line.start.y).minus(absMove).toNumber(); } else if (isSamePoint(newPoint, line.end)) { newPoint.y = Big(line.end.y).minus(absMove).toNumber(); } break; } } break; case 'down': // Move down: increase Y (toward bottom of screen) for (const line of oppositeLine) { if (line.position === 'bottom') { console.log('oldPoint:', point); if (isSamePoint(newPoint, line.start)) { newPoint.y = Big(line.start.y).minus(absMove).toNumber(); } else if (isSamePoint(newPoint, line.end)) { newPoint.y = Big(line.end.y).minus(absMove).toNumber(); } break; } } break; default : } console.log('newPoint:', newPoint); //baseline 변경 return newPoint; }) } else if(moveUpDown !== 0) { const position = movePosition //result.position; const absMove = Big(moveUpDown).times(1).div(10); const modifiedStartPoints = []; // oldPoints를 복사해서 새로운 points 배열 생성 let newPoints = oldPoints.map(point => ({...point})); // selectLine과 일치하는 baseLines 찾기 const matchingLines = baseLines .map((line, index) => ({ ...line, findIndex: index })) .filter(line => (isSamePoint(line.startPoint, selectLine.startPoint) && isSamePoint(line.endPoint, selectLine.endPoint)) || (isSamePoint(line.startPoint, selectLine.endPoint) && isSamePoint(line.endPoint, selectLine.startPoint)) ); matchingLines.forEach(line => { const originalStartPoint = line.startPoint; const originalEndPoint = line.endPoint; const offset = line.attributes.offset // 새로운 좌표 계산 let newStartPoint = {...originalStartPoint}; let newEndPoint = {...originalEndPoint}; // 원본 라인 업데이트 // newPoints 배열에서 일치하는 포인트들을 찾아서 업데이트 console.log('absMove::', absMove); newPoints.forEach((point, index) => { if(position === 'bottom'){ if (moveDirection === 'in') { if(isSamePoint(roof.basePoints[index], originalStartPoint) || isSamePoint(roof.basePoints[index], originalEndPoint)) { point.y = Big(point.y).minus(absMove).toNumber(); } // if (isSamePoint(roof.basePoints[index], originalEndPoint)) { // point.y = Big(point.y).minus(absMove).toNumber(); // } }else if (moveDirection === 'out'){ if(isSamePoint(roof.basePoints[index], originalStartPoint) || isSamePoint(roof.basePoints[index], originalEndPoint)) { point.y = Big(point.y).plus(absMove).toNumber(); } // if (isSamePoint(roof.basePoints[index], originalEndPoint)) { // point.y = Big(point.y).plus(absMove).toNumber(); // } } }else if (position === 'top'){ if(moveDirection === 'in'){ if(isSamePoint(roof.basePoints[index], originalStartPoint)) { point.y = Big(point.y).plus(absMove).toNumber(); } if (isSamePoint(roof.basePoints[index], originalEndPoint)) { point.y = Big(point.y).plus(absMove).toNumber(); } }else if(moveDirection === 'out'){ if(isSamePoint(roof.basePoints[index], originalStartPoint)) { point.y = Big(point.y).minus(absMove).toNumber(); } if (isSamePoint(roof.basePoints[index], originalEndPoint)) { point.y = Big(point.y).minus(absMove).toNumber(); } } }else if(position === 'left'){ if(moveDirection === 'in'){ if(isSamePoint(roof.basePoints[index], originalStartPoint) || isSamePoint(roof.basePoints[index], originalEndPoint)) { point.x = Big(point.x).plus(absMove).toNumber(); } // if (isSamePoint(roof.basePoints[index], originalEndPoint)) { // point.x = Big(point.x).plus(absMove).toNumber(); // } }else if(moveDirection === 'out'){ if(isSamePoint(roof.basePoints[index], originalStartPoint) || isSamePoint(roof.basePoints[index], originalEndPoint)) { point.x = Big(point.x).minus(absMove).toNumber(); } // if (isSamePoint(roof.basePoints[index], originalEndPoint)) { // point.x = Big(point.x).minus(absMove).toNumber(); // } } }else if(position === 'right'){ if(moveDirection === 'in'){ if(isSamePoint(roof.basePoints[index], originalStartPoint)) { point.x = Big(point.x).minus(absMove).toNumber(); } if (isSamePoint(roof.basePoints[index], originalEndPoint)) { point.x = Big(point.x).minus(absMove).toNumber(); } }else if(moveDirection === 'out'){ if(isSamePoint(roof.basePoints[index], originalStartPoint)) { point.x = Big(point.x).plus(absMove).toNumber(); } if (isSamePoint(roof.basePoints[index], originalEndPoint)) { point.x = Big(point.x).plus(absMove).toNumber(); } } } }); // 원본 baseLine도 업데이트 line.startPoint = newStartPoint; line.endPoint = newEndPoint; }); return newPoints; } } const result = movingLineFromSkeleton(roofId, canvas); if (result) { points = result; } } console.log('points:', points); const geoJSONPolygon = toGeoJSON(points) try { // SkeletonBuilder는 닫히지 않은 폴리곤을 기대하므로 마지막 점 제거 geoJSONPolygon.pop() const skeleton = SkeletonBuilder.BuildFromGeoJSON([[geoJSONPolygon]]) // 스켈레톤 데이터를 기반으로 내부선 생성 roof.innerLines = roof.innerLines || []; roof.innerLines = createInnerLinesFromSkeleton(roofId, canvas, skeleton, textMode) // 캔버스에 스켈레톤 상태 저장 if (!canvas.skeletonStates) { canvas.skeletonStates = {} canvas.skeletonLines = [] } canvas.skeletonStates[roofId] = true canvas.skeletonLines = []; canvas.skeletonLines.push(...roof.innerLines) roof.skeletonLines = canvas.skeletonLines; const cleanSkeleton = { Edges: skeleton.Edges.map(edge => ({ X1: edge.Edge.Begin.X, Y1: edge.Edge.Begin.Y, X2: edge.Edge.End.X, Y2: edge.Edge.End.Y, Polygon: edge.Polygon, // Add other necessary properties, but skip circular references })), roofId: roofId, // Add other necessary top-level properties }; canvas.skeleton = []; canvas.skeleton = cleanSkeleton canvas.skeleton.lastPoints = points canvas.set("skeleton", cleanSkeleton); canvas.renderAll() console.log('skeleton rendered.', canvas); } catch (e) { console.error('스켈레톤 생성 중 오류 발생:', e) if (canvas.skeletonStates) { canvas.skeletonStates[roofId] = false canvas.skeletonStates = {} canvas.skeletonLines = [] } } }