치도리 배치 기능
This commit is contained in:
parent
da90a6d26a
commit
76af0e208d
@ -35,6 +35,12 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
|
||||
}
|
||||
}, [])
|
||||
|
||||
const placementRef = {
|
||||
isChidori: useRef('true'),
|
||||
setupLocation: useRef(null),
|
||||
isMaxSetup: useRef('false'),
|
||||
}
|
||||
|
||||
return (
|
||||
<WithDraggable isShow={true} pos={pos}>
|
||||
<div className={`modal-pop-wrap lx-2`}>
|
||||
@ -55,7 +61,7 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
|
||||
{tabNum === 1 && <Orientation ref={orientationRef} tabNum={tabNum} setTabNum={setTabNum} />}
|
||||
{/*배치면 초기설정 - 입력방법: 복시도 입력 || 실측값 입력*/}
|
||||
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet != 3 && tabNum === 2 && <Module setTabNum={setTabNum} />}
|
||||
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet != 3 && tabNum === 3 && <Placement setTabNum={setTabNum} />}
|
||||
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet != 3 && tabNum === 3 && <Placement setTabNum={setTabNum} ref={placementRef} />}
|
||||
|
||||
{/*배치면 초기설정 - 입력방법: 육지붕*/}
|
||||
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet == 3 && tabNum === 2 && <PitchModule setTabNum={setTabNum} />}
|
||||
@ -78,7 +84,7 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
|
||||
<button className="btn-frame modal mr5" onClick={manualModuleSetup}>
|
||||
{getMessage('modal.module.basic.setting.passivity.placement')}
|
||||
</button>
|
||||
<button className="btn-frame modal act" onClick={autoModuleSetup}>
|
||||
<button className="btn-frame modal act" onClick={() => autoModuleSetup(placementRef)}>
|
||||
{getMessage('modal.module.basic.setting.auto.placement')}
|
||||
</button>
|
||||
</>
|
||||
|
||||
@ -1,7 +1,12 @@
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { forwardRef, useState } from 'react'
|
||||
|
||||
export default function Placement() {
|
||||
const Placement = forwardRef((props, refs) => {
|
||||
const { getMessage } = useMessage()
|
||||
const [isChidori, setIsChidori] = useState('true')
|
||||
|
||||
console.log(refs)
|
||||
|
||||
const moduleData = {
|
||||
header: [
|
||||
{ type: 'check', name: '', prop: 'check', width: 70 },
|
||||
@ -24,6 +29,12 @@ export default function Placement() {
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const handleChangeChidori = (e) => {
|
||||
setIsChidori(e.target.value)
|
||||
refs.isChidori.current = e.target.value
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="module-table-flex-wrap mb10">
|
||||
@ -96,12 +107,20 @@ export default function Placement() {
|
||||
<div className="self-item-td">
|
||||
<div className="pop-form-radio">
|
||||
<div className="d-check-radio pop">
|
||||
<input type="radio" name="radio01" id="ra01" />
|
||||
<input
|
||||
type="radio"
|
||||
name="radio01"
|
||||
id="ra01"
|
||||
defaultChecked
|
||||
checked={isChidori === 'true'}
|
||||
value={'true'}
|
||||
onChange={handleChangeChidori}
|
||||
/>
|
||||
<label htmlFor="ra01">{getMessage('modal.module.basic.setting.module.placement.do')}</label>
|
||||
</div>
|
||||
<div className="d-check-radio pop">
|
||||
<input type="radio" name="radio01" id="ra02" />
|
||||
<label htmlFor="ra01">{getMessage('modal.module.basic.setting.module.placement.do.not')}</label>
|
||||
<input type="radio" name="radio02" id="ra02" value={'false'} checked={isChidori === 'false'} onChange={handleChangeChidori} />
|
||||
<label htmlFor="ra02">{getMessage('modal.module.basic.setting.module.placement.do.not')}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -137,4 +156,6 @@ export default function Placement() {
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
export default Placement
|
||||
|
||||
@ -31,7 +31,7 @@ export function useModuleBasicSetting() {
|
||||
setSurfaceShapePattern(roof, roofDisplay.column, true) //패턴 변경
|
||||
const offsetPoints = offsetPolygon(roof.points, -20) //안쪽 offset
|
||||
//모듈설치영역?? 생성
|
||||
const setupSurface = new QPolygon(offsetPoints, {
|
||||
let setupSurface = new QPolygon(offsetPoints, {
|
||||
stroke: 'red',
|
||||
fill: 'transparent',
|
||||
strokeDashArray: [10, 4],
|
||||
@ -45,6 +45,8 @@ export function useModuleBasicSetting() {
|
||||
parentId: roof.id, //가대 폴리곤의 임시 인덱스를 넣어줌
|
||||
name: POLYGON_TYPE.MODULE_SETUP_SURFACE,
|
||||
flowDirection: roof.direction,
|
||||
flipX: roof.flipX,
|
||||
flipY: roof.flipY,
|
||||
})
|
||||
|
||||
setupSurface.setViewLengthText(false)
|
||||
@ -65,7 +67,6 @@ export function useModuleBasicSetting() {
|
||||
//설치 범위 지정 클릭 이벤트
|
||||
const toggleSelection = (setupSurface) => {
|
||||
console.log('setupSurface', setupSurface)
|
||||
|
||||
const isExist = selectedModuleInstSurfaceArray.some((obj) => obj.parentId === setupSurface.parentId)
|
||||
//최초 선택일때
|
||||
if (!isExist) {
|
||||
@ -380,7 +381,9 @@ export function useModuleBasicSetting() {
|
||||
}
|
||||
|
||||
//자동 모듈 설치(그리드 방식)
|
||||
const autoModuleSetup = () => {
|
||||
const autoModuleSetup = (placementRef) => {
|
||||
const isChidori = placementRef.isChidori.current
|
||||
|
||||
initEvent()
|
||||
const moduleSetupSurfaces = moduleSetupSurface //선택 설치면
|
||||
|
||||
@ -405,6 +408,9 @@ export function useModuleBasicSetting() {
|
||||
|
||||
if (moduleIsSetup.length > 0) {
|
||||
alert('기존 모듈은 제거됩니다.')
|
||||
moduleIsSetup.forEach((module) => {
|
||||
canvas?.remove(module)
|
||||
})
|
||||
}
|
||||
|
||||
notSelectedTrestlePolygons.forEach((obj) => {
|
||||
@ -484,16 +490,11 @@ export function useModuleBasicSetting() {
|
||||
width = moduleSetupSurface.flowDirection === 'south' || moduleSetupSurface.flowDirection === 'north' ? 172.2 : 113.4
|
||||
height = moduleSetupSurface.flowDirection === 'south' || moduleSetupSurface.flowDirection === 'north' ? 113.4 : 172.2
|
||||
}
|
||||
const cols = Math.floor((bbox[2] - bbox[0]) / width)
|
||||
const rows = Math.floor((bbox[3] - bbox[1]) / height)
|
||||
let cols = Math.floor((bbox[2] - bbox[0]) / width)
|
||||
let rows = Math.floor((bbox[3] - bbox[1]) / height)
|
||||
|
||||
// cols = cols * 2
|
||||
|
||||
let startCoords = { x: 0, y: 0 }
|
||||
if (moduleSetupSurface.flowDirection === 'south') {
|
||||
startCoords = {
|
||||
x: surfaceBbox.minX,
|
||||
y: surfaceBbox.maxY,
|
||||
}
|
||||
}
|
||||
for (let col = 0; col <= cols; col++) {
|
||||
for (let row = 0; row <= rows; row++) {
|
||||
let x = 0,
|
||||
@ -530,13 +531,43 @@ export function useModuleBasicSetting() {
|
||||
x = bbox[0] + col * width
|
||||
y = bbox[1] + row * height
|
||||
}
|
||||
square = [
|
||||
[x, y],
|
||||
[x + width, y],
|
||||
[x + width, y + height],
|
||||
[x, y + height],
|
||||
[x, y],
|
||||
]
|
||||
|
||||
if (isChidori === 'true') {
|
||||
if (row % 2 !== 0) {
|
||||
square = [
|
||||
[x, y],
|
||||
[x + width, y],
|
||||
[x + width, y + height],
|
||||
[x, y + height],
|
||||
[x, y],
|
||||
]
|
||||
} else {
|
||||
square = [
|
||||
[x - width / 2, y],
|
||||
[x - width / 2 + width, y],
|
||||
[x - width / 2 + width, y + height],
|
||||
[x - width / 2, y + height],
|
||||
[x - width / 2, y],
|
||||
]
|
||||
}
|
||||
} else {
|
||||
square = [
|
||||
[x, y],
|
||||
[x + width, y],
|
||||
[x + width, y + height],
|
||||
[x, y + height],
|
||||
[x, y],
|
||||
]
|
||||
}
|
||||
|
||||
// square = [
|
||||
// [x - width / 2, y],
|
||||
// [x - width / 2 + width, y],
|
||||
// [x - width / 2 + width, y + height],
|
||||
// [x - width / 2, y + height],
|
||||
// [x - width / 2, y],
|
||||
// ]
|
||||
|
||||
const squarePolygon = turf.polygon([square])
|
||||
const disjointFromTrestle =
|
||||
turf.booleanContains(turfModuleSetupSurface, squarePolygon) || turf.booleanWithin(squarePolygon, turfModuleSetupSurface)
|
||||
@ -720,7 +751,7 @@ export function useModuleBasicSetting() {
|
||||
)
|
||||
}
|
||||
|
||||
function batchObjectGroupToTurfPolygon(group) {
|
||||
const batchObjectGroupToTurfPolygon = (group) => {
|
||||
const polygons = group.getObjects().filter((obj) => obj.type === 'QPolygon')
|
||||
let allPoints = []
|
||||
|
||||
@ -732,32 +763,76 @@ export function useModuleBasicSetting() {
|
||||
return hull
|
||||
}
|
||||
|
||||
//도형의 내각을 구하는 로직
|
||||
function calculateInteriorAngles(polygon) {
|
||||
const points = polygon.get('points')
|
||||
const angles = []
|
||||
function calculatePerpendicularLine(hypotenuseStart, hypotenuseEnd, height) {
|
||||
const { x: x1, y: y1 } = hypotenuseStart
|
||||
const { x: x2, y: y2 } = hypotenuseEnd
|
||||
|
||||
for (let i = 0; i < points.length; i++) {
|
||||
// 현재 점과 이전 및 다음 점 정의
|
||||
const current = points[i]
|
||||
const prev = points[(i - 1 + points.length) % points.length]
|
||||
const next = points[(i + 1) % points.length]
|
||||
// 1. 빗변의 기울기 계산
|
||||
const slope = (y2 - y1) / (x2 - x1)
|
||||
|
||||
// 벡터 계산
|
||||
const vecA = { x: prev.x - current.x, y: prev.y - current.y }
|
||||
const vecB = { x: next.x - current.x, y: next.y - current.y }
|
||||
// 2. 중점 계산
|
||||
const xC = (x1 + x2) / 2
|
||||
const yC = (y1 + y2) / 2
|
||||
|
||||
// 두 벡터 간 각도 계산
|
||||
const dotProduct = vecA.x * vecB.x + vecA.y * vecB.y
|
||||
const magA = Math.sqrt(vecA.x * vecA.x + vecA.y * vecA.y)
|
||||
const magB = Math.sqrt(vecB.x * vecB.x + vecB.y * vecB.y)
|
||||
const angleRad = Math.acos(dotProduct / (magA * magB))
|
||||
const angleDeg = (angleRad * 180) / Math.PI
|
||||
// 3. 수직 기울기의 정규화 인자 계산
|
||||
const norm = Math.sqrt(1 + Math.pow(slope, 2))
|
||||
|
||||
// 내부 각도 저장
|
||||
angles.push(180 - angleDeg)
|
||||
// 4. 수직선의 끝점 계산
|
||||
const xOffset = -height / norm
|
||||
const yOffset = (height * slope) / norm
|
||||
|
||||
const point1 = { x: xC + xOffset, y: yC + yOffset }
|
||||
const point2 = { x: xC - xOffset, y: yC - yOffset }
|
||||
|
||||
return { point1, point2 }
|
||||
}
|
||||
|
||||
// 예제 사용
|
||||
const hypotenuseStart = { x: 2, y: 3 }
|
||||
const hypotenuseEnd = { x: 8, y: 9 }
|
||||
const height = 4
|
||||
|
||||
const result = calculatePerpendicularLine(hypotenuseStart, hypotenuseEnd, height)
|
||||
console.log(result)
|
||||
|
||||
const calcMinXByHeightDistance = (surface) => {
|
||||
let minXIndex = surface.lines.reduce((minIdx, current, index, arr) => {
|
||||
console.log('reduce', minIdx, current, index, arr)
|
||||
|
||||
return current.x1 < arr[minIdx].x1 ? index : minIdx
|
||||
}, surface.lines[0].x1)
|
||||
|
||||
console.log('minXIndex', minXIndex)
|
||||
|
||||
function calculateIntersection(diagonalA, lineB) {
|
||||
// Diagonal A coordinates
|
||||
const { x1: ax1, y1: ay1, x2: ax2, y2: ay2 } = diagonalA
|
||||
|
||||
// Line B coordinates
|
||||
const { x2: bx2, y2: by2 } = lineB
|
||||
|
||||
// Calculate slope (m) and intercept (c) for diagonal A
|
||||
const slopeA = (ay2 - ay1) / (ax2 - ax1)
|
||||
const interceptA = ay1 - slopeA * ax1
|
||||
|
||||
// Use fixed y (from lineB's y2)
|
||||
const yFixed = by2
|
||||
|
||||
// Calculate x on diagonal A where y = yFixed
|
||||
const xFixed = (yFixed - interceptA) / slopeA
|
||||
|
||||
// Return the intersection point
|
||||
return { x: xFixed, y: yFixed }
|
||||
}
|
||||
return angles
|
||||
|
||||
console.log('line', line)
|
||||
|
||||
// Example usage:
|
||||
const diagonalA = { x1: 490.4, y1: 94.7, x2: 303.7, y2: 654.7 }
|
||||
const lineB = { x1: 303.7, y1: 654.7, x2: 303.7, y2: 541.3 }
|
||||
|
||||
const intersection = calculateIntersection(diagonalA, lineB)
|
||||
console.log(`Intersection point: x = ${intersection.x}, y = ${intersection.y}`)
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@ -102,6 +102,15 @@ export function useSurfaceShapeBatch() {
|
||||
|
||||
canvas?.add(obj)
|
||||
|
||||
canvas?.renderAll()
|
||||
closePopup(id)
|
||||
})
|
||||
|
||||
addCanvasMouseEventListener('mouse:down', (e) => {
|
||||
isDrawing = false
|
||||
|
||||
canvas?.remove(obj)
|
||||
|
||||
//각도 추가
|
||||
let originAngle = 0 //기본 남쪽
|
||||
let direction = 'south'
|
||||
@ -119,21 +128,31 @@ export function useSurfaceShapeBatch() {
|
||||
direction = 'north'
|
||||
}
|
||||
|
||||
obj.set({ direction: direction })
|
||||
obj.set({ originAngle: originAngle })
|
||||
|
||||
canvas?.renderAll()
|
||||
//회전, flip등이 먹은 기준으로 새로생성
|
||||
const batchSurface = new QPolygon(obj.getCurrentPoints(), {
|
||||
fill: 'transparent',
|
||||
stroke: 'red',
|
||||
strokeWidth: 1,
|
||||
strokeDasharray: [10, 4],
|
||||
fontSize: 12,
|
||||
selectable: true,
|
||||
lockMovementX: true, // X 축 이동 잠금
|
||||
lockMovementY: true, // Y 축 이동 잠금
|
||||
lockRotation: true, // 회전 잠금
|
||||
lockScalingX: true, // X 축 크기 조정 잠금
|
||||
lockScalingY: true, // Y 축 크기 조정 잠금
|
||||
name: POLYGON_TYPE.ROOF,
|
||||
originX: 'center',
|
||||
originY: 'center',
|
||||
pitch: globalPitch,
|
||||
surfaceId: surfaceId,
|
||||
direction: direction,
|
||||
})
|
||||
canvas?.add(batchSurface)
|
||||
setSurfaceShapePattern(batchSurface, roofDisplay.column)
|
||||
drawDirectionArrow(batchSurface)
|
||||
closePopup(id)
|
||||
})
|
||||
|
||||
addCanvasMouseEventListener('mouse:down', (e) => {
|
||||
isDrawing = false
|
||||
obj.set('name', POLYGON_TYPE.ROOF)
|
||||
obj.set('surfaceId', surfaceId)
|
||||
initEvent()
|
||||
setSurfaceShapePattern(obj, roofDisplay.column)
|
||||
closePopup(id)
|
||||
drawDirectionArrow(obj)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -880,12 +899,45 @@ export function useSurfaceShapeBatch() {
|
||||
canvas?.renderAll()
|
||||
}
|
||||
|
||||
const changeSurfaceFlowDirection = (roof, direction, orientation) => {
|
||||
roof.set({
|
||||
direction: direction,
|
||||
const updateFlippedPoints = (polygon) => {
|
||||
if (!(polygon instanceof fabric.Polygon)) {
|
||||
console.error('The object is not a Polygon.')
|
||||
return
|
||||
}
|
||||
|
||||
const { flipX, flipY, width, height, points, left, top, scaleX, scaleY } = polygon
|
||||
|
||||
// 현재 points의 사본 가져오기
|
||||
const newPoints = points.map((point) => {
|
||||
let x = point.x
|
||||
let y = point.y
|
||||
|
||||
// flipX 적용
|
||||
if (flipX) {
|
||||
x = width - x
|
||||
}
|
||||
|
||||
// flipY 적용
|
||||
if (flipY) {
|
||||
y = height - y
|
||||
}
|
||||
|
||||
// 스케일 및 전역 좌표 고려
|
||||
x = (x - width / 2) * scaleX + width / 2
|
||||
y = (y - height / 2) * scaleY + height / 2
|
||||
|
||||
return { x, y }
|
||||
})
|
||||
drawDirectionArrow(roof)
|
||||
canvas?.renderAll()
|
||||
|
||||
// flipX, flipY를 초기화
|
||||
polygon.flipX = false
|
||||
polygon.flipY = false
|
||||
|
||||
// points 업데이트
|
||||
polygon.set({ points: newPoints })
|
||||
polygon.setCoords()
|
||||
|
||||
return polygon
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@ -285,8 +285,6 @@ export function useContextMenu() {
|
||||
}, [currentContextMenu])
|
||||
|
||||
useEffect(() => {
|
||||
console.log(currentObject)
|
||||
|
||||
if (currentObject?.name) {
|
||||
console.log('object', currentObject)
|
||||
switch (currentObject.name) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user