diff --git a/src/components/common/input/CalcInput.jsx b/src/components/common/input/CalcInput.jsx index 17af010e..5cb2bb42 100644 --- a/src/components/common/input/CalcInput.jsx +++ b/src/components/common/input/CalcInput.jsx @@ -3,7 +3,7 @@ import { createCalculator } from '@/util/calc-utils' import '@/styles/calc.scss' export const CalculatorInput = forwardRef( - ({ value, onChange, label, options = {}, id, className = 'calculator-input', readOnly = false, placeholder, name='', disabled = false }, ref) => { + ({ value, onChange, label, options = {}, id, className = 'calculator-input', readOnly = false, placeholder, name='', disabled = false, maxLength = 12 }, ref) => { const [showKeypad, setShowKeypad] = useState(false) const [displayValue, setDisplayValue] = useState(value || '0') const [hasOperation, setHasOperation] = useState(false) @@ -48,28 +48,56 @@ export const CalculatorInput = forwardRef( const calculator = calculatorRef.current let newDisplayValue = '' + // maxLength 체크 + if (maxLength > 0) { + const currentLength = (calculator.currentOperand || '').length + (calculator.previousOperand || '').length + (calculator.operation || '').length + if (currentLength >= maxLength) { + return + } + } + // 소수점 이하 2자리 제한 로직 추가 const shouldPreventInput = (value) => { - const decimalParts = (value || '').split('.') + if (!value) return false + const decimalParts = value.toString().split('.') return decimalParts.length > 1 && decimalParts[1].length >= 2 } + // 숫자 추가 함수 + const appendNumber = (current, num) => { + // maxLength 체크 + if (maxLength > 0 && (current + num).length > maxLength) { + return current + } + // 현재 값이 0이고 소수점이 없을 때 0이 아닌 숫자를 입력하면 대체 + if (current === '0' && num !== '.' && !current.includes('.')) { + return num.toString() + } + // 0. 다음에 0을 입력하는 경우 허용 + if (current === '0' && num === '0') { + return '0.' + } + return current + num + } + if (hasOperation) { // 연산자 이후 숫자 입력 시 - if (calculator.currentOperand === '0' || calculator.shouldResetDisplay) { + if (calculator.shouldResetDisplay) { calculator.currentOperand = num.toString() calculator.shouldResetDisplay = false - }else if (!shouldPreventInput(calculator.currentOperand)) { //소수점 이하2자리 - calculator.currentOperand = (calculator.currentOperand || '') + num + } else if (num === '.') { + if (!calculator.currentOperand.includes('.')) { + calculator.currentOperand = calculator.currentOperand || '0' + '.' + } + } else if (!shouldPreventInput(calculator.currentOperand)) { + calculator.currentOperand = appendNumber(calculator.currentOperand || '0', num) } - // else { - // calculator.currentOperand = (calculator.currentOperand || '') + num - // } + newDisplayValue = calculator.previousOperand + calculator.operation + calculator.currentOperand setDisplayValue(newDisplayValue) } else { // 첫 번째 숫자 입력 시 - if (displayValue === '0' || calculator.shouldResetDisplay) { + if (calculator.shouldResetDisplay) { calculator.currentOperand = num.toString() calculator.shouldResetDisplay = false newDisplayValue = calculator.currentOperand @@ -77,8 +105,17 @@ export const CalculatorInput = forwardRef( if (!hasOperation) { onChange(calculator.currentOperand) } - } else if (!shouldPreventInput(calculator.currentOperand)) { //소수점 이하2자리 - calculator.currentOperand = (calculator.currentOperand || '') + num + } else if (num === '.') { + if (!calculator.currentOperand.includes('.')) { + calculator.currentOperand = (calculator.currentOperand || '0') + '.' + newDisplayValue = calculator.currentOperand + setDisplayValue(newDisplayValue) + if (!hasOperation) { + onChange(newDisplayValue) + } + } + } else if (!shouldPreventInput(calculator.currentOperand)) { + calculator.currentOperand = appendNumber(calculator.currentOperand || '0', num) newDisplayValue = calculator.currentOperand setDisplayValue(newDisplayValue) if (!hasOperation) { @@ -382,6 +419,7 @@ export const CalculatorInput = forwardRef( placeholder={placeholder} autoComplete={'off'} disabled={disabled} + maxLength={maxLength} /> {showKeypad && !readOnly && ( diff --git a/src/components/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx index 4cdffbed..a8f5f148 100644 --- a/src/components/estimate/Estimate.jsx +++ b/src/components/estimate/Estimate.jsx @@ -24,6 +24,7 @@ import { useSwal } from '@/hooks/useSwal' import { QcastContext } from '@/app/QcastProvider' import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' import {normalizeDigits, normalizeDecimal} from '@/util/input-utils' +import { CalculatorInput } from '@/components/common/input/CalcInput' export default function Estimate({}) { const [uniqueData, setUniqueData] = useState([]) const [handlePricingFlag, setHandlePricingFlag] = useState(false) @@ -2106,25 +2107,60 @@ export default function Estimate({}) {
- {*/} + {/* onChangeAmount(e.target.value, item.dispOrder, index)*/} + {/* }}*/} + {/* maxLength={6}*/} + {/*/>*/} + { - onChangeAmount(e.target.value, item.dispOrder, index) + onChange={(value) =>{ + onChangeAmount(value, item.dispOrder, index) }} - maxLength={6} - /> + options={{ + allowNegative: false, + allowDecimal: false + }} + />
{item.unit}
- {*/} + {/* onChangeSalePrice(e.target.value, item.dispOrder, index)*/} + {/* }}*/} + {/* maxLength={12}*/} + {/*/>*/} + { - onChangeSalePrice(e.target.value, item.dispOrder, index) + onChange={(value) =>{ + onChangeSalePrice(value, item.dispOrder, index) }} maxLength={12} + options={{ + allowNegative: false, + allowDecimal: false + }} />
{item.openFlg === '1' && ( diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index c87d161f..8d173bc6 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -845,37 +845,33 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { // 먼저 좌표 업데이트 this.setCoords() - // 캔버스 줌과 viewport transform 고려한 좌표 변환 - let localPoint = point + // viewport transform만 역변환 (캔버스 줌/팬 보정) + // 결과는 WORLD 좌표 (캔버스 좌표계) + let canvasPoint = point if (this.canvas) { const vpt = this.canvas.viewportTransform if (vpt) { - // viewport transform 역변환 const inverted = fabric.util.invertTransform(vpt) - localPoint = fabric.util.transformPoint(point, inverted) + canvasPoint = fabric.util.transformPoint(point, inverted) } } - // 오브젝트의 transform matrix를 고려한 좌표 변환 - const matrix = this.calcTransformMatrix() - const invertedMatrix = fabric.util.invertTransform(matrix) - const transformedPoint = fabric.util.transformPoint(localPoint, invertedMatrix) - - // pathOffset을 고려한 최종 좌표 계산 - const pathOffset = this.get('pathOffset') - const finalPoint = { - x: Number((transformedPoint.x + pathOffset.x).toFixed(this.toFixed)), - y: Number((transformedPoint.y + pathOffset.y).toFixed(this.toFixed)), + // canvasPoint는 WORLD 좌표 + // inPolygonImproved에서 getCurrentPoints()도 WORLD 좌표를 반환 + // 따라서 좌표 시스템이 일치함 + const checkPoint = { + x: Number(canvasPoint.x.toFixed(this.toFixed)), + y: Number(canvasPoint.y.toFixed(this.toFixed)), } if (this.name === POLYGON_TYPE.ROOF && this.isFixed) { - const isInside = this.inPolygonImproved(finalPoint) + const isInside = this.inPolygonImproved(checkPoint) if (!this.selectable) { this.set('selectable', isInside) } return isInside } else { - return this.inPolygonImproved(finalPoint) + return this.inPolygonImproved(checkPoint) } }, diff --git a/src/components/floor-plan/modal/basic/step/Module.jsx b/src/components/floor-plan/modal/basic/step/Module.jsx index 426724eb..a708f749 100644 --- a/src/components/floor-plan/modal/basic/step/Module.jsx +++ b/src/components/floor-plan/modal/basic/step/Module.jsx @@ -235,11 +235,23 @@ export default function Module({ setTabNum }) {
- setInputVerticalSnowCover(normalizeDecimal(e.target.value))}*/} + {/*/>*/} + setInputVerticalSnowCover(normalizeDecimal(e.target.value))} + onChange={(value) => setInputVerticalSnowCover(value)} + options={{ + allowNegative: false, + allowDecimal: false + }} />
cm diff --git a/src/components/floor-plan/modal/basic/step/Orientation.jsx b/src/components/floor-plan/modal/basic/step/Orientation.jsx index fdf599be..4feeb41b 100644 --- a/src/components/floor-plan/modal/basic/step/Orientation.jsx +++ b/src/components/floor-plan/modal/basic/step/Orientation.jsx @@ -638,7 +638,7 @@ export const Orientation = forwardRef((props, ref) => { name="" label="" className="input-origin block" - value={inputInstallHeight} + value={inputVerticalSnowCover} onChange={(value) => handleChangeVerticalSnowCover(value)} options={{ allowNegative: false, diff --git a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx index f86a7ead..32e20ad4 100644 --- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx @@ -5,12 +5,13 @@ import StepUp from '@/components/floor-plan/modal/circuitTrestle/step/StepUp' import { useMessage } from '@/hooks/useMessage' import { usePopup } from '@/hooks/usePopup' import PassivityCircuitAllocation from './step/type/PassivityCircuitAllocation' +import BasicSetting from '@/components/floor-plan/modal/basic/BasicSetting' import { useMasterController } from '@/hooks/common/useMasterController' -import { useRecoilState, useRecoilValue } from 'recoil' +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { GlobalDataContext } from '@/app/GlobalDataProvider' -import { POLYGON_TYPE } from '@/common/common' +import { POLYGON_TYPE, MENU } from '@/common/common' import { useSwal } from '@/hooks/useSwal' -import { canvasState, canvasZoomState } from '@/store/canvasAtom' +import { canvasState, canvasZoomState, currentMenuState } from '@/store/canvasAtom' import { useTrestle } from '@/hooks/module/useTrestle' import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions' @@ -29,11 +30,12 @@ const ALLOCATION_TYPE = { } export default function CircuitTrestleSetting({ id }) { const { getMessage } = useMessage() - const { closePopup } = usePopup() + const { closePopup, addPopup } = usePopup() const { apply, setViewCircuitNumberTexts, getEstimateData, clear: clearTrestle, setAllModuleSurfaceIsComplete } = useTrestle() const { swalFire } = useSwal() const { saveEstimate } = useEstimate() const canvas = useRecoilValue(canvasState) + const setCurrentMenu = useSetRecoilState(currentMenuState) const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState) const [tabNum, setTabNum] = useState(1) const [allocationType, setAllocationType] = useState(ALLOCATION_TYPE.AUTO) @@ -106,6 +108,167 @@ export default function CircuitTrestleSetting({ id }) { } }, []) + // 모듈이 설치된 경우 rack설치 여부에 따라 설치 된 모듈 아래에 작은 모듈이 설치되어 있을 경우는 모듈 설치 메뉴 reopen + useEffect(() => { + const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE) + if (modules.length === 0) { + return + } + + /** + * 랙 설치 시 모듈 크기 검증 + * - 남쪽: 아래쪽 모듈이 위쪽 모듈보다 커야 함 + * - 북쪽: 위쪽 모듈이 아래쪽 모듈보다 커야 함 + * - 동쪽: 오른쪽 모듈이 왼쪽 모듈보다 커야 함 + * - 서쪽: 왼쪽 모듈이 오른쪽 모듈보다 커야 함 + */ + const validateModuleSizeForRack = (surface) => { + const { modules, direction, trestleDetail } = surface + const { rackYn, moduleIntvlHor, moduleIntvlVer } = trestleDetail + + if (rackYn === 'N' || !modules || modules.length < 2) { + return true // 검증 통과 + } + + // 모듈 중심점 및 크기 정보 계산 + const centerPoints = modules.map((module) => { + const { x, y } = module.getCenterPoint() + const { width, height } = module + return { + x, + y, + width: Math.floor(width), + height: Math.floor(height), + area: Math.floor(width) * Math.floor(height), + } + }) + + // 방향별 설정 + const isVertical = direction === 'south' || direction === 'north' + const primaryInterval = isVertical ? moduleIntvlVer : moduleIntvlHor + const secondaryInterval = isVertical ? moduleIntvlHor : moduleIntvlVer + + // 정렬 함수: 큰 모듈이 있어야 할 위치부터 시작 + const getSortFn = () => { + switch (direction) { + case 'south': return (a, b) => b.y - a.y // 아래쪽(y 큼)부터 + case 'north': return (a, b) => a.y - b.y // 위쪽(y 작음)부터 + case 'east': return (a, b) => b.x - a.x // 오른쪽(x 큼)부터 + case 'west': return (a, b) => a.x - b.x // 왼쪽(x 작음)부터 + default: return () => 0 + } + } + + // 타겟 모듈 찾기 (현재 모듈보다 작아야 할 위치의 모듈) + const findTargetModules = (current, margin) => { + return centerPoints.filter(cp => { + const sameAxis = isVertical + ? Math.abs(cp.x - current.x) < margin + : Math.abs(cp.y - current.y) < margin + const targetDirection = direction === 'south' ? cp.y < current.y + : direction === 'north' ? cp.y > current.y + : direction === 'east' ? cp.x < current.x + : cp.x > current.x + return sameAxis && targetDirection + }) + } + + // 가장 가까운 타겟 모듈 찾기 + const getClosestTarget = (filtered) => { + if (filtered.length === 0) return null + return filtered.reduce((closest, cp) => { + switch (direction) { + case 'south': return cp.y > closest.y ? cp : closest + case 'north': return cp.y < closest.y ? cp : closest + case 'east': return cp.x > closest.x ? cp : closest + case 'west': return cp.x < closest.x ? cp : closest + default: return closest + } + }) + } + + // 두 모듈 간 간격 계산 + const getGap = (current, target) => { + if (isVertical) { + return direction === 'south' + ? (current.y - current.height / 2) - (target.y + target.height / 2) + : (target.y - target.height / 2) - (current.y + current.height / 2) + } else { + return direction === 'east' + ? (current.x - current.width / 2) - (target.x + target.width / 2) + : (target.x - target.width / 2) - (current.x + current.width / 2) + } + } + + // 인접 모듈 여부 확인 + const isAdjacent = (current, target) => { + const gap = getGap(current, target) + return gap >= 0 && gap <= primaryInterval + 1 + } + + // 정렬된 모듈 순회 + const sortedPoints = [...centerPoints].sort(getSortFn()) + + for (const current of sortedPoints) { + // 1. 일반 배치: 같은 라인에서 인접 모듈 검사 + const directTargets = findTargetModules(current, secondaryInterval) + const closestTarget = getClosestTarget(directTargets) + + if (closestTarget && isAdjacent(current, closestTarget) && closestTarget.area > current.area) { + return false // 검증 실패 + } + + // 2. 물떼새 배치: 반 오프셋 위치의 인접 모듈 검사 + const size = isVertical ? current.width : current.height + const halfOffset = (size + secondaryInterval) / 2 + + for (const sign of [-1, 1]) { + const offsetValue = sign * halfOffset + const findHalfTarget = centerPoints.filter((cp) => { + const offsetAxis = isVertical + ? Math.abs(cp.x - (current.x + offsetValue)) <= primaryInterval + : Math.abs(cp.y - (current.y + offsetValue)) <= primaryInterval + const targetDirection = direction === 'south' ? cp.y < current.y + : direction === 'north' ? cp.y > current.y + : direction === 'east' ? cp.x < current.x + : cp.x > current.x + return offsetAxis && targetDirection + }) + + const closestHalf = getClosestTarget(findHalfTarget) + if (closestHalf && isAdjacent(current, closestHalf) && closestHalf.area > current.area) { + return false // 검증 실패 + } + } + } + + return true // 검증 통과 + } + + // 모든 설치면에 대해 검증 수행 + const moduleSetupSurfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) + for (const surface of moduleSetupSurfaces) { + if (!validateModuleSizeForRack(surface)) { + swalFire({ + text: getMessage('module.size.validation.rack.error'), + icon: 'error', + confirmFn: () => { + // 현재 팝업 닫기 + closePopup(id) + // 메뉴 하이라이트 변경 + setCurrentMenu(MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING) + // 모듈/가대설정 팝업 열기 + const newPopupId = uuidv4() + clearTrestle() + setAllModuleSurfaceIsComplete(false) + addPopup(newPopupId, 1, ) + }, + }) + return + } + } + }, []) + const capture = async (type) => { beforeCapture(type) diff --git a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx index 5b956cc2..b0b9a1e5 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx @@ -1,13 +1,10 @@ -import { GlobalDataContext } from '@/app/GlobalDataProvider' import QSelectBox from '@/components/common/select/QSelectBox' import { useMessage } from '@/hooks/useMessage' import { canvasState } from '@/store/canvasAtom' -import { modelState, pcsCheckState } from '@/store/circuitTrestleAtom' +import { pcsCheckState } from '@/store/circuitTrestleAtom' import { selectedModuleState } from '@/store/selectedModuleOptions' -import { useContext, useEffect, useState } from 'react' +import { useEffect, useState } from 'react' import { useRecoilState, useRecoilValue } from 'recoil' -import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController' -import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom' import { useMasterController } from '@/hooks/common/useMasterController' import { v4 as uuidv4 } from 'uuid' import { globalLocaleStore } from '@/store/localeAtom' @@ -15,7 +12,6 @@ import { POLYGON_TYPE } from '@/common/common' import { useSwal } from '@/hooks/useSwal' import { circuitNumDisplaySelector } from '@/store/settingAtom' import { fontSelector } from '@/store/fontAtom' -import { PCS_MKR_MULTI_TYPE } from './PowerConditionalSelect' export default function StepUp(props) { const { @@ -42,6 +38,7 @@ export default function StepUp(props) { const [arrayLength, setArrayLength] = useState(3) //module-table-inner의 반복 개수 const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState) const { getPcsVoltageStepUpList, getPcsAutoRecommendList, getPcsVoltageChk, getPcsConnOptionItemList } = useMasterController() + const [originPcsVoltageStepUpList, setOriginPcsVoltageStepUpList] = useState([]) const canvas = useRecoilValue(canvasState) const selectedModules = useRecoilValue(selectedModuleState) const [optCodes, setOptCodes] = useState([]) @@ -100,6 +97,9 @@ export default function StepUp(props) { /** PCS 승압설정 정보 SET */ setStepUpListData(stepUpListData) + if (originPcsVoltageStepUpList.length === 0) { + setOriginPcsVoltageStepUpList(stepUpListData) + } /** PCS 옵션 조회 */ // const formattedOptCodes = formatOptionCodes(res.data.optionList) @@ -108,8 +108,7 @@ export default function StepUp(props) { /** 캔버스에 회로 정보 적용 */ // 병설일때 pcs 있으면 setSubOpsions, 없으면 setMainOptions - console.log('stepUpListData', stepUpListData) - let mChk = 0; + let mChk = 0 stepUpListData[0].pcsItemList.forEach((pcsItem, index) => { const optionList = formatOptionCodes(pcsItem.optionList) if (isMultiOptions()) { @@ -166,7 +165,7 @@ export default function StepUp(props) { targetModule.circuitNumber = module.circuit canvas.add(moduleCircuitText) } else { - mChk++; + mChk++ } }) }) @@ -399,10 +398,14 @@ export default function StepUp(props) { })) } + const handleChangeApplyParalQty = (mainIdx, subIdx, applyParalQty) => { + handleRowClick(mainIdx, subIdx, applyParalQty) + } + /** * 행 선택 핸들러 함수 추가 */ - const handleRowClick = (mainIdx, subIdx) => { + const handleRowClick = (mainIdx, subIdx, applyParalQty = null) => { /** 자동 승압 설정인 경우만 실행 */ if (allocationType !== 'auto') return @@ -434,7 +437,13 @@ export default function StepUp(props) { /** 선택된 serQty 찾기 */ const selectedSerQty = matchingPcsItem?.serQtyList.find((serQty) => serQty.selected)?.serQty || 0 - + if (index === 0) { + return { + ...pcsItem, + applySerQty: selectedSerQty, + applyParalQty: +applyParalQty, + } + } return { ...pcsItem, applySerQty: selectedSerQty, @@ -474,7 +483,7 @@ export default function StepUp(props) { module.pcsItemId = null }) - /** 선택된 모듈 목록 추가 */ + /** 선택된 모듈 목록 추가 */ selectedData.roofSurfaceList.forEach((roofSurface) => { const targetSurface = canvas.getObjects().filter((obj) => obj.id === roofSurface.roofSurfaceId)[0] const moduleIds = targetSurface.modules.map((module) => { @@ -523,7 +532,7 @@ export default function StepUp(props) { canvas.renderAll() setModuleStatisticsData() - } + } /** * 현재 선택된 값들을 가져오는 함수 추가 @@ -645,15 +654,49 @@ export default function StepUp(props) { handleRowClick(idx, serQtyIdx)} style={{ cursor: allocationType === 'auto' ? 'pointer' : 'default' }} > - {item.serQty} + { + handleRowClick(idx, serQtyIdx, item.paralQty) + }} + > + {item.serQty} + {/* 2025.12.04 select 추가 */} - + {idx === 0 ? ( + + ) : ( + <>{item.paralQty} + )} {/* {item.paralQty} */} diff --git a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx index 22b0dd16..df8ecde2 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx @@ -103,17 +103,6 @@ export default function PassivityCircuitAllocation(props) { surfaceType[`${surface.direction}-${surface.roofMaterial.pitch}`] = surface }) - if (surfaceList.length > 1) { - if (Object.keys(surfaceType).length > 1) { - swalFire({ - text: getMessage('module.circuit.fix.not.same.roof.error'), - type: 'alert', - icon: 'warning', - }) - return - } - } - if (!circuitNumber || circuitNumber === 0) { swalFire({ text: getMessage('module.circuit.minimun.error'), @@ -145,7 +134,11 @@ export default function PassivityCircuitAllocation(props) { originSurfaceList.concat(originSurfaceList).forEach((surface) => { surfaceType[`${surface.direction}-${surface.roofMaterial.pitch}`] = surface }) + + break + } + case 'OUTDMULTI': { if (surfaceList.length > 1) { if (Object.keys(surfaceType).length > 1) { swalFire({ @@ -156,10 +149,6 @@ export default function PassivityCircuitAllocation(props) { return } } - - break - } - case 'OUTDMULTI': { if (selectedModels.length > 1) { let result = false diff --git a/src/hooks/module/useModule.js b/src/hooks/module/useModule.js index fa51ca75..45b3b50f 100644 --- a/src/hooks/module/useModule.js +++ b/src/hooks/module/useModule.js @@ -84,6 +84,7 @@ export function useModule() { canvas.renderAll() }) + const surfaceId = selectedModules[0].surfaceId if (isWarning) { swalFire({ title: getMessage('can.not.move.module'), @@ -96,11 +97,15 @@ export function useModule() { top: module.originCoords.top, fill: module.originCoords.fill, }) + module.dirty = true module.setCoords() }) - canvas.renderAll() + canvas.requestRenderAll() + recalculateAllModulesCoords(surfaceId) }, }) + } else { + recalculateAllModulesCoords(surfaceId) } } } @@ -157,6 +162,7 @@ export function useModule() { activeModule.set({ strokeWidth: 3 }) canvas.renderAll() + const surfaceId = activeModule.surfaceId if (isWarning) { swalFire({ title: getMessage('can.not.move.module'), @@ -165,11 +171,15 @@ export function useModule() { confirmFn: () => { modules.forEach((module) => { module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill }) + module.dirty = true module.setCoords() }) - canvas.renderAll() + canvas.requestRenderAll() + recalculateAllModulesCoords(surfaceId) }, }) + } else { + recalculateAllModulesCoords(surfaceId) } } @@ -202,6 +212,7 @@ export function useModule() { }) canvas.renderAll() + const surfaceId = surface.id if (isWarning) { swalFire({ title: getMessage('can.not.move.module'), @@ -210,11 +221,15 @@ export function useModule() { confirmFn: () => { modules.forEach((module) => { module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill }) + module.dirty = true module.setCoords() }) - canvas.renderAll() + canvas.requestRenderAll() + recalculateAllModulesCoords(surfaceId) }, }) + } else { + recalculateAllModulesCoords(surfaceId) } }) } @@ -269,6 +284,7 @@ export function useModule() { canvas.renderAll() }) + const surfaceId = surface.id if (isWarning) { swalFire({ title: getMessage('can.not.copy.module'), @@ -276,11 +292,13 @@ export function useModule() { type: 'alert', confirmFn: () => { canvas.remove(...copyModules) - canvas.renderAll() + canvas.requestRenderAll() + recalculateAllModulesCoords(surfaceId) }, }) } else { surface.set({ modules: [...surface.modules, ...copyModules] }) + recalculateAllModulesCoords(surfaceId) } }) @@ -333,6 +351,7 @@ export function useModule() { } }) + const surfaceId = modules[0].surfaceId if (isWarning) { swalFire({ title: getMessage('can.not.copy.module'), @@ -340,11 +359,13 @@ export function useModule() { type: 'alert', confirmFn: () => { canvas.remove(...copyModules) - canvas.renderAll() + canvas.requestRenderAll() + recalculateAllModulesCoords(surfaceId) }, }) } else { moduleSetupSurface.set({ modules: [...moduleSetupSurface.modules, ...copyModules] }) + recalculateAllModulesCoords(surfaceId) } setModuleStatisticsData() } @@ -426,6 +447,7 @@ export function useModule() { }) activeModule.set({ strokeWidth: 3 }) + const surfaceId = activeModule.surfaceId if (isWarning) { swalFire({ title: getMessage('can.not.copy.module'), @@ -433,12 +455,14 @@ export function useModule() { type: 'alert', confirmFn: () => { canvas.remove(...copyModules) - canvas.renderAll() + canvas.requestRenderAll() + recalculateAllModulesCoords(surfaceId) }, }) } else { moduleSetupSurface.set({ modules: [...moduleSetupSurface.modules, ...copyModules] }) setModuleStatisticsData() + recalculateAllModulesCoords(surfaceId) } } @@ -477,6 +501,7 @@ export function useModule() { } if (width === -1) width = module.left - activeModule.left module.set({ left: module.left - width }) + module.dirty = true module.setCoords() canvas.renderAll() if (isOverlapOtherModules(module, leftModules) || isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) { @@ -484,7 +509,7 @@ export function useModule() { isWarning = true } }) - canvas.renderAll() + canvas.requestRenderAll() targetModules = rightModules } else if (type === MODULE_REMOVE_TYPE.RIGHT) { leftModules.forEach((module) => { @@ -495,6 +520,7 @@ export function useModule() { } if (width === -1) width = activeModule.left - module.left module.set({ left: module.left + width }) + module.dirty = true module.setCoords() canvas.renderAll() if (isOverlapOtherModules(module, rightModules) || isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) { @@ -502,7 +528,7 @@ export function useModule() { isWarning = true } }) - canvas.renderAll() + canvas.requestRenderAll() targetModules = leftModules } else if (type === MODULE_REMOVE_TYPE.HORIZONTAL_SIDE) { const sideModules = [...leftModules, ...rightModules] @@ -514,6 +540,7 @@ export function useModule() { } if (width === -1) width = activeModule.left - module.left module.set({ left: module.left + width / 2 }) + module.dirty = true module.setCoords() canvas.renderAll() }) @@ -526,6 +553,7 @@ export function useModule() { } if (width === -1) width = module.left - activeModule.left module.set({ left: module.left - width / 2 }) + module.dirty = true module.setCoords() canvas.renderAll() }) @@ -547,6 +575,7 @@ export function useModule() { targetModules = sideModules } canvas.renderAll() + const surfaceId = activeModule.surfaceId if (isWarning) { swalFire({ title: getMessage('can.not.remove.module'), @@ -557,17 +586,24 @@ export function useModule() { canvas.add(...columnModules) targetModules.forEach((module) => { module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill }) + module.dirty = true module.setCoords() }) - canvas.renderAll() + columnModules.forEach((module) => { + module.dirty = true + module.setCoords() + }) + canvas.requestRenderAll() + recalculateAllModulesCoords(surfaceId) }, }) } else { moduleSetupSurface.modules = moduleSetupSurface.modules.filter( (module) => !columnModules.map((copyModule) => copyModule.id).includes(module.id), ) + setModuleStatisticsData() + recalculateAllModulesCoords(surfaceId) } - setModuleStatisticsData() } const moduleRowRemove = (type) => { @@ -599,6 +635,7 @@ export function useModule() { } if (height === -1) height = module.top - activeModule.top module.set({ top: module.top - height }) + module.dirty = true module.setCoords() canvas.renderAll() if (isOverlapOtherModules(module, topModules) || isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) { @@ -606,7 +643,7 @@ export function useModule() { module.set({ fill: 'red' }) } }) - canvas.renderAll() + canvas.requestRenderAll() targetModules = bottomModules } else if (type === MODULE_REMOVE_TYPE.BOTTOM) { topModules.forEach((module) => { @@ -617,6 +654,7 @@ export function useModule() { } if (height === -1) height = activeModule.top - module.top module.set({ top: module.top + activeModule.height }) + module.dirty = true module.setCoords() canvas.renderAll() if (isOverlapOtherModules(module, bottomModules) || isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) { @@ -624,6 +662,7 @@ export function useModule() { module.set({ fill: 'red' }) } }) + canvas.requestRenderAll() targetModules = topModules } else if (type === MODULE_REMOVE_TYPE.VERTICAL_SIDE) { topModules.forEach((module) => { @@ -635,6 +674,7 @@ export function useModule() { // if (height === -1) height = activeModule.top - module.top if (height === -1) height = activeModule.height module.set({ top: module.top + height / 2 }) + module.dirty = true module.setCoords() }) @@ -647,10 +687,11 @@ export function useModule() { // if (height === -1) height = module.top - activeModule.top if (height === -1) height = activeModule.height module.set({ top: module.top - height / 2 }) + module.dirty = true module.setCoords() }) - canvas.renderAll() + canvas.requestRenderAll() const sideModules = [...topModules, ...bottomModules] sideModules.forEach((module) => { if ( @@ -668,6 +709,7 @@ export function useModule() { targetModules = sideModules } canvas.renderAll() + const surfaceId = activeModule.surfaceId if (isWarning && type !== MODULE_REMOVE_TYPE.NONE) { targetModules.forEach((rect) => rect.set({ fill: 'red' })) swalFire({ @@ -679,13 +721,20 @@ export function useModule() { canvas.add(...rowModules) targetModules.forEach((module) => { module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill }) + module.dirty = true module.setCoords() }) - canvas.renderAll() + rowModules.forEach((module) => { + module.dirty = true + module.setCoords() + }) + canvas.requestRenderAll() + recalculateAllModulesCoords(surfaceId) }, }) } setModuleStatisticsData() + recalculateAllModulesCoords(surfaceId) } const moduleColumnInsert = (type) => { @@ -756,6 +805,7 @@ export function useModule() { module.setCoords() }) canvas.renderAll() + const surfaceId = activeModule.surfaceId if (isWarning) { swalFire({ title: getMessage('can.not.insert.module'), @@ -764,16 +814,19 @@ export function useModule() { confirmFn: () => { targetModules.forEach((module) => { module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill }) + module.dirty = true module.setCoords() }) canvas.remove(...copyModules) - canvas.renderAll() + canvas.requestRenderAll() + recalculateAllModulesCoords(surfaceId) }, }) } else { moduleSetupSurface.modules = [...moduleSetupSurface.modules, ...copyModules] + setModuleStatisticsData() + recalculateAllModulesCoords(surfaceId) } - setModuleStatisticsData() } const isFixedModule = () => { @@ -863,6 +916,7 @@ export function useModule() { }) canvas.renderAll() + const surfaceId = activeModule.surfaceId if (isWarning) { swalFire({ title: getMessage('can.not.insert.module'), @@ -871,16 +925,19 @@ export function useModule() { confirmFn: () => { targetModules.forEach((module) => { module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill }) + module.dirty = true module.setCoords() }) canvas.remove(...copyModules) - canvas.renderAll() + canvas.requestRenderAll() + recalculateAllModulesCoords(surfaceId) }, }) } else { moduleSetupSurface.modules = [...moduleSetupSurface.modules, ...copyModules] + setModuleStatisticsData() + recalculateAllModulesCoords(surfaceId) } - setModuleStatisticsData() } const alignModule = (type, surfaceArray) => { @@ -924,6 +981,7 @@ export function useModule() { } }) canvas.renderAll() + const surfaceId = surface.id if (isWarning) { swalFire({ title: getMessage('can.not.align.module'), @@ -932,11 +990,15 @@ export function useModule() { confirmFn: () => { modules.forEach((module) => { module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill }) + module.dirty = true module.setCoords() }) - canvas.renderAll() + canvas.requestRenderAll() + recalculateAllModulesCoords(surfaceId) }, }) + } else { + recalculateAllModulesCoords(surfaceId) } }) } @@ -964,6 +1026,7 @@ export function useModule() { canvas.remove(activeModule) canvas.renderAll() setModuleStatisticsData() + recalculateAllModulesCoords(activeModule.surfaceId) } const moduleRoofRemove = (surfaceArray) => { @@ -1049,6 +1112,38 @@ export function useModule() { removeTrestleMaterials() } + /** + * 모든 모듈의 좌표를 재계산 + * 열/단 삭제, 복사, 추가 후 호출하여 선택 영역(bounding box)을 업데이트 + * @param {string} surfaceId - 특정 surface의 모듈만 재계산 (선택적) + */ + const recalculateAllModulesCoords = (surfaceId = null) => { + if (!canvas) return + + const modules = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE) + .filter((obj) => (surfaceId ? obj.surfaceId === surfaceId : true)) + + // 모듈의 캐시를 초기화하고 좌표 재계산 + modules.forEach((module) => { + // Fabric.js 내부 캐시 초기화 + delete module.oCoords + delete module.aCoords + delete module.lineCoords + delete module.__corner + delete module.matrixCache + delete module.ownMatrixCache + + // dirty 플래그 설정 및 좌표 재계산 + module.dirty = true + module.setCoords() + }) + + // 렌더링 + canvas.renderAll() + } + return { moduleMove, moduleMultiMove, @@ -1063,5 +1158,6 @@ export function useModule() { modulesRemove, moduleRoofRemove, alignModule, + recalculateAllModulesCoords, } } diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index a0392407..f298c916 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -123,6 +123,7 @@ export function useModuleBasicSetting(tabNum) { .getObjects() .filter((roof) => roof.name === POLYGON_TYPE.ROOF) .forEach((roof) => { + changeLineType(roof) if (!roof.roofMaterial) return const roofIndex = roof.roofMaterial.index //지붕의 지붕재의 순번 @@ -168,6 +169,61 @@ export function useModuleBasicSetting(tabNum) { } }, [trestleDetailList]) + const changeLineType = (polygon) => { + if (!polygon || !polygon.lines || polygon.lines.length === 0) return + + const direction = polygon.direction + + // 1. 모든 라인을 케라바(GABLE)로 초기화 + polygon.lines.forEach((line) => { + line.attributes = { + ...line.attributes, + type: LINE_TYPE.WALLLINE.GABLE, + } + }) + + // 방향에 따른 좌표 설정 + const directionConfig = { + south: { coord1: 'y1', coord2: 'y2', findExtreme: Math.max }, + north: { coord1: 'y1', coord2: 'y2', findExtreme: Math.min }, + east: { coord1: 'x1', coord2: 'x2', findExtreme: Math.max }, + west: { coord1: 'x1', coord2: 'x2', findExtreme: Math.min }, + } + + const config = directionConfig[direction] || directionConfig.south + const { coord1, coord2, findExtreme } = config + + // 2. 직선만 필터링 (대각선 제외) + // 남/북: y1 === y2 인 경우 수평 직선 + // 동/서: x1 === x2 인 경우 수직 직선 + const straightLines = polygon.lines.filter((line) => line[coord1] === line[coord2]) + + if (straightLines.length === 0) return + + // 3. 가장 끝에 있는 직선 찾기 + // 남쪽: 가장 하단 (y값이 가장 큰), 북쪽: 가장 상단 (y값이 가장 작은) + // 동쪽: 가장 오른쪽 (x값이 가장 큰), 서쪽: 가장 왼쪽 (x값이 가장 작은) + const extremeValue = findExtreme(...straightLines.map((line) => line[coord1])) + const eavesLines = straightLines.filter((line) => line[coord1] === extremeValue) + + // 4. 직선에 대해 타입 설정 + straightLines.forEach((line) => { + if (eavesLines.includes(line)) { + // 가장 끝에 있는 직선은 eaves + line.attributes = { + ...line.attributes, + type: LINE_TYPE.WALLLINE.EAVES, + } + } else { + // 나머지 직선은 ridge + line.attributes = { + ...line.attributes, + type: LINE_TYPE.SUBLINE.RIDGE, + } + } + }) + } + const roofOutlineColor = (roofIndex) => { if (roofIndex === 1) { return '#FFC000' @@ -267,14 +323,14 @@ export function useModuleBasicSetting(tabNum) { //도머일때 if (obj.name === BATCH_TYPE.TRIANGLE_DORMER || obj.name === BATCH_TYPE.PENTAGON_DORMER) { const groupPoints = obj.getCurrentPoints() - const offsetObjects = offsetPolygon(groupPoints, 10) + const offsetObjects = offsetPolygon(groupPoints, 30) const dormerOffset = new QPolygon(offsetObjects, batchObjectOptions) dormerOffset.setViewLengthText(false) canvas.add(dormerOffset) //모듈설치면 만들기 } else { //개구, 그림자일때 const points = obj.getCurrentPoints() - const offsetObjects = offsetPolygon(points, 10) + const offsetObjects = offsetPolygon(points, 30) const offset = new QPolygon(offsetObjects, batchObjectOptions) offset.setViewLengthText(false) canvas.add(offset) //모듈설치면 만들기 diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index f93e230d..4bb3d8ca 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -316,12 +316,13 @@ export function useRoofAllocationSetting(id) { addPopup(popupId, 1, ) } else { apply() - //기존 지붕 선은 남겨둔다. - drawOriginRoofLine() + resetPoints() basicSettingSave() } + //기존 지붕 선은 남겨둔다. + drawOriginRoofLine() } const drawOriginRoofLine = () => { @@ -473,7 +474,20 @@ export function useRoofAllocationSetting(id) { // Filter out any eaveHelpLines that are already in lines to avoid duplicates const existingEaveLineIds = new Set(roofBase.lines.map((line) => line.id)) const newEaveLines = roofEaveHelpLines.filter((line) => !existingEaveLineIds.has(line.id)) - roofBase.lines = [...newEaveLines] + // Filter out lines from roofBase.lines that share any points with newEaveLines + const linesToKeep = roofBase.lines.filter(roofLine => { + return !newEaveLines.some(eaveLine => { + // Check if any endpoint of roofLine matches any endpoint of eaveLine + return ( + // Check if any endpoint of roofLine matches any endpoint of eaveLine + (Math.abs(roofLine.x1 - eaveLine.x1) < 0.1 && Math.abs(roofLine.y1 - eaveLine.y1) < 0.1) || // p1 matches p1 + (Math.abs(roofLine.x2 - eaveLine.x2) < 0.1 && Math.abs(roofLine.y2 - eaveLine.y2) < 0.1) // p2 matches p2 + ); + }); + }); + +// Combine remaining lines with newEaveLines + roofBase.lines = [...linesToKeep, ...newEaveLines]; } else { roofBase.lines = [...roofEaveHelpLines] } diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index cc4ac608..7808bb5f 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -50,6 +50,10 @@ export function useCanvasEvent() { if (target) { // settleDown(target) + // roof 이동 후 좌표 재계산 + if (target.name === POLYGON_TYPE.ROOF && target.type === 'QPolygon') { + target.fire('polygonMoved') + } } }, addEvent: (e) => { diff --git a/src/hooks/useCirCuitTrestle.js b/src/hooks/useCirCuitTrestle.js index 83bb0b84..0c332ec8 100644 --- a/src/hooks/useCirCuitTrestle.js +++ b/src/hooks/useCirCuitTrestle.js @@ -91,6 +91,7 @@ export function useCircuitTrestle(executeEffect = false) { return { itemId: m.itemId, mixMatlNo: m.mixMatlNo, + northModuleYn: m.northModuleYn, } }) } diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index a863fd01..1f6a33b0 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -355,6 +355,12 @@ export function useContextMenu() { canvas.remove(line) }) + //동이동현이동 + const eaveHelpLines = canvas.getObjects().filter((obj) => obj.name === 'eaveHelpLine' && obj.parentId === currentObject.attributes.roofId) + eaveHelpLines.forEach((line) => { + canvas.remove(line) + }) + canvas.renderAll() }, }, diff --git a/src/locales/ja.json b/src/locales/ja.json index e738ebaa..7fb83f4e 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -134,6 +134,7 @@ "modal.module.basic.settting.module.error10": "棟側の配置領域の値を{0} mm以上に変更してください。\n(屋根材: {1})", "modal.module.basic.settting.module.error11": "ケラバ側の配置領域の値を{0} mm以上に変更してください。\n(屋根材: {1})", "modal.module.basic.settting.module.error12": "施工方法を選択してください。\n(屋根材: {0})", + "module.size.validation.rack.error": "モジュール配置が不正です。 正しく配置し直してください。", "modal.module.basic.setting.module.placement": "モジュールの配置", "modal.module.basic.setting.module.placement.select.fitting.type": "設置形態を選択してください。", "modal.module.basic.setting.module.placement.waterfowl.arrangement": "千鳥配置", diff --git a/src/locales/ko.json b/src/locales/ko.json index bed23c44..4d237fd6 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -134,6 +134,7 @@ "modal.module.basic.settting.module.error10": "용마루쪽 값은 {0}mm 이상이어야 합니다.\n(지붕재: {1})", "modal.module.basic.settting.module.error11": "케라바쪽 값은 {0}mm 이상이어야 합니다.\n(지붕재: {1})", "modal.module.basic.settting.module.error12": "시공법을 선택해주세요.\n(지붕재: {0})", + "module.size.validation.rack.error": "모듈 배치가 잘못되었습니다. 올바르게 다시 배치해 주세요.", "modal.module.basic.setting.module.placement": "모듈 배치", "modal.module.basic.setting.module.placement.select.fitting.type": "설치형태를 선택합니다.", "modal.module.basic.setting.module.placement.waterfowl.arrangement": "물떼새 배치", diff --git a/src/util/skeleton-utils.js b/src/util/skeleton-utils.js index 1599bd84..c92cea69 100644 --- a/src/util/skeleton-utils.js +++ b/src/util/skeleton-utils.js @@ -677,8 +677,9 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { // 조건에 맞는 라인들만 필터링 const validWallLines = [...wallLines].sort((a, b) => a.idx - b.idx).filter((wallLine, index) => wallLine.idx - 1 === index) - console.log('', sortRoofLines, sortWallLines, sortWallBaseLines) - sortWallLines.length > 3 && + console.log('', sortRoofLines, sortWallLines, sortWallBaseLines); + + (sortWallLines.length === sortWallBaseLines.length && sortWallBaseLines.length > 3) && sortWallLines.forEach((wallLine, index) => { const roofLine = sortRoofLines[index] @@ -729,7 +730,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { }, }) - coordinateText(line) + //coordinateText(line) canvas.add(line) line.bringToFront() canvas.renderAll() @@ -844,7 +845,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length const nextIndex = (index + 1) % sortRoofLines.length - const newLine = sortRoofLines[prevIndex] + const newLine = sortRoofLines[nextIndex] if (Math.abs(wallBaseLine.y1 - wallLine.y1) < 0.1) { if (inLine) { @@ -871,7 +872,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { //newPStart.y = wallLine.y1; //외곽 라인 그리기 const rLineM = Big(wallBaseLine.x2).minus(roofLine.x2).abs().toNumber() - newPStart.y = Big(wallBaseLine.y1).minus(rLineM).abs().toNumber() + newPStart.y = Big(wallBaseLine.y1).minus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x }) if (inLine) { if (inLine.x2 > inLine.x1) { @@ -898,7 +899,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length; const nextIndex = (index + 1) % sortRoofLines.length; - const newLine = sortRoofLines[nextIndex] + const newLine = sortRoofLines[prevIndex] if (Math.abs(wallBaseLine.y2 - wallLine.y2) < 0.1) { @@ -927,7 +928,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { //외곽 라인 그리기 const rLineM = Big(wallBaseLine.x2).minus(roofLine.x2).abs().toNumber() - newPEnd.y = Big(wallBaseLine.y2).plus(rLineM).abs().toNumber() + newPEnd.y = Big(wallBaseLine.y2).plus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x }) if (inLine) { if (inLine.x2 > inLine.x1) { @@ -1002,8 +1003,8 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { if (isStartEnd.start) { //x1 inside const moveDist = Big(wallLine.x1).minus(wallBaseLine.x1).abs().toNumber() - const aStartY = Big(roofLine.y1).plus(moveDist).abs().toNumber() - const bStartY = Big(wallLine.y1).plus(moveDist).abs().toNumber() + const aStartY = Big(roofLine.y1).plus(moveDist).toNumber() + const bStartY = Big(wallLine.y1).plus(moveDist).toNumber() const inLine = findLineContainingPoint(innerLines, { y: aStartY, x: roofLine.x1 }) console.log('startLines:::::::', inLine) const eLineY = Big(bStartY).minus(wallLine.y1).abs().toNumber() @@ -1014,7 +1015,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length const nextIndex = (index + 1) % sortRoofLines.length - const newLine = sortRoofLines[prevIndex] + const newLine = sortRoofLines[nextIndex] if (Math.abs(wallBaseLine.y1 - wallLine.y1) < 0.1) { if (inLine) { @@ -1041,7 +1042,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { //newPStart.y = wallLine.y1; //외곽 라인 그리기 const rLineM = Big(wallBaseLine.x1).minus(roofLine.x1).abs().toNumber() - newPStart.y = Big(wallBaseLine.y1).plus(rLineM).abs().toNumber() + newPStart.y = Big(wallBaseLine.y1).plus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x }) if (inLine) { if (inLine.x2 > inLine.x1) { @@ -1056,8 +1057,8 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { if (isStartEnd.end) { const moveDist = Big(wallLine.x1).minus(wallBaseLine.x1).abs().toNumber() - const aStartY = Big(roofLine.y2).minus(moveDist).abs().toNumber() - const bStartY = Big(wallLine.y2).minus(moveDist).abs().toNumber() + const aStartY = Big(roofLine.y2).minus(moveDist).toNumber() + const bStartY = Big(wallLine.y2).minus(moveDist).toNumber() const inLine = findLineContainingPoint(innerLines, { y: aStartY, x: roofLine.x1 }) console.log('startLines:::::::', inLine) const eLineY = Big(bStartY).minus(wallLine.y2).abs().toNumber() @@ -1068,7 +1069,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length; const nextIndex = (index + 1) % sortRoofLines.length; - const newLine = sortRoofLines[nextIndex] + const newLine = sortRoofLines[prevIndex] if (inLine) { if (inLine.x2 < inLine.x1) { @@ -1096,7 +1097,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { //외곽 라인 그리기 const rLineM = Big(wallBaseLine.x2).minus(roofLine.x2).abs().toNumber() - newPEnd.y = Big(wallBaseLine.y2).minus(rLineM).abs().toNumber() + newPEnd.y = Big(wallBaseLine.y2).minus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x }) if (inLine) { if (inLine.x2 > inLine.x1) { @@ -1167,7 +1168,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const newPointY = Big(roofLine.y1).plus(moveDist).toNumber() const pDist = Big(wallLine.y1).minus(roofLine.y1).abs().toNumber() - const pLineX = Big(roofLine.x2).minus(0).abs().toNumber() + const pLineX = Big(roofLine.x2).minus(0).toNumber() // let idx = sortRoofLines.length < index + 1 ? 0 : index // const pLineY = sortRoofLines[idx + 1].y2 @@ -1203,7 +1204,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length; const nextIndex = (index + 1) % sortRoofLines.length; - const newLine = sortRoofLines[prevIndex] + const newLine = sortRoofLines[nextIndex] if (Math.abs(wallBaseLine.x1 - wallLine.x1) < 0.1) { if (inLine) { @@ -1229,7 +1230,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { } else { //외곽 라인 그리기 const rLineM = Big(wallBaseLine.y1).minus(roofLine.y1).abs().toNumber() - newPStart.x = Big(wallBaseLine.x1).plus(rLineM).abs().toNumber() + newPStart.x = Big(wallBaseLine.x1).plus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x }) if (inLine) { if (inLine.y2 > inLine.y1) { @@ -1243,11 +1244,11 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { } if (isStartEnd.end) { const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber() - const aStartX = Big(roofLine.x2).minus(moveDist).abs().toNumber() - const bStartX = Big(wallLine.x2).minus(moveDist).abs().toNumber() + const aStartX = Big(roofLine.x2).minus(moveDist).toNumber() + const bStartX = Big(wallLine.x2).minus(moveDist).toNumber() const inLine = findLineContainingPoint(innerLines, { x: aStartX, y: newPEnd.y }) console.log('startLines:::::::', inLine) - const eLineX = Big(bStartX).minus(wallLine.x2).abs().toNumber() + const eLineX = Big(bStartX).minus(wallLine.x2).toNumber() newPStart.x = roofLine.x1 //Big(newPStart.x).minus(eLineX).abs().toNumber() newPEnd.x = aStartX // let idx = sortRoofLines.length < index + 1 ? 0 : index @@ -1255,7 +1256,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length; const nextIndex = (index + 1) % sortRoofLines.length; - const newLine = sortRoofLines[nextIndex] + const newLine = sortRoofLines[prevIndex] if (Math.abs(wallBaseLine.x2 - wallLine.x2) < 0.1) { if (inLine) { @@ -1282,7 +1283,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { //newPEnd.x = wallLine.x2; //외곽 라인 그리기 const rLineM = Big(wallBaseLine.y2).minus(roofLine.y2).abs().toNumber() - newPEnd.x = Big(wallBaseLine.x2).minus(rLineM).abs().toNumber() + newPEnd.x = Big(wallBaseLine.x2).minus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x }) if (inLine) { if (inLine.y1 > inLine.y2) { @@ -1303,7 +1304,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const newPointY = Big(roofLine.y2).minus(moveDist).toNumber() const pDist = Big(wallLine.y2).minus(roofLine.y2).abs().toNumber() - const pLineX = Big(roofLine.x1).minus(0).abs().toNumber() + const pLineX = Big(roofLine.x1).minus(0).toNumber() // let idx = 0 > index - 1 ? sortRoofLines.length : index // const pLineY = sortRoofLines[idx - 1].y1 @@ -1330,7 +1331,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const newPointY = Big(roofLine.y1).minus(moveDist).toNumber() const pDist = Big(wallLine.y1).minus(roofLine.y1).abs().toNumber() - const pLineX = Big(roofLine.x2).minus(0).abs().toNumber() + const pLineX = Big(roofLine.x2).minus(0).toNumber() // let idx = sortRoofLines.length < index + 1 ? 0 : index // const pLineY = sortRoofLines[idx + 1].y2 @@ -1353,8 +1354,8 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { console.log('bottom_out isStartEnd:::::::', isStartEnd) if (isStartEnd.start) { const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber() - const aStartX = Big(roofLine.x1).minus(moveDist).abs().toNumber() - const bStartX = Big(wallLine.x1).minus(moveDist).abs().toNumber() + const aStartX = Big(roofLine.x1).minus(moveDist).toNumber() + const bStartX = Big(wallLine.x1).minus(moveDist).toNumber() const inLine = findLineContainingPoint(innerLines, { x: aStartX, y: roofLine.y1 }) console.log('startLines:::::::', inLine) const eLineX = Big(bStartX).minus(wallLine.x1).abs().toNumber() @@ -1365,7 +1366,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length; const nextIndex = (index + 1) % sortRoofLines.length; - const newLine = sortRoofLines[prevIndex] + const newLine = sortRoofLines[nextIndex] if (Math.abs(wallBaseLine.x1 - wallLine.x1) < 0.1) { if (inLine) { @@ -1392,7 +1393,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { //newPStart.x = wallLine.x1; //외곽 라인 그리기 const rLineM = Big(wallBaseLine.y1).minus(roofLine.y1).abs().toNumber() - newPStart.x = Big(wallBaseLine.x1).minus(rLineM).abs().toNumber() + newPStart.x = Big(wallBaseLine.x1).minus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPStart.y, x: newPStart.x }) if (inLine) { if (inLine.y2 > inLine.y1) { @@ -1419,7 +1420,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const prevIndex = (index - 1 + sortRoofLines.length) % sortRoofLines.length; const nextIndex = (index + 1) % sortRoofLines.length; - const newLine = sortRoofLines[nextIndex] + const newLine = sortRoofLines[prevIndex] if (Math.abs(wallBaseLine.x2 - wallLine.x2) < 0.1) { if (inLine) { @@ -1446,7 +1447,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { //newPEnd.x = wallLine.x2; //외곽 라인 그리기 const rLineM = Big(wallBaseLine.y2).minus(roofLine.y2).abs().toNumber() - newPEnd.x = Big(wallBaseLine.x2).plus(rLineM).abs().toNumber() + newPEnd.x = Big(wallBaseLine.x2).plus(rLineM).toNumber() const inLine = findLineContainingPoint(innerLines, { y: newPEnd.y, x: newPEnd.x }) if (inLine) { if (inLine.y1 > inLine.y2) {