Compare commits

...

8 Commits

7 changed files with 286 additions and 111 deletions

View File

@ -13,6 +13,7 @@ import { currentMenuState } from '@/store/canvasAtom'
import { globalLocaleStore } from '@/store/localeAtom' import { globalLocaleStore } from '@/store/localeAtom'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { GlobalDataContext } from '@/app/GlobalDataProvider' import { GlobalDataContext } from '@/app/GlobalDataProvider'
import { sessionStore } from '@/store/commonAtom'
export default function FloorPlan({ children }) { export default function FloorPlan({ children }) {
const [correntObjectNo, setCurrentObjectNo] = useRecoilState(correntObjectNoState) const [correntObjectNo, setCurrentObjectNo] = useRecoilState(correntObjectNoState)
@ -26,6 +27,7 @@ export default function FloorPlan({ children }) {
const globalLocaleState = useRecoilValue(globalLocaleStore) const globalLocaleState = useRecoilValue(globalLocaleStore)
const { promiseGet } = useAxios(globalLocaleState) const { promiseGet } = useAxios(globalLocaleState)
const { setManagementState } = useContext(GlobalDataContext) const { setManagementState } = useContext(GlobalDataContext)
const [sessionState, setSessionState] = useRecoilState(sessionStore)
useEffect(() => { useEffect(() => {
getStuffDetailInfo() getStuffDetailInfo()
@ -51,6 +53,12 @@ export default function FloorPlan({ children }) {
if (res.data.installHeight === '0') { if (res.data.installHeight === '0') {
res.data.installHeight = '' res.data.installHeight = ''
} }
setSessionState((prev) => ({
...prev,
oneTwoStoreId: res.data.saleStoreId
}));
setManagementState({ ...res.data, surfaceTypeValue: surfaceTypeValue }) setManagementState({ ...res.data, surfaceTypeValue: surfaceTypeValue })
} }
}) })

View File

@ -132,7 +132,7 @@ export default function PowerConditionalSelect(props) {
mixMatlNo: item.mixMatlNo, mixMatlNo: item.mixMatlNo,
} }
}) })
getPcsModelList({ pcsMkrCd, pcsSerList, moduleItemList, storeId: sessionState.storeId }).then((res) => { getPcsModelList({ pcsMkrCd, pcsSerList, moduleItemList, storeId: sessionState.oneTwoStoreId }).then((res) => {
if (res?.result.code === 200 && res?.data) { if (res?.result.code === 200 && res?.data) {
setModels( setModels(
res.data.map((model) => { res.data.map((model) => {
@ -201,6 +201,7 @@ export default function PowerConditionalSelect(props) {
pcsMkrCd: option.pcsMkrCd, pcsMkrCd: option.pcsMkrCd,
mixMatlNo: moduleSelectionData.module.mixMatlNo, mixMatlNo: moduleSelectionData.module.mixMatlNo,
moduleMatlCds: moduleSelectionData.module.itemList.map((item) => item.itemId).join(','), moduleMatlCds: moduleSelectionData.module.itemList.map((item) => item.itemId).join(','),
storeId: sessionState.oneTwoStoreId,
} }
getPcsMakerList(param).then((res) => { getPcsMakerList(param).then((res) => {

View File

@ -45,6 +45,7 @@ export default function PassivityCircuitAllocation(props) {
.getObjects() .getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE) .filter((obj) => obj.name === POLYGON_TYPE.MODULE)
.forEach((obj) => { .forEach((obj) => {
obj.set({ pcs: null })
obj.on('mousedown', (e) => handleTargetModules(obj)) obj.on('mousedown', (e) => handleTargetModules(obj))
}) })
@ -135,6 +136,14 @@ export default function PassivityCircuitAllocation(props) {
surfaceType[`${surface.direction}-${surface.roofMaterial.pitch}`] = surface surfaceType[`${surface.direction}-${surface.roofMaterial.pitch}`] = surface
}) })
if (Object.keys(surfaceType).length > 1) {
swalFire({
text: getMessage('module.circuit.fix.not.same.roof.error'),
type: 'alert',
icon: 'warning',
})
return
}
break break
} }
@ -341,6 +350,7 @@ export default function PassivityCircuitAllocation(props) {
obj.circuit = null obj.circuit = null
obj.circuitNumber = null obj.circuitNumber = null
obj.pcsItemId = null obj.pcsItemId = null
obj.pcs = null
}) })
setCircuitNumber(minCircuitNumber) setCircuitNumber(minCircuitNumber)
setTargetModules([]) setTargetModules([])
@ -367,6 +377,7 @@ export default function PassivityCircuitAllocation(props) {
obj.circuit = null obj.circuit = null
obj.circuitNumber = null obj.circuitNumber = null
obj.pcsItemId = null obj.pcsItemId = null
obj.pcs = null
}) })
canvas.renderAll() canvas.renderAll()
setCircuitNumber(1) setCircuitNumber(1)

View File

@ -104,14 +104,16 @@ export default function PanelEdit(props) {
<WithDraggable isShow={true} pos={pos} className="xm"> <WithDraggable isShow={true} pos={pos} className="xm">
<WithDraggable.Header <WithDraggable.Header
title={getMessage( title={getMessage(
[PANEL_EDIT_TYPE.MOVE, PANEL_EDIT_TYPE.MOVE_ALL, PANEL_EDIT_TYPE.COLUMN_MOVE].includes(type) ? 'modal.move.setting' : 'modal.copy.setting', [PANEL_EDIT_TYPE.MOVE, PANEL_EDIT_TYPE.MOVE_ALL, PANEL_EDIT_TYPE.COLUMN_MOVE, PANEL_EDIT_TYPE.ROW_MOVE].includes(type)
? 'modal.move.setting'
: 'modal.copy.setting',
)} )}
onClose={() => closePopup(id)} onClose={() => closePopup(id)}
/> />
<WithDraggable.Body> <WithDraggable.Body>
<div className="grid-option-tit"> <div className="grid-option-tit">
{getMessage( {getMessage(
[PANEL_EDIT_TYPE.MOVE, PANEL_EDIT_TYPE.MOVE_ALL, PANEL_EDIT_TYPE.COLUMN_MOVE].includes(type) [PANEL_EDIT_TYPE.MOVE, PANEL_EDIT_TYPE.MOVE_ALL, PANEL_EDIT_TYPE.COLUMN_MOVE, PANEL_EDIT_TYPE.ROW_MOVE].includes(type)
? 'modal.move.setting.info' ? 'modal.move.setting.info'
: 'modal.copy.setting.info', : 'modal.copy.setting.info',
)} )}

View File

@ -37,7 +37,7 @@ export function useMasterController() {
return null return null
} }
const paramString = `?${paramArr.map((item) => `arrRoofMatlCd=${item}`).join('&')}` const paramString = `?${paramArr.map((item) => `arrRoofMatlCd=${item}`).join('&')}`
return await get({ url: `/api/v1/master/getModuleTypeItemList${paramString}&storeId=${sessionState.storeId}` }).then((res) => { return await get({ url: `/api/v1/master/getModuleTypeItemList${paramString}&storeId=${sessionState.oneTwoStoreId}` }).then((res) => {
// console.log('🚀🚀 ~ getModuleTypeItemList ~ res:', res) // console.log('🚀🚀 ~ getModuleTypeItemList ~ res:', res)
return res return res
}) })

View File

@ -21,7 +21,9 @@ export const dimmedStore = atom({
export const sessionStore = atom({ export const sessionStore = atom({
key: 'sessionState', key: 'sessionState',
default: {}, default: {
oneTwoStoreId: '',
},
}) })
export const slopeSelector = selectorFamily({ export const slopeSelector = selectorFamily({

View File

@ -212,12 +212,14 @@ const movingLineFromSkeleton = (roofId, canvas) => {
point.y = Big(point.y).plus(moveUpDownLength).toNumber(); point.y = Big(point.y).plus(moveUpDownLength).toNumber();
} }
}else if(moveDirection === 'out'){ }else if(moveDirection === 'out'){
if(isSamePoint(roof.basePoints[index], originalStartPoint)) { if(isSamePoint(roof.basePoints[index], originalStartPoint) || isSamePoint(roof.basePoints[index], originalEndPoint)) {
point.y = Big(point.y).minus(moveUpDownLength).toNumber();
}
if (isSamePoint(roof.basePoints[index], originalEndPoint)) {
point.y = Big(point.y).minus(moveUpDownLength).toNumber(); point.y = Big(point.y).minus(moveUpDownLength).toNumber();
// console.log('roof.basePoints[index]', roof.basePoints[index])
// console.log('point.x::::', point)
// console.log('originalStartPoint', originalStartPoint)
// console.log('originalEndPoint', originalEndPoint)
} }
} }
}else if(position === 'left'){ }else if(position === 'left'){
@ -262,7 +264,69 @@ const movingLineFromSkeleton = (roofId, canvas) => {
line.startPoint = newStartPoint; line.startPoint = newStartPoint;
line.endPoint = newEndPoint; line.endPoint = newEndPoint;
}); });
return newPoints;
/**
* 직선다각형을 이루지 못하는 좌표를 삭제합니다.
* @param {Array<object>} points - 폴리곤 좌표 배열
* @returns {Array<object>} 정리된 좌표 배열
*/
function removeNonOrthogonalPoints(points) {
if (!points || points.length < 3) return points;
const EPSILON = 1.0;
const isOrthogonal = (p1, p2) =>
Math.abs(p1.x - p2.x) < EPSILON || Math.abs(p1.y - p2.y) < EPSILON;
let current = [...points];
let changed = true;
// 1. 대각선을 만드는 점 제거
while (changed && current.length >= 3) {
changed = false;
for (let i = 0; i < current.length; i++) {
const pPrev = current[(i - 1 + current.length) % current.length];
const pCurr = current[i];
const pNext = current[(i + 1) % current.length];
// 현재 점(pCurr)을 기준으로 앞뒤 연결이 모두 직교하지 않거나,
// 현재 점을 제거했을 때 앞뒤 점(pPrev, pNext)이 직교하게 된다면 현재 점이 불필요한 "꺾임"일 수 있음.
if (!isOrthogonal(pPrev, pCurr) || !isOrthogonal(pCurr, pNext)) {
if (isOrthogonal(pPrev, pNext)) {
current.splice(i, 1);
changed = true;
break;
}
}
}
}
// 2. 일직선상의 중간 점 제거 (수평 또는 수직선상에 세 점이 있는 경우)
changed = true;
while (changed && current.length >= 3) {
changed = false;
for (let i = 0; i < current.length; i++) {
const p1 = current[i];
const p2 = current[(i + 1) % current.length];
const p3 = current[(i + 2) % current.length];
if ((Math.abs(p1.x - p2.x) < EPSILON && Math.abs(p2.x - p3.x) < EPSILON) ||
(Math.abs(p1.y - p2.y) < EPSILON && Math.abs(p2.y - p3.y) < EPSILON)) {
current.splice((i + 1) % current.length, 1);
changed = true;
break;
}
}
}
return current;
}
const cleaned = removeNonOrthogonalPoints(newPoints);
console.log(cleaned); // 결과: 4개의 점만 남음 (P1, P2, P3, P4)
return cleaned;
} }
} }
@ -376,7 +440,7 @@ export const skeletonBuilder = (roofId, canvas, textMode) => {
canvas.set('skeleton', cleanSkeleton) canvas.set('skeleton', cleanSkeleton)
canvas.renderAll() canvas.renderAll()
console.log('skeleton rendered.', canvas) //console.log('skeleton rendered.', canvas)
} catch (e) { } catch (e) {
console.error('스켈레톤 생성 중 오류 발생:', e) console.error('스켈레톤 생성 중 오류 발생:', e)
if (canvas.skeletonStates) { if (canvas.skeletonStates) {
@ -471,8 +535,13 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
); );
if (gableBaseLine) { if (gableBaseLine) {
// Store current state before processing // Store current state before processing - avoid circular refs by only picking needed data
const beforeGableProcessing = JSON.parse(JSON.stringify(skeletonLines)); const beforeGableProcessing = skeletonLines.map(line => ({
p1: { x: line.p1.x, y: line.p1.y },
p2: { x: line.p2.x, y: line.p2.y },
attributes: { ...line.attributes },
lineStyle: { ...line.lineStyle }
}));
// if(canvas.skeletonLines.length > 0){ // if(canvas.skeletonLines.length > 0){
// skeletonLines = canvas.skeletonLines; // skeletonLines = canvas.skeletonLines;
@ -623,51 +692,51 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
const sortRoofLines = ensureCounterClockwiseLines(roofLines) const sortRoofLines = ensureCounterClockwiseLines(roofLines)
// roofLines의 방향에 맞춰 currentRoofLines의 방향을 조정 // roofLines의 방향에 맞춰 currentRoofLines의 방향을 조정
const alignLineDirection = (sourceLines, targetLines) => { // const alignLineDirection = (sourceLines, targetLines) => {
return sourceLines.map((sourceLine) => { // return sourceLines.map((sourceLine) => {
// 가장 가까운 targetLine 찾기 // // 가장 가까운 targetLine 찾기
const nearestTarget = targetLines.reduce((nearest, targetLine) => { // const nearestTarget = targetLines.reduce((nearest, targetLine) => {
const sourceCenter = { // const sourceCenter = {
x: (sourceLine.x1 + sourceLine.x2) / 2, // x: (sourceLine.x1 + sourceLine.x2) / 2,
y: (sourceLine.y1 + sourceLine.y2) / 2, // y: (sourceLine.y1 + sourceLine.y2) / 2,
} // }
const targetCenter = { // const targetCenter = {
x: (targetLine.x1 + targetLine.x2) / 2, // x: (targetLine.x1 + targetLine.x2) / 2,
y: (targetLine.y1 + targetLine.y2) / 2, // y: (targetLine.y1 + targetLine.y2) / 2,
} // }
const distance = Math.hypot(sourceCenter.x - targetCenter.x, sourceCenter.y - targetCenter.y) // const distance = Math.hypot(sourceCenter.x - targetCenter.x, sourceCenter.y - targetCenter.y)
//
return !nearest || distance < nearest.distance ? { line: targetLine, distance } : nearest // return !nearest || distance < nearest.distance ? { line: targetLine, distance } : nearest
}, null)?.line // }, null)?.line
//
if (!nearestTarget) return sourceLine // if (!nearestTarget) return sourceLine
//
// 방향이 반대인지 확인 (벡터 내적을 사용) // // 방향이 반대인지 확인 (벡터 내적을 사용)
const sourceVec = { // const sourceVec = {
x: sourceLine.x2 - sourceLine.x1, // x: sourceLine.x2 - sourceLine.x1,
y: sourceLine.y2 - sourceLine.y1, // y: sourceLine.y2 - sourceLine.y1,
} // }
const targetVec = { // const targetVec = {
x: nearestTarget.x2 - nearestTarget.x1, // x: nearestTarget.x2 - nearestTarget.x1,
y: nearestTarget.y2 - nearestTarget.y1, // y: nearestTarget.y2 - nearestTarget.y1,
} // }
//
const dotProduct = sourceVec.x * targetVec.x + sourceVec.y * targetVec.y // const dotProduct = sourceVec.x * targetVec.x + sourceVec.y * targetVec.y
//
// 내적이 음수이면 방향이 반대이므로 뒤집기 // // 내적이 음수이면 방향이 반대이므로 뒤집기
if (dotProduct < 0) { // if (dotProduct < 0) {
return { // return {
...sourceLine, // ...sourceLine,
x1: sourceLine.x2, // x1: sourceLine.x2,
y1: sourceLine.y2, // y1: sourceLine.y2,
x2: sourceLine.x1, // x2: sourceLine.x1,
y2: sourceLine.y1, // y2: sourceLine.y1,
} // }
} // }
//
return sourceLine // return sourceLine
}) // })
} // }
console.log('wallBaseLines', wall.baseLines) console.log('wallBaseLines', wall.baseLines)
@ -693,10 +762,32 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
console.log('wallBaseLine:', wallBaseLine.x1, wallBaseLine.y1, wallBaseLine.x2, wallBaseLine.y2) console.log('wallBaseLine:', wallBaseLine.x1, wallBaseLine.y1, wallBaseLine.x2, wallBaseLine.y2)
console.log('isSamePoint result:', isSameLine2(wallBaseLine, wallLine)) console.log('isSamePoint result:', isSameLine2(wallBaseLine, wallLine))
const isCollinear = (l1, l2, tolerance = 0.1) => {
const slope1 = Math.abs(l1.x2 - l1.x1) < tolerance ? Infinity : (l1.y2 - l1.y1) / (l1.x2 - l1.x1)
const slope2 = Math.abs(l2.x2 - l2.x1) < tolerance ? Infinity : (l2.y2 - l2.y1) / (l2.x2 - l2.x1)
if (slope1 === Infinity && slope2 === Infinity) {
return Math.abs(l1.x1 - l2.x1) < tolerance
}
if (Math.abs(slope1 - slope2) > tolerance) return false
const yIntercept1 = l1.y1 - slope1 * l1.x1
const yIntercept2 = l2.y1 - slope2 * l2.x1
return Math.abs(yIntercept1 - yIntercept2) < tolerance
}
if (isCollinear(wallBaseLine, wallLine)) {
return
}
if (isSameLine2(wallBaseLine, wallLine)) { if (isSameLine2(wallBaseLine, wallLine)) {
return return
} }
const movedStart = Math.abs(wallBaseLine.x1 - wallLine.x1) > EPSILON || Math.abs(wallBaseLine.y1 - wallLine.y1) > EPSILON const movedStart = Math.abs(wallBaseLine.x1 - wallLine.x1) > EPSILON || Math.abs(wallBaseLine.y1 - wallLine.y1) > EPSILON
const movedEnd = Math.abs(wallBaseLine.x2 - wallLine.x2) > EPSILON || Math.abs(wallBaseLine.y2 - wallLine.y2) > EPSILON const movedEnd = Math.abs(wallBaseLine.x2 - wallLine.x2) > EPSILON || Math.abs(wallBaseLine.y2 - wallLine.y2) > EPSILON
@ -799,6 +890,8 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
getAddLine({ x: pLineX, y: pLineY }, { x: newPointX, y: pLineY }, 'green') getAddLine({ x: pLineX, y: pLineY }, { x: newPointX, y: pLineY }, 'green')
getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink') getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink')
} }
getAddLine(newPStart, newPEnd, 'red')
} }
if (isStartEnd.end) { if (isStartEnd.end) {
@ -828,6 +921,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink') getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink')
} }
//getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: newPointX, y: roofLine.y2 }, 'orange') //getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: newPointX, y: roofLine.y2 }, 'orange')
getAddLine(newPStart, newPEnd, 'red')
} }
} else if (condition === 'left_out') { } else if (condition === 'left_out') {
console.log('left_out::::isStartEnd:::::', isStartEnd) console.log('left_out::::isStartEnd:::::', isStartEnd)
@ -854,10 +948,13 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} else { } else {
getAddLine({ y: inLine.y2, x: inLine.x2 }, { y: bStartY, x: wallLine.x2 }, 'pink') getAddLine({ y: inLine.y2, x: inLine.x2 }, { y: bStartY, x: wallLine.x2 }, 'pink')
} }
}
getAddLine({ y: bStartY, x: wallLine.x2 }, { y: roofLine.y1, x: wallLine.x1 }, 'magenta') getAddLine({ y: bStartY, x: wallLine.x2 }, { y: roofLine.y1, x: wallLine.x1 }, 'magenta')
getAddLine({ y: newLine.y1, x: newLine.x1 }, { y: newLine.y2, x: wallLine.x2 }, 'Gray') getAddLine({ y: newLine.y1, x: newLine.x1 }, { y: newLine.y2, x: wallLine.x2 }, 'Gray')
findPoints.push({ y: aStartY, x: newPStart.x, position: 'left_out_start' }) findPoints.push({ y: aStartY, x: newPStart.x, position: 'left_out_start' })
}else{
newPStart.y = roofLine.y1
}
} else { } else {
const cLineY = Big(wallBaseLine.x1).minus(wallLine.x1).abs().toNumber() const cLineY = Big(wallBaseLine.x1).minus(wallLine.x1).abs().toNumber()
newPStart.y = Big(newPStart.y).minus(cLineY).toNumber() newPStart.y = Big(newPStart.y).minus(cLineY).toNumber()
@ -883,6 +980,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} }
} }
} }
getAddLine(newPStart, newPEnd, 'red')
} }
if (isStartEnd.end) { if (isStartEnd.end) {
@ -909,10 +1007,13 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} else { } else {
getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: bStartY, x: wallLine.x1 }, 'pink') getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: bStartY, x: wallLine.x1 }, 'pink')
} }
}
getAddLine({ y: bStartY, x: wallLine.x1 }, { y: roofLine.y2, x: wallLine.x2 }, 'magenta') getAddLine({ y: bStartY, x: wallLine.x1 }, { y: roofLine.y2, x: wallLine.x2 }, 'magenta')
getAddLine({ y: newLine.y2, x: newLine.x2 }, { y: newLine.y1, x: wallLine.x1 }, 'Gray') getAddLine({ y: newLine.y2, x: newLine.x2 }, { y: newLine.y1, x: wallLine.x1 }, 'Gray')
findPoints.push({ y: aStartY, x: newPEnd.x, position: 'left_out_end' }) findPoints.push({ y: aStartY, x: newPEnd.x, position: 'left_out_end' })
}else{
newPEnd.y = roofLine.y2
}
} else { } else {
const cLineY = Big(wallBaseLine.x2).minus(wallLine.x2).abs().toNumber() const cLineY = Big(wallBaseLine.x2).minus(wallLine.x2).abs().toNumber()
newPEnd.y = Big(newPEnd.y).plus(cLineY).toNumber() newPEnd.y = Big(newPEnd.y).plus(cLineY).toNumber()
@ -940,6 +1041,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} }
} }
findPoints.push({ y: newPStart.y, x: newPEnd.x, position: 'left_out_end' }) findPoints.push({ y: newPStart.y, x: newPEnd.x, position: 'left_out_end' })
getAddLine(newPStart, newPEnd, 'red')
} }
} else if (condition === 'right_in') { } else if (condition === 'right_in') {
if (isStartEnd.start) { if (isStartEnd.start) {
@ -968,6 +1070,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
getAddLine({ x: pLineX, y: pLineY }, { x: newPointX, y: pLineY }, 'green') getAddLine({ x: pLineX, y: pLineY }, { x: newPointX, y: pLineY }, 'green')
getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink') getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink')
} }
getAddLine(newPStart, newPEnd, 'red')
} }
if (isStartEnd.end) { if (isStartEnd.end) {
@ -997,6 +1100,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink') getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink')
} }
getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: newPointX, y: roofLine.y2 }, 'orange') getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: newPointX, y: roofLine.y2 }, 'orange')
getAddLine(newPStart, newPEnd, 'red')
} }
} else if (condition === 'right_out') { } else if (condition === 'right_out') {
console.log('right_out::::isStartEnd:::::', isStartEnd) console.log('right_out::::isStartEnd:::::', isStartEnd)
@ -1024,10 +1128,13 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} else { } else {
getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: bStartY, x: wallLine.x2 }, 'pink') getAddLine({ y: inLine.y1, x: inLine.x1 }, { y: bStartY, x: wallLine.x2 }, 'pink')
} }
}
getAddLine({ y: bStartY, x: wallLine.x2 }, { y: roofLine.y1, x: wallLine.x1 }, 'magenta') getAddLine({ y: bStartY, x: wallLine.x2 }, { y: roofLine.y1, x: wallLine.x1 }, 'magenta')
getAddLine({ y: newLine.y1, x: newLine.x1 }, { y: newLine.y2, x: wallLine.x2 }, 'Gray') getAddLine({ y: newLine.y1, x: newLine.x1 }, { y: newLine.y2, x: wallLine.x2 }, 'Gray')
findPoints.push({ y: aStartY, x: newPEnd.x, position: 'right_out_start' }) findPoints.push({ y: aStartY, x: newPEnd.x, position: 'right_out_start' })
}else{
newPStart.y = roofLine.y1
}
} else { } else {
const cLineY = Big(wallBaseLine.x1).minus(wallLine.x1).abs().toNumber() const cLineY = Big(wallBaseLine.x1).minus(wallLine.x1).abs().toNumber()
newPStart.y = Big(newPStart.y).plus(cLineY).toNumber() newPStart.y = Big(newPStart.y).plus(cLineY).toNumber()
@ -1053,6 +1160,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} }
} }
} }
getAddLine(newPStart, newPEnd, 'red')
} }
if (isStartEnd.end) { if (isStartEnd.end) {
@ -1108,6 +1216,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} }
} }
} }
getAddLine(newPStart, newPEnd, 'red')
} }
} }
} }
@ -1158,6 +1267,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
getAddLine({ x: pLineX, y: newPointY }, { x: sPoint.x, y: sPoint.y }, 'pink') getAddLine({ x: pLineX, y: newPointY }, { x: sPoint.x, y: sPoint.y }, 'pink')
} }
//getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: roofLine.x2, y: newPointY }, 'orange') //getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: roofLine.x2, y: newPointY }, 'orange')
getAddLine(newPStart, newPEnd, 'red')
} }
if (isStartEnd.end) { if (isStartEnd.end) {
@ -1186,6 +1296,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} }
//getAddLine({ x: roofLine.x1, y: roofLine.y1 }, { x: roofLine.x1, y: newPointY }, 'orange') //getAddLine({ x: roofLine.x1, y: roofLine.y1 }, { x: roofLine.x1, y: newPointY }, 'orange')
getAddLine(newPStart, newPEnd, 'red')
} }
} else if (condition === 'top_out') { } else if (condition === 'top_out') {
console.log('top_out isStartEnd:::::::', isStartEnd) console.log('top_out isStartEnd:::::::', isStartEnd)
@ -1213,10 +1324,13 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} else { } else {
getAddLine({ x: inLine.x1, y: inLine.y1 }, { x: bStartX, y: wallLine.y1 }, 'pink') getAddLine({ x: inLine.x1, y: inLine.y1 }, { x: bStartX, y: wallLine.y1 }, 'pink')
} }
}
getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x1, y: wallLine.y1 }, 'magenta') getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x1, y: wallLine.y1 }, 'magenta')
getAddLine({ x: newLine.x1, y: newLine.y1 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray') getAddLine({ x: newLine.x1, y: newLine.y1 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray')
findPoints.push({ x: aStartX, y: newPEnd.y, position: 'top_out_start' }) findPoints.push({ x: aStartX, y: newPEnd.y, position: 'top_out_start' })
}else{ //라인머지
newPStart.x = roofLine.x1
}
} else { } else {
const cLineX = Big(wallBaseLine.y1).minus(wallLine.y1).abs().toNumber() const cLineX = Big(wallBaseLine.y1).minus(wallLine.y1).abs().toNumber()
newPStart.x = Big(newPStart.x).plus(cLineX).toNumber() newPStart.x = Big(newPStart.x).plus(cLineX).toNumber()
@ -1241,6 +1355,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} }
} }
} }
getAddLine(newPStart, newPEnd, 'red')
} }
if (isStartEnd.end) { if (isStartEnd.end) {
const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber() const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
@ -1265,10 +1380,13 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} else { } else {
getAddLine({ x: inLine.x1, y: inLine.y1 }, { x: bStartX, y: wallLine.y1 }, 'pink') getAddLine({ x: inLine.x1, y: inLine.y1 }, { x: bStartX, y: wallLine.y1 }, 'pink')
} }
}
getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x2, y: wallLine.y2 }, 'magenta') getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x2, y: wallLine.y2 }, 'magenta')
getAddLine({ x: newLine.x2, y: newLine.y2 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray') getAddLine({ x: newLine.x2, y: newLine.y2 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray')
findPoints.push({ x: aStartX, y: newPEnd.y, position: 'top_out_end' }) findPoints.push({ x: aStartX, y: newPEnd.y, position: 'top_out_end' })
}else{
newPEnd.x = roofLine.x2
}
} else { } else {
const cLineX = Big(wallLine.y2).minus(wallBaseLine.y2).abs().toNumber() const cLineX = Big(wallLine.y2).minus(wallBaseLine.y2).abs().toNumber()
newPEnd.x = Big(newPEnd.x).minus(cLineX).toNumber() newPEnd.x = Big(newPEnd.x).minus(cLineX).toNumber()
@ -1294,6 +1412,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} }
} }
} }
getAddLine(newPStart, newPEnd, 'red')
} }
} else if (condition === 'bottom_in') { } else if (condition === 'bottom_in') {
if (isStartEnd.start) { if (isStartEnd.start) {
@ -1321,6 +1440,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
getAddLine({ x: pLineX, y: newPointY }, { x: sPoint.x, y: sPoint.y }, 'pink') getAddLine({ x: pLineX, y: newPointY }, { x: sPoint.x, y: sPoint.y }, 'pink')
} }
getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: roofLine.x2, y: newPointY }, 'orange') getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: roofLine.x2, y: newPointY }, 'orange')
getAddLine(newPStart, newPEnd, 'red')
} }
if (isStartEnd.end) { if (isStartEnd.end) {
@ -1349,6 +1469,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
getAddLine({ x: pLineX, y: newPointY }, { x: sPoint.x, y: sPoint.y }, 'pink') getAddLine({ x: pLineX, y: newPointY }, { x: sPoint.x, y: sPoint.y }, 'pink')
} }
getAddLine({ x: roofLine.x1, y: roofLine.y1 }, { x: roofLine.x1, y: newPointY }, 'orange') getAddLine({ x: roofLine.x1, y: roofLine.y1 }, { x: roofLine.x1, y: newPointY }, 'orange')
getAddLine(newPStart, newPEnd, 'red')
} }
} else if (condition === 'bottom_out') { } else if (condition === 'bottom_out') {
console.log('bottom_out isStartEnd:::::::', isStartEnd) console.log('bottom_out isStartEnd:::::::', isStartEnd)
@ -1375,10 +1496,13 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} else { } else {
getAddLine({ x: inLine.x1, y: inLine.y1 }, { x: bStartX, y: wallLine.y1 }, 'pink') getAddLine({ x: inLine.x1, y: inLine.y1 }, { x: bStartX, y: wallLine.y1 }, 'pink')
} }
}
getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x1, y: wallLine.y1 }, 'magenta') getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x1, y: wallLine.y1 }, 'magenta')
getAddLine({ x: newLine.x1, y: newLine.y1 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray') getAddLine({ x: newLine.x1, y: newLine.y1 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray')
findPoints.push({ x: aStartX, y: newPEnd.y, position: 'bottom_out_start' }) findPoints.push({ x: aStartX, y: newPEnd.y, position: 'bottom_out_start' })
}else {
newPStart.x = roofLine.x1
}
} else { } else {
const cLineX = Big(wallBaseLine.y1).minus(wallLine.y1).abs().toNumber() const cLineX = Big(wallBaseLine.y1).minus(wallLine.y1).abs().toNumber()
newPStart.x = Big(newPStart.x).minus(cLineX).toNumber() newPStart.x = Big(newPStart.x).minus(cLineX).toNumber()
@ -1404,6 +1528,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} }
} }
} }
getAddLine(newPStart, newPEnd, 'red')
} }
if (isStartEnd.end) { if (isStartEnd.end) {
@ -1429,10 +1554,13 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} else { } else {
getAddLine({ x: inLine.x1, y: inLine.y1 }, { x: bStartX, y: wallLine.y1 }, 'pink') getAddLine({ x: inLine.x1, y: inLine.y1 }, { x: bStartX, y: wallLine.y1 }, 'pink')
} }
}
getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x2, y: wallLine.y2 }, 'magenta') getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x2, y: wallLine.y2 }, 'magenta')
getAddLine({ x: newLine.x2, y: newLine.y2 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray') getAddLine({ x: newLine.x2, y: newLine.y2 }, { x: newLine.x1, y: wallLine.y1 }, 'Gray')
findPoints.push({ x: aStartX, y: newPEnd.y, position: 'bottom_out_end' }) findPoints.push({ x: aStartX, y: newPEnd.y, position: 'bottom_out_end' })
}else{
newPEnd.x = roofLine.x2
}
} else { } else {
const cLineX = Big(wallBaseLine.y2).minus(wallLine.y2).abs().toNumber() const cLineX = Big(wallBaseLine.y2).minus(wallLine.y2).abs().toNumber()
newPEnd.x = Big(newPEnd.x).plus(cLineX).toNumber() newPEnd.x = Big(newPEnd.x).plus(cLineX).toNumber()
@ -1458,12 +1586,13 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
} }
} }
} }
getAddLine(newPStart, newPEnd, 'red')
} }
} }
} }
} }
getAddLine(newPStart, newPEnd, 'red') //getAddLine(newPStart, newPEnd, 'red')
//canvas.remove(roofLine) //canvas.remove(roofLine)
} else { } else {
getAddLine(roofLine.startPoint, roofLine.endPoint) getAddLine(roofLine.startPoint, roofLine.endPoint)
@ -3424,58 +3553,78 @@ function getTurnDirection(p1, p2, p3) {
function isValleyVertex(targetPoint, connectedLine, allLines, isStartVertex) { function isValleyVertex(targetPoint, connectedLine, allLines, isStartVertex) {
const tolerance = 0.1; const tolerance = 0.1;
// 1. 연결된 '다른' 라인을 찾습니다. const connectedLineData = {
// isStartVertex가 true면 : 이 점으로 '들어오는' 라인(Previous Line)을 찾아야 함 x1: connectedLine.x1 ?? connectedLine.get?.('x1'),
// isStartVertex가 false면 : 이 점에서 '나가는' 라인(Next Line)을 찾아야 함 y1: connectedLine.y1 ?? connectedLine.get?.('y1'),
x2: connectedLine.x2 ?? connectedLine.get?.('x2'),
y2: connectedLine.y2 ?? connectedLine.get?.('y2'),
startPoint: connectedLine.startPoint,
endPoint: connectedLine.endPoint
};
let neighborLine = null; let neighborLine = null;
if (isStartVertex) { if (isStartVertex) {
// targetPoint가 Start이므로, 어떤 라인의 End가 targetPoint와 같아야 함 (Previous Line) neighborLine = allLines.find(l => {
neighborLine = allLines.find(l => if (l === connectedLine) return false;
l !== connectedLine && const lx1 = l.x1 ?? l.get?.('x1');
isSamePoint(l.endPoint || {x:l.x2, y:l.y2}, targetPoint, tolerance) const ly1 = l.y1 ?? l.get?.('y1');
); const lx2 = l.x2 ?? l.get?.('x2');
const ly2 = l.y2 ?? l.get?.('y2');
const end = l.endPoint || { x: lx2, y: ly2 };
return isSamePoint(end, targetPoint, tolerance);
});
} else { } else {
// targetPoint가 End이므로, 어떤 라인의 Start가 targetPoint와 같아야 함 (Next Line) neighborLine = allLines.find(l => {
neighborLine = allLines.find(l => if (l === connectedLine) return false;
l !== connectedLine && const lx1 = l.x1 ?? l.get?.('x1');
isSamePoint(l.startPoint || {x:l.x1, y:l.y1}, targetPoint, tolerance) const ly1 = l.y1 ?? l.get?.('y1');
); const lx2 = l.x2 ?? l.get?.('x2');
const ly2 = l.y2 ?? l.get?.('y2');
const start = l.startPoint || { x: lx1, y: ly1 };
return isSamePoint(start, targetPoint, tolerance);
});
} }
// 연결된 라인을 못 찾았거나 끊겨있으면 판단 불가 (일단 false)
if (!neighborLine) return false; if (!neighborLine) return false;
// 2. 세 점을 구성하여 회전 방향(Turn) 계산 const nlx1 = neighborLine.x1 ?? neighborLine.get?.('x1');
// 순서: PrevLine.Start -> [TargetVertex] -> NextLine.End const nly1 = neighborLine.y1 ?? neighborLine.get?.('y1');
const nlx2 = neighborLine.x2 ?? neighborLine.get?.('x2');
const nly2 = neighborLine.y2 ?? neighborLine.get?.('y2');
const clx1 = connectedLineData.x1;
const cly1 = connectedLineData.y1;
const clx2 = connectedLineData.x2;
const cly2 = connectedLineData.y2;
let p1, p2, p3; let p1, p2, p3;
if (isStartVertex) { if (isStartVertex) {
// neighbor(Prev) -> connected(Current) p1 = neighborLine.startPoint || { x: nlx1, y: nly1 };
p1 = neighborLine.startPoint || {x: neighborLine.x1, y: neighborLine.y1}; p2 = targetPoint;
p2 = targetPoint; // 접점 p3 = connectedLineData.endPoint || { x: clx2, y: cly2 };
p3 = connectedLine.endPoint || {x: connectedLine.x2, y: connectedLine.y2};
} else { } else {
// connected(Current) -> neighbor(Next) p1 = connectedLineData.startPoint || { x: clx1, y: cly1 };
p1 = connectedLine.startPoint || {x: connectedLine.x1, y: connectedLine.y1}; p2 = targetPoint;
p2 = targetPoint; // 접점 p3 = neighborLine.endPoint || { x: nlx2, y: nly2 };
p3 = neighborLine.endPoint || {x: neighborLine.x2, y: neighborLine.y2};
} }
// 3. 외적 계산 (Y축이 아래로 증가하는 캔버스 좌표계 + CCW 진행 기준)
// 값이 양수(+)면 오른쪽 턴 = 골짜기
const crossProduct = getTurnDirection(p1, p2, p3); const crossProduct = getTurnDirection(p1, p2, p3);
console.log('crossProduct:', crossProduct);
return crossProduct > 0; return crossProduct > 0;
} }
function findInteriorPoint(line, polygonLines) { function findInteriorPoint(line, polygonLines) {
const { x1, y1, x2, y2 } = line; const x1 = line.x1 ?? line.get?.('x1');
const y1 = line.y1 ?? line.get?.('y1');
const x2 = line.x2 ?? line.get?.('x2');
const y2 = line.y2 ?? line.get?.('y2');
// line 객체 포맷 통일 // line 객체 포맷 통일 (함수 내부용)
const currentLine = { const currentLine = {
...line, ...line,
x1, y1, x2, y2,
startPoint: { x: x1, y: y1 }, startPoint: { x: x1, y: y1 },
endPoint: { x: x2, y: y2 } endPoint: { x: x2, y: y2 }
}; };
@ -3486,6 +3635,8 @@ function findInteriorPoint(line, polygonLines) {
// 2. 끝점이 골짜기인지 확인 // 2. 끝점이 골짜기인지 확인
const endIsValley = isValleyVertex(currentLine.endPoint, currentLine, polygonLines, false); const endIsValley = isValleyVertex(currentLine.endPoint, currentLine, polygonLines, false);
return { return {
start: startIsValley, start: startIsValley,
end: endIsValley end: endIsValley