Compare commits

...

10 Commits

8 changed files with 3050 additions and 2806 deletions

View File

@ -244,21 +244,10 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
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)))
) {
drawGabledRoof(this.id, this.canvas, textMode)
} else*/
if (hasShed) {
const sheds = this.lines.filter((line) => line.attributes !== undefined && line.attributes.type === LINE_TYPE.WALLLINE.SHED)
const areLinesParallel = function (line1, line2) {

View File

@ -25,7 +25,7 @@ import { useCommonUtils } from '@/hooks/common/useCommonUtils'
import useMenu from '@/hooks/common/useMenu'
import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController'
import { useAxios } from '@/hooks/useAxios'
import { canvasSettingState, canvasState, canvasZoomState, currentMenuState, verticalHorizontalModeState } from '@/store/canvasAtom'
import { canvasSettingState, canvasState, canvasZoomState, currentMenuState, verticalHorizontalModeState, currentCanvasPlanState } from '@/store/canvasAtom'
import { sessionStore } from '@/store/commonAtom'
import { outerLinePointsState } from '@/store/outerLineAtom'
import { appMessageStore, globalLocaleStore } from '@/store/localeAtom'
@ -52,6 +52,7 @@ import { useRoofFn } from '@/hooks/common/useRoofFn'
import { usePolygon } from '@/hooks/usePolygon'
import { useTrestle } from '@/hooks/module/useTrestle'
export default function CanvasMenu(props) {
const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
const { selectedMenu, setSelectedMenu } = props
const pathname = usePathname()
const router = useRouter()
@ -234,7 +235,7 @@ export default function CanvasMenu(props) {
router.push(`/floor-plan?pid=${pid}&objectNo=${objectNo}`)
setSelectedMenu('module')
}
await reloadCanvasStatus(objectNo, pid)
await reloadCanvasStatus(objectNo, currentCanvasPlan?.planNo ?? pid)
break
case 'estimate':
if (!isAllComplete()) {

View File

@ -18,7 +18,7 @@ export default function WallMerge({ offsetRef, radioTypeRef }) {
<div className="eaves-keraba-th">
<div className="d-check-radio pop">
<input type="radio" name="radio01" id="ra01" value="1" checked={type === '1'} onChange={(e) => onChange(e)} />
<label htmlFor="ra01">{getMessage('has.sleeve')}</label>
<label htmlFor="ra01">{getMessage('has.not.sleeve')}</label>
</div>
</div>
<div className="eaves-keraba-td">
@ -31,7 +31,7 @@ export default function WallMerge({ offsetRef, radioTypeRef }) {
<div className="eaves-keraba-th">
<div className="d-check-radio pop">
<input type="radio" name="radio01" id="ra02" value="2" checked={type === '2'} onChange={(e) => onChange(e)} />
<label htmlFor="ra02">{getMessage('has.not.sleeve')}</label>
<label htmlFor="ra02">{getMessage('has.sleeve')}</label>
</div>
</div>
<div className="eaves-keraba-td">

View File

@ -2726,16 +2726,26 @@ export const useTrestle = () => {
moduleRowResultData.touchedHalfSurfaceBracketCnt += 1
} else if (!halfBottomLeftModule && !findSamePointInBottom(exposedBottomModules, module, direction)) {
// 왼쪽 아래가 없고, 하단에 같은 점이 없는 경우는 touched는 1개, exposed는 2개
moduleRowResultData.exposedHalfBottomBracketCnt += 1
moduleRowResultData.touchedHalfSurfaceBracketCnt += 2
if (level % 2 === 0) {
moduleRowResultData.exposedHalfBottomBracketCnt += 1
moduleRowResultData.touchedHalfSurfaceBracketCnt += 2
} else {
moduleRowResultData.exposedHalfBottomBracketCnt += 2
moduleRowResultData.touchedHalfSurfaceBracketCnt += 1
}
} else if (!halfBottomRightModule && findSamePointInBottom(exposedBottomModules, module, direction)) {
// 오른쪽 아래가 없고, 하단에 같은 점이 있는 경우는 exposed는 2개, touched는 1개
moduleRowResultData.exposedHalfBottomBracketCnt += 1
moduleRowResultData.touchedHalfSurfaceBracketCnt += 2
} else if (!halfBottomRightModule && !findSamePointInBottom(exposedBottomModules, module, direction)) {
// 오른쪽 아래가 없고, 하단에 같은 점이 없는 경우는 exposed는 1개, touched는 2개
moduleRowResultData.exposedHalfBottomBracketCnt += 2
moduleRowResultData.touchedHalfSurfaceBracketCnt += 1
if (level % 2 === 0) {
moduleRowResultData.exposedHalfBottomBracketCnt += 2
moduleRowResultData.touchedHalfSurfaceBracketCnt += 1
} else {
moduleRowResultData.exposedHalfBottomBracketCnt += 1
moduleRowResultData.touchedHalfSurfaceBracketCnt += 2
}
}
}
}
@ -2774,6 +2784,20 @@ export const useTrestle = () => {
if (rackYn === 'N') {
if (rackQty !== 3) {
moduleRowResultData.exposedHalfTopBracketCnt += rackQty / 2
} else {
if (halfTopLeftModule) {
if (level % 2 === 0) {
moduleRowResultData.exposedHalfTopBracketCnt += 2
} else {
moduleRowResultData.exposedHalfTopBracketCnt += 1
}
} else if (halfTopRightModule) {
if (level % 2 === 0) {
moduleRowResultData.exposedHalfTopBracketCnt += 1
} else {
moduleRowResultData.exposedHalfTopBracketCnt += 2
}
}
}
}
} else if (!halfTopLeftModule && !halfTopRightModule) {

View File

@ -61,8 +61,7 @@ export function useEavesGableEdit(id) {
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
wallLines.forEach((wallLine) => {
const id = wallLine.id
wallLine.lines = outerLines.filter((line) => line.attributes?.wallId === id)
wallLine.lines = outerLines.filter((line) => line.attributes?.wallId === wallLine.id).sort((a, b) => a.idx - b.idx)
})
wallLines.forEach((wallLine) => {
convertPolygonToLines(wallLine)
@ -77,6 +76,41 @@ export function useEavesGableEdit(id) {
convertLinesToPolygon(wallLine)
})
initEvent()
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
outerLines.forEach((line) => {
let stroke, strokeWidth
if (line.attributes) {
if (line.attributes.type === LINE_TYPE.WALLLINE.EAVES || line.attributes.type === LINE_TYPE.WALLLINE.HIPANDGABLE) {
stroke = '#45CD7D'
strokeWidth = 4
} else if (line.attributes.type === LINE_TYPE.WALLLINE.GABLE || line.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) {
stroke = '#3FBAE6'
strokeWidth = 4
} else {
stroke = '#000000'
strokeWidth = 4
}
line.set({
visible: true,
stroke,
strokeWidth,
selectable: false,
})
line.bringToFront()
}
})
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
roofs.forEach((roof) => {
roof.innerLines.forEach((line) => {
line.set({ selectable: true })
line.bringToFront()
})
})
canvas.renderAll()
}
}, [])
@ -106,6 +140,7 @@ export function useEavesGableEdit(id) {
}
const mouseDownEvent = (e) => {
canvas.discardActiveObject()
if (!e.target || (e.target && e.target.name !== 'outerLine')) {
return
}

View File

@ -3,18 +3,16 @@ import { fabric } from 'fabric'
import { actionHandler, anchorWrapper, polygonPositionHandler } from '@/util/canvas-util'
import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { canvasSizeState, canvasState, canvasZoomState, fontSizeState } from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine'
import { QPolygon } from '@/components/fabric/QPolygon'
import { defineQLine } from '@/util/qline-utils'
import { defineQPloygon } from '@/util/qpolygon-utils'
import { defineQPolygon } from '@/util/qpolygon-utils'
import { writeImage } from '@/lib/canvas'
import { useCanvasEvent } from '@/hooks/useCanvasEvent'
import { useAxios } from '@/hooks/useAxios'
import { useFont } from '@/hooks/common/useFont'
import { OBJECT_PROTOTYPE, POLYGON_TYPE, RELOAD_TYPE_PROTOTYPE, SAVE_KEY } from '@/common/common'
import { usePlan } from './usePlan'
import { OBJECT_PROTOTYPE, SAVE_KEY } from '@/common/common'
import { imageDisplaySelector } from '@/store/settingAtom'
export function useCanvas(id) {
@ -140,7 +138,7 @@ export function useCanvas(id) {
QPolygon.prototype.canvas = canvas
QLine.prototype.canvas = canvas
defineQLine()
defineQPloygon()
defineQPolygon()
}
/**
@ -376,6 +374,8 @@ export function useCanvas(id) {
/**
* 이미지로 저장하는 함수
* @param {string} title - 저장할 이미지 이름
* @param userId
* @param setThumbnails
*/
const saveImage = async (title = 'canvas', userId, setThumbnails) => {
removeMouseLines()

View File

@ -551,6 +551,30 @@ export function isPointOnLine({ x1, y1, x2, y2 }, { x, y }, epsilon = 2) {
return withinXRange && withinYRange
}
/**
* 라인위에 좌표가 존재하는지 확인한다. 함수가 끝포인트를 계산 못하는 경우가 발생하여 신규 추가.
* @param line - 라인 좌표
* @param point - 확인 좌표
* @param tolerance - 오차 허용 범위 (기본값 0.1)
* @returns {boolean}
*/
export function isPointOnLineNew({ x1, y1, x2, y2 }, { x, y }, tolerance = 0.1) {
// 1. 거리 계산을 통한 방법
const d1 = Math.sqrt(Math.pow(x - x1, 2) + Math.pow(y - y1, 2))
const d2 = Math.sqrt(Math.pow(x - x2, 2) + Math.pow(y - y2, 2))
const lineLength = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
// 점이 선분 위에 있다면, 두 끝점까지의 거리의 합이 선분의 길이와 같아야 함
const diff = Math.abs(d1 + d2 - lineLength)
// 2. 점이 선분의 범위 내에 있는지 확인
const isWithinBounds =
x >= Math.min(x1, x2) - tolerance && x <= Math.max(x1, x2) + tolerance && y >= Math.min(y1, y2) - tolerance && y <= Math.max(y1, y2) + tolerance
return diff <= tolerance && isWithinBounds
}
/**
* 점과 가까운 line 찾기
* @param point

File diff suppressed because it is too large Load Diff