This commit is contained in:
minsik 2024-11-04 16:15:51 +09:00
commit 40fa42b19b
22 changed files with 2100 additions and 1236 deletions

View File

@ -19,9 +19,12 @@ Allpainted : allPainted
출폭: offset
폭: width
경사(구배): pitch
각도: degree
이구배: doublePitch
소매: sleeve
개구: openSpace
도머: dormer
그림자: shadow
치수선: dimensionLine
치수선: dimensionLine
복도치수: planeSize
실제치수: actualSize

View File

@ -1,16 +1,7 @@
import Roof2 from '@/components/Roof2'
// import { initCheck } from '@/util/session-util'
import RoofSelect from '@/app/roof2/RoofSelect'
export default async function Roof2Page() {
// const session = await initCheck()
const roof2Props = {
// name: session.name || '',
// userId: session.userId || '',
// email: session.email || '',
// isLoggedIn: session.isLoggedIn,
}
return (
<>
<div>
@ -19,7 +10,7 @@ export default async function Roof2Page() {
</div>
</div>
<div className="flex flex-col justify-center my-8 pt-20">
<Roof2 {...roof2Props} />
<Roof2 />
</div>
</>
)

View File

@ -65,6 +65,7 @@ export const LINE_TYPE = {
HIPANDGABLE: 'hipAndGable',
JERKINHEAD: 'jerkinhead',
SHED: 'shed',
ETC: 'etc',
},
SUBLINE: {
/**
@ -116,6 +117,7 @@ export const INPUT_TYPE = {
export const POLYGON_TYPE = {
ROOF: 'roof',
WALL: 'wall',
TRESTLE: 'trestle',
}

View File

@ -4,7 +4,7 @@ import { useCanvas } from '@/hooks/useCanvas'
import { useEffect, useRef, useState } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { useMode } from '@/hooks/useMode'
import { Mode } from '@/common/common'
import { LINE_TYPE, Mode } from '@/common/common'
import { Button, Input } from '@nextui-org/react'
import RangeSlider from './ui/RangeSlider'
import { useRecoilState, useRecoilValue } from 'recoil'
@ -39,7 +39,7 @@ import QEmptyContextMenu from '@/components/common/context-menu/QEmptyContextMen
import InitSettingsModal from './InitSettingsModal'
import GridSettingsModal from './GridSettingsModal'
import { SurfaceShapeModal } from '@/components/ui/SurfaceShape'
import { drawDirectionStringToArrow } from '@/util/qpolygon-utils'
import { changeCurrentRoof, drawDirectionStringToArrow } from '@/util/qpolygon-utils'
import ThumbnailList from '@/components/ui/ThumbnailLIst'
import ObjectPlacement from '@/components/ui/ObjectPlacement'
import { globalLocaleStore } from '@/store/localeAtom'
@ -409,6 +409,20 @@ export default function Roof2(props) {
{ x: 600, y: 100 },
]
const rectangleType1 = [
{ x: 100, y: 100 },
{ x: 100, y: 600 },
{ x: 300, y: 600 },
{ x: 300, y: 100 },
]
const rectangleType2 = [
{ x: 100, y: 100 },
{ x: 100, y: 300 },
{ x: 600, y: 300 },
{ x: 600, y: 100 },
]
const types = [type1, type2, type3, type4, type1A, type1B, eightPoint, eightPoint2, eightPoint3, eightPoint4, twelvePoint]
const newP = [
{ x: 450, y: 450 },
@ -417,7 +431,7 @@ export default function Roof2(props) {
{ x: 450, y: 850 },
]
const polygon = new QPolygon(twelvePoint, {
const polygon = new QPolygon(rectangleType2, {
fill: 'transparent',
stroke: 'green',
strokeWidth: 1,
@ -658,17 +672,52 @@ export default function Roof2(props) {
canvas?.renderAll()
}
const setAllGableRoof = () => {
let offset = Number(prompt('gable roof offset', '50'))
const setHipRoof = () => {
const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof')
const currentRoof = polygon.lines[2]
currentRoof.attributes.type = LINE_TYPE.WALLLINE.EAVES
currentRoof.attributes.offset = 50
changeCurrentRoof(currentRoof, canvas)
}
const setGableRoof = () => {
const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof')
const currentRoof = polygon.lines[2]
currentRoof.attributes.type = LINE_TYPE.WALLLINE.GABLE
currentRoof.attributes.offset = 30
changeCurrentRoof(currentRoof, canvas)
}
const setHipAndGableRoof = () => {
let offset = Number(prompt('팔작지붕 폭', '50'))
if (!isNaN(offset) && offset > 0) {
const polygon = canvas?.getObjects()
console.log('gable roof offset : ', offset)
console.log('polygon : ', polygon)
changeAllGableRoof(polygon, offset, canvas)
const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof')
const currentRoof = polygon.lines[2]
currentRoof.attributes.type = LINE_TYPE.WALLLINE.HIPANDGABLE
currentRoof.attributes.width = offset
changeCurrentRoof(currentRoof, canvas)
} else {
alert('offset 은 0 보다 커야 함')
alert('은 0 보다 커야 함')
}
}
const setJerkInHeadRoof = () => {
let offset = Number(prompt('팔작지붕 폭', '50'))
if (!isNaN(offset) && offset > 0) {
const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof')
const currentRoof = polygon.lines[2]
currentRoof.attributes.type = LINE_TYPE.WALLLINE.JERKINHEAD
currentRoof.attributes.width = offset
changeCurrentRoof(currentRoof, canvas)
} else {
alert('폭은 0 보다 커야 함')
}
}
const setWallRoof = () => {
let offset = Number(prompt('소매 폭', '0'))
const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof')
const currentRoof = polygon.lines[2]
currentRoof.attributes.type = LINE_TYPE.WALLLINE.WALL
currentRoof.attributes.width = offset
changeCurrentRoof(currentRoof, canvas)
}
return (
<>
{canvas && (
@ -788,16 +837,28 @@ export default function Roof2(props) {
<Button className="m-1 p-2" onClick={makePolygon}>
다각형 추가
</Button>
{templateType === 0 && (
<>
<Button className="m-1 p-2" onClick={makeQPolygon}>
QPolygon
</Button>
</>
)}
<Button className={'m-1 p-2'} onClick={setAllGableRoof}>
{/*{templateType === 0 && (*/}
{/* <>*/}
<Button className="m-1 p-2" onClick={makeQPolygon}>
QPolygon
</Button>
{/* </>*/}
{/*)}*/}
<Button className={'m-1 p-2'} onClick={setHipRoof}>
용마루지붕
</Button>
<Button className={'m-1 p-2'} onClick={setHipAndGableRoof}>
팔작지붕
</Button>
<Button className={'m-1 p-2'} onClick={setGableRoof}>
박공지붕
</Button>
<Button className={'m-1 p-2'} onClick={setJerkInHeadRoof}>
반절처지붕
</Button>
<Button className={'m-1 p-2'} onClick={setWallRoof}>
벽지붕
</Button>
<Button className="m-1 p-2" onClick={() => saveImage(uuidv4(), userId, setThumbnails)}>
저장
</Button>

View File

@ -2,26 +2,36 @@ import { fabric } from 'fabric'
import { v4 as uuidv4 } from 'uuid'
import { QLine } from '@/components/fabric/QLine'
import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPointLessEightPoint, sortedPoints } from '@/util/canvas-util'
import { calculateAngle, drawHippedRoof, inPolygon, toGeoJSON } from '@/util/qpolygon-utils'
import { calculateAngle, drawRidgeRoof, drawHippedRoof, inPolygon, toGeoJSON } from '@/util/qpolygon-utils'
import * as turf from '@turf/turf'
import { LINE_TYPE } from '@/common/common'
export const QPolygon = fabric.util.createClass(fabric.Polygon, {
type: 'QPolygon',
lines: [],
texts: [],
// lines: [],
// texts: [],
id: null,
length: 0,
hips: [],
ridges: [],
connectRidges: [],
cells: [],
// hips: [],
// ridges: [],
// connectRidges: [],
// cells: [],
parentId: null,
innerLines: [],
children: [],
// innerLines: [],
// children: [],
initOptions: null,
direction: null,
arrow: null,
initialize: function (points, options, canvas) {
this.lines = []
this.texts = []
this.hips = []
this.ridges = []
this.connectRidges = []
this.cells = []
this.innerLines = []
this.children = []
// 소수점 전부 제거
points.forEach((point) => {
point.x = Number(point.x.toFixed(1))
@ -153,9 +163,42 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
},
// 보조선 그리기
drawHelpLine(chon = 4) {
// drawHelpLineInHexagon(this, chon)
drawHippedRoof(this, chon)
drawHelpLine() {
// drawHelpLineInHexagon(this, pitch)
const types = []
this.lines.forEach((line) => types.push(line.attributes.type))
const eavesType = [LINE_TYPE.WALLLINE.EAVES, LINE_TYPE.WALLLINE.HIPANDGABLE]
const gableType = [LINE_TYPE.WALLLINE.GABLE, LINE_TYPE.WALLLINE.JERKINHEAD]
const isEaves = types.every((type) => eavesType.includes(type))
const gableOdd = types.filter((type, i) => i % 2 === 0)
const gableEven = types.filter((type, i) => i % 2 === 1)
const hasShed = types.includes(LINE_TYPE.WALLLINE.SHED)
// A형, B형 박공 지붕
if (
(gableOdd.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableEven.every((type) => gableType.includes(type))) ||
(gableEven.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableOdd.every((type) => gableType.includes(type)))
) {
console.log('박공 지붕')
} else if (hasShed) {
//편류지붕
let shedIndex = 0
types.forEach((type, i) => {
if (type === LINE_TYPE.WALLLINE.SHED) {
shedIndex = i
}
})
const shedOdd = types.filter((type, i) => i % 2 === shedIndex % 2).filter((type) => type !== LINE_TYPE.WALLLINE.SHED)
const shedEven = types.filter((type, i) => i % 2 !== shedIndex % 2)
types.forEach((type, i) => console.log(type, i, i % 2, shedIndex % 2, i % 2 === shedIndex % 2))
if (shedOdd.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && shedEven.every((type) => type === LINE_TYPE.WALLLINE.GABLE)) {
console.log('편류지붕')
}
} else {
drawRidgeRoof(this.id, this.canvas)
}
},
addLengthText() {

View File

@ -32,6 +32,8 @@ import { menusState, menuTypeState } from '@/store/menuAtom'
import useMenu from '@/hooks/common/useMenu'
import { MENU } from '@/common/common'
import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController'
export default function CanvasMenu(props) {
const { menuNumber, setMenuNumber } = props
const pathname = usePathname()
@ -51,6 +53,7 @@ export default function CanvasMenu(props) {
const canvas = useRecoilValue(canvasState)
const { handleZoomClear, handleZoom } = useCanvasEvent()
const { handleMenu } = useMenu()
const { handleEstimateSubmit } = useEstimateController()
const { getMessage } = useMessage()
const { currentCanvasPlan, saveCanvas } = usePlan()
@ -226,7 +229,7 @@ export default function CanvasMenu(props) {
<span className="ico ico01"></span>
<span>{getMessage('plan.menu.estimate.docDown')}</span>
</button>
<button className="btn-frame gray ico-flx">
<button className="btn-frame gray ico-flx" onClick={handleEstimateSubmit}>
<span className="ico ico02"></span>
<span>{getMessage('plan.menu.estimate.save')}</span>
</button>

View File

@ -0,0 +1,60 @@
import { useAxios } from '@/hooks/useAxios'
import { useReducer } from 'react'
const reducer = (prevState, nextState) => {
return { ...prevState, ...nextState }
}
// Constants
const ESTIMATE_API_ENDPOINT = '/api/estimates' // API 엔드포인트 정의
const defaultEstimateData = {
name: '',
objectName: '',
estimateDate: '',
itemList: [{ id: 1, name: '' }],
}
// Helper functions
const updateItemInList = (itemList, id, updates) => {
return itemList.map((item) => (item.id === id ? { ...item, ...updates } : item))
}
export const useEstimateController = () => {
const { promisePost } = useAxios()
const [state, setState] = useReducer(reducer, defaultEstimateData)
const updateItem = (id, updates) => {
setState({
itemList: updateItemInList(state.itemList, id, updates),
})
}
const addItem = () => {
const newId = Math.max(...state.itemList.map((item) => item.id)) + 1
setState({
itemList: [...state.itemList, { id: newId, name: '' }],
})
}
const handleEstimateSubmit = async () => {
try {
const result = await promisePost({
url: ESTIMATE_API_ENDPOINT,
data: state,
})
return result
} catch (error) {
console.error('Failed to submit estimate:', error)
throw error
}
}
return {
state,
setState,
updateItem,
addItem,
handleEstimateSubmit,
}
}

View File

@ -225,9 +225,9 @@ export function useCanvasSetting() {
const option1 = settingModalFirstOptions.option1
// 'allocDisplay' 할당 표시
// 'outlineDisplay' 외벽선 표시 'outerLine', 'wallLine'
// 'outlineDisplay' 외벽선 표시 'outerLine', POLYGON_TYPE.WALL
// 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid'
// 'lineDisplay' 지붕선 표시 'roof', 'roofBase'
// 'lineDisplay' 지붕선 표시 'roof', POLYGON_TYPE.ROOF
// 'wordDisplay' 문자 표시
// 'circuitNumDisplay' 회로번호 표시
// 'flowDisplay' 흐름방향 표시 'arrow'
@ -244,13 +244,13 @@ export function useCanvasSetting() {
optionName = ['1']
break
case 'outlineDisplay': //외벽선 표시
optionName = ['outerLine', 'wallLine']
optionName = ['outerLine', POLYGON_TYPE.WALL]
break
case 'gridDisplay': //그리드 표시
optionName = ['lindGrid', 'dotGrid']
break
case 'lineDisplay': //지붕선 표시
optionName = ['roof', 'roofBase']
optionName = ['roof', POLYGON_TYPE.ROOF]
break
case 'wordDisplay': //문자 표시
optionName = ['6']

View File

@ -12,9 +12,9 @@ export function useFirstOption() {
const option1 = settingModalFirstOptions.option1
// 'allocDisplay' 할당 표시
// 'outlineDisplay' 외벽선 표시 'outerLine', 'wallLine'
// 'outlineDisplay' 외벽선 표시 'outerLine', POLYGON_TYPE.WALL
// 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid'
// 'lineDisplay' 지붕선 표시 'roof', 'roofBase'
// 'lineDisplay' 지붕선 표시 'roof', POLYGON_TYPE.ROOF
// 'wordDisplay' 문자 표시
// 'circuitNumDisplay' 회로번호 표시
// 'flowDisplay' 흐름방향 표시 'arrow'
@ -30,13 +30,13 @@ export function useFirstOption() {
optionName = ['1']
break
case 'outlineDisplay': //외벽선 표시
optionName = ['outerLine', 'wallLine']
optionName = ['outerLine', POLYGON_TYPE.WALL]
break
case 'gridDisplay': //그리드 표시
optionName = ['lineGrid', 'dotGrid', 'adsorptionPoint', 'tempGrid']
break
case 'lineDisplay': //지붕선 표시
optionName = ['roof', 'roofBase']
optionName = ['roof', POLYGON_TYPE.ROOF]
break
case 'wordDisplay': //문자 표시
optionName = ['6']

View File

@ -15,7 +15,7 @@ import {
outerLineLength2State,
outerLineTypeState,
} from '@/store/outerLineAtom'
import { calculateIntersection, distanceBetweenPoints, findClosestPoint, polygonToTurfPolygon } from '@/util/canvas-util'
import { calculateIntersection, distanceBetweenPoints, findClosestPoint, isPointOnLine, polygonToTurfPolygon } from '@/util/canvas-util'
import { fabric } from 'fabric'
import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint'
import { useSwal } from '@/hooks/useSwal'
@ -23,6 +23,7 @@ import { booleanPointInPolygon } from '@turf/turf'
import { usePopup } from '@/hooks/usePopup'
import { calculateAngle } from '@/util/qpolygon-utils'
import { QPolygon } from '@/components/fabric/QPolygon'
import { POLYGON_TYPE } from '@/common/common'
// 보조선 작성
export function useAuxiliaryDrawing(id) {
@ -80,7 +81,7 @@ export function useAuxiliaryDrawing(id) {
useEffect(() => {
// innerLines가 있을경우 삭제
const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roofBase')
const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
if (roofs.length === 0) {
swalFire({ text: '지붕형상이 없습니다.' })
closePopup(id)
@ -561,7 +562,7 @@ export function useAuxiliaryDrawing(id) {
return
}
const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
/*const allLines = [...auxiliaryLines]
roofBases.forEach((roofBase) => {
@ -611,9 +612,41 @@ export function useAuxiliaryDrawing(id) {
},
)
lineHistory.current.push(newLine)
lineHistory.current = lineHistory.current.filter((history) => history !== line1)
removeLine(line1)
intersectionPoints.current.push(...interSectionPointsWithRoofLines)
return
} else if (interSectionPointsWithRoofLines.length === 1) {
//지붕선과 만나는 점이 하나일 경우
const distance1 = distanceBetweenPoints({ x: line1.x1, y: line1.y1 }, interSectionPointsWithRoofLines[0])
const distance2 = distanceBetweenPoints({ x: line1.x2, y: line1.y2 }, interSectionPointsWithRoofLines[0])
if (!(distance1 === 0 || distance2 === 0)) {
if (distance1 >= distance2) {
const newLine = addLine([line1.x1, line1.y1, interSectionPointsWithRoofLines[0].x, interSectionPointsWithRoofLines[0].y], {
stroke: 'black',
strokeWidth: 1,
selectable: false,
name: 'auxiliaryLine',
isFixed: true,
})
lineHistory.current.push(newLine)
lineHistory.current = lineHistory.current.filter((history) => history !== line1)
removeLine(line1)
} else {
const newLine = addLine([line1.x2, line1.y2, interSectionPointsWithRoofLines[0].x, interSectionPointsWithRoofLines[0].y], {
stroke: 'black',
strokeWidth: 1,
selectable: false,
name: 'auxiliaryLine',
isFixed: true,
})
lineHistory.current.push(newLine)
lineHistory.current = lineHistory.current.filter((history) => history !== line1)
removeLine(line1)
}
intersectionPoints.current.push(interSectionPointsWithRoofLines[0])
}
}
//보조선과 만나는 점을 찾는다.
@ -659,6 +692,7 @@ export function useAuxiliaryDrawing(id) {
})
}
lineHistory.current.push(newLine)
lineHistory.current = lineHistory.current.filter((history) => history !== line1)
removeLine(line1)
})
@ -742,7 +776,7 @@ export function useAuxiliaryDrawing(id) {
return
}
const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
//lineHistory.current에 있는 선들 중 startPoint와 endPoint가 겹치는 line은 제거
// 겹치는 선 하나는 canvas에서 제거한다.
@ -772,9 +806,13 @@ export function useAuxiliaryDrawing(id) {
})
const roofInnerLines = innerLines.filter((line) => {
const inPolygon1 =
tempPolygonPoints.some((point) => point.x === line.x1 && point.y === line.y1) || roofBase.inPolygon({ x: line.x1, y: line.y1 })
tempPolygonPoints.some((point) => point.x === line.x1 && point.y === line.y1) ||
roofBase.inPolygon({ x: line.x1, y: line.y1 }) ||
roofBase.lines.some((line) => isPointOnLine(line, { x: line.x1, y: line.y1 }))
const inPolygon2 =
tempPolygonPoints.some((point) => point.x === line.x2 && point.y === line.y2) || roofBase.inPolygon({ x: line.x2, y: line.y2 })
tempPolygonPoints.some((point) => point.x === line.x2 && point.y === line.y2) ||
roofBase.inPolygon({ x: line.x2, y: line.y2 }) ||
roofBase.lines.some((line) => isPointOnLine(line, { x: line.x2, y: line.y2 }))
if (inPolygon1 && inPolygon2) {
line.attributes = { ...line.attributes, roofId: roofBase.id }

View File

@ -3,7 +3,7 @@ import { useRecoilValue } from 'recoil'
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, pitchTextSelector } from '@/store/canvasAtom'
import { useMessage } from '@/hooks/useMessage'
import { useEvent } from '@/hooks/useEvent'
import { LINE_TYPE } from '@/common/common'
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import { useLine } from '@/hooks/useLine'
import { useMode } from '@/hooks/useMode'
import { outerLineFixState } from '@/store/outerLineAtom'
@ -54,7 +54,7 @@ export function useEavesGableEdit(id) {
}, [])
useEffect(() => {
const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine')
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
wallLines.forEach((wallLine) => {
convertPolygonToLines(wallLine)
})
@ -160,7 +160,7 @@ export function useEavesGableEdit(id) {
attributes,
})
const roofBases = canvas?.getObjects().filter((obj) => obj.name === 'roofBase')
const roofBases = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
roofBases.forEach((roof) => {
roof.innerLines.forEach((line) => {
@ -169,7 +169,7 @@ export function useEavesGableEdit(id) {
canvas.remove(roof)
})
const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine')
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'pitchText')
removeTargets.forEach((obj) => {
canvas.remove(obj)

View File

@ -4,6 +4,7 @@ import { usePopup } from '@/hooks/usePopup'
import { useMessage } from '@/hooks/useMessage'
import { useEffect, useRef, useState } from 'react'
import { useEvent } from '@/hooks/useEvent'
import { POLYGON_TYPE } from '@/common/common'
//동선이동 형 올림 내림
export function useMovementSetting(id) {
@ -41,7 +42,7 @@ export function useMovementSetting(id) {
}, [type])
useEffect(() => {
const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') // 기존 wallLine의 visible false
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) // 기존 wallLine의 visible false
wallLines.forEach((line) => {
line.set({ visible: false })
})
@ -55,7 +56,7 @@ export function useMovementSetting(id) {
addCanvasMouseEventListener('mouse:move', mouseMoveEvent)
return () => {
initEvent()
const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine')
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
wallLines.forEach((line) => {
line.set({ visible: true })
})

View File

@ -1,5 +1,5 @@
import { useEffect, useRef } from 'react'
import { LINE_TYPE } from '@/common/common'
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { canvasState, currentObjectState } from '@/store/canvasAtom'
import { useMode } from '@/hooks/useMode'
@ -135,7 +135,7 @@ export function usePropertiesSetting(id) {
hideLine(line)
})
const wall = addPolygonByLines(lines, { name: 'wallLine', fill: 'transparent', stroke: 'black' })
const wall = addPolygonByLines(lines, { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' })
wall.lines = [...lines]

View File

@ -7,6 +7,7 @@ import { useSwal } from '@/hooks/useSwal'
import { usePolygon } from '@/hooks/usePolygon'
import { roofDisplaySelector } from '@/store/settingAtom'
import { usePopup } from '@/hooks/usePopup'
import { POLYGON_TYPE } from '@/common/common'
// 지붕면 할당
export function useRoofAllocationSetting(id) {
@ -81,12 +82,12 @@ export function useRoofAllocationSetting(id) {
const [selectedRoofMaterial, setSelectedRoofMaterial] = useState(roofMaterials[0])
useEffect(() => {
const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
if (roofBases.length === 0) {
swalFire({ text: '할당할 지붕이 없습니다.' })
closePopup(id)
}
// if (type === 'roofBase') {
// if (type === POLYGON_TYPE.ROOF) {
// // 지붕면 할당
//
// } else if ('roof') {
@ -104,8 +105,8 @@ export function useRoofAllocationSetting(id) {
// 선택한 지붕재로 할당
const handleSave = () => {
const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine')
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
roofBases.forEach((roofBase) => {
try {
splitPolygonWithLines(roofBase)
@ -117,7 +118,7 @@ export function useRoofAllocationSetting(id) {
canvas.remove(line)
})
canvas.remove(roofBase)
// canvas.remove(roofBase)
})
wallLines.forEach((wallLine) => {

View File

@ -4,7 +4,7 @@ import { useEffect, useRef, useState } from 'react'
import { useLine } from '@/hooks/useLine'
import { useMessage } from '@/hooks/useMessage'
import { useEvent } from '@/hooks/useEvent'
import { LINE_TYPE } from '@/common/common'
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import { useMode } from '@/hooks/useMode'
import { usePolygon } from '@/hooks/usePolygon'
import { outerLineFixState } from '@/store/outerLineAtom'
@ -60,7 +60,7 @@ export function useRoofShapePassivitySetting(id) {
useEffect(() => {
if (!isLoading) return
addCanvasMouseEventListener('mouse:down', mouseDown)
const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine')
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
canvas?.remove(...wallLines)
@ -185,7 +185,7 @@ export function useRoofShapePassivitySetting(id) {
}
const handleLineToPolygon = () => {
const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
const exceptObjs = canvas.getObjects().filter((obj) => obj.name !== 'outerLine' && obj.parent?.name !== 'outerLine')
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
exceptObjs.forEach((obj) => {
@ -199,10 +199,10 @@ export function useRoofShapePassivitySetting(id) {
let wall
if (isFix.current) {
wall = addPolygonByLines(lines, { name: 'wallLine', fill: 'transparent', stroke: 'black' })
wall = addPolygonByLines(lines, { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' })
} else {
// 그냥 닫을 경우 처리
wall = addPolygonByLines([...initLines.current], { name: 'wallLine', fill: 'transparent', stroke: 'black' })
wall = addPolygonByLines([...initLines.current], { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' })
lines.forEach((line, idx) => {
line.attributes = initLines.current[idx].attributes
})

View File

@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { useRecoilValue, useSetRecoilState } from 'recoil'
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, currentMenuState, currentObjectState, pitchTextSelector } from '@/store/canvasAtom'
import { LINE_TYPE } from '@/common/common'
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import { usePolygon } from '@/hooks/usePolygon'
import { useMode } from '@/hooks/useMode'
import { useLine } from '@/hooks/useLine'
@ -129,7 +129,7 @@ export function useRoofShapeSetting(id) {
useEffect(() => {
if (shapeNum === 4) {
canvas?.remove(canvas.getObjects().find((obj) => obj.name === 'wallLine'))
canvas?.remove(canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.WALL))
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
outerLines.forEach((line) => {
showLine(line)
@ -376,20 +376,20 @@ export function useRoofShapeSetting(id) {
// 기존 wallLine, roofBase 제거
canvas
.getObjects()
.filter((obj) => obj.name === 'wallLine')
.filter((obj) => obj.name === POLYGON_TYPE.WALL)
.forEach((line) => {
canvas.remove(line)
})
canvas
.getObjects()
.filter((obj) => obj.name === 'roofBase')
.filter((obj) => obj.name === POLYGON_TYPE.ROOF)
.forEach((obj) => {
canvas.remove(...obj.innerLines)
canvas.remove(obj)
})
const polygon = addPolygonByLines(outerLines, { name: 'wallLine' })
const polygon = addPolygonByLines(outerLines, { name: POLYGON_TYPE.WALL })
polygon.lines = [...outerLines]
addPitchTextsByOuterLines()

View File

@ -36,10 +36,7 @@ import { QPolygon } from '@/components/fabric/QPolygon'
import offsetPolygon from '@/util/qpolygon-utils'
import { isObjectNotEmpty } from '@/util/common-utils'
import * as turf from '@turf/turf'
import { INPUT_TYPE, Mode } from '@/common/common'
import { m } from 'framer-motion'
import { set } from 'react-hook-form'
import { FaWineGlassEmpty } from 'react-icons/fa6'
import { INPUT_TYPE, LINE_TYPE, Mode, POLYGON_TYPE } from '@/common/common'
export function useMode() {
const [mode, setMode] = useRecoilState(modeState)
@ -1509,6 +1506,59 @@ export function useMode() {
* 지붕 외곽선 생성 polygon을 입력받아 만들기
*/
const handleOuterlinesTest2 = (polygon, offset = 50) => {
// TODO [ljyoung] : offset 입력 처리 후 제거 해야함.
polygon.lines.forEach((line, index) => {
line.attributes = {
type: LINE_TYPE.WALLLINE.EAVES,
offset: 40,
width: 50,
pitch: 4,
sleeve: true,
}
/*if (index === 1 || index === 3) {
line.attributes = {
type: LINE_TYPE.WALLLINE.WALL,
offset: 50, //출폭
width: 30, //폭
pitch: 4, //구배
sleeve: true, //소매
}
} else {
line.attributes = {
type: LINE_TYPE.WALLLINE.EAVES,
offset: 40,
width: 50,
pitch: 4,
sleeve: true,
}
}*/
/* if (index === 1) {
line.attributes = {
type: LINE_TYPE.WALLLINE.SHED,
offset: 20, //출폭
width: 30, //폭
pitch: 4, //구배
sleeve: true, //소매
}
} else if (index === 3) {
line.attributes = {
type: LINE_TYPE.WALLLINE.EAVES,
offset: 50, //출폭
width: 30, //폭
pitch: 4, //구배
sleeve: true, //소매
}
} else {
line.attributes = {
type: LINE_TYPE.WALLLINE.GABLE,
offset: 30,
width: 50,
pitch: 4,
sleeve: true,
}
}*/
})
const roof = drawRoofPolygon(polygon) //지붕 그리기
roof.drawHelpLine()
// roof.divideLine()
@ -1677,21 +1727,6 @@ export function useMode() {
}
const drawRoofPolygon = (wall) => {
// TODO [ljyoung] : offset 입력 처리 후 제거 해야함.
/*wall.lines.forEach((line, index) => {
if (index === wall.lines.length - 1 || index === 3) {
line.attributes = {
type: 'gable',
offset: 30,
}
} else {
line.attributes = {
type: 'hip',
offset: 50,
}
}
})*/
const polygon = createRoofPolygon(wall.points)
const originPolygon = new QPolygon(wall.points, { fontSize: 0 })
originPolygon.setViewLengthText(false)
@ -1711,13 +1746,33 @@ export function useMode() {
return { x1: point.x, y1: point.y }
}),
)
roof.name = 'roofBase'
roof.name = POLYGON_TYPE.ROOF
roof.setWall(wall)
roof.lines.forEach((line, index) => {
line.attributes = wall.lines[index].attributes
line.attributes = {
roofId: roof.id,
wallLine: wall.lines[index].id,
type: wall.lines[index].attributes.type,
offset: wall.lines[index].attributes.offset,
width: wall.lines[index].attributes.width,
pitch: wall.lines[index].attributes.pitch,
sleeve: wall.lines[index].attributes.sleeve || false,
}
})
wall.attributes = {
roofId: roof.id,
}
wall.lines.forEach((line, index) => {
line.attributes.roofId = roof.id
line.attributes.currentRoof = roof.lines[index].id
})
console.log('drawRoofPolygon roof : ', roof)
console.log('drawRoofPolygon wall : ', wall)
setRoof(roof)
setWall(wall)

View File

@ -814,7 +814,10 @@
"estimate.detail.sepcialEstimateProductInfo.calcFormula2": "PKG単価 (W)×PKG容量(W)",
"estimate.detail.header.showPrice": "価格表示",
"estimate.detail.showPrice.btn1": "Pricing",
"estimate.detail.showPrice.description": "クリックして製品の特異性を確認する",
"estimate.detail.showPrice.description1": "製品価格 OPEN",
"estimate.detail.showPrice.description2": "追加, 変更資材",
"estimate.detail.showPrice.description3": "添付必須",
"estimate.detail.showPrice.description4": "クリックして製品の特異性を確認する",
"estimate.detail.showPrice.btn2": "製品を追加",
"estimate.detail.showPrice.btn3": "製品削除"
}

View File

@ -820,7 +820,10 @@
"estimate.detail.sepcialEstimateProductInfo.calcFormula2": "PKG단가(W) * PKG용량(W)",
"estimate.detail.header.showPrice": "가격표시",
"estimate.detail.showPrice.btn1": "Pricing",
"estimate.detail.showPrice.description": "클릭하여 제품 특이사항 확인",
"estimate.detail.showPrice.description1": "제품 가격 OPEN",
"estimate.detail.showPrice.description2": "추가, 변경 자재",
"estimate.detail.showPrice.description3": "첨부필수",
"estimate.detail.showPrice.description4": "클릭하여 제품 특이사항 확인",
"estimate.detail.showPrice.btn2": "제품추가",
"estimate.detail.showPrice.btn3": "제품삭제"
}

View File

@ -5,7 +5,7 @@ export const settingModalFirstOptionsState = atom({
default: {
option1: [
{ id: 1, column: 'allocDisplay', name: 'modal.canvas.setting.first.option.alloc', selected: false },
{ id: 2, column: 'outlineDisplay', name: 'modal.canvas.setting.first.option.outline', selected: false },
{ id: 2, column: 'outlineDisplay', name: 'modal.canvas.setting.first.option.outline', selected: true },
{ id: 3, column: 'gridDisplay', name: 'modal.canvas.setting.first.option.grid', selected: false },
{ id: 4, column: 'lineDisplay', name: 'modal.canvas.setting.first.option.roof.line', selected: false },
{ id: 5, column: 'wordDisplay', name: 'modal.canvas.setting.first.option.word', selected: false },

View File

@ -263,12 +263,12 @@ export const getDegreeByChon = (chon) => {
}
/**
*
* 각도를 입력받아 촌을 반환
* @param degree
* @returns {number}
*/
export const getChonByDegree = (degree) => {
// tan(theta) = height / base
const radians = (degree * Math.PI) / 180
return Number(Number(Math.tan(radians) * 10).toFixed(2))
return Number((Math.tan((degree * Math.PI) / 180) * 10).toFixed(2))
}
/**
@ -521,9 +521,11 @@ export function isPointOnLine(line, point) {
const a = line.y2 - line.y1
const b = line.x1 - line.x2
const c = line.x2 * line.y1 - line.x1 * line.y2
return a * point.x + b * point.y + c === 0
}
const result = Math.abs(a * point.x + b * point.y + c) / 100
// 점이 선 위에 있는지 확인
return result <= 10
}
/**
* 점과 가까운 line 찾기
* @param point

File diff suppressed because it is too large Load Diff