Merge pull request 'feature/jaeyoung' (#46) from feature/jaeyoung into dev
Reviewed-on: #46
This commit is contained in:
commit
ec93257720
@ -208,6 +208,8 @@ export const SAVE_KEY = [
|
|||||||
'fontWeight',
|
'fontWeight',
|
||||||
'dormerAttributes',
|
'dormerAttributes',
|
||||||
'toFixed',
|
'toFixed',
|
||||||
|
'startPoint',
|
||||||
|
'endPoint',
|
||||||
'isSortedPoints',
|
'isSortedPoints',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { fabric } from 'fabric'
|
|||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPointLessEightPoint, sortedPoints } from '@/util/canvas-util'
|
import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPointLessEightPoint, sortedPoints } from '@/util/canvas-util'
|
||||||
import { calculateAngle, drawGabledRoof, drawRidgeRoof, drawShedRoof, toGeoJSON } from '@/util/qpolygon-utils'
|
import { calculateAngle, drawRidgeRoof, drawShedRoof, toGeoJSON } from '@/util/qpolygon-utils'
|
||||||
import * as turf from '@turf/turf'
|
import * as turf from '@turf/turf'
|
||||||
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
|
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
|
||||||
import Big from 'big.js'
|
import Big from 'big.js'
|
||||||
@ -29,12 +29,13 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
this.texts = []
|
this.texts = []
|
||||||
this.hips = []
|
this.hips = []
|
||||||
this.ridges = []
|
this.ridges = []
|
||||||
this.connectRidges = []
|
|
||||||
this.cells = []
|
this.cells = []
|
||||||
this.innerLines = []
|
this.innerLines = []
|
||||||
this.children = []
|
this.children = []
|
||||||
this.separatePolygon = []
|
this.separatePolygon = []
|
||||||
this.toFixed = options.toFixed ?? 1
|
this.toFixed = options.toFixed ?? 1
|
||||||
|
this.baseLines = []
|
||||||
|
// this.colorLines = []
|
||||||
|
|
||||||
// 소수점 전부 제거
|
// 소수점 전부 제거
|
||||||
points.forEach((point) => {
|
points.forEach((point) => {
|
||||||
@ -217,6 +218,12 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
* @param settingModalFirstOptions
|
* @param settingModalFirstOptions
|
||||||
*/
|
*/
|
||||||
drawHelpLine(settingModalFirstOptions) {
|
drawHelpLine(settingModalFirstOptions) {
|
||||||
|
/* innerLines 초기화 */
|
||||||
|
this.innerLines.forEach((line) => {
|
||||||
|
this.canvas.remove(line)
|
||||||
|
})
|
||||||
|
this.canvas.renderAll()
|
||||||
|
|
||||||
let textMode = 'plane'
|
let textMode = 'plane'
|
||||||
|
|
||||||
const dimensionDisplay = settingModalFirstOptions?.dimensionDisplay.find((opt) => opt.selected).id
|
const dimensionDisplay = settingModalFirstOptions?.dimensionDisplay.find((opt) => opt.selected).id
|
||||||
@ -246,12 +253,13 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
const hasShed = types.includes(LINE_TYPE.WALLLINE.SHED)
|
const hasShed = types.includes(LINE_TYPE.WALLLINE.SHED)
|
||||||
|
|
||||||
// A형, B형 박공 지붕
|
// A형, B형 박공 지붕
|
||||||
if (
|
/* if (
|
||||||
(gableOdd.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableEven.every((type) => gableType.includes(type))) ||
|
(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)))
|
(gableEven.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableOdd.every((type) => gableType.includes(type)))
|
||||||
) {
|
) {
|
||||||
drawGabledRoof(this.id, this.canvas, textMode)
|
drawGabledRoof(this.id, this.canvas, textMode)
|
||||||
} else if (hasShed) {
|
} else*/
|
||||||
|
if (hasShed) {
|
||||||
const sheds = this.lines.filter((line) => line.attributes !== undefined && line.attributes.type === LINE_TYPE.WALLLINE.SHED)
|
const sheds = this.lines.filter((line) => line.attributes !== undefined && line.attributes.type === LINE_TYPE.WALLLINE.SHED)
|
||||||
const areLinesParallel = function (line1, line2) {
|
const areLinesParallel = function (line1, line2) {
|
||||||
const angle1 = calculateAngle(line1.startPoint, line1.endPoint)
|
const angle1 = calculateAngle(line1.startPoint, line1.endPoint)
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import { usePlan } from '@/hooks/usePlan'
|
|||||||
import { useContextMenu } from '@/hooks/useContextMenu'
|
import { useContextMenu } from '@/hooks/useContextMenu'
|
||||||
import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize'
|
import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize'
|
||||||
import { currentMenuState } from '@/store/canvasAtom'
|
import { currentMenuState } from '@/store/canvasAtom'
|
||||||
import { totalDisplaySelector } from '@/store/settingAtom'
|
import { roofMaterialsAtom, totalDisplaySelector } from '@/store/settingAtom'
|
||||||
import { MENU, POLYGON_TYPE } from '@/common/common'
|
import { MENU, POLYGON_TYPE } from '@/common/common'
|
||||||
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
|
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
|
||||||
import { QcastContext } from '@/app/QcastProvider'
|
import { QcastContext } from '@/app/QcastProvider'
|
||||||
@ -30,10 +30,40 @@ import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
|
|||||||
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
|
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
|
||||||
import { useEvent } from '@/hooks/useEvent'
|
import { useEvent } from '@/hooks/useEvent'
|
||||||
import { compasDegAtom } from '@/store/orientationAtom'
|
import { compasDegAtom } from '@/store/orientationAtom'
|
||||||
|
import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting'
|
||||||
|
import { useMasterController } from '@/hooks/common/useMasterController'
|
||||||
import { hotkeyStore } from '@/store/hotkeyAtom'
|
import { hotkeyStore } from '@/store/hotkeyAtom'
|
||||||
import { usePopup } from '@/hooks/usePopup'
|
import { usePopup } from '@/hooks/usePopup'
|
||||||
|
|
||||||
export default function CanvasFrame() {
|
export default function CanvasFrame() {
|
||||||
|
const [roofMaterials, setRoofMaterials] = useRecoilState(roofMaterialsAtom)
|
||||||
|
const { getRoofMaterialList } = useMasterController()
|
||||||
|
useEffect(() => {
|
||||||
|
async function initRoofMaterial() {
|
||||||
|
if (roofMaterials.length !== 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { data } = await getRoofMaterialList()
|
||||||
|
|
||||||
|
const roofLists = data.map((item, idx) => ({
|
||||||
|
...item,
|
||||||
|
id: item.roofMatlCd,
|
||||||
|
name: item.roofMatlNm,
|
||||||
|
selected: idx === 0,
|
||||||
|
index: idx,
|
||||||
|
nameJp: item.roofMatlNmJp,
|
||||||
|
length: item.lenBase && parseInt(item.lenBase),
|
||||||
|
width: item.widBase && parseInt(item.widBase),
|
||||||
|
raft: item.raftBase && parseInt(item.raftBase),
|
||||||
|
layout: ['ROOF_ID_SLATE', 'ROOF_ID_SINGLE'].includes(item.roofMatlCd) ? ROOF_MATERIAL_LAYOUT.STAIRS : ROOF_MATERIAL_LAYOUT.PARALLEL,
|
||||||
|
hajebichi: item.roofPchBase && parseInt(item.roofPchBase),
|
||||||
|
pitch: item.pitch ? parseInt(item.pitch) : 4,
|
||||||
|
angle: item.angle ? parseInt(item.angle) : 21.8,
|
||||||
|
}))
|
||||||
|
setRoofMaterials(roofLists)
|
||||||
|
}
|
||||||
|
initRoofMaterial()
|
||||||
|
}, [])
|
||||||
const canvasRef = useRef(null)
|
const canvasRef = useRef(null)
|
||||||
const { canvas } = useCanvas('canvas')
|
const { canvas } = useCanvas('canvas')
|
||||||
const { canvasLoadInit, gridInit } = useCanvasConfigInitialize()
|
const { canvasLoadInit, gridInit } = useCanvasConfigInitialize()
|
||||||
|
|||||||
@ -15,13 +15,18 @@ export default function FlowLine({ FLOW_LINE_REF }) {
|
|||||||
const currentObject = useRecoilValue(currentObjectState)
|
const currentObject = useRecoilValue(currentObjectState)
|
||||||
const handleFocus = () => {
|
const handleFocus = () => {
|
||||||
if (currentObject === null) {
|
if (currentObject === null) {
|
||||||
|
FLOW_LINE_REF.POINTER_INPUT_REF.current.value = ''
|
||||||
FLOW_LINE_REF.FILLED_INPUT_REF.current.value = ''
|
FLOW_LINE_REF.FILLED_INPUT_REF.current.value = ''
|
||||||
FLOW_LINE_REF.FILLED_INPUT_REF.current.blur()
|
FLOW_LINE_REF.FILLED_INPUT_REF.current.blur()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleInput = (e) => {
|
const handleInput = (e) => {
|
||||||
const value = e.target.value.replace(/^0+/, '')
|
const regex = /^-?\d*$/
|
||||||
setFilledInput(value.replace(/[^0-9]/g, ''))
|
let value = e.target.value
|
||||||
|
if (!regex.test(value) && value !== '') return
|
||||||
|
if (value.startsWith('0') || value === '-0') return
|
||||||
|
|
||||||
|
setFilledInput(value.replace(/[^0-9-]/g, ''))
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -47,7 +52,7 @@ export default function FlowLine({ FLOW_LINE_REF }) {
|
|||||||
<div className="eaves-keraba-td">
|
<div className="eaves-keraba-td">
|
||||||
<div className="outline-form">
|
<div className="outline-form">
|
||||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||||
{/*<input type="text" className="input-origin block" readOnly={true} ref={FLOW_LINE_REF.POINTER_INPUT_REF} />*/}
|
{<input type="text" className="input-origin block" readOnly={true} ref={FLOW_LINE_REF.POINTER_INPUT_REF} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -15,6 +15,7 @@ export default function Updown({ UP_DOWN_REF }) {
|
|||||||
const currentObject = useRecoilValue(currentObjectState)
|
const currentObject = useRecoilValue(currentObjectState)
|
||||||
const handleFocus = () => {
|
const handleFocus = () => {
|
||||||
if (currentObject === null) {
|
if (currentObject === null) {
|
||||||
|
UP_DOWN_REF.POINTER_INPUT_REF.current.value = ''
|
||||||
UP_DOWN_REF.FILLED_INPUT_REF.current.value = ''
|
UP_DOWN_REF.FILLED_INPUT_REF.current.value = ''
|
||||||
UP_DOWN_REF.FILLED_INPUT_REF.current.blur()
|
UP_DOWN_REF.FILLED_INPUT_REF.current.blur()
|
||||||
}
|
}
|
||||||
@ -48,7 +49,7 @@ export default function Updown({ UP_DOWN_REF }) {
|
|||||||
<div className="eaves-keraba-td">
|
<div className="eaves-keraba-td">
|
||||||
<div className="outline-form">
|
<div className="outline-form">
|
||||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||||
{/*<input type="text" className="input-origin block" readOnly={true} ref={UP_DOWN_REF.UP_INPUT_REF} />*/}
|
{<input type="text" className="input-origin block" readOnly={true} ref={UP_DOWN_REF.POINTER_INPUT_REF} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -74,7 +74,7 @@ export default function Offset({ length1Ref, arrow1Ref, currentWallLineRef }) {
|
|||||||
<div className="eaves-keraba-td">
|
<div className="eaves-keraba-td">
|
||||||
<div className="outline-form">
|
<div className="outline-form">
|
||||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||||
<input type="text" className="input-origin block" defaultValue={0} ref={length1Ref} />
|
<input type="text" className="input-origin block" placeholder={0} ref={length1Ref} />
|
||||||
</div>
|
</div>
|
||||||
<span className="thin">mm</span>
|
<span className="thin">mm</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -46,7 +46,7 @@ export default forwardRef(function WallLine({ length1Ref, length2Ref, arrow1Ref,
|
|||||||
<div className="eaves-keraba-td">
|
<div className="eaves-keraba-td">
|
||||||
<div className="outline-form">
|
<div className="outline-form">
|
||||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||||
<input type="text" className="input-origin block" defaultValue={0} readOnly={type !== 1} ref={length1Ref} />
|
<input type="text" className="input-origin block" placeholder={0} readOnly={type !== 1} ref={length1Ref} />
|
||||||
</div>
|
</div>
|
||||||
<span className="thin">mm</span>
|
<span className="thin">mm</span>
|
||||||
</div>
|
</div>
|
||||||
@ -80,7 +80,7 @@ export default forwardRef(function WallLine({ length1Ref, length2Ref, arrow1Ref,
|
|||||||
<div className="eaves-keraba-td">
|
<div className="eaves-keraba-td">
|
||||||
<div className="outline-form">
|
<div className="outline-form">
|
||||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||||
<input type="text" className="input-origin block" defaultValue={0} readOnly={type !== 2} ref={length2Ref} />
|
<input type="text" className="input-origin block" placeholder={0} readOnly={type !== 2} ref={length2Ref} />
|
||||||
</div>
|
</div>
|
||||||
<span className="thin">mm</span>
|
<span className="thin">mm</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { globalFontAtom } from '@/store/fontAtom'
|
|||||||
import { useRoof } from '@/hooks/common/useRoof'
|
import { useRoof } from '@/hooks/common/useRoof'
|
||||||
import { usePolygon } from '@/hooks/usePolygon'
|
import { usePolygon } from '@/hooks/usePolygon'
|
||||||
import { useRoofFn } from '@/hooks/common/useRoofFn'
|
import { useRoofFn } from '@/hooks/common/useRoofFn'
|
||||||
import { POLYGON_TYPE } from '@/common/common'
|
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
|
||||||
|
|
||||||
export function useCanvasConfigInitialize() {
|
export function useCanvasConfigInitialize() {
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
@ -64,6 +64,7 @@ export function useCanvasConfigInitialize() {
|
|||||||
groupDimensionInit()
|
groupDimensionInit()
|
||||||
reGroupInit() //그룹 객체 재그룹
|
reGroupInit() //그룹 객체 재그룹
|
||||||
moduleInit()
|
moduleInit()
|
||||||
|
innerLinesInit() // innerLines 세팅 추가
|
||||||
}
|
}
|
||||||
|
|
||||||
const gridInit = () => {
|
const gridInit = () => {
|
||||||
@ -228,5 +229,23 @@ export function useCanvasConfigInitialize() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const innerLinesInit = () => {
|
||||||
|
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
|
// innerLine이 세팅이 안되어있는경우 찾아서 세팅한다.
|
||||||
|
let innerLineTypes = Object.keys(LINE_TYPE.SUBLINE).map((key, value) => LINE_TYPE.SUBLINE[key])
|
||||||
|
|
||||||
|
roofs.forEach((roof) => {
|
||||||
|
roof.innerLines = canvas
|
||||||
|
.getObjects()
|
||||||
|
.filter(
|
||||||
|
(obj) =>
|
||||||
|
obj.type === 'QLine' &&
|
||||||
|
obj.attributes?.type !== 'pitchSizeLine' &&
|
||||||
|
obj.attributes?.roofId === roof.id &&
|
||||||
|
innerLineTypes.includes(obj.name),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return { canvasLoadInit, gridInit }
|
return { canvasLoadInit, gridInit }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,102 +23,65 @@ export function useRoofFn() {
|
|||||||
|
|
||||||
//면형상 선택 클릭시 지붕 패턴 입히기
|
//면형상 선택 클릭시 지붕 패턴 입히기
|
||||||
function setSurfaceShapePattern(polygon, mode = 'onlyBorder', trestleMode = false, roofMaterial, isForceChange = false, isDisplay = false) {
|
function setSurfaceShapePattern(polygon, mode = 'onlyBorder', trestleMode = false, roofMaterial, isForceChange = false, isDisplay = false) {
|
||||||
if (!polygon) {
|
try {
|
||||||
return
|
if (!polygon) {
|
||||||
}
|
return
|
||||||
if (polygon.points.length < 3) {
|
}
|
||||||
return
|
if (polygon.points.length < 3) {
|
||||||
}
|
return
|
||||||
if (isForceChange && !isDisplay) {
|
}
|
||||||
/*if (polygon.roofMaterial) {
|
if (isForceChange && !isDisplay) {
|
||||||
|
/*if (polygon.roofMaterial) {
|
||||||
polygon.roofMaterial = null
|
polygon.roofMaterial = null
|
||||||
}*/
|
}*/
|
||||||
}
|
|
||||||
if (!roofMaterial) {
|
|
||||||
roofMaterial = polygon.roofMaterial ?? selectedRoofMaterial
|
|
||||||
}
|
|
||||||
|
|
||||||
const ratio = window.devicePixelRatio || 1
|
|
||||||
const layout = roofMaterial.layout
|
|
||||||
|
|
||||||
let width = (roofMaterial.width || 226) / 10
|
|
||||||
let height = (roofMaterial.length || 158) / 10
|
|
||||||
const index = roofMaterial.index ?? 0
|
|
||||||
let roofStyle = 2
|
|
||||||
const inputPatternSize = { width: width, height: height } //임시 사이즈
|
|
||||||
const patternSize = { ...inputPatternSize } // 입력된 값을 뒤집기 위해
|
|
||||||
|
|
||||||
if (polygon.direction === 'east' || polygon.direction === 'west') {
|
|
||||||
//세로형이면 width height를 바꿈
|
|
||||||
;[patternSize.width, patternSize.height] = [inputPatternSize.height, patternSize.width]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 패턴 소스를 위한 임시 캔버스 생성
|
|
||||||
const patternSourceCanvas = document.createElement('canvas')
|
|
||||||
patternSourceCanvas.width = polygon.width * ratio
|
|
||||||
patternSourceCanvas.height = polygon.height * ratio
|
|
||||||
const ctx = patternSourceCanvas.getContext('2d')
|
|
||||||
let offset = roofStyle === 1 ? 0 : patternSize.width / 2
|
|
||||||
|
|
||||||
const rows = Math.floor(patternSourceCanvas.height / patternSize.height)
|
|
||||||
const cols = Math.floor(patternSourceCanvas.width / patternSize.width)
|
|
||||||
|
|
||||||
ctx.strokeStyle = mode === 'allPainted' ? 'black' : ROOF_COLOR[index]
|
|
||||||
ctx.lineWidth = 2
|
|
||||||
ctx.fillStyle = mode === 'allPainted' ? 'rgba(0, 159, 64, 0.7)' : 'white'
|
|
||||||
|
|
||||||
if (trestleMode) {
|
|
||||||
ctx.strokeStyle = 'black'
|
|
||||||
ctx.lineWidth = 0.2
|
|
||||||
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'
|
|
||||||
} else {
|
|
||||||
ctx.fillStyle = 'rgba(255, 255, 255, 1)'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (polygon.direction === 'east' || polygon.direction === 'west') {
|
|
||||||
offset = roofStyle === 1 ? 0 : patternSize.height / 2
|
|
||||||
for (let col = 0; col <= cols; col++) {
|
|
||||||
const x = col * patternSize.width
|
|
||||||
const yStart = 0
|
|
||||||
const yEnd = patternSourceCanvas.height
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.moveTo(x, yStart) // 선 시작점
|
|
||||||
ctx.lineTo(x, yEnd) // 선 끝점
|
|
||||||
ctx.stroke()
|
|
||||||
if (mode === 'allPainted' || trestleMode) {
|
|
||||||
ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let row = 0; row <= rows; row++) {
|
|
||||||
const y = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? row * patternSize.height + (col % 2 === 0 ? 0 : offset) : row * patternSize.height
|
|
||||||
const xStart = col * patternSize.width
|
|
||||||
const xEnd = xStart + patternSize.width
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.moveTo(xStart, y) // 선 시작점
|
|
||||||
ctx.lineTo(xEnd, y) // 선 끝점
|
|
||||||
ctx.stroke()
|
|
||||||
if (mode === 'allPainted' || trestleMode) {
|
|
||||||
ctx.fillRect(xStart, y, xEnd - xStart, patternSize.height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
if (!roofMaterial) {
|
||||||
for (let row = 0; row <= rows; row++) {
|
roofMaterial = polygon.roofMaterial ?? selectedRoofMaterial
|
||||||
const y = row * patternSize.height
|
}
|
||||||
|
|
||||||
ctx.beginPath()
|
const ratio = window.devicePixelRatio || 1
|
||||||
ctx.moveTo(0, y) // 선 시작점
|
const layout = roofMaterial.layout
|
||||||
ctx.lineTo(patternSourceCanvas.width, y) // 선 끝점
|
|
||||||
ctx.stroke()
|
|
||||||
if (mode === 'allPainted' || trestleMode) {
|
|
||||||
ctx.fillRect(0, y, patternSourceCanvas.width, patternSize.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let width = (roofMaterial.width || 226) / 10
|
||||||
|
let height = (roofMaterial.length || 158) / 10
|
||||||
|
const index = roofMaterial.index ?? 0
|
||||||
|
let roofStyle = 2
|
||||||
|
const inputPatternSize = { width: width, height: height } //임시 사이즈
|
||||||
|
const patternSize = { ...inputPatternSize } // 입력된 값을 뒤집기 위해
|
||||||
|
|
||||||
|
if (polygon.direction === 'east' || polygon.direction === 'west') {
|
||||||
|
//세로형이면 width height를 바꿈
|
||||||
|
;[patternSize.width, patternSize.height] = [inputPatternSize.height, patternSize.width]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 패턴 소스를 위한 임시 캔버스 생성
|
||||||
|
const patternSourceCanvas = document.createElement('canvas')
|
||||||
|
patternSourceCanvas.width = polygon.width * ratio
|
||||||
|
patternSourceCanvas.height = polygon.height * ratio
|
||||||
|
const ctx = patternSourceCanvas.getContext('2d')
|
||||||
|
let offset = roofStyle === 1 ? 0 : patternSize.width / 2
|
||||||
|
|
||||||
|
const rows = Math.floor(patternSourceCanvas.height / patternSize.height)
|
||||||
|
const cols = Math.floor(patternSourceCanvas.width / patternSize.width)
|
||||||
|
|
||||||
|
ctx.strokeStyle = mode === 'allPainted' ? 'black' : ROOF_COLOR[index]
|
||||||
|
ctx.lineWidth = 2
|
||||||
|
ctx.fillStyle = mode === 'allPainted' ? 'rgba(0, 159, 64, 0.7)' : 'white'
|
||||||
|
|
||||||
|
if (trestleMode) {
|
||||||
|
ctx.strokeStyle = 'black'
|
||||||
|
ctx.lineWidth = 0.2
|
||||||
|
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'
|
||||||
|
} else {
|
||||||
|
ctx.fillStyle = 'rgba(255, 255, 255, 1)'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (polygon.direction === 'east' || polygon.direction === 'west') {
|
||||||
|
offset = roofStyle === 1 ? 0 : patternSize.height / 2
|
||||||
for (let col = 0; col <= cols; col++) {
|
for (let col = 0; col <= cols; col++) {
|
||||||
const x = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? col * patternSize.width + (row % 2 === 0 ? 0 : offset) : col * patternSize.width
|
const x = col * patternSize.width
|
||||||
const yStart = row * patternSize.height
|
const yStart = 0
|
||||||
const yEnd = yStart + patternSize.height
|
const yEnd = patternSourceCanvas.height
|
||||||
|
|
||||||
ctx.beginPath()
|
ctx.beginPath()
|
||||||
ctx.moveTo(x, yStart) // 선 시작점
|
ctx.moveTo(x, yStart) // 선 시작점
|
||||||
ctx.lineTo(x, yEnd) // 선 끝점
|
ctx.lineTo(x, yEnd) // 선 끝점
|
||||||
@ -126,49 +89,90 @@ export function useRoofFn() {
|
|||||||
if (mode === 'allPainted' || trestleMode) {
|
if (mode === 'allPainted' || trestleMode) {
|
||||||
ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart)
|
ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let row = 0; row <= rows; row++) {
|
||||||
|
const y = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? row * patternSize.height + (col % 2 === 0 ? 0 : offset) : row * patternSize.height
|
||||||
|
const xStart = col * patternSize.width
|
||||||
|
const xEnd = xStart + patternSize.width
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(xStart, y) // 선 시작점
|
||||||
|
ctx.lineTo(xEnd, y) // 선 끝점
|
||||||
|
ctx.stroke()
|
||||||
|
if (mode === 'allPainted' || trestleMode) {
|
||||||
|
ctx.fillRect(xStart, y, xEnd - xStart, patternSize.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let row = 0; row <= rows; row++) {
|
||||||
|
const y = row * patternSize.height
|
||||||
|
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(0, y) // 선 시작점
|
||||||
|
ctx.lineTo(patternSourceCanvas.width, y) // 선 끝점
|
||||||
|
ctx.stroke()
|
||||||
|
if (mode === 'allPainted' || trestleMode) {
|
||||||
|
ctx.fillRect(0, y, patternSourceCanvas.width, patternSize.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let col = 0; col <= cols; col++) {
|
||||||
|
const x = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? col * patternSize.width + (row % 2 === 0 ? 0 : offset) : col * patternSize.width
|
||||||
|
const yStart = row * patternSize.height
|
||||||
|
const yEnd = yStart + patternSize.height
|
||||||
|
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(x, yStart) // 선 시작점
|
||||||
|
ctx.lineTo(x, yEnd) // 선 끝점
|
||||||
|
ctx.stroke()
|
||||||
|
if (mode === 'allPainted' || trestleMode) {
|
||||||
|
ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const hachingPatternSourceCanvas = document.createElement('canvas')
|
const hachingPatternSourceCanvas = document.createElement('canvas')
|
||||||
|
|
||||||
if (mode === 'lineHatch') {
|
if (mode === 'lineHatch') {
|
||||||
hachingPatternSourceCanvas.width = polygon.width * ratio
|
hachingPatternSourceCanvas.width = polygon.width * ratio
|
||||||
hachingPatternSourceCanvas.height = polygon.height * ratio
|
hachingPatternSourceCanvas.height = polygon.height * ratio
|
||||||
|
|
||||||
const ctx1 = hachingPatternSourceCanvas.getContext('2d')
|
const ctx1 = hachingPatternSourceCanvas.getContext('2d')
|
||||||
|
|
||||||
const gap = 10
|
const gap = 10
|
||||||
|
|
||||||
ctx1.strokeStyle = 'green' // 선 색상
|
ctx1.strokeStyle = 'green' // 선 색상
|
||||||
ctx1.lineWidth = 0.3 // 선 두께
|
ctx1.lineWidth = 0.3 // 선 두께
|
||||||
|
|
||||||
for (let x = 0; x < hachingPatternSourceCanvas.width + hachingPatternSourceCanvas.height; x += gap) {
|
for (let x = 0; x < hachingPatternSourceCanvas.width + hachingPatternSourceCanvas.height; x += gap) {
|
||||||
ctx1.beginPath()
|
ctx1.beginPath()
|
||||||
ctx1.moveTo(x, 0) // 선 시작점
|
ctx1.moveTo(x, 0) // 선 시작점
|
||||||
ctx1.lineTo(0, x) // 선 끝점
|
ctx1.lineTo(0, x) // 선 끝점
|
||||||
ctx1.stroke()
|
ctx1.stroke()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const combinedPatternCanvas = document.createElement('canvas')
|
||||||
|
combinedPatternCanvas.width = polygon.width * ratio
|
||||||
|
combinedPatternCanvas.height = polygon.height * ratio
|
||||||
|
const combinedCtx = combinedPatternCanvas.getContext('2d')
|
||||||
|
// 첫 번째 패턴을 그린 후 두 번째 패턴을 덧입힘
|
||||||
|
combinedCtx.drawImage(patternSourceCanvas, 0, 0)
|
||||||
|
combinedCtx.drawImage(hachingPatternSourceCanvas, 0, 0)
|
||||||
|
|
||||||
|
// 패턴 생성
|
||||||
|
const pattern = new fabric.Pattern({
|
||||||
|
source: combinedPatternCanvas,
|
||||||
|
repeat: 'repeat',
|
||||||
|
})
|
||||||
|
|
||||||
|
polygon.set('fill', null)
|
||||||
|
polygon.set('fill', pattern)
|
||||||
|
polygon.roofMaterial = roofMaterial
|
||||||
|
polygon.canvas?.renderAll()
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
const combinedPatternCanvas = document.createElement('canvas')
|
|
||||||
combinedPatternCanvas.width = polygon.width * ratio
|
|
||||||
combinedPatternCanvas.height = polygon.height * ratio
|
|
||||||
const combinedCtx = combinedPatternCanvas.getContext('2d')
|
|
||||||
// 첫 번째 패턴을 그린 후 두 번째 패턴을 덧입힘
|
|
||||||
combinedCtx.drawImage(patternSourceCanvas, 0, 0)
|
|
||||||
combinedCtx.drawImage(hachingPatternSourceCanvas, 0, 0)
|
|
||||||
|
|
||||||
// 패턴 생성
|
|
||||||
const pattern = new fabric.Pattern({
|
|
||||||
source: combinedPatternCanvas,
|
|
||||||
repeat: 'repeat',
|
|
||||||
})
|
|
||||||
|
|
||||||
polygon.set('fill', null)
|
|
||||||
polygon.set('fill', pattern)
|
|
||||||
polygon.roofMaterial = roofMaterial
|
|
||||||
polygon.canvas?.renderAll()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeRoofMaterial(roof = currentObject) {
|
function removeRoofMaterial(roof = currentObject) {
|
||||||
|
|||||||
@ -149,7 +149,7 @@ export function useCanvasSetting(executeEffect = true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 초 1회만 실행하도록 처리 */
|
/** 초 1회만 실행하도록 처리 */
|
||||||
addRoofMaterials()
|
//addRoofMaterials()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -675,7 +675,7 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
|
|||||||
const distance1 = distanceBetweenPoints({ x: line1.x1, y: line1.y1 }, interSectionPointsWithRoofLines[0])
|
const distance1 = distanceBetweenPoints({ x: line1.x1, y: line1.y1 }, interSectionPointsWithRoofLines[0])
|
||||||
const distance2 = distanceBetweenPoints({ x: line1.x2, y: line1.y2 }, interSectionPointsWithRoofLines[0])
|
const distance2 = distanceBetweenPoints({ x: line1.x2, y: line1.y2 }, interSectionPointsWithRoofLines[0])
|
||||||
|
|
||||||
if (!(distance1 === 0 || distance2 === 0)) {
|
if (!(distance1 < 1 || distance2 < 1)) {
|
||||||
if (distance1 >= distance2) {
|
if (distance1 >= distance2) {
|
||||||
const newLine = addLine([line1.x1, line1.y1, interSectionPointsWithRoofLines[0].x, interSectionPointsWithRoofLines[0].y], {
|
const newLine = addLine([line1.x1, line1.y1, interSectionPointsWithRoofLines[0].x, interSectionPointsWithRoofLines[0].y], {
|
||||||
stroke: 'black',
|
stroke: 'black',
|
||||||
@ -704,6 +704,7 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
|
|||||||
removeLine(line1)
|
removeLine(line1)
|
||||||
}
|
}
|
||||||
intersectionPoints.current.push(interSectionPointsWithRoofLines[0])
|
intersectionPoints.current.push(interSectionPointsWithRoofLines[0])
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -722,7 +723,7 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
|
|||||||
const distance1 = distanceBetweenPoints({ x: line1.x1, y: line1.y1 }, intersectionPoint)
|
const distance1 = distanceBetweenPoints({ x: line1.x1, y: line1.y1 }, intersectionPoint)
|
||||||
const distance2 = distanceBetweenPoints({ x: line1.x2, y: line1.y2 }, intersectionPoint)
|
const distance2 = distanceBetweenPoints({ x: line1.x2, y: line1.y2 }, intersectionPoint)
|
||||||
|
|
||||||
if (distance1 === 0 || distance2 === 0) {
|
if (distance1 < 1 || distance2 < 1) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//historyLine에서 기존 line을 제거한다.
|
//historyLine에서 기존 line을 제거한다.
|
||||||
@ -849,8 +850,14 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
|
|||||||
if (
|
if (
|
||||||
lineHistory.current.some(
|
lineHistory.current.some(
|
||||||
(history) =>
|
(history) =>
|
||||||
JSON.stringify(history.startPoint) === JSON.stringify(line.startPoint) &&
|
(Math.abs(history.startPoint.x - line.startPoint.x) < 2 &&
|
||||||
JSON.stringify(history.endPoint) === JSON.stringify(line.endPoint),
|
Math.abs(history.startPoint.y - line.startPoint.y) < 2 &&
|
||||||
|
Math.abs(history.endPoint.x - line.endPoint.x) < 2 &&
|
||||||
|
Math.abs(history.endPoint.y - line.endPoint.y) < 2) ||
|
||||||
|
(Math.abs(history.startPoint.x - line.endPoint.x) < 2 &&
|
||||||
|
Math.abs(history.startPoint.y - line.endPoint.y) < 2 &&
|
||||||
|
Math.abs(history.endPoint.x - line.startPoint.x) < 2 &&
|
||||||
|
Math.abs(history.endPoint.y - line.startPoint.y) < 2),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
canvas.remove(line)
|
canvas.remove(line)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -148,7 +148,6 @@ export function useOuterLineWall(id, propertiesId) {
|
|||||||
const mouseDown = (e) => {
|
const mouseDown = (e) => {
|
||||||
let pointer = getIntersectMousePoint(e)
|
let pointer = getIntersectMousePoint(e)
|
||||||
pointer = { x: Big(pointer.x).round(1).toNumber(), y: Big(pointer.y).round(1).toNumber() }
|
pointer = { x: Big(pointer.x).round(1).toNumber(), y: Big(pointer.y).round(1).toNumber() }
|
||||||
console.log('mouseDown', pointer, points)
|
|
||||||
|
|
||||||
if (points.length === 0) {
|
if (points.length === 0) {
|
||||||
setPoints((prev) => [...prev, pointer])
|
setPoints((prev) => [...prev, pointer])
|
||||||
@ -156,14 +155,11 @@ export function useOuterLineWall(id, propertiesId) {
|
|||||||
const lastPoint = points[points.length - 1]
|
const lastPoint = points[points.length - 1]
|
||||||
let newPoint = { x: pointer.x, y: pointer.y }
|
let newPoint = { x: pointer.x, y: pointer.y }
|
||||||
const length = distanceBetweenPoints(lastPoint, newPoint)
|
const length = distanceBetweenPoints(lastPoint, newPoint)
|
||||||
console.log('length', length)
|
|
||||||
if (verticalHorizontalMode) {
|
if (verticalHorizontalMode) {
|
||||||
const vector = {
|
const vector = {
|
||||||
x: Big(pointer.x).minus(Big(points[points.length - 1].x)),
|
x: Big(pointer.x).minus(Big(points[points.length - 1].x)),
|
||||||
y: Big(pointer.y).minus(Big(points[points.length - 1].y)),
|
y: Big(pointer.y).minus(Big(points[points.length - 1].y)),
|
||||||
}
|
}
|
||||||
// const slope = Math.abs(vector.y / vector.x) // 기울기 계산
|
|
||||||
console.log('vector', vector.x.toNumber(), vector.y.toNumber(), Math.abs(vector.y.toNumber() / vector.x.toNumber()) >= 1)
|
|
||||||
const slope = vector.x.eq(0) ? Big(1) : vector.y.div(vector.x).abs() // 기울기 계산
|
const slope = vector.x.eq(0) ? Big(1) : vector.y.div(vector.x).abs() // 기울기 계산
|
||||||
|
|
||||||
let scaledVector
|
let scaledVector
|
||||||
@ -172,13 +168,11 @@ export function useOuterLineWall(id, propertiesId) {
|
|||||||
// 기울기가 1 이상이면 x축 방향으로 그림
|
// 기울기가 1 이상이면 x축 방향으로 그림
|
||||||
scaledVector = {
|
scaledVector = {
|
||||||
x: 0,
|
x: 0,
|
||||||
// y: vector.y >= 0 ? Number(length) : -Number(length),
|
|
||||||
y: vector.y.gte(0) ? Big(length).toNumber() : Big(length).neg().toNumber(),
|
y: vector.y.gte(0) ? Big(length).toNumber() : Big(length).neg().toNumber(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 기울기가 1 미만이면 y축 방향으로 그림
|
// 기울기가 1 미만이면 y축 방향으로 그림
|
||||||
scaledVector = {
|
scaledVector = {
|
||||||
// x: vector.x >= 0 ? Number(length) : -Number(length),
|
|
||||||
x: vector.x.gte(0) ? Big(length).toNumber() : Big(length).neg().toNumber(),
|
x: vector.x.gte(0) ? Big(length).toNumber() : Big(length).neg().toNumber(),
|
||||||
y: 0,
|
y: 0,
|
||||||
}
|
}
|
||||||
@ -187,8 +181,6 @@ export function useOuterLineWall(id, propertiesId) {
|
|||||||
const verticalLength = scaledVector.y
|
const verticalLength = scaledVector.y
|
||||||
const horizontalLength = scaledVector.x
|
const horizontalLength = scaledVector.x
|
||||||
|
|
||||||
console.log('verticalLength', verticalLength, 'horizontalLength', horizontalLength)
|
|
||||||
|
|
||||||
newPoint = {
|
newPoint = {
|
||||||
x: Big(lastPoint.x).plus(horizontalLength).toNumber(),
|
x: Big(lastPoint.x).plus(horizontalLength).toNumber(),
|
||||||
y: Big(lastPoint.y).plus(verticalLength).toNumber(),
|
y: Big(lastPoint.y).plus(verticalLength).toNumber(),
|
||||||
@ -885,8 +877,6 @@ export function useOuterLineWall(id, propertiesId) {
|
|||||||
|
|
||||||
const firstPoint = points[0]
|
const firstPoint = points[0]
|
||||||
|
|
||||||
console.log('points 좌표 : ', points)
|
|
||||||
|
|
||||||
points.forEach((point, idx) => {
|
points.forEach((point, idx) => {
|
||||||
if (idx === 0 || !isAllRightAngle) {
|
if (idx === 0 || !isAllRightAngle) {
|
||||||
return
|
return
|
||||||
|
|||||||
@ -214,7 +214,6 @@ export function useRoofAllocationSetting(id) {
|
|||||||
await post({ url: `/api/canvas-management/roof-allocation-settings`, data: patternData }).then((res) => {
|
await post({ url: `/api/canvas-management/roof-allocation-settings`, data: patternData }).then((res) => {
|
||||||
swalFire({ text: getMessage(res.returnMessage) })
|
swalFire({ text: getMessage(res.returnMessage) })
|
||||||
setIsGlobalLoading(false)
|
setIsGlobalLoading(false)
|
||||||
saveCanvas(false)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
//Recoil 설정
|
//Recoil 설정
|
||||||
@ -357,7 +356,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
roofBases.forEach((roof) => {
|
roofBases.forEach((roof) => {
|
||||||
if (roof.separatePolygon.length === 0) {
|
if (roof.separatePolygon.length === 0) {
|
||||||
roof.innerLines.forEach((line) => {
|
roof.innerLines.forEach((line) => {
|
||||||
if (!line.attributes.actualSize || line.attributes?.actualSize === 0) {
|
if ((!line.attributes.actualSize || line.attributes?.actualSize === 0) && line.length > 1) {
|
||||||
line.set({ strokeWidth: 4, stroke: 'black', selectable: true })
|
line.set({ strokeWidth: 4, stroke: 'black', selectable: true })
|
||||||
result = true
|
result = true
|
||||||
}
|
}
|
||||||
@ -384,6 +383,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
|
canvas.discardActiveObject()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,7 +429,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
setRoofMaterials(newRoofList)
|
setRoofMaterials(newRoofList)
|
||||||
setRoofsStore(newRoofList)
|
setRoofsStore(newRoofList)
|
||||||
/** 외곽선 삭제 */
|
/** 외곽선 삭제 */
|
||||||
const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'outerLinePoint' || obj.name === 'outerLine')
|
const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'outerLinePoint' || obj.name === 'outerLine' || obj.name === 'pitchText')
|
||||||
removeTargets.forEach((obj) => {
|
removeTargets.forEach((obj) => {
|
||||||
canvas.remove(obj)
|
canvas.remove(obj)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -79,13 +79,6 @@ export function useRoofShapeSetting(id) {
|
|||||||
}, [jerkinHeadPitch])
|
}, [jerkinHeadPitch])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
|
||||||
// if (!outerLineFix || outerLines.length === 0) {
|
|
||||||
// swalFire({ text: '외벽선이 없습니다.' })
|
|
||||||
// // setShowRoofShapeSettingModal(false)
|
|
||||||
// closePopup(id)
|
|
||||||
// }
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (!isFixRef.current) {
|
if (!isFixRef.current) {
|
||||||
return
|
return
|
||||||
@ -93,6 +86,7 @@ export function useRoofShapeSetting(id) {
|
|||||||
|
|
||||||
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||||
const pitchTexts = canvas.getObjects().filter((obj) => obj.name === 'pitchText')
|
const pitchTexts = canvas.getObjects().filter((obj) => obj.name === 'pitchText')
|
||||||
|
|
||||||
canvas.remove(...pitchTexts)
|
canvas.remove(...pitchTexts)
|
||||||
outerLines.forEach((line) => {
|
outerLines.forEach((line) => {
|
||||||
let stroke, strokeWidth
|
let stroke, strokeWidth
|
||||||
@ -114,6 +108,7 @@ export function useRoofShapeSetting(id) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
addPitchText(line)
|
addPitchText(line)
|
||||||
|
line.bringToFront()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
canvas.renderAll()
|
canvas.renderAll()
|
||||||
@ -131,14 +126,6 @@ export function useRoofShapeSetting(id) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/*const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
|
||||||
outerLines.forEach((line) => {
|
|
||||||
line.set({
|
|
||||||
stroke: '#000000',
|
|
||||||
strokeWidth: 4,
|
|
||||||
})
|
|
||||||
})*/
|
|
||||||
|
|
||||||
currentObject.set({
|
currentObject.set({
|
||||||
stroke: '#EA10AC',
|
stroke: '#EA10AC',
|
||||||
strokeWidth: 4,
|
strokeWidth: 4,
|
||||||
|
|||||||
@ -6,6 +6,8 @@ import { useEvent } from '@/hooks/useEvent'
|
|||||||
import { useLine } from '@/hooks/useLine'
|
import { useLine } from '@/hooks/useLine'
|
||||||
import { useSwal } from '@/hooks/useSwal'
|
import { useSwal } from '@/hooks/useSwal'
|
||||||
import { usePopup } from '@/hooks/usePopup'
|
import { usePopup } from '@/hooks/usePopup'
|
||||||
|
import Big from 'big.js'
|
||||||
|
import { outerLineFixState } from '@/store/outerLineAtom'
|
||||||
|
|
||||||
// 외벽선 편집 및 오프셋
|
// 외벽선 편집 및 오프셋
|
||||||
export function useWallLineOffsetSetting(id) {
|
export function useWallLineOffsetSetting(id) {
|
||||||
@ -28,6 +30,8 @@ export function useWallLineOffsetSetting(id) {
|
|||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
|
||||||
|
const outerLineFix = useRecoilValue(outerLineFixState)
|
||||||
|
|
||||||
const drawLine = (point1, point2, idx, direction = currentWallLineRef.current.direction) => {
|
const drawLine = (point1, point2, idx, direction = currentWallLineRef.current.direction) => {
|
||||||
const line = addLine([point1.x, point1.y, point2.x, point2.y], {
|
const line = addLine([point1.x, point1.y, point2.x, point2.y], {
|
||||||
stroke: 'black',
|
stroke: 'black',
|
||||||
@ -59,6 +63,7 @@ export function useWallLineOffsetSetting(id) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||||
|
|
||||||
if (outerLines.length === 0) {
|
if (outerLines.length === 0) {
|
||||||
swalFire({ text: getMessage('wall.line.not.found') })
|
swalFire({ text: getMessage('wall.line.not.found') })
|
||||||
closePopup(id)
|
closePopup(id)
|
||||||
@ -277,7 +282,7 @@ export function useWallLineOffsetSetting(id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rearrangeOuterLine(currentIdx + 1)
|
reArrangeOuterLine(currentIdx + 1)
|
||||||
|
|
||||||
drawLine(point1, point2, currentIdx)
|
drawLine(point1, point2, currentIdx)
|
||||||
drawLine(point2, point3, currentIdx + 1)
|
drawLine(point2, point3, currentIdx + 1)
|
||||||
@ -286,229 +291,217 @@ export function useWallLineOffsetSetting(id) {
|
|||||||
canvas.remove(currentWallLineRef.current)
|
canvas.remove(currentWallLineRef.current)
|
||||||
currentWallLineRef.current = null
|
currentWallLineRef.current = null
|
||||||
canvas.renderAll()
|
canvas.renderAll()
|
||||||
|
|
||||||
|
canvas
|
||||||
|
.getObjects()
|
||||||
|
.filter((obj) => obj.name === 'outerLine')
|
||||||
|
.forEach((obj) => obj.fire('modified'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const rearrangeOuterLine = (idxParam) => {
|
/**
|
||||||
|
* outreLine의 index를 조절한다.
|
||||||
|
* @param idxParam
|
||||||
|
* @param isNegative
|
||||||
|
*/
|
||||||
|
const reArrangeOuterLine = (idxParam, isNegative = false) => {
|
||||||
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||||
outerLines.forEach((outerLine) => {
|
outerLines.forEach((outerLine) => {
|
||||||
if (outerLine.idx >= idxParam) {
|
if (outerLine.idx >= idxParam) {
|
||||||
outerLine.idx = outerLine.idx + 1
|
outerLine.idx = isNegative ? outerLine.idx - 1 : outerLine.idx + 1
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* offset 저장
|
||||||
|
*/
|
||||||
const handleOffsetSave = () => {
|
const handleOffsetSave = () => {
|
||||||
const direction = currentWallLineRef.current.direction
|
if (!currentObject) return
|
||||||
let canDirections = direction === 'left' || direction === 'right' ? ['up', 'down'] : ['left', 'right']
|
const currentLine = currentObject
|
||||||
const currentIdx = currentWallLineRef.current.idx
|
const currentVector = currentLine.y1 === currentLine.y2 ? 'horizontal' : 'vertical'
|
||||||
|
const canDirections = currentVector === 'horizontal' ? ['up', 'down'] : ['left', 'right']
|
||||||
if (!canDirections.includes(arrow1Ref.current)) {
|
if (!canDirections.includes(arrow1Ref.current)) {
|
||||||
alert('방향을 다시 선택하세요')
|
alert('방향을 다시 선택하세요')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||||
|
outerLines.sort((a, b) => a.idx - b.idx)
|
||||||
|
|
||||||
const idx = currentWallLineRef.current.idx
|
const currentIdx = currentLine.idx
|
||||||
const prevIdx = idx - 1 <= 0 ? outerLines.length : idx - 1
|
const prevIdx = currentIdx - 1 <= 0 ? outerLines.length : currentIdx - 1
|
||||||
const nextIdx = idx + 1 > outerLines.length ? 1 : idx + 1
|
const nextIdx = currentLine.idx + 1 > outerLines.length ? 1 : currentIdx + 1
|
||||||
|
|
||||||
const currentLine = currentWallLineRef.current
|
|
||||||
const prevLine = outerLines.find((line) => line.idx === prevIdx)
|
const prevLine = outerLines.find((line) => line.idx === prevIdx)
|
||||||
const nextLine = outerLines.find((line) => line.idx === nextIdx)
|
const nextLine = outerLines.find((line) => line.idx === nextIdx)
|
||||||
|
const prevVector = prevLine.y1 === prevLine.y2 ? 'horizontal' : 'vertical'
|
||||||
|
const nextVector = nextLine.y1 === nextLine.y2 ? 'horizontal' : 'vertical'
|
||||||
|
|
||||||
const length = length1Ref.current.value / 10
|
const offsetLength = Big(Number(length1Ref.current.value)).div(10)
|
||||||
const currentLineX = Math.floor(Math.max(currentLine.x1, currentLine.x2))
|
if (offsetLength.eq(0)) return
|
||||||
const currentLineY = Math.floor(Math.max(currentLine.y1, currentLine.y2))
|
|
||||||
switch (arrow1Ref.current) {
|
|
||||||
case 'up': {
|
|
||||||
if (prevLine.direction === currentLine.direction) {
|
|
||||||
const newX =
|
|
||||||
currentLine.direction === 'left'
|
|
||||||
? Math.floor(Math.max(currentLine.x1, currentLine.x2))
|
|
||||||
: Math.floor(Math.min(currentLine.x1, currentLine.x2))
|
|
||||||
|
|
||||||
const newPoint1 = { x: newX, y: currentLineY - length }
|
const currentLineMinX = Big(Math.max(currentLine.x1, currentLine.x2))
|
||||||
const newPoint2 = { x: prevLine.x2, y: prevLine.y2 }
|
const currentLineMaxX = Big(Math.max(currentLine.x1, currentLine.x2))
|
||||||
rearrangeOuterLine(currentIdx)
|
const currentLineMinY = Big(Math.max(currentLine.y1, currentLine.y2))
|
||||||
drawLine(newPoint1, newPoint2, currentIdx, 'top')
|
const currentLineMaxY = Big(Math.max(currentLine.y1, currentLine.y2))
|
||||||
|
|
||||||
if (Math.abs(currentLineY - nextLine.y1) < 2) {
|
if (currentVector === 'horizontal') {
|
||||||
nextLine.set({ y1: currentLineY - length })
|
const prevX = currentLine.x1 < currentLine.x2 ? Math.min(currentLine.x1, currentLine.x2) : Math.max(currentLine.x1, currentLine.x2)
|
||||||
} else {
|
const nextX = currentLine.x1 < currentLine.x2 ? Math.max(currentLine.x1, currentLine.x2) : Math.min(currentLine.x1, currentLine.x2)
|
||||||
nextLine.set({ y2: currentLineY - length })
|
if (arrow1Ref.current === 'up') {
|
||||||
}
|
currentLine.set({ y1: currentLineMaxY.minus(offsetLength).toNumber(), y2: currentLineMaxY.minus(offsetLength).toNumber() })
|
||||||
} else if (nextLine.direction === currentLine.direction) {
|
if (prevVector === currentVector) {
|
||||||
const newX =
|
const point1 = { x: prevX, y: prevLine.y2 }
|
||||||
currentLine.direction === 'left'
|
const point2 = { x: prevX, y: currentLine.y1 }
|
||||||
? Math.floor(Math.min(currentLine.x1, currentLine.x2))
|
reArrangeOuterLine(currentIdx)
|
||||||
: Math.floor(Math.max(currentLine.x1, currentLine.x2))
|
drawLine(point1, point2, currentIdx, arrow1Ref.current)
|
||||||
|
|
||||||
const newPoint1 = { x: newX, y: currentLineY - length }
|
|
||||||
const newPoint2 = { x: nextLine.x1, y: nextLine.y1 }
|
|
||||||
rearrangeOuterLine(currentIdx + 1)
|
|
||||||
drawLine(newPoint1, newPoint2, currentIdx + 1, 'top')
|
|
||||||
|
|
||||||
if (Math.abs(currentLineY - prevLine.y1) < 2) {
|
|
||||||
prevLine.set({ y1: currentLineY - length })
|
|
||||||
} else {
|
|
||||||
prevLine.set({ y2: currentLineY - length })
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (Math.abs(currentLineY - prevLine.y1) < 2) {
|
if (Big(prevLine.y1).minus(currentLineMinY).abs().lte(Big(prevLine.y2).minus(currentLineMinY).abs())) {
|
||||||
prevLine.set({ y1: prevLine.y1 - length })
|
prevLine.set({ y1: currentLine.y1 })
|
||||||
} else {
|
} else {
|
||||||
prevLine.set({ y2: prevLine.y2 - length })
|
prevLine.set({ y2: currentLine.y1 })
|
||||||
}
|
}
|
||||||
if (Math.abs(currentLineY - nextLine.y1) < 2) {
|
if (Big(prevLine.y1).minus(Big(prevLine.y2)).eq(0)) {
|
||||||
nextLine.set({ y1: nextLine.y1 - length })
|
reArrangeOuterLine(currentIdx - 1, true)
|
||||||
} else {
|
canvas.remove(prevLine)
|
||||||
nextLine.set({ y2: nextLine.y2 - length })
|
}
|
||||||
|
}
|
||||||
|
if (nextVector === currentVector) {
|
||||||
|
const point1 = { x: nextX, y: nextLine.y2 }
|
||||||
|
const point2 = { x: nextX, y: currentLine.y1 }
|
||||||
|
reArrangeOuterLine(currentIdx + 1)
|
||||||
|
drawLine(point1, point2, currentIdx + 1, arrow1Ref.current)
|
||||||
|
} else {
|
||||||
|
if (Big(nextLine.y1).minus(currentLineMaxY).abs().lte(Big(nextLine.y2).minus(currentLineMaxY).abs())) {
|
||||||
|
nextLine.set({ y1: currentLine.y1 })
|
||||||
|
} else {
|
||||||
|
nextLine.set({ y2: currentLine.y1 })
|
||||||
|
}
|
||||||
|
if (Big(nextLine.y1).minus(Big(nextLine.y2)).eq(0)) {
|
||||||
|
reArrangeOuterLine(currentIdx + 1, true)
|
||||||
|
canvas.remove(nextLine)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentLine.set({ y1: currentLine.y1 - length, y2: currentLine.y2 - length })
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
case 'down': {
|
if (arrow1Ref.current === 'down') {
|
||||||
if (prevLine.direction === currentLine.direction) {
|
currentLine.set({ y1: currentLineMaxY.plus(offsetLength).toNumber(), y2: currentLineMaxY.plus(offsetLength).toNumber() })
|
||||||
const newX =
|
if (prevVector === currentVector) {
|
||||||
currentLine.direction === 'left'
|
const point1 = { x: prevX, y: prevLine.y2 }
|
||||||
? Math.floor(Math.max(currentLine.x1, currentLine.x2))
|
const point2 = { x: prevX, y: currentLine.y1 }
|
||||||
: Math.floor(Math.min(currentLine.x1, currentLine.x2))
|
reArrangeOuterLine(currentIdx)
|
||||||
const newPoint1 = { x: newX, y: currentLineY + length }
|
drawLine(point1, point2, currentIdx, arrow1Ref.current)
|
||||||
const newPoint2 = { x: prevLine.x2, y: prevLine.y2 }
|
|
||||||
rearrangeOuterLine(currentIdx)
|
|
||||||
drawLine(newPoint1, newPoint2, currentIdx, 'bottom')
|
|
||||||
if (Math.abs(currentLineY - nextLine.y1) < 2) {
|
|
||||||
nextLine.set({ y1: currentLineY + length })
|
|
||||||
} else {
|
|
||||||
nextLine.set({ y2: currentLineY + length })
|
|
||||||
}
|
|
||||||
} else if (nextLine.direction === currentLine.direction) {
|
|
||||||
const newX =
|
|
||||||
currentLine.direction === 'left'
|
|
||||||
? Math.floor(Math.min(currentLine.x1, currentLine.x2))
|
|
||||||
: Math.floor(Math.max(currentLine.x1, currentLine.x2))
|
|
||||||
const newPoint1 = { x: newX, y: currentLineY + length }
|
|
||||||
const newPoint2 = { x: nextLine.x1, y: nextLine.y1 }
|
|
||||||
rearrangeOuterLine(currentIdx + 1)
|
|
||||||
drawLine(newPoint1, newPoint2, currentIdx + 1, 'bottom')
|
|
||||||
if (Math.abs(currentLineY - prevLine.y1) < 2) {
|
|
||||||
prevLine.set({ y1: currentLineY + length })
|
|
||||||
} else {
|
|
||||||
prevLine.set({ y2: currentLineY + length })
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (Math.abs(currentLineY - prevLine.y1) < 2) {
|
if (Big(prevLine.y1).minus(currentLineMinY).abs().lte(Big(prevLine.y2).minus(currentLineMinY).abs())) {
|
||||||
prevLine.set({ y1: prevLine.y1 + length })
|
prevLine.set({ y1: currentLine.y1 })
|
||||||
} else {
|
} else {
|
||||||
prevLine.set({ y2: prevLine.y2 + length })
|
prevLine.set({ y2: currentLine.y1 })
|
||||||
}
|
}
|
||||||
if (Math.abs(currentLineY - nextLine.y1) < 2) {
|
if (Big(prevLine.y1).minus(Big(prevLine.y2)).eq(0)) {
|
||||||
nextLine.set({ y1: nextLine.y1 + length })
|
reArrangeOuterLine(currentIdx - 1, true)
|
||||||
} else {
|
canvas.remove(prevLine)
|
||||||
nextLine.set({ y2: nextLine.y2 + length })
|
}
|
||||||
|
}
|
||||||
|
if (nextVector === currentVector) {
|
||||||
|
const point1 = { x: nextX, y: nextLine.y2 }
|
||||||
|
const point2 = { x: nextX, y: currentLine.y1 }
|
||||||
|
reArrangeOuterLine(currentIdx + 1)
|
||||||
|
drawLine(point1, point2, currentIdx + 1, arrow1Ref.current)
|
||||||
|
} else {
|
||||||
|
if (Big(nextLine.y1).minus(currentLineMaxY).abs().lte(Big(nextLine.y2).minus(currentLineMaxY).abs())) {
|
||||||
|
nextLine.set({ y1: currentLine.y1 })
|
||||||
|
} else {
|
||||||
|
nextLine.set({ y2: currentLine.y1 })
|
||||||
|
}
|
||||||
|
if (Big(nextLine.y1).minus(Big(nextLine.y2)).eq(0)) {
|
||||||
|
reArrangeOuterLine(currentIdx + 1, true)
|
||||||
|
canvas.remove(nextLine)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentLine.set({ y1: currentLine.y1 + length, y2: currentLine.y2 + length })
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
case 'left': {
|
} else {
|
||||||
if (prevLine.direction === currentLine.direction) {
|
const prevY = currentLine.y1 < currentLine.y2 ? Math.min(currentLine.y1, currentLine.y2) : Math.max(currentLine.y1, currentLine.y2)
|
||||||
const newY =
|
const nextY = currentLine.y1 < currentLine.y2 ? Math.max(currentLine.y1, currentLine.y2) : Math.min(currentLine.y1, currentLine.y2)
|
||||||
currentLine.direction === 'top'
|
if (arrow1Ref.current === 'left') {
|
||||||
? Math.floor(Math.max(currentLine.y1, currentLine.y2))
|
currentLine.set({ x1: currentLineMaxX.minus(offsetLength).toNumber(), x2: currentLineMaxX.minus(offsetLength).toNumber() })
|
||||||
: Math.floor(Math.min(currentLine.y1, currentLine.y2))
|
|
||||||
const newPoint1 = { x: currentLineX - length, y: newY }
|
|
||||||
const newPoint2 = { x: prevLine.x2, y: prevLine.y2 }
|
|
||||||
rearrangeOuterLine(currentIdx)
|
|
||||||
drawLine(newPoint1, newPoint2, currentIdx, 'left')
|
|
||||||
if (Math.abs(currentLineX - nextLine.x1) < 2) {
|
|
||||||
nextLine.set({ x1: currentLineX - length })
|
|
||||||
} else {
|
|
||||||
nextLine.set({ x2: currentLineX - length })
|
|
||||||
}
|
|
||||||
} else if (nextLine.direction === currentLine.direction) {
|
|
||||||
const newY =
|
|
||||||
currentLine.direction === 'top'
|
|
||||||
? Math.floor(Math.min(currentLine.y1, currentLine.y2))
|
|
||||||
: Math.floor(Math.max(currentLine.y1, currentLine.y2))
|
|
||||||
const newPoint1 = { x: currentLineX - length, y: newY }
|
|
||||||
const newPoint2 = { x: nextLine.x1, y: nextLine.y1 }
|
|
||||||
rearrangeOuterLine(currentIdx + 1)
|
|
||||||
drawLine(newPoint1, newPoint2, currentIdx + 1, 'left')
|
|
||||||
if (Math.abs(currentLineX - prevLine.x1) < 2) {
|
|
||||||
prevLine.set({ x1: currentLineX - length })
|
|
||||||
} else {
|
|
||||||
prevLine.set({ x2: currentLineX - length })
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (Math.abs(currentLineX - prevLine.x1) < 2) {
|
|
||||||
prevLine.set({ x1: prevLine.x1 - length })
|
|
||||||
} else {
|
|
||||||
prevLine.set({ x2: prevLine.x2 - length })
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Math.abs(currentLineX - nextLine.x1) < 2) {
|
if (prevVector === currentVector) {
|
||||||
nextLine.set({ x1: nextLine.x1 - length })
|
const point1 = { x: prevLine.x2, y: prevY }
|
||||||
|
const point2 = { x: currentLine.x1, y: prevY }
|
||||||
|
reArrangeOuterLine(currentIdx)
|
||||||
|
drawLine(point1, point2, currentIdx, arrow1Ref.current)
|
||||||
|
} else {
|
||||||
|
if (Big(prevLine.x1).minus(currentLineMinX).abs().lte(Big(prevLine.x2).minus(currentLineMinX).abs())) {
|
||||||
|
prevLine.set({ x1: currentLine.x1 })
|
||||||
} else {
|
} else {
|
||||||
nextLine.set({ x2: nextLine.x2 - length })
|
prevLine.set({ x2: currentLine.x1 })
|
||||||
|
}
|
||||||
|
if (Big(prevLine.x1).minus(Big(prevLine.x2)).eq(0)) {
|
||||||
|
reArrangeOuterLine(currentIdx - 1, true)
|
||||||
|
canvas.remove(prevLine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nextVector === currentVector) {
|
||||||
|
const point1 = { x: currentLine.x2, y: nextY }
|
||||||
|
const point2 = { x: nextLine.x1, y: nextY }
|
||||||
|
reArrangeOuterLine(currentIdx + 1)
|
||||||
|
drawLine(point1, point2, currentIdx + 1, arrow1Ref.current)
|
||||||
|
} else {
|
||||||
|
if (Big(nextLine.x1).minus(currentLineMaxX).abs().lte(Big(nextLine.x2).minus(currentLineMaxX).abs())) {
|
||||||
|
nextLine.set({ x1: currentLine.x2 })
|
||||||
|
} else {
|
||||||
|
nextLine.set({ x2: currentLine.x2 })
|
||||||
|
}
|
||||||
|
if (Big(nextLine.x1).minus(Big(nextLine.x2)).eq(0)) {
|
||||||
|
reArrangeOuterLine(currentIdx + 1, true)
|
||||||
|
canvas.remove(nextLine)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentLine.set({ x1: currentLine.x1 - length, x2: currentLine.x2 - length })
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
case 'right': {
|
if (arrow1Ref.current === 'right') {
|
||||||
if (prevLine.direction === currentLine.direction) {
|
currentLine.set({ x1: currentLineMaxX.plus(offsetLength).toNumber(), x2: currentLineMaxX.plus(offsetLength).toNumber() })
|
||||||
const newY =
|
|
||||||
currentLine.direction === 'top'
|
|
||||||
? Math.floor(Math.max(currentLine.y1, currentLine.y2))
|
|
||||||
: Math.floor(Math.min(currentLine.y1, currentLine.y2))
|
|
||||||
const newPoint1 = { x: currentLineX + length, y: newY }
|
|
||||||
const newPoint2 = { x: prevLine.x2, y: prevLine.y2 }
|
|
||||||
rearrangeOuterLine(currentIdx)
|
|
||||||
drawLine(newPoint1, newPoint2, currentIdx, 'right')
|
|
||||||
if (Math.abs(currentLineX - nextLine.x1) < 2) {
|
|
||||||
nextLine.set({ x1: currentLineX + length })
|
|
||||||
} else {
|
|
||||||
nextLine.set({ x2: currentLineX + length })
|
|
||||||
}
|
|
||||||
} else if (nextLine.direction === currentLine.direction) {
|
|
||||||
const newY =
|
|
||||||
currentLine.direction === 'top'
|
|
||||||
? Math.floor(Math.min(currentLine.y1, currentLine.y2))
|
|
||||||
: Math.floor(Math.max(currentLine.y1, currentLine.y2))
|
|
||||||
const newPoint1 = { x: currentLineX + length, y: newY }
|
|
||||||
const newPoint2 = { x: nextLine.x1, y: nextLine.y1 }
|
|
||||||
rearrangeOuterLine(currentIdx + 1)
|
|
||||||
drawLine(newPoint1, newPoint2, currentIdx + 1, 'right')
|
|
||||||
|
|
||||||
if (Math.abs(currentLineX - prevLine.x1) < 2) {
|
if (prevVector === currentVector) {
|
||||||
prevLine.set({ x1: currentLineX + length })
|
const point1 = { x: prevLine.x2, y: prevY }
|
||||||
} else {
|
const point2 = { x: currentLine.x1, y: prevY }
|
||||||
prevLine.set({ x2: currentLineX + length })
|
reArrangeOuterLine(currentIdx)
|
||||||
}
|
drawLine(point1, point2, currentIdx, arrow1Ref.current)
|
||||||
} else {
|
} else {
|
||||||
if (Math.abs(currentLineX - prevLine.x1) < 2) {
|
if (Big(prevLine.x1).minus(currentLineMinX).abs().lte(Big(prevLine.x2).minus(currentLineMinX).abs())) {
|
||||||
prevLine.set({ x1: prevLine.x1 + length })
|
prevLine.set({ x1: currentLine.x1 })
|
||||||
} else {
|
} else {
|
||||||
prevLine.set({ x2: prevLine.x2 + length })
|
prevLine.set({ x2: currentLine.x1 })
|
||||||
}
|
}
|
||||||
if (Math.abs(currentLineX - nextLine.x1) < 2) {
|
|
||||||
nextLine.set({ x1: nextLine.x1 + length })
|
if (Big(prevLine.x1).minus(Big(prevLine.x2)).eq(0)) {
|
||||||
} else {
|
reArrangeOuterLine(currentIdx - 1, true)
|
||||||
nextLine.set({ x2: nextLine.x2 + length })
|
canvas.remove(prevLine)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (nextVector === currentVector) {
|
||||||
|
const point1 = { x: currentLine.x2, y: nextY }
|
||||||
|
const point2 = { x: nextLine.x1, y: nextY }
|
||||||
|
reArrangeOuterLine(currentIdx + 1)
|
||||||
|
drawLine(point1, point2, currentIdx + 1, arrow1Ref.current)
|
||||||
|
} else {
|
||||||
|
if (Big(nextLine.x1).minus(currentLineMaxX).abs().lte(Big(nextLine.x2).minus(currentLineMaxX).abs())) {
|
||||||
|
nextLine.set({ x1: currentLine.x2 })
|
||||||
|
} else {
|
||||||
|
nextLine.set({ x2: currentLine.x2 })
|
||||||
|
}
|
||||||
|
|
||||||
currentLine.set({ x1: currentLine.x1 + length, x2: currentLine.x2 + length })
|
if (Big(nextLine.x1).minus(Big(nextLine.x2)).eq(0)) {
|
||||||
|
reArrangeOuterLine(currentIdx + 1, true)
|
||||||
break
|
canvas.remove(nextLine)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const newOuterLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||||
|
newOuterLines.sort((a, b) => a.idx - b.idx)
|
||||||
|
newOuterLines.forEach((line, idx) => {
|
||||||
|
line.fire('modified')
|
||||||
|
})
|
||||||
|
|
||||||
canvas.renderAll()
|
canvas.renderAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -38,12 +38,12 @@ export const useLine = () => {
|
|||||||
line.set({
|
line.set({
|
||||||
visible: false,
|
visible: false,
|
||||||
})
|
})
|
||||||
canvas
|
const obj = canvas?.getObjects().find((obj) => obj.parentId === line.id)
|
||||||
?.getObjects()
|
if (obj) {
|
||||||
.find((obj) => obj.parentId === line.id)
|
obj.set({
|
||||||
.set({
|
|
||||||
visible: false,
|
visible: false,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
canvas?.renderAll()
|
canvas?.renderAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -33,7 +33,7 @@ import {
|
|||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
import { fabric } from 'fabric'
|
import { fabric } from 'fabric'
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
import offsetPolygon from '@/util/qpolygon-utils'
|
import offsetPolygon, { calculateAngle } from '@/util/qpolygon-utils'
|
||||||
import { isObjectNotEmpty } from '@/util/common-utils'
|
import { isObjectNotEmpty } from '@/util/common-utils'
|
||||||
import * as turf from '@turf/turf'
|
import * as turf from '@turf/turf'
|
||||||
import { INPUT_TYPE, LINE_TYPE, Mode, POLYGON_TYPE } from '@/common/common'
|
import { INPUT_TYPE, LINE_TYPE, Mode, POLYGON_TYPE } from '@/common/common'
|
||||||
@ -1679,10 +1679,11 @@ export function useMode() {
|
|||||||
const offsetEdges = []
|
const offsetEdges = []
|
||||||
|
|
||||||
polygon.edges.forEach((edge, i) => {
|
polygon.edges.forEach((edge, i) => {
|
||||||
const offset =
|
/* const offset =
|
||||||
lines[i % lines.length].attributes.offset === undefined || lines[i % lines.length].attributes.offset === 0
|
lines[i % lines.length].attributes.offset === undefined || lines[i % lines.length].attributes.offset === 0
|
||||||
? 0.1
|
? 0.1
|
||||||
: lines[i % lines.length].attributes.offset
|
: lines[i % lines.length].attributes.offset*/
|
||||||
|
const offset = lines[i % lines.length].attributes.offset
|
||||||
const dx = edge.outwardNormal.x * offset
|
const dx = edge.outwardNormal.x * offset
|
||||||
const dy = edge.outwardNormal.y * offset
|
const dy = edge.outwardNormal.y * offset
|
||||||
offsetEdges.push(createOffsetEdge(edge, dx, dy))
|
offsetEdges.push(createOffsetEdge(edge, dx, dy))
|
||||||
@ -1717,10 +1718,12 @@ export function useMode() {
|
|||||||
const offsetEdges = []
|
const offsetEdges = []
|
||||||
|
|
||||||
polygon.edges.forEach((edge, i) => {
|
polygon.edges.forEach((edge, i) => {
|
||||||
const offset =
|
/*const offset =
|
||||||
lines[i % lines.length].attributes.offset === undefined || lines[i % lines.length].attributes.offset === 0
|
lines[i % lines.length].attributes.offset === undefined || lines[i % lines.length].attributes.offset === 0
|
||||||
? 0.1
|
? 0.1
|
||||||
: lines[i % lines.length].attributes.offset
|
: lines[i % lines.length].attributes.offset*/
|
||||||
|
const offset = lines[i % lines.length].attributes.offset
|
||||||
|
|
||||||
const dx = edge.inwardNormal.x * offset
|
const dx = edge.inwardNormal.x * offset
|
||||||
const dy = edge.inwardNormal.y * offset
|
const dy = edge.inwardNormal.y * offset
|
||||||
offsetEdges.push(createOffsetEdge(edge, dx, dy))
|
offsetEdges.push(createOffsetEdge(edge, dx, dy))
|
||||||
@ -1767,10 +1770,19 @@ export function useMode() {
|
|||||||
afterLine.push(line)
|
afterLine.push(line)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
wall.lines = afterLine.concat(beforeLine)
|
wall.lines = afterLine.concat(beforeLine)
|
||||||
|
|
||||||
//외벽선을 기준으로 polygon을 생성한다. 지붕선의 기준이 됨.
|
//외벽선을 기준으로 polygon을 생성한다. 지붕선의 기준이 됨.
|
||||||
|
const divWallLines = []
|
||||||
|
wall.lines.forEach((currentWall, index) => {
|
||||||
|
const nextWall = wall.lines[(index + 1) % wall.lines.length]
|
||||||
|
const currentAngle = calculateAngle(currentWall.startPoint, currentWall.endPoint)
|
||||||
|
const nextAngle = calculateAngle(nextWall.startPoint, nextWall.endPoint)
|
||||||
|
if (currentAngle === nextAngle) {
|
||||||
|
divWallLines.push({ currentWall: currentWall, nextWall: nextWall, index: index })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const polygon = createRoofPolygon(wall.points)
|
const polygon = createRoofPolygon(wall.points)
|
||||||
const originPolygon = new QPolygon(wall.points, { fontSize: 0 })
|
const originPolygon = new QPolygon(wall.points, { fontSize: 0 })
|
||||||
originPolygon.setViewLengthText(false)
|
originPolygon.setViewLengthText(false)
|
||||||
@ -1787,6 +1799,45 @@ export function useMode() {
|
|||||||
offsetPolygon = createPaddingPolygon(polygon, wall.lines).vertices
|
offsetPolygon = createPaddingPolygon(polygon, wall.lines).vertices
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (divWallLines.length > 0) {
|
||||||
|
/**
|
||||||
|
* 외벽선을 분기한 횟수를 저장한다. 외벽선은 offset이 같지 않을때 분기한다.
|
||||||
|
*/
|
||||||
|
let addPoint = 0
|
||||||
|
|
||||||
|
divWallLines.forEach((line) => {
|
||||||
|
const currentWall = line.currentWall
|
||||||
|
const nextWall = line.nextWall
|
||||||
|
const index = line.index + addPoint
|
||||||
|
const xDiff = Big(currentWall.x1).minus(Big(nextWall.x1))
|
||||||
|
const yDiff = Big(currentWall.y1).minus(Big(nextWall.y1))
|
||||||
|
const offsetCurrentPoint = offsetPolygon[index]
|
||||||
|
let offsetNextPoint = offsetPolygon[(index + 1) % offsetPolygon.length]
|
||||||
|
line.index = index
|
||||||
|
|
||||||
|
if (currentWall.attributes.offset !== nextWall.attributes.offset) {
|
||||||
|
const offsetPoint1 = {
|
||||||
|
x: xDiff.eq(0) ? offsetCurrentPoint.x : nextWall.x1,
|
||||||
|
y: yDiff.eq(0) ? offsetCurrentPoint.y : nextWall.y1,
|
||||||
|
}
|
||||||
|
const diffOffset = Big(nextWall.attributes.offset).minus(Big(currentWall.attributes.offset))
|
||||||
|
const offsetPoint2 = {
|
||||||
|
x: yDiff.eq(0) ? offsetPoint1.x : Big(offsetPoint1.x).plus(diffOffset).toNumber(),
|
||||||
|
y: xDiff.eq(0) ? offsetPoint1.y : Big(offsetPoint1.y).plus(diffOffset).toNumber(),
|
||||||
|
}
|
||||||
|
const offsetPoint3 = {
|
||||||
|
x: yDiff.eq(0) ? offsetNextPoint.x : Big(offsetNextPoint.x).plus(diffOffset).toNumber(),
|
||||||
|
y: xDiff.eq(0) ? offsetNextPoint.y : Big(offsetNextPoint.y).plus(diffOffset).toNumber(),
|
||||||
|
}
|
||||||
|
offsetPolygon.splice(index + 1, 0, offsetPoint1, offsetPoint2)
|
||||||
|
offsetNextPoint = offsetPoint3
|
||||||
|
addPoint++
|
||||||
|
} else {
|
||||||
|
addPoint--
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const roof = makePolygon(
|
const roof = makePolygon(
|
||||||
offsetPolygon.map((point) => {
|
offsetPolygon.map((point) => {
|
||||||
return { x1: point.x, y1: point.y }
|
return { x1: point.x, y1: point.y }
|
||||||
@ -1806,6 +1857,8 @@ export function useMode() {
|
|||||||
roof.name = POLYGON_TYPE.ROOF
|
roof.name = POLYGON_TYPE.ROOF
|
||||||
roof.setWall(wall)
|
roof.setWall(wall)
|
||||||
|
|
||||||
|
let roofWallIndex = 0
|
||||||
|
|
||||||
roof.lines.forEach((line, index) => {
|
roof.lines.forEach((line, index) => {
|
||||||
const x1 = Big(line.x1)
|
const x1 = Big(line.x1)
|
||||||
const x2 = Big(line.x2)
|
const x2 = Big(line.x2)
|
||||||
@ -1816,18 +1869,21 @@ export function useMode() {
|
|||||||
roofId: roof.id,
|
roofId: roof.id,
|
||||||
planeSize: lineLength,
|
planeSize: lineLength,
|
||||||
actualSize: lineLength,
|
actualSize: lineLength,
|
||||||
wallLine: wall.lines[index].id,
|
wallLine: wall.lines[roofWallIndex].id,
|
||||||
type: wall.lines[index].attributes.type,
|
type: wall.lines[roofWallIndex].attributes.type,
|
||||||
offset: wall.lines[index].attributes.offset,
|
offset: wall.lines[roofWallIndex].attributes.offset,
|
||||||
width: wall.lines[index].attributes.width,
|
width: wall.lines[roofWallIndex].attributes.width,
|
||||||
pitch: wall.lines[index].attributes.pitch,
|
pitch: wall.lines[roofWallIndex].attributes.pitch,
|
||||||
sleeve: wall.lines[index].attributes.sleeve || false,
|
sleeve: wall.lines[roofWallIndex].attributes.sleeve || false,
|
||||||
|
}
|
||||||
|
|
||||||
|
const isDivLine = divWallLines.some((divLine) => divLine.index === index)
|
||||||
|
if (!isDivLine) {
|
||||||
|
roofWallIndex++
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
wall.set({
|
wall.set({
|
||||||
// originX: 'center',
|
|
||||||
// originY: 'center',
|
|
||||||
attributes: {
|
attributes: {
|
||||||
roofId: roof.id,
|
roofId: roof.id,
|
||||||
},
|
},
|
||||||
@ -1846,54 +1902,22 @@ export function useMode() {
|
|||||||
const y2 = Big(line.y2)
|
const y2 = Big(line.y2)
|
||||||
const lineLength = x1.minus(x2).abs().pow(2).plus(y1.minus(y2).abs().pow(2)).sqrt().times(10).round().toNumber()
|
const lineLength = x1.minus(x2).abs().pow(2).plus(y1.minus(y2).abs().pow(2)).sqrt().times(10).round().toNumber()
|
||||||
line.attributes.roofId = roof.id
|
line.attributes.roofId = roof.id
|
||||||
line.attributes.currentRoofId = roof.lines[index].id
|
line.attributes.wallId = wall.id
|
||||||
|
// line.attributes.currentRoofId = roof.lines[index].id
|
||||||
line.attributes.planeSize = lineLength
|
line.attributes.planeSize = lineLength
|
||||||
line.attributes.actualSize = lineLength
|
line.attributes.actualSize = lineLength
|
||||||
|
|
||||||
let wallStroke, wallStrokeWidth
|
const baseLine = new fabric.Line([line.x1, line.y1, line.x2, line.y2], {
|
||||||
switch (line.attributes.type) {
|
visible: false,
|
||||||
case LINE_TYPE.WALLLINE.EAVES:
|
attributes: line.attributes,
|
||||||
wallStroke = '#45CD7D'
|
startPoint: line.startPoint,
|
||||||
wallStrokeWidth = 4
|
endPoint: line.endPoint,
|
||||||
break
|
parentId: roof.id,
|
||||||
case LINE_TYPE.WALLLINE.HIPANDGABLE:
|
name: 'baseLine',
|
||||||
wallStroke = '#45CD7D'
|
|
||||||
wallStrokeWidth = 4
|
|
||||||
break
|
|
||||||
case LINE_TYPE.WALLLINE.GABLE:
|
|
||||||
wallStroke = '#3FBAE6'
|
|
||||||
wallStrokeWidth = 4
|
|
||||||
break
|
|
||||||
case LINE_TYPE.WALLLINE.JERKINHEAD:
|
|
||||||
wallStroke = '#3FBAE6'
|
|
||||||
wallStrokeWidth = 4
|
|
||||||
break
|
|
||||||
case LINE_TYPE.WALLLINE.SHED:
|
|
||||||
wallStroke = '#000000'
|
|
||||||
wallStrokeWidth = 4
|
|
||||||
break
|
|
||||||
case LINE_TYPE.WALLLINE.WALL:
|
|
||||||
wallStroke = '#000000'
|
|
||||||
wallStrokeWidth = 4
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
//외벽선의 색깔 표시를 위해 라인을 추가한다.
|
|
||||||
const wallLine = new fabric.Line([line.x1, line.y1, line.x2, line.y2], {
|
|
||||||
parentId: wall.id,
|
|
||||||
name: 'wallLine',
|
|
||||||
attributes: {
|
|
||||||
wallId: wall.id,
|
|
||||||
roofId: roof.id,
|
|
||||||
type: line.attributes.type,
|
|
||||||
currentRoofId: line.attributes.currentRoofId,
|
|
||||||
currentWall: line.id,
|
|
||||||
},
|
|
||||||
stroke: wallStroke,
|
|
||||||
strokeWidth: wallStrokeWidth,
|
|
||||||
selectable: false,
|
|
||||||
})
|
})
|
||||||
canvas.add(wallLine)
|
baseLine.attributes.originPoint = { x1: line.x1, y1: line.y1, x2: line.x2, y2: line.y2 }
|
||||||
|
roof.wall.baseLines.push(baseLine)
|
||||||
|
canvas.add(baseLine)
|
||||||
})
|
})
|
||||||
|
|
||||||
setRoof(roof)
|
setRoof(roof)
|
||||||
|
|||||||
@ -1,7 +1,14 @@
|
|||||||
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, pitchTextSelector } from '@/store/canvasAtom'
|
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, pitchTextSelector } from '@/store/canvasAtom'
|
||||||
import { useRecoilValue } from 'recoil'
|
import { useRecoilValue } from 'recoil'
|
||||||
import { fabric } from 'fabric'
|
import { fabric } from 'fabric'
|
||||||
import { findAndRemoveClosestPoint, getDegreeByChon, getDegreeInOrientation, isPointOnLine } from '@/util/canvas-util'
|
import {
|
||||||
|
distanceBetweenPoints,
|
||||||
|
findAndRemoveClosestPoint,
|
||||||
|
getDegreeByChon,
|
||||||
|
getDegreeInOrientation,
|
||||||
|
isPointOnLine,
|
||||||
|
toFixedWithoutRounding,
|
||||||
|
} from '@/util/canvas-util'
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
import { isSamePoint, removeDuplicatePolygons } from '@/util/qpolygon-utils'
|
import { isSamePoint, removeDuplicatePolygons } from '@/util/qpolygon-utils'
|
||||||
import { flowDisplaySelector } from '@/store/settingAtom'
|
import { flowDisplaySelector } from '@/store/settingAtom'
|
||||||
@ -759,9 +766,9 @@ export const usePolygon = () => {
|
|||||||
|
|
||||||
const splitPolygonWithLines = (polygon) => {
|
const splitPolygonWithLines = (polygon) => {
|
||||||
polygon.set({ visible: false })
|
polygon.set({ visible: false })
|
||||||
let innerLines = [...polygon.innerLines]
|
let innerLines = [...polygon.innerLines].filter((line) => line.visible)
|
||||||
|
|
||||||
// innerLine이 세팅이 안되어있는경우 찾아서 세팅한다.
|
/*// innerLine이 세팅이 안되어있는경우 찾아서 세팅한다.
|
||||||
if (!innerLines || innerLines.length === 0) {
|
if (!innerLines || innerLines.length === 0) {
|
||||||
let innerLineTypes = Object.keys(LINE_TYPE.SUBLINE).map((key, value) => LINE_TYPE.SUBLINE[key])
|
let innerLineTypes = Object.keys(LINE_TYPE.SUBLINE).map((key, value) => LINE_TYPE.SUBLINE[key])
|
||||||
polygon.innerLines = canvas
|
polygon.innerLines = canvas
|
||||||
@ -775,8 +782,7 @@ export const usePolygon = () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
innerLines = [...polygon.innerLines]
|
innerLines = [...polygon.innerLines]
|
||||||
}
|
}*/
|
||||||
|
|
||||||
canvas.renderAll()
|
canvas.renderAll()
|
||||||
let polygonLines = [...polygon.lines]
|
let polygonLines = [...polygon.lines]
|
||||||
const roofs = []
|
const roofs = []
|
||||||
@ -827,86 +833,104 @@ export const usePolygon = () => {
|
|||||||
line.endPoint = endPoint
|
line.endPoint = endPoint
|
||||||
})
|
})
|
||||||
|
|
||||||
polygonLines.forEach((line) => {
|
/*polygonLines.forEach((line) => {
|
||||||
line.set({ strokeWidth: 10 })
|
line.set({ strokeWidth: 10 })
|
||||||
canvas.add(line)
|
canvas.add(line)
|
||||||
})
|
})
|
||||||
canvas.renderAll()
|
canvas.renderAll()*/
|
||||||
|
|
||||||
polygonLines.forEach((line) => {
|
polygonLines.forEach((line) => {
|
||||||
|
/*const originStroke = line.stroke
|
||||||
|
line.set({ stroke: 'red' })
|
||||||
|
canvas.renderAll()*/
|
||||||
const intersections = []
|
const intersections = []
|
||||||
innerLines.forEach((innerLine) => {
|
innerLines.forEach((innerLine) => {
|
||||||
|
/*const originInnerStroke = innerLine.stroke
|
||||||
|
innerLine.set({ stroke: 'red' })
|
||||||
|
canvas.renderAll()*/
|
||||||
if (isPointOnLine(line, innerLine.startPoint)) {
|
if (isPointOnLine(line, innerLine.startPoint)) {
|
||||||
|
canvas.renderAll()
|
||||||
if (isSamePoint(line.startPoint, innerLine.startPoint) || isSamePoint(line.endPoint, innerLine.startPoint)) {
|
if (isSamePoint(line.startPoint, innerLine.startPoint) || isSamePoint(line.endPoint, innerLine.startPoint)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
intersections.push(innerLine.startPoint)
|
intersections.push(innerLine.startPoint)
|
||||||
}
|
}
|
||||||
if (isPointOnLine(line, innerLine.endPoint)) {
|
if (isPointOnLine(line, innerLine.endPoint)) {
|
||||||
|
canvas.renderAll()
|
||||||
if (isSamePoint(line.startPoint, innerLine.endPoint) || isSamePoint(line.endPoint, innerLine.endPoint)) {
|
if (isSamePoint(line.startPoint, innerLine.endPoint) || isSamePoint(line.endPoint, innerLine.endPoint)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
intersections.push(innerLine.endPoint)
|
intersections.push(innerLine.endPoint)
|
||||||
}
|
}
|
||||||
|
/*innerLine.set({ stroke: originInnerStroke })
|
||||||
|
canvas.renderAll()*/
|
||||||
})
|
})
|
||||||
line.set({ intersections })
|
line.set({ intersections })
|
||||||
|
|
||||||
|
/*line.set({ stroke: originStroke })
|
||||||
|
canvas.renderAll()*/
|
||||||
})
|
})
|
||||||
|
|
||||||
const divideLines = polygonLines.filter((line) => line.intersections.length > 0)
|
const divideLines = polygonLines.filter((line) => line.intersections?.length > 0)
|
||||||
let newLines = []
|
let newLines = []
|
||||||
|
polygonLines = polygonLines.filter((line) => !line.intersections || line.intersections.length === 0)
|
||||||
divideLines.forEach((line) => {
|
for (let i = divideLines.length - 1; i >= 0; i--) {
|
||||||
|
const line = divideLines[i]
|
||||||
const { intersections, startPoint, endPoint } = line
|
const { intersections, startPoint, endPoint } = line
|
||||||
|
|
||||||
if (intersections.length === 1) {
|
if (intersections.length === 1) {
|
||||||
// 한 점만 교차하는 경우
|
|
||||||
const newLinePoint1 = [line.x1, line.y1, intersections[0].x, intersections[0].y]
|
const newLinePoint1 = [line.x1, line.y1, intersections[0].x, intersections[0].y]
|
||||||
const newLinePoint2 = [intersections[0].x, intersections[0].y, line.x2, line.y2]
|
const newLinePoint2 = [intersections[0].x, intersections[0].y, line.x2, line.y2]
|
||||||
|
|
||||||
const newLine1 = new QLine(newLinePoint1, {
|
const newLine1 = new QLine(newLinePoint1, {
|
||||||
stroke: 'blue',
|
stroke: 'blue',
|
||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
attributes: line.attributes,
|
attributes: line.attributes,
|
||||||
|
name: 'newLine',
|
||||||
})
|
})
|
||||||
const newLine2 = new QLine(newLinePoint2, {
|
const newLine2 = new QLine(newLinePoint2, {
|
||||||
stroke: 'blue',
|
stroke: 'blue',
|
||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
attributes: line.attributes,
|
attributes: line.attributes,
|
||||||
|
name: 'newLine',
|
||||||
})
|
})
|
||||||
|
|
||||||
newLine1.attributes = {
|
newLine1.attributes = {
|
||||||
...line.attributes,
|
...line.attributes,
|
||||||
planeSize: Math.round(Math.sqrt(Math.pow(newLine1.x1 - newLine1.x2, 2) + Math.pow(newLine1.y1 - newLine1.y2, 2))) * 10,
|
planeSize: Math.round(Math.hypot(newLine1.x1 - newLine1.x2, newLine1.y1 - newLine1.y2)) * 10,
|
||||||
actualSize: Math.round(Math.sqrt(Math.pow(newLine1.x1 - newLine1.x2, 2) + Math.pow(newLine1.y1 - newLine1.y2, 2))) * 10,
|
actualSize: Math.round(Math.hypot(newLine1.x1 - newLine1.x2, newLine1.y1 - newLine1.y2)) * 10,
|
||||||
}
|
}
|
||||||
newLine2.attributes = {
|
newLine2.attributes = {
|
||||||
...line.attributes,
|
...line.attributes,
|
||||||
planeSize: Math.round(Math.sqrt(Math.pow(newLine2.x1 - newLine2.x2, 2) + Math.pow(newLine2.y1 - newLine2.y2, 2))) * 10,
|
planeSize: Math.round(Math.hypot(newLine2.x1 - newLine2.x2, newLine2.y1 - newLine2.y2)) * 10,
|
||||||
actualSize: Math.round(Math.sqrt(Math.pow(newLine2.x1 - newLine2.x2, 2) + Math.pow(newLine2.y1 - newLine2.y2, 2))) * 10,
|
actualSize: Math.round(Math.hypot(newLine2.x1 - newLine2.x2, newLine2.y1 - newLine2.y2)) * 10,
|
||||||
}
|
}
|
||||||
newLines.push(newLine1)
|
|
||||||
newLines.push(newLine2)
|
|
||||||
} else {
|
|
||||||
// 두 점 이상 교차하는 경우
|
|
||||||
//1. intersections중에 startPoint와 가장 가까운 점을 찾는다.
|
|
||||||
//2. 가장 가까운 점을 기준으로 line을 나눈다.
|
|
||||||
|
|
||||||
|
newLines.push(newLine1, newLine2)
|
||||||
|
divideLines.splice(i, 1) // 기존 line 제거
|
||||||
|
} else {
|
||||||
let currentPoint = startPoint
|
let currentPoint = startPoint
|
||||||
|
|
||||||
while (intersections.length !== 0) {
|
while (intersections.length !== 0) {
|
||||||
const minDistancePoint = findAndRemoveClosestPoint(currentPoint, intersections)
|
const minDistancePoint = findAndRemoveClosestPoint(currentPoint, intersections)
|
||||||
const newLinePoint = [currentPoint.x, currentPoint.y, minDistancePoint.x, minDistancePoint.y]
|
const newLinePoint = [currentPoint.x, currentPoint.y, minDistancePoint.x, minDistancePoint.y]
|
||||||
|
|
||||||
const newLine = new QLine(newLinePoint, {
|
const newLine = new QLine(newLinePoint, {
|
||||||
stroke: 'blue',
|
stroke: 'blue',
|
||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
attributes: line.attributes,
|
attributes: line.attributes,
|
||||||
|
name: 'newLine',
|
||||||
})
|
})
|
||||||
|
|
||||||
newLine.attributes = {
|
newLine.attributes = {
|
||||||
...line.attributes,
|
...line.attributes,
|
||||||
planeSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10,
|
planeSize: Math.round(Math.hypot(newLine.x1 - newLine.x2, newLine.y1 - newLine.y2)) * 10,
|
||||||
actualSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10,
|
actualSize: Math.round(Math.hypot(newLine.x1 - newLine.x2, newLine.y1 - newLine.y2)) * 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
newLines.push(newLine)
|
newLines.push(newLine)
|
||||||
currentPoint = minDistancePoint
|
currentPoint = minDistancePoint
|
||||||
}
|
}
|
||||||
@ -917,21 +941,66 @@ export const usePolygon = () => {
|
|||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
attributes: line.attributes,
|
attributes: line.attributes,
|
||||||
|
name: 'newLine',
|
||||||
})
|
})
|
||||||
newLine.attributes = {
|
newLine.attributes = {
|
||||||
...line.attributes,
|
...line.attributes,
|
||||||
planeSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10,
|
planeSize: Math.round(Math.hypot(newLine.x1 - newLine.x2, newLine.y1 - newLine.y2)) * 10,
|
||||||
actualSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10,
|
actualSize: Math.round(Math.hypot(newLine.x1 - newLine.x2, newLine.y1 - newLine.y2)) * 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
newLines.push(newLine)
|
newLines.push(newLine)
|
||||||
|
divideLines.splice(i, 1) // 기존 line 제거
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
//polygonLines에서 divideLines를 제거하고 newLines를 추가한다.
|
//polygonLines에서 divideLines를 제거하고 newLines를 추가한다.
|
||||||
polygonLines = polygonLines.filter((line) => !divideLines.includes(line))
|
newLines = newLines.filter((line) => !(Math.abs(line.startPoint.x - line.endPoint.x) < 1 && Math.abs(line.startPoint.y - line.endPoint.y) < 1))
|
||||||
|
|
||||||
polygonLines = [...polygonLines, ...newLines]
|
polygonLines = [...polygonLines, ...newLines]
|
||||||
|
|
||||||
const allLines = [...polygonLines, ...innerLines]
|
let allLines = [...polygonLines, ...innerLines]
|
||||||
|
|
||||||
|
/*allLines.forEach((line) => {
|
||||||
|
const originColor = line.stroke
|
||||||
|
|
||||||
|
line.set('stroke', 'red')
|
||||||
|
canvas.renderAll()
|
||||||
|
|
||||||
|
line.set('stroke', originColor)
|
||||||
|
canvas.renderAll()
|
||||||
|
})*/
|
||||||
|
|
||||||
|
const allPoints = []
|
||||||
|
|
||||||
|
// test용 좌표
|
||||||
|
const polygonLinesPoints = polygonLines.map((line) => {
|
||||||
|
return { startPoint: line.startPoint, endPoint: line.endPoint }
|
||||||
|
})
|
||||||
|
|
||||||
|
const innerLinesPoints = innerLines.map((line) => {
|
||||||
|
return { startPoint: line.startPoint, endPoint: line.endPoint }
|
||||||
|
})
|
||||||
|
|
||||||
|
polygonLinesPoints.forEach(({ startPoint, endPoint }) => {
|
||||||
|
allPoints.push(startPoint)
|
||||||
|
allPoints.push(endPoint)
|
||||||
|
})
|
||||||
|
|
||||||
|
innerLinesPoints.forEach(({ startPoint, endPoint }) => {
|
||||||
|
allPoints.push(startPoint)
|
||||||
|
allPoints.push(endPoint)
|
||||||
|
})
|
||||||
|
|
||||||
|
// allPoints에서 중복을 제거한다.
|
||||||
|
const uniquePoints = allPoints.filter((point, index, self) => {
|
||||||
|
return (
|
||||||
|
index ===
|
||||||
|
self.findIndex((p) => {
|
||||||
|
return isSamePoint(p, point)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
// 2025-02-19 대각선은 케라바, 직선은 용마루로 세팅
|
// 2025-02-19 대각선은 케라바, 직선은 용마루로 세팅
|
||||||
innerLines.forEach((innerLine) => {
|
innerLines.forEach((innerLine) => {
|
||||||
@ -956,6 +1025,13 @@ export const usePolygon = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/*innerLines.forEach((line) => {
|
||||||
|
const startPoint = line.startPoint
|
||||||
|
const endPoint = line.endPoint
|
||||||
|
/!*canvas.add(new fabric.Circle({ left: startPoint.x, top: startPoint.y + 10, radius: 5, fill: 'red' }))
|
||||||
|
canvas.add(new fabric.Circle({ left: endPoint.x, top: endPoint.y - 10, radius: 5, fill: 'blue' }))*!/
|
||||||
|
})*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 왼쪽 상단을 startPoint로 전부 변경
|
* 왼쪽 상단을 startPoint로 전부 변경
|
||||||
*/
|
*/
|
||||||
@ -982,102 +1058,18 @@ export const usePolygon = () => {
|
|||||||
line.endPoint = endPoint
|
line.endPoint = endPoint
|
||||||
})
|
})
|
||||||
|
|
||||||
// polygon line에서 각각 출발한다.
|
//allLines에서 중복을 제거한다.
|
||||||
polygonLines.forEach((line) => {
|
allLines = allLines.filter((line, index, self) => {
|
||||||
/*line.set({ strokeWidth: 5, stroke: 'green' })
|
return (
|
||||||
canvas.add(line)
|
index ===
|
||||||
canvas.renderAll()*/
|
self.findIndex((l) => {
|
||||||
const startPoint = { ...line.startPoint } // 시작점
|
return isSamePoint(l.startPoint, line.startPoint) && isSamePoint(l.endPoint, line.endPoint)
|
||||||
let arrivalPoint = { ...line.endPoint } // 도착점
|
|
||||||
|
|
||||||
let currentPoint = startPoint
|
|
||||||
let roofPoints = [startPoint]
|
|
||||||
|
|
||||||
let startLine = line
|
|
||||||
let visitPoints = [startPoint]
|
|
||||||
let visitLines = [startLine]
|
|
||||||
let notVisitedLines = []
|
|
||||||
let cnt = 0
|
|
||||||
|
|
||||||
while (!isSamePoint(currentPoint, arrivalPoint)) {
|
|
||||||
//현재 점으로 부터 갈 수 있는 다른 라인을 찾는다.
|
|
||||||
let nextLines = allLines.filter(
|
|
||||||
(line2) =>
|
|
||||||
(isSamePoint(line2.startPoint, currentPoint) || isSamePoint(line2.endPoint, currentPoint)) &&
|
|
||||||
line !== line2 &&
|
|
||||||
innerLines.includes(line2) &&
|
|
||||||
!visitLines.includes(line2),
|
|
||||||
)
|
|
||||||
|
|
||||||
if (nextLines.length === 0) {
|
|
||||||
nextLines = allLines.filter(
|
|
||||||
(line2) =>
|
|
||||||
(isSamePoint(line2.startPoint, currentPoint) || isSamePoint(line2.endPoint, currentPoint)) &&
|
|
||||||
line !== line2 &&
|
|
||||||
!visitLines.includes(line2),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextLines.length === 0) {
|
|
||||||
//아직 안갔던 line중 0번째를 선택한다.
|
|
||||||
if (notVisitedLines.length === 0) {
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
let notVisitedLine = notVisitedLines.shift()
|
|
||||||
roofPoints = [...notVisitedLine.roofPoints]
|
|
||||||
currentPoint = { ...notVisitedLine.currentPoint }
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let comparisonPoints = []
|
|
||||||
|
|
||||||
nextLines.forEach((nextLine) => {
|
|
||||||
if (isSamePoint(nextLine.startPoint, currentPoint)) {
|
|
||||||
comparisonPoints.push(nextLine.endPoint)
|
|
||||||
} else {
|
|
||||||
comparisonPoints.push(nextLine.startPoint)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
)
|
||||||
comparisonPoints = comparisonPoints.filter((point) => !visitPoints.some((visitPoint) => isSamePoint(visitPoint, point)))
|
|
||||||
comparisonPoints = comparisonPoints.filter((point) => !isSamePoint(point, currentPoint))
|
|
||||||
|
|
||||||
const minDistancePoint = comparisonPoints.reduce((prev, current) => {
|
|
||||||
const prevDistance = Math.sqrt(Math.pow(prev.x - arrivalPoint.x, 2) + Math.pow(prev.y - arrivalPoint.y, 2))
|
|
||||||
const currentDistance = Math.sqrt(Math.pow(current.x - arrivalPoint.x, 2) + Math.pow(current.y - arrivalPoint.y, 2))
|
|
||||||
|
|
||||||
return prevDistance < currentDistance ? prev : current
|
|
||||||
}, comparisonPoints[0])
|
|
||||||
|
|
||||||
nextLines.forEach((nextLine) => {
|
|
||||||
if (isSamePoint(nextLine.startPoint, minDistancePoint) || isSamePoint(nextLine.endPoint, minDistancePoint)) {
|
|
||||||
visitLines.push(nextLine)
|
|
||||||
} else {
|
|
||||||
notVisitedLines.push({
|
|
||||||
line: nextLine,
|
|
||||||
endPoint: nextLine.endPoint,
|
|
||||||
startPoint: nextLine.startPoint,
|
|
||||||
currentPoint: { ...currentPoint },
|
|
||||||
roofPoints: [...roofPoints],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
currentPoint = { ...minDistancePoint }
|
|
||||||
roofPoints.push(currentPoint)
|
|
||||||
cnt++
|
|
||||||
|
|
||||||
if (cnt > 100) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
roofs.push(roofPoints)
|
|
||||||
canvas.remove(line)
|
|
||||||
canvas.renderAll()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const newRoofs = removeDuplicatePolygons(roofs.filter((roof) => roof.length < 100))
|
// 나눠서 중복 제거된 roof return
|
||||||
|
const newRoofs = getSplitRoofsPoints(allLines)
|
||||||
|
|
||||||
newRoofs.forEach((roofPoint, index) => {
|
newRoofs.forEach((roofPoint, index) => {
|
||||||
let defense, pitch
|
let defense, pitch
|
||||||
@ -1108,7 +1100,7 @@ export const usePolygon = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// blue로 생성된 것들은 대표라인이 될 수 없음.
|
// blue로 생성된 것들은 대표라인이 될 수 없음.
|
||||||
representLines = representLines.filter((line) => line.stroke !== 'blue')
|
// representLines = representLines.filter((line) => line.stroke !== 'blue')
|
||||||
// representLines중 가장 긴 line을 찾는다.
|
// representLines중 가장 긴 line을 찾는다.
|
||||||
representLines.forEach((line) => {
|
representLines.forEach((line) => {
|
||||||
if (!representLine) {
|
if (!representLine) {
|
||||||
@ -1119,7 +1111,7 @@ export const usePolygon = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const direction = polygon.direction ?? representLine.direction
|
const direction = polygon.direction ?? representLine?.direction
|
||||||
const polygonDirection = polygon.direction
|
const polygonDirection = polygon.direction
|
||||||
|
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
@ -1135,8 +1127,11 @@ export const usePolygon = () => {
|
|||||||
case 'left':
|
case 'left':
|
||||||
defense = 'north'
|
defense = 'north'
|
||||||
break
|
break
|
||||||
|
default:
|
||||||
|
defense = 'south'
|
||||||
|
break
|
||||||
}
|
}
|
||||||
pitch = polygon.lines[index].attributes?.pitch ?? 0
|
pitch = polygon.lines[index]?.attributes?.pitch ?? 0
|
||||||
|
|
||||||
const roof = new QPolygon(roofPoint, {
|
const roof = new QPolygon(roofPoint, {
|
||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
@ -1172,10 +1167,144 @@ export const usePolygon = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
canvas.add(roof)
|
canvas.add(roof)
|
||||||
addLengthText(roof)
|
// addLengthText(roof)
|
||||||
canvas.remove(polygon)
|
canvas.remove(polygon)
|
||||||
canvas.renderAll()
|
canvas.renderAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//지붕 완료 후 보조선을 전부 제거한다.
|
||||||
|
const auxiliaryLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine')
|
||||||
|
|
||||||
|
auxiliaryLines.forEach((line) => {
|
||||||
|
canvas.remove(line)
|
||||||
|
})
|
||||||
|
canvas.renderAll()
|
||||||
|
canvas.discardActiveObject()
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSplitRoofsPoints = (allLines) => {
|
||||||
|
// ==== Utility functions ====
|
||||||
|
|
||||||
|
function isSamePoint(p1, p2, epsilon = 1) {
|
||||||
|
return Math.abs(p1.x - p2.x) <= 2 && Math.abs(p1.y - p2.y) <= 2
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePoint(p, epsilon = 1) {
|
||||||
|
return {
|
||||||
|
x: Math.round(p.x / epsilon) * epsilon,
|
||||||
|
y: Math.round(p.y / epsilon) * epsilon,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pointToKey(p, epsilon = 1) {
|
||||||
|
const norm = normalizePoint(p, epsilon)
|
||||||
|
return `${norm.x},${norm.y}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 거리 계산
|
||||||
|
function calcDistance(p1, p2) {
|
||||||
|
return Math.hypot(p2.x - p1.x, p2.y - p1.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==== Direct edge check ====
|
||||||
|
|
||||||
|
function isDirectlyConnected(start, end, graph, epsilon = 1) {
|
||||||
|
const startKey = pointToKey(start, epsilon)
|
||||||
|
return (graph[startKey] || []).some((neighbor) => isSamePoint(neighbor.point, end, epsilon))
|
||||||
|
}
|
||||||
|
// ==== Dijkstra pathfinding ====
|
||||||
|
|
||||||
|
function findShortestPath(start, end, graph, epsilon = 1) {
|
||||||
|
const startKey = pointToKey(start, epsilon)
|
||||||
|
const endKey = pointToKey(end, epsilon)
|
||||||
|
|
||||||
|
const distances = {}
|
||||||
|
const previous = {}
|
||||||
|
const visited = new Set()
|
||||||
|
const queue = [{ key: startKey, dist: 0 }]
|
||||||
|
|
||||||
|
for (const key in graph) distances[key] = Infinity
|
||||||
|
distances[startKey] = 0
|
||||||
|
|
||||||
|
while (queue.length > 0) {
|
||||||
|
queue.sort((a, b) => a.dist - b.dist)
|
||||||
|
const { key } = queue.shift()
|
||||||
|
if (visited.has(key)) continue
|
||||||
|
visited.add(key)
|
||||||
|
|
||||||
|
for (const neighbor of graph[key] || []) {
|
||||||
|
const neighborKey = pointToKey(neighbor.point, epsilon)
|
||||||
|
const alt = distances[key] + neighbor.distance
|
||||||
|
if (alt < distances[neighborKey]) {
|
||||||
|
distances[neighborKey] = alt
|
||||||
|
previous[neighborKey] = key
|
||||||
|
queue.push({ key: neighborKey, dist: alt })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const path = []
|
||||||
|
let currentKey = endKey
|
||||||
|
|
||||||
|
if (!previous[currentKey]) return null
|
||||||
|
|
||||||
|
while (currentKey !== startKey) {
|
||||||
|
const [x, y] = currentKey.split(',').map(Number)
|
||||||
|
path.unshift({ x, y })
|
||||||
|
currentKey = previous[currentKey]
|
||||||
|
}
|
||||||
|
|
||||||
|
const [sx, sy] = startKey.split(',').map(Number)
|
||||||
|
path.unshift({ x: sx, y: sy })
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
// 최종 함수
|
||||||
|
function getPath(start, end, graph, epsilon = 1) {
|
||||||
|
if (isDirectlyConnected(start, end, graph, epsilon)) {
|
||||||
|
console.log('직선 연결 있음. 무시.')
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const path = findShortestPath(start, end, graph, epsilon)
|
||||||
|
if (!path || path.length < 3) {
|
||||||
|
console.log('경로 존재하나 3개 미만 좌표. 무시.')
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
const roofs = []
|
||||||
|
|
||||||
|
allLines.forEach((line) => {
|
||||||
|
// 그래프 생성
|
||||||
|
const graph = {}
|
||||||
|
const edges = allLines
|
||||||
|
.filter((line2) => line !== line2)
|
||||||
|
.map((line) => {
|
||||||
|
return [line.startPoint, line.endPoint]
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const [p1, p2] of edges) {
|
||||||
|
const key1 = pointToKey(p1)
|
||||||
|
const key2 = pointToKey(p2)
|
||||||
|
const distance = calcDistance(p1, p2)
|
||||||
|
|
||||||
|
if (!graph[key1]) graph[key1] = []
|
||||||
|
if (!graph[key2]) graph[key2] = []
|
||||||
|
|
||||||
|
graph[key1].push({ point: p2, distance })
|
||||||
|
graph[key2].push({ point: p1, distance })
|
||||||
|
}
|
||||||
|
|
||||||
|
const startPoint = { ...line.startPoint } // 시작점
|
||||||
|
let arrivalPoint = { ...line.endPoint } // 도착점
|
||||||
|
roofs.push(getPath(startPoint, arrivalPoint, graph))
|
||||||
|
})
|
||||||
|
|
||||||
|
return removeDuplicatePolygons(roofs.filter((roof) => roof.length < 100))
|
||||||
}
|
}
|
||||||
|
|
||||||
const splitPolygonWithSeparate = (separates) => {
|
const splitPolygonWithSeparate = (separates) => {
|
||||||
|
|||||||
@ -360,16 +360,16 @@ export const calculateIntersection = (line1, line2) => {
|
|||||||
|
|
||||||
// Check if the intersection X and Y are within the range of both lines
|
// Check if the intersection X and Y are within the range of both lines
|
||||||
if (
|
if (
|
||||||
result[0] >= line1MinX &&
|
result[0] >= line1MinX - 1 &&
|
||||||
result[0] <= line1MaxX &&
|
result[0] <= line1MaxX + 1 &&
|
||||||
result[0] >= line2MinX &&
|
result[0] >= line2MinX - 1 &&
|
||||||
result[0] <= line2MaxX &&
|
result[0] <= line2MaxX + 1 &&
|
||||||
result[1] >= line1MinY &&
|
result[1] >= line1MinY - 1 &&
|
||||||
result[1] <= line1MaxY &&
|
result[1] <= line1MaxY + 1 &&
|
||||||
result[1] >= line2MinY &&
|
result[1] >= line2MinY - 1 &&
|
||||||
result[1] <= line2MaxY
|
result[1] <= line2MaxY + 1
|
||||||
) {
|
) {
|
||||||
return { x: Math.round(result[0]), y: Math.round(result[1]) }
|
return { x: result[0], y: result[1] }
|
||||||
} else {
|
} else {
|
||||||
return null // Intersection is out of range
|
return null // Intersection is out of range
|
||||||
}
|
}
|
||||||
@ -515,24 +515,39 @@ export const sortedPointLessEightPoint = (points) => {
|
|||||||
* @param line
|
* @param line
|
||||||
* @param point
|
* @param point
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
|
* @param epsilon
|
||||||
*/
|
*/
|
||||||
// 직선의 방정식.
|
// 직선의 방정식.
|
||||||
// 방정식은 ax + by + c = 0이며, 점의 좌표를 대입하여 계산된 값은 직선과 점 사이의 관계를 나타낸다.
|
// 방정식은 ax + by + c = 0이며, 점의 좌표를 대입하여 계산된 값은 직선과 점 사이의 관계를 나타낸다.
|
||||||
export function isPointOnLine({ x1, y1, x2, y2 }, { x, y }) {
|
export function isPointOnLine({ x1, y1, x2, y2 }, { x, y }, epsilon = 2) {
|
||||||
/*const a = line.y2 - line.y1
|
/*const a = y2 - y1
|
||||||
|
const b = x1 - x2
|
||||||
|
const c = x2 * y1 - x1 * y2
|
||||||
|
return Math.abs(a * x + b * y + c) < 1000*/
|
||||||
|
/*/!*const a = line.y2 - line.y1
|
||||||
const b = line.x1 - line.x2
|
const b = line.x1 - line.x2
|
||||||
const c = line.x2 * line.y1 - line.x1 * line.y2
|
const c = line.x2 * line.y1 - line.x1 * line.y2
|
||||||
const result = Math.abs(a * point.x + b * point.y + c) / 100
|
const result = Math.abs(a * point.x + b * point.y + c) / 100
|
||||||
|
|
||||||
// 점이 선 위에 있는지 확인
|
// 점이 선 위에 있는지 확인
|
||||||
return result <= 10*/
|
return result <= 10*!*/
|
||||||
// 직선 방정식 만족 여부 확인
|
// 직선 방정식 만족 여부 확인
|
||||||
const crossProduct = (y - y1) * (x2 - x1) - (x - x1) * (y2 - y1)
|
const crossProduct = (y - y1) * (x2 - x1) - (x - x1) * (y2 - y1)
|
||||||
if (Math.abs(crossProduct) > 5) return false // 작은 오차 허용
|
if (Math.abs(crossProduct) > 1000) return false // 작은 오차 허용
|
||||||
|
|
||||||
|
const isSameX = Math.abs(x1 - x2) < 2
|
||||||
|
const isSameY = Math.abs(y1 - y2) < 2
|
||||||
|
|
||||||
// 점이 선분의 범위 내에 있는지 확인
|
// 점이 선분의 범위 내에 있는지 확인
|
||||||
const withinXRange = Math.min(x1, x2) <= x && x <= Math.max(x1, x2)
|
let withinXRange = Math.min(x1, x2) - x <= 2
|
||||||
const withinYRange = Math.min(y1, y2) <= y && y <= Math.max(y1, y2)
|
if (!isSameX) {
|
||||||
|
withinXRange = withinXRange && 2 <= Math.max(x1, x2) - x
|
||||||
|
}
|
||||||
|
|
||||||
|
let withinYRange = Math.min(y1, y2) - y <= 2
|
||||||
|
if (!isSameY) {
|
||||||
|
withinYRange = withinYRange && 2 <= Math.max(y1, y2) - y
|
||||||
|
}
|
||||||
|
|
||||||
return withinXRange && withinYRange
|
return withinXRange && withinYRange
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user