Compare commits

..

4 Commits

Author SHA1 Message Date
e9d0668ed2 group object 좌표 재계산 로직 수정 2025-12-13 17:09:50 +09:00
6633677890 도머 오프셋 선택 시 오류 수정 2025-12-13 17:09:50 +09:00
d519f9f080 플랜 이동 시 외벽선 남아있는 현상 수정
지붕재 변경 시 같은 지붕재를 가지고 있는 다른 지붕들의 지붕재도 변경 추가
2025-12-13 17:09:48 +09:00
fb8ce256ff 복사 후 문제 수정 2025-12-13 17:09:47 +09:00
5 changed files with 53 additions and 19 deletions

View File

@ -32,6 +32,7 @@ import { useEvent } from '@/hooks/useEvent'
import { compasDegAtom } from '@/store/orientationAtom' import { compasDegAtom } from '@/store/orientationAtom'
import { hotkeyStore } from '@/store/hotkeyAtom' import { hotkeyStore } from '@/store/hotkeyAtom'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { outerLinePointsState } from '@/store/outerLineAtom'
export default function CanvasFrame() { export default function CanvasFrame() {
const canvasRef = useRef(null) const canvasRef = useRef(null)
@ -45,6 +46,7 @@ export default function CanvasFrame() {
const totalDisplay = useRecoilValue(totalDisplaySelector) // const totalDisplay = useRecoilValue(totalDisplaySelector) //
const { setIsGlobalLoading } = useContext(QcastContext) const { setIsGlobalLoading } = useContext(QcastContext)
const resetModuleStatisticsState = useResetRecoilState(moduleStatisticsState) const resetModuleStatisticsState = useResetRecoilState(moduleStatisticsState)
const resetOuterLinePoints = useResetRecoilState(outerLinePointsState)
const resetMakersState = useResetRecoilState(makersState) const resetMakersState = useResetRecoilState(makersState)
const resetSelectedMakerState = useResetRecoilState(selectedMakerState) const resetSelectedMakerState = useResetRecoilState(selectedMakerState)
const resetSeriesState = useResetRecoilState(seriesState) const resetSeriesState = useResetRecoilState(seriesState)
@ -137,6 +139,7 @@ export default function CanvasFrame() {
const resetRecoilData = () => { const resetRecoilData = () => {
// resetModuleStatisticsState() // resetModuleStatisticsState()
resetOuterLinePoints()
resetMakersState() resetMakersState()
resetSelectedMakerState() resetSelectedMakerState()
resetSeriesState() resetSeriesState()

View File

@ -1,4 +1,4 @@
import { useState, useEffect, useRef } from 'react' import { useEffect, useRef, useState } from 'react'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import WithDraggable from '@/components/common/draggable/WithDraggable' import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
@ -15,8 +15,8 @@ export default function DormerOffset(props) {
const { closePopup } = usePopup() const { closePopup } = usePopup()
const [arrow1, setArrow1] = useState(null) const [arrow1, setArrow1] = useState(null)
const [arrow2, setArrow2] = useState(null) const [arrow2, setArrow2] = useState(null)
const arrow1LengthRef = useRef() const arrow1LengthRef = useRef(0)
const arrow2LengthRef = useRef() const arrow2LengthRef = useRef(0)
const [arrow1Length, setArrow1Length] = useState(0) const [arrow1Length, setArrow1Length] = useState(0)
const [arrow2Length, setArrow2Length] = useState(0) const [arrow2Length, setArrow2Length] = useState(0)
@ -59,12 +59,12 @@ export default function DormerOffset(props) {
name="" name=""
label="" label=""
className="input-origin block" className="input-origin block"
value={arrow1LengthRef.current.value} value={arrow1LengthRef.current.value ?? 0}
ref={arrow1LengthRef} ref={arrow1LengthRef}
onChange={(value) => setArrow1Length(value)} onChange={(value) => setArrow1Length(value)}
options={{ options={{
allowNegative: false, allowNegative: false,
allowDecimal: false allowDecimal: false,
}} }}
/> />
</div> </div>

View File

@ -648,6 +648,7 @@ export function useCommonUtils() {
lockMovementY: true, lockMovementY: true,
name: obj.name, name: obj.name,
editable: false, editable: false,
selectable: true, // 복사된 객체 선택 가능하도록 설정
id: uuidv4(), //복사된 객체라 새로 따준다 id: uuidv4(), //복사된 객체라 새로 따준다
}) })
@ -656,19 +657,25 @@ export function useCommonUtils() {
//배치면일 경우 //배치면일 경우
if (obj.name === 'roof') { if (obj.name === 'roof') {
clonedObj.setCoords() clonedObj.canvas = canvas // canvas 참조 설정
clonedObj.fire('modified')
// clonedObj.fire('polygonMoved')
clonedObj.set({ clonedObj.set({
direction: obj.direction, direction: obj.direction,
directionText: obj.directionText, directionText: obj.directionText,
roofMaterial: obj.roofMaterial, roofMaterial: obj.roofMaterial,
stroke: 'black', // 복사된 객체는 선택 해제 상태의 색상으로 설정
selectable: true, // 선택 가능하도록 설정
evented: true, // 마우스 이벤트를 받을 수 있도록 설정
isFixed: false, // containsPoint에서 특별 처리 방지
}) })
obj.lines.forEach((line, index) => { obj.lines.forEach((line, index) => {
clonedObj.lines[index].set({ attributes: line.attributes }) clonedObj.lines[index].set({ attributes: line.attributes })
}) })
clonedObj.fire('polygonMoved') // 내부 좌표 재계산 (points, pathOffset)
clonedObj.fire('modified')
clonedObj.setCoords() // 모든 속성 설정 후 좌표 업데이트
canvas.setActiveObject(clonedObj)
canvas.renderAll() canvas.renderAll()
addLengthText(clonedObj) //수치 추가 addLengthText(clonedObj) //수치 추가
drawDirectionArrow(clonedObj) //방향 화살표 추가 drawDirectionArrow(clonedObj) //방향 화살표 추가

View File

@ -372,11 +372,18 @@ export function useRoofAllocationSetting(id) {
setBasicSetting((prev) => { setBasicSetting((prev) => {
return { ...prev, selectedRoofMaterial: newRoofList.find((roof) => roof.selected) } return { ...prev, selectedRoofMaterial: newRoofList.find((roof) => roof.selected) }
}) })
const selectedRoofMaterial = newRoofList.find((roof) => roof.selected)
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF && obj.roofMaterial?.index === selectedRoofMaterial.index)
roofs.forEach((roof) => {
setSurfaceShapePattern(roof, roofDisplay.column, false, { ...selectedRoofMaterial }, true)
drawDirectionArrow(roof)
})
setRoofList(newRoofList) setRoofList(newRoofList)
setRoofMaterials(newRoofList) setRoofMaterials(newRoofList)
setRoofsStore(newRoofList) setRoofsStore(newRoofList)
const selectedRoofMaterial = newRoofList.find((roof) => roof.selected)
setSurfaceShapePattern(currentObject, roofDisplay.column, false, selectedRoofMaterial, true) setSurfaceShapePattern(currentObject, roofDisplay.column, false, selectedRoofMaterial, true)
drawDirectionArrow(currentObject) drawDirectionArrow(currentObject)
modifyModuleSelectionData() modifyModuleSelectionData()

View File

@ -29,22 +29,39 @@ fabric.Rect.prototype.getCurrentPoints = function () {
/** /**
* fabric.Group에 getCurrentPoints 메서드를 추가 (도머 그룹용) * fabric.Group에 getCurrentPoints 메서드를 추가 (도머 그룹용)
* 그룹groupPoints를 다시 계산하여 반환 * 그룹 객체들의 점들을 수집하여 현재 월드 좌표를 반환
*/ */
fabric.Group.prototype.getCurrentPoints = function () { fabric.Group.prototype.getCurrentPoints = function () {
// groupPoints를 다시 계산 // 그룹 내 객체들로부터 실시간으로 점들을 계산
if (this._objects && this._objects.length > 0) {
let allPoints = []
// 그룹에 groupPoints가 있으면 해당 점들을 사용 (도머의 경우) // 그룹 내 모든 객체의 점들을 수집
if (this.groupPoints && Array.isArray(this.groupPoints)) { this._objects.forEach(function (obj) {
const matrix = this.calcTransformMatrix() if (obj.getCurrentPoints && typeof obj.getCurrentPoints === 'function') {
console.log('this.groupPoints', this.groupPoints) const objPoints = obj.getCurrentPoints()
return this.groupPoints.map(function (p) { allPoints = allPoints.concat(objPoints)
const point = new fabric.Point(p.x, p.y) } else if (obj.points && Array.isArray(obj.points)) {
return fabric.util.transformPoint(point, matrix) const pathOffset = obj.pathOffset || { x: 0, y: 0 }
const matrix = obj.calcTransformMatrix()
const transformedPoints = obj.points
.map(function (p) {
return new fabric.Point(p.x - pathOffset.x, p.y - pathOffset.y)
})
.map(function (p) {
return fabric.util.transformPoint(p, matrix)
})
allPoints = allPoints.concat(transformedPoints)
}
}) })
if (allPoints.length > 0) {
// Convex Hull 알고리즘을 사용하여 외곽 점들만 반환
return this.getConvexHull(allPoints)
}
} }
// groupPoints가 없으면 바운딩 박스를 사용 // 객체가 없으면 바운딩 박스를 사용
const bounds = this.getBoundingRect() const bounds = this.getBoundingRect()
const points = [ const points = [
{ x: bounds.left, y: bounds.top }, { x: bounds.left, y: bounds.top },