diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeDrawing.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeDrawing.jsx index c705b0eb..62bbab5d 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeDrawing.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeDrawing.jsx @@ -8,6 +8,7 @@ import Diagonal from '@/components/floor-plan/modal/lineTypes/Diagonal' import { useOuterLineWall } from '@/hooks/roofcover/useOuterLineWall' import { OUTER_LINE_TYPE } from '@/store/outerLineAtom' import OuterLineWall from '@/components/floor-plan/modal/lineTypes/OuterLineWall' +import { usePlacementShapeDrawing } from '@/hooks/surface/usePlacementShapeDrawing' export default function PlacementShapeDrawing({ setShowPlaceShapeDrawingModal }) { const { getMessage } = useMessage() @@ -45,7 +46,7 @@ export default function PlacementShapeDrawing({ setShowPlaceShapeDrawingModal }) outerLineDiagonalLengthRef, handleRollback, handleFix, - } = useOuterLineWall() + } = usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) const outerLineProps = { length1, @@ -145,8 +146,12 @@ export default function PlacementShapeDrawing({ setShowPlaceShapeDrawingModal })
- - + +
diff --git a/src/hooks/surface/usePlacementShapeDrawing.js b/src/hooks/surface/usePlacementShapeDrawing.js new file mode 100644 index 00000000..b07a8031 --- /dev/null +++ b/src/hooks/surface/usePlacementShapeDrawing.js @@ -0,0 +1,825 @@ +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' +import { + adsorptionPointAddModeState, + adsorptionPointModeState, + adsorptionRangeState, + canvasState, + dotLineIntervalSelector, + verticalHorizontalModeState, +} from '@/store/canvasAtom' +import { useEvent } from '@/hooks/useEvent' +import { useMouse } from '@/hooks/useMouse' +import { useLine } from '@/hooks/useLine' +import { useTempGrid } from '@/hooks/useTempGrid' +import { useEffect, useRef } from 'react' +import { distanceBetweenPoints, setSurfaceShapePattern } from '@/util/canvas-util' +import { fabric } from 'fabric' +import { calculateAngle } from '@/util/qpolygon-utils' +import { + placementShapeDrawingAngle1State, + placementShapeDrawingAngle2State, + placementShapeDrawingArrow1State, + placementShapeDrawingArrow2State, + placementShapeDrawingDiagonalState, + placementShapeDrawingFixState, + placementShapeDrawingLength1State, + placementShapeDrawingLength2State, + placementShapeDrawingPointsState, + placementShapeDrawingTypeState, +} from '@/store/placementShapeDrawingAtom' +import { usePolygon } from '@/hooks/usePolygon' +import { POLYGON_TYPE } from '@/common/common' + +// 면형상 배치 +export function usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) { + const canvas = useRecoilValue(canvasState) + const { addCanvasMouseEventListener, addDocumentEventListener, removeAllMouseEventListeners, removeAllDocumentEventListeners, removeMouseEvent } = + useEvent() + const { getIntersectMousePoint } = useMouse() + const { addLine, removeLine } = useLine() + const { addPolygonByLines } = usePolygon() + const { tempGridMode } = useTempGrid() + + const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState) + const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState) + const adsorptionPointMode = useRecoilValue(adsorptionPointModeState) + const adsorptionRange = useRecoilValue(adsorptionRangeState) + const interval = useRecoilValue(dotLineIntervalSelector) // 가로 세로 간격 + + const length1Ref = useRef(null) + const length2Ref = useRef(null) + const angle1Ref = useRef(null) + const angle2Ref = useRef(null) + const [length1, setLength1] = useRecoilState(placementShapeDrawingLength1State) + const [length2, setLength2] = useRecoilState(placementShapeDrawingLength2State) + const [arrow1, setArrow1] = useRecoilState(placementShapeDrawingArrow1State) + const [arrow2, setArrow2] = useRecoilState(placementShapeDrawingArrow2State) + const [points, setPoints] = useRecoilState(placementShapeDrawingPointsState) + const [type, setType] = useRecoilState(placementShapeDrawingTypeState) + const [angle1, setAngle1] = useRecoilState(placementShapeDrawingAngle1State) + const [angle2, setAngle2] = useRecoilState(placementShapeDrawingAngle2State) + const [outerLineDiagonalLength, setOuterLineDiagonalLength] = useRecoilState(placementShapeDrawingDiagonalState) + const setOuterLineFix = useSetRecoilState(placementShapeDrawingFixState) + const arrow1Ref = useRef(arrow1) + const arrow2Ref = useRef(arrow2) + + const outerLineDiagonalLengthRef = useRef(null) + + const isFix = useRef(false) + + useEffect(() => { + if (adsorptionPointAddMode || tempGridMode) { + return + } + + addCanvasMouseEventListener('mouse:down', mouseDown) + clear() + }, [verticalHorizontalMode, points, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, interval, tempGridMode]) + + useEffect(() => { + arrow1Ref.current = arrow1 + }, [arrow1]) + + useEffect(() => { + arrow2Ref.current = arrow2 + }, [arrow2]) + + useEffect(() => { + clear() + addDocumentEventListener('keydown', document, keydown[type]) + }, [type]) + + const clear = () => { + setLength1(0) + setLength2(0) + + setArrow1('') + setArrow2('') + + setAngle1(0) + setAngle2(0) + + setOuterLineDiagonalLength(0) + } + + const mouseDown = (e) => { + let pointer = getIntersectMousePoint(e) + + if (points.length === 0) { + setPoints((prev) => [...prev, pointer]) + } else { + const lastPoint = points[points.length - 1] + let newPoint = { x: pointer.x, y: pointer.y } + const length = distanceBetweenPoints(lastPoint, newPoint) + if (verticalHorizontalMode) { + const vector = { + x: pointer.x - points[points.length - 1].x, + y: pointer.y - points[points.length - 1].y, + } + const slope = Math.abs(vector.y / vector.x) // 기울기 계산 + + let scaledVector + if (slope >= 1) { + // 기울기가 1 이상이면 x축 방향으로 그림 + scaledVector = { + x: 0, + y: vector.y >= 0 ? Number(length) : -Number(length), + } + } else { + // 기울기가 1 미만이면 y축 방향으로 그림 + scaledVector = { + x: vector.x >= 0 ? Number(length) : -Number(length), + y: 0, + } + } + + const verticalLength = scaledVector.y + const horizontalLength = scaledVector.x + + newPoint = { + x: lastPoint.x + horizontalLength, + y: lastPoint.y + verticalLength, + } + } + setPoints((prev) => [...prev, newPoint]) + } + } + + useEffect(() => { + canvas + ?.getObjects() + .filter((obj) => obj.name === 'placementShapeDrawingLine' || obj.name === 'helpGuideLine') + .forEach((obj) => { + removeLine(obj) + }) + + canvas?.remove(canvas?.getObjects().find((obj) => obj.name === 'placementShapeDrawingStartPoint')) + + if (points.length === 0) { + setOuterLineFix(true) + removeAllDocumentEventListeners() + return + } + + addDocumentEventListener('keydown', document, keydown[type]) + + if (points.length === 1) { + const point = new fabric.Circle({ + radius: 5, + fill: 'transparent', + stroke: 'red', + left: points[0].x - 5, + top: points[0].y - 5, + selectable: false, + name: 'placementShapeDrawingStartPoint', + }) + + canvas?.add(point) + } else { + setOuterLineFix(false) + canvas + .getObjects() + .filter((obj) => obj.name === 'placementShapeDrawingPoint') + .forEach((obj) => { + canvas.remove(obj) + }) + points.forEach((point, idx) => { + const circle = new fabric.Circle({ + left: point.x, + top: point.y, + visible: false, + name: 'placementShapeDrawingPoint', + }) + canvas.add(circle) + }) + points.forEach((point, idx) => { + if (idx === 0) { + return + } + drawLine(points[idx - 1], point, idx) + }) + + const lastPoint = points[points.length - 1] + const firstPoint = points[0] + + if (isFix.current) { + removeAllMouseEventListeners() + removeAllDocumentEventListeners() + + const lines = canvas?.getObjects().filter((obj) => obj.name === 'placementShapeDrawingLine') + const roof = addPolygonByLines(lines, { + stroke: 'black', + strokeWidth: 3, + selectable: true, + name: POLYGON_TYPE.ROOF, + }) + + setSurfaceShapePattern(roof) + + lines.forEach((line) => { + removeLine(line) + }) + + canvas?.renderAll() + setShowPlaceShapeDrawingModal(false) + } + + if (points.length < 3) { + return + } + + /*if (lastPoint.x === firstPoint.x && lastPoint.y === firstPoint.y) { + return + } + + if (lastPoint.x === firstPoint.x || lastPoint.y === firstPoint.y) { + let isAllRightAngle = true + + const firstPoint = points[0] + + points.forEach((point, idx) => { + if (idx === 0 || !isAllRightAngle) { + return + } + + const angle = calculateAngle(point, firstPoint) + if (angle % 90 !== 0) { + isAllRightAngle = false + } + }) + + if (isAllRightAngle) { + return + } + const line = new QLine([lastPoint.x, lastPoint.y, firstPoint.x, firstPoint.y], { + stroke: 'grey', + strokeWidth: 1, + selectable: false, + name: 'helpGuideLine', + }) + + canvas?.add(line) + addLineText(line) + } else { + const guideLine1 = new QLine([lastPoint.x, lastPoint.y, lastPoint.x, firstPoint.y], { + stroke: 'grey', + strokeWidth: 1, + strokeDashArray: [1, 1, 1], + name: 'helpGuideLine', + }) + + const guideLine2 = new QLine([guideLine1.x2, guideLine1.y2, firstPoint.x, firstPoint.y], { + stroke: 'grey', + strokeWidth: 1, + strokeDashArray: [1, 1, 1], + name: 'helpGuideLine', + }) + if (guideLine1.length > 0) { + canvas?.add(guideLine1) + addLineText(guideLine1) + } + + canvas?.add(guideLine2) + + addLineText(guideLine2) + }*/ + } + }, [points]) + + const drawLine = (point1, point2, idx) => { + addLine([point1.x, point1.y, point2.x, point2.y], { + stroke: 'black', + strokeWidth: 3, + idx: idx, + selectable: true, + name: 'placementShapeDrawingLine', + x1: point1.x, + y1: point1.y, + x2: point2.x, + y2: point2.y, + }) + } + + // 직각 완료될 경우 확인 + const checkRightAngle = (direction) => { + const activeElem = document.activeElement + + const canDirection = + direction === '↓' || direction === '↑' + ? arrow1Ref.current === '←' || arrow1Ref.current === '→' + : arrow1Ref.current === '↓' || arrow1Ref.current === '↑' + + if (activeElem === length1Ref.current || activeElem === angle1Ref.current) { + setArrow1(direction) + arrow1Ref.current = direction + length2Ref.current.focus() + } else if (activeElem === length2Ref.current || activeElem === angle2Ref.current) { + if (!canDirection) { + return + } + setArrow2(direction) + arrow2Ref.current = direction + } + + const length1Num = Number(length1Ref.current.value) / 10 + const length2Num = Number(length2Ref.current.value) / 10 + + if (points.length === 0) { + return + } + + if (length1Num === 0 || length2Num === 0 || arrow1Ref.current === '' || arrow2Ref.current === '') { + return + } + + if (arrow1Ref.current === '↓' && arrow2Ref.current === '→') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + length2Num, y: prev[prev.length - 1].y + length1Num }] + }) + } else if (arrow1Ref.current === '↓' && arrow2Ref.current === '←') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - length2Num, y: prev[prev.length - 1].y + length1Num }] + }) + } else if (arrow1Ref.current === '↑' && arrow2Ref.current === '→') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + length2Num, y: prev[prev.length - 1].y - length1Num }] + }) + } else if (arrow1Ref.current === '↑' && arrow2Ref.current === '←') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - length2Num, y: prev[prev.length - 1].y - length1Num }] + }) + } else if (arrow1Ref.current === '→' && arrow2Ref.current === '↓') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + length1Num, y: prev[prev.length - 1].y + length2Num }] + }) + } else if (arrow1Ref.current === '→' && arrow2Ref.current === '↑') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + length1Num, y: prev[prev.length - 1].y - length2Num }] + }) + } else if (arrow1Ref.current === '←' && arrow2Ref.current === '↓') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - length1Num, y: prev[prev.length - 1].y + length2Num }] + }) + } else if (arrow1Ref.current === '←' && arrow2Ref.current === '↑') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - length1Num, y: prev[prev.length - 1].y - length2Num }] + }) + } + } + + //이구배 완료될 경우 확인 ↓, ↑, ←, → + const checkDoublePitch = (direction) => { + const activeElem = document.activeElement + + const canDirection = + direction === '↓' || direction === '↑' + ? arrow1Ref.current === '←' || arrow1Ref.current === '→' + : arrow1Ref.current === '↓' || arrow1Ref.current === '↑' + + if (activeElem === length1Ref.current || activeElem === angle1Ref.current) { + setArrow1(direction) + arrow1Ref.current = direction + angle2Ref.current.focus() + } else if (activeElem === length2Ref.current || activeElem === angle2Ref.current) { + if (!canDirection) { + return + } + setArrow2(direction) + arrow2Ref.current = direction + } + + const angle1Value = angle1Ref.current.value + const angle2Value = angle2Ref.current.value + const length1Value = length1Ref.current.value + const length2Value = length2Ref.current.value + + const arrow1Value = arrow1Ref.current + const arrow2Value = arrow2Ref.current + + if (angle1Value !== 0 && length1Value !== 0 && angle2Value !== 0 && arrow1Value !== '' && arrow2Value !== '') { + if (arrow1Value === '↓' && arrow2Value === '→') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + length1Value / 10, y: prev[prev.length - 1].y + length2Value / 10 }] + }) + } else if (arrow1Value === '↓' && arrow2Value === '←') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - length1Value / 10, y: prev[prev.length - 1].y + length2Value / 10 }] + }) + } else if (arrow1Value === '↑' && arrow2Value === '→') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + length1Value / 10, y: prev[prev.length - 1].y - length2Value / 10 }] + }) + } else if (arrow1Value === '↑' && arrow2Value === '←') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - length1Value / 10, y: prev[prev.length - 1].y - length2Value / 10 }] + }) + } else if (arrow1Value === '→' && arrow2Value === '↓') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }] + }) + } else if (arrow1Value === '→' && arrow2Value === '↑') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }] + }) + } else if (arrow1Value === '←' && arrow2Value === '↓') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }] + }) + } else if (arrow1Value === '←' && arrow2Value === '↑') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }] + }) + } + + angle1Ref.current.focus() + } + } + + //대각선 완료될 경우 확인 + const checkDiagonal = (direction) => { + const activeElem = document.activeElement + const diagonalLength = outerLineDiagonalLengthRef.current.value // 대각선 길이 + + const length1Value = length1Ref.current.value + + if (diagonalLength <= length1Value) { + alert('대각선 길이는 직선 길이보다 길어야 합니다.') + return + } + + const canDirection = + direction === '↓' || direction === '↑' + ? arrow1Ref.current === '←' || arrow1Ref.current === '→' + : arrow1Ref.current === '↓' || arrow1Ref.current === '↑' + + if (activeElem === length1Ref.current) { + setArrow1(direction) + arrow1Ref.current = direction + } else if (activeElem === length2Ref.current || activeElem === angle2Ref.current) { + if (!canDirection) { + return + } + setArrow2(direction) + arrow2Ref.current = direction + } + + const arrow1Value = arrow1Ref.current + const arrow2Value = arrow2Ref.current + + const getLength2 = () => { + return Math.floor(Math.sqrt(diagonalLength ** 2 - length1Value ** 2)) + } + + const length2Value = getLength2() + + if (diagonalLength !== 0 && length1Value !== 0 && arrow1Value !== '') { + setLength2(getLength2()) + length2Ref.current.focus() + } + + if (length1Value !== 0 && length2Value !== 0 && arrow1Value !== '' && arrow2Value !== '') { + if (arrow1Value === '↓' && arrow2Value === '→') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }] + }) + } else if (arrow1Value === '↓' && arrow2Value === '←') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }] + }) + } else if (arrow1Value === '↑' && arrow2Value === '→') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }] + }) + } else if (arrow1Value === '↑' && arrow2Value === '←') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }] + }) + } else if (arrow1Value === '→' && arrow2Value === '↓') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + length1Value / 10, y: prev[prev.length - 1].y + length2Value / 10 }] + }) + } else if (arrow1Value === '→' && arrow2Value === '↑') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [ + ...prev, + { + x: prev[prev.length - 1].x + length1Value / 10, + y: prev[prev.length - 1].y - length2Value / 10, + }, + ] + }) + } + } + } + + const keydown = { + outerLine: (e) => { + if (points.length === 0) { + return + } + // 포커스가 length1에 있지 않으면 length1에 포커스를 줌 + const activeElem = document.activeElement + if (activeElem !== length1Ref.current) { + length1Ref.current.focus() + } + + const key = e.key + + if (!length1Ref.current) { + return + } + + const lengthNum = Number(length1Ref.current.value) / 10 + if (lengthNum === 0) { + return + } + switch (key) { + case 'Down': // IE/Edge에서 사용되는 값 + case 'ArrowDown': { + setArrow1('↓') + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x, y: prev[prev.length - 1].y + lengthNum }] + }) + break + } + case 'Up': // IE/Edge에서 사용되는 값 + case 'ArrowUp': + setArrow1('↑') + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x, y: prev[prev.length - 1].y - lengthNum }] + }) + break + case 'Left': // IE/Edge에서 사용되는 값 + case 'ArrowLeft': + setArrow1('←') + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - lengthNum, y: prev[prev.length - 1].y }] + }) + break + case 'Right': // IE/Edge에서 사용되는 값 + case 'ArrowRight': + setArrow1('→') + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + lengthNum, y: prev[prev.length - 1].y }] + }) + break + } + }, + rightAngle: (e) => { + if (points.length === 0) { + return + } + const key = e.key + + const activeElem = document.activeElement + if (activeElem !== length1Ref.current && activeElem !== length2Ref.current) { + length1Ref.current.focus() + } + + switch (key) { + case 'Down': // IE/Edge에서 사용되는 값 + case 'ArrowDown': { + checkRightAngle('↓') + break + } + case 'Up': // IE/Edge에서 사용되는 값 + case 'ArrowUp': + checkRightAngle('↑') + break + case 'Left': // IE/Edge에서 사용되는 값 + case 'ArrowLeft': + checkRightAngle('←') + break + case 'Right': // IE/Edge에서 사용되는 값 + case 'ArrowRight': + checkRightAngle('→') + break + case 'Enter': + break + } + }, + doublePitch: (e) => { + if (points.length === 0) { + return + } + const key = e.key + switch (key) { + case 'Down': // IE/Edge에서 사용되는 값 + case 'ArrowDown': { + checkDoublePitch('↓') + break + } + case 'Up': // IE/Edge에서 사용되는 값 + case 'ArrowUp': + checkDoublePitch('↑') + break + case 'Left': // IE/Edge에서 사용되는 값 + case 'ArrowLeft': + checkDoublePitch('←') + break + case 'Right': // IE/Edge에서 사용되는 값 + case 'ArrowRight': + checkDoublePitch('→') + break + } + }, + angle: (e) => { + if (points.length === 0) { + return + } + const key = e.key + switch (key) { + case 'Enter': { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + const lastPoint = prev[prev.length - 1] + const length = length1Ref.current.value / 10 + const angle = angle1Ref.current.value + //lastPoint로부터 angle1만큼의 각도로 length1만큼의 길이를 가지는 선을 그림 + const radian = (angle * Math.PI) / 180 + + const x = lastPoint.x + length * Math.cos(radian) + const y = lastPoint.y - length * Math.sin(radian) + return [...prev, { x, y }] + }) + } + } + }, + diagonalLine: (e) => { + if (points.length === 0) { + return + } + + const key = e.key + switch (key) { + case 'Down': // IE/Edge에서 사용되는 값 + case 'ArrowDown': { + checkDiagonal('↓') + break + } + case 'Up': // IE/Edge에서 사용되는 값 + case 'ArrowUp': + checkDiagonal('↑') + break + case 'Left': // IE/Edge에서 사용되는 값 + case 'ArrowLeft': + checkDiagonal('←') + break + case 'Right': // IE/Edge에서 사용되는 값 + case 'ArrowRight': + checkDiagonal('→') + break + } + }, + } + + /** + * 일변전으로 돌아가기 + */ + const handleRollback = () => { + //points의 마지막 요소를 제거 + setPoints((prev) => prev.slice(0, prev.length - 1)) + } + + const handleFix = () => { + if (points.length < 3) { + return + } + + let isAllRightAngle = true + + const firstPoint = points[0] + + points.forEach((point, idx) => { + if (idx === 0 || !isAllRightAngle) { + return + } + + const angle = calculateAngle(point, firstPoint) + if (angle % 90 !== 0) { + isAllRightAngle = false + } + }) + + if (isAllRightAngle) { + alert('부정확한 다각형입니다.') + return + } + + setPoints((prev) => { + return [...prev, { x: prev[0].x, y: prev[0].y }] + }) + + isFix.current = true + } + + return { + points, + setPoints, + length1, + setLength1, + length2, + setLength2, + length1Ref, + length2Ref, + arrow1, + setArrow1, + arrow2, + setArrow2, + arrow1Ref, + arrow2Ref, + angle1, + setAngle1, + angle1Ref, + angle2, + setAngle2, + angle2Ref, + outerLineDiagonalLength, + setOuterLineDiagonalLength, + outerLineDiagonalLengthRef, + type, + setType, + handleFix, + handleRollback, + } +} diff --git a/src/store/placementShapeDrawingAtom.js b/src/store/placementShapeDrawingAtom.js new file mode 100644 index 00000000..b7a65107 --- /dev/null +++ b/src/store/placementShapeDrawingAtom.js @@ -0,0 +1,70 @@ +import { atom } from 'recoil' + +export const OUTER_LINE_TYPE = { + OUTER_LINE: 'outerLine', // 외벽선 + RIGHT_ANGLE: 'rightAngle', // 직각 + DOUBLE_PITCH: 'doublePitch', + ANGLE: 'angle', // 각도 + DIAGONAL_LINE: 'diagonalLine', // 대각선 +} + +/** + * 외벽선 작성에서 사용하는 recoilState + */ + +export const placementShapeDrawingLength1State = atom({ + //길이1 + key: 'placementShapeDrawingLength1State', + default: 0, +}) + +export const placementShapeDrawingLength2State = atom({ + // 길이2 + key: 'placementShapeDrawingLength2State', + default: 0, +}) + +export const placementShapeDrawingArrow1State = atom({ + // 방향1 + key: 'placementShapeDrawingArrow1State', + default: '', +}) + +export const placementShapeDrawingArrow2State = atom({ + // 방향2 + key: 'placementShapeDrawingArrow2State', + default: '', +}) + +export const placementShapeDrawingAngle1State = atom({ + // 각도1 + key: 'placementShapeDrawingAngle1State', + default: 0, +}) + +export const placementShapeDrawingAngle2State = atom({ + // 각도2 + key: 'placementShapeDrawingAngle2State', + default: 0, +}) + +export const placementShapeDrawingDiagonalState = atom({ + // 대각선 + key: 'placementShapeDrawingDiagonalState', + default: 0, +}) + +export const placementShapeDrawingTypeState = atom({ + key: 'placementShapeDrawingTypeState', + default: OUTER_LINE_TYPE.OUTER_LINE, +}) + +export const placementShapeDrawingPointsState = atom({ + key: 'placementShapeDrawingPointsState', + default: [], +}) + +export const placementShapeDrawingFixState = atom({ + key: 'placementShapeDrawingFixState', + default: false, +})