diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx
index f31bbcaa..77bbafcc 100644
--- a/src/components/management/StuffDetail.jsx
+++ b/src/components/management/StuffDetail.jsx
@@ -53,7 +53,7 @@ export default function StuffDetail() {
const formInitValue = {
// 물건번호 T...(임시) R...(진짜)
planReqNo: '', //설계의뢰No
- receiveUser: '', //담당자
+ receiveUser: session?.userNm, //담당자 로그인사용자명 디폴트
objectStatusId: '0', //물건구분(신축:0 기축 : 1)
objectName: '', //물건명
objectNameOmit: '', //경칭선택
@@ -1745,7 +1745,7 @@ export default function StuffDetail() {
onChange={onSelectionChange2}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
- isDisabled={otherSaleStoreList.length > 1 ? false : true}
+ isDisabled={otherSaleStoreList != null && otherSaleStoreList.length > 0 ? false : true}
isClearable={true}
value={otherSaleStoreList.filter(function (option) {
return option.saleStoreId === otherSelOptions
diff --git a/src/components/management/StuffSearchCondition.jsx b/src/components/management/StuffSearchCondition.jsx
index 3b093201..a72fda59 100644
--- a/src/components/management/StuffSearchCondition.jsx
+++ b/src/components/management/StuffSearchCondition.jsx
@@ -60,6 +60,7 @@ export default function StuffSearchCondition() {
const [schSelSaleStoreId, setSchSelSaleStoreId] = useState('') //판매대리점 선택
const [receiveUser, setReceiveUser] = useState('') //담당자
const [dateType, setDateType] = useState('U') //갱신일(U)/등록일(R)
+ const [tempFlg, setTempFlg] = useState('') //임시저장여부
const [schSelSaleStoreList, setSchSelSaleStoreList] = useState([]) //판매대리점 자동완성 SELECT 전체
const [favoriteStoreList, setFavoriteStoreList] = useState([]) //즐겨찾기한 판매점목록
@@ -95,12 +96,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : '',
schReceiveUser: receiveUser ? receiveUser.trim() : '',
schDateType: dateType,
+ schTempFlg: tempFlg, //임시저장물건
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E',
startRow: 1,
endRow: 1 * stuffSearch?.pageSize,
- schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R',
+ schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
pageNo: 1,
pageSize: stuffSearch?.pageSize,
})
@@ -115,12 +117,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : '',
schReceiveUser: receiveUser ? receiveUser.trim() : '',
schDateType: dateType,
+ schTempFlg: tempFlg, //임시저장물건
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E',
startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1,
endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100,
- schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R',
+ schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
pageNo: stuffSearch?.pageNo,
pageSize: stuffSearch?.pageSize,
})
@@ -136,12 +139,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: otherSaleStoreId,
schReceiveUser: receiveUser.trim(),
schDateType: dateType,
+ schTempFlg: tempFlg, //임시저장물건
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E',
startRow: 1,
endRow: 100,
- schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R',
+ schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
})
} else if (stuffSearch.code === 'E') {
if (session.storeId !== 'T01' && session.storeLvl === '1') {
@@ -155,12 +159,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: otherSaleStoreId,
schReceiveUser: stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser.trim() : receiveUser.trim(),
schDateType: dateType,
+ schTempFlg: tempFlg, //임시저장물건
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E',
startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1,
endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100,
- schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R',
+ schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
pageNo: stuffSearch?.pageNo,
pageSize: stuffSearch?.pageSize,
})
@@ -176,12 +181,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : '',
schReceiveUser: receiveUser ? receiveUser.trim() : '',
schDateType: dateType,
+ schTempFlg: tempFlg, //임시저장물건
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E',
startRow: 1,
endRow: 1 * stuffSearch?.pageSize,
- schSortType: 'R',
+ schSortType: 'U',
pageNo: 1,
pageSize: stuffSearch?.pageSize,
})
@@ -196,12 +202,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: otherSaleStoreId,
schReceiveUser: stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser.trim() : receiveUser.trim(),
schDateType: dateType,
+ schTempFlg: tempFlg, //임시저장물건
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E',
startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1,
endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100,
- schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R',
+ schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
pageNo: stuffSearch?.pageNo,
pageSize: stuffSearch?.pageSize,
})
@@ -217,12 +224,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: otherSaleStoreId,
schReceiveUser: stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser.trim() : receiveUser.trim(),
schDateType: dateType,
+ schTempFlg: tempFlg, //임시저장물건
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E',
startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1,
endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100,
- schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R',
+ schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
pageNo: stuffSearch?.pageNo,
pageSize: stuffSearch?.pageSize,
})
@@ -238,12 +246,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: otherSaleStoreId,
schReceiveUser: receiveUser.trim(),
schDateType: dateType,
+ schTempFlg: tempFlg, //임시저장물건
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E',
startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1,
endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100,
- schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R',
+ schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
pageNo: stuffSearch?.pageNo,
pageSize: stuffSearch?.pageSize,
})
@@ -261,6 +270,7 @@ export default function StuffSearchCondition() {
dispCompanyNameRef.current.value = ''
receiveUserRef.current.value = ''
stuffSearch.schDateType = 'U'
+ stuffSearch.schTempFlg = ''
setObjectNo('')
setAddress('')
setobjectName('')
@@ -268,6 +278,7 @@ export default function StuffSearchCondition() {
setReceiveUser('')
setDispCompanyName('')
setDateType('U')
+ setTempFlg('')
setStartDate(dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'))
setEndDate(dayjs(new Date()).format('YYYY-MM-DD'))
if (session?.storeId === 'T01') {
@@ -285,12 +296,12 @@ export default function StuffSearchCondition() {
schSelSaleStoreId: '',
schOtherSelSaleStoreId: '',
schDateType: 'U',
+ schTempFlg: '',
startRow: 1,
endRow: 100,
- schSortType: 'R',
+ schSortType: 'U',
pageNo: 1,
pageSize: 100,
- // code: 'S',
})
} else {
if (otherSaleStoreList.length > 1) {
@@ -303,10 +314,11 @@ export default function StuffSearchCondition() {
stuffSearch.schReceiveUser = ''
stuffSearch.schDispCompanyName = ''
stuffSearch.schDateType = 'U'
+ stuffSearch.schTempFlg = ''
stuffSearch.startRow = 1
stuffSearch.endRow = 100
- stuffSearch.schSortType = 'R'
+ stuffSearch.schSortType = 'U'
stuffSearch.pageNo = 1
stuffSearch.pageSize = 100
} else {
@@ -317,10 +329,11 @@ export default function StuffSearchCondition() {
stuffSearch.schReceiveUser = ''
stuffSearch.schDispCompanyName = ''
stuffSearch.schDateType = 'U'
+ stuffSearch.schTempFlg = ''
stuffSearch.startRow = 1
stuffSearch.endRow = 100
- stuffSearch.schSortType = 'R'
+ stuffSearch.schSortType = 'U'
stuffSearch.pageNo = 1
stuffSearch.pageSize = 100
}
@@ -543,13 +556,14 @@ export default function StuffSearchCondition() {
stuffSearch.schReceiveUser = ''
stuffSearch.schDispCompanyName = ''
stuffSearch.schDateType = 'U'
+ stuffSearch.schTempFlg = ''
stuffSearch.schFromDt = dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD')
stuffSearch.schToDt = dayjs(new Date()).format('YYYY-MM-DD')
stuffSearch.startRow = 1
stuffSearch.endRow = 100
stuffSearch.schSelSaleStoreId = ''
stuffSearch.schOtherSelSaleStoreId = ''
- stuffSearch.schSortType = 'R'
+ stuffSearch.schSortType = 'U'
stuffSearch.pageNo = 1
stuffSearch.pageSize = 100
@@ -575,13 +589,14 @@ export default function StuffSearchCondition() {
stuffSearch.schReceiveUser = ''
stuffSearch.schDispCompanyName = ''
stuffSearch.schDateType = 'U'
+ stuffSearch.schTempFlg = ''
stuffSearch.schFromDt = dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD')
stuffSearch.schToDt = dayjs(new Date()).format('YYYY-MM-DD')
stuffSearch.startRow = 1
stuffSearch.endRow = 100
stuffSearch.schSelSaleStoreId = ''
stuffSearch.schOtherSelSaleStoreId = ''
- stuffSearch.schSortType = 'R'
+ stuffSearch.schSortType = 'U'
stuffSearch.pageNo = 1
stuffSearch.pageSize = 100
setSchSelSaleStoreId('')
@@ -597,6 +612,17 @@ export default function StuffSearchCondition() {
setDispCompanyName(stuffSearch.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName)
setReceiveUser(stuffSearch.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser)
setDateType(stuffSearch.schDateType ? stuffSearch.schDateType : dateType)
+ setTempFlg(stuffSearch.schTempFlg ? stuffSearch.schTempFlg : tempFlg)
+ }
+
+ if (stuffSearch.schDateType === 'R') {
+ setDateType('R')
+ }
+
+ if (stuffSearch.schTempFlg === '0') {
+ setTempFlg('0')
+ } else if (stuffSearch.schTempFlg === '1') {
+ setTempFlg('1')
}
}, [stuffSearch])
@@ -648,8 +674,8 @@ export default function StuffSearchCondition() {
-
-
+ {/*
+
*/}
@@ -685,22 +711,7 @@ export default function StuffSearchCondition() {
/>
- | {getMessage('stuff.search.schAddress')} |
-
-
- {
- stuffSearch.schAddress = addressRef.current.value
- setAddress(addressRef.current.value)
- }}
- onKeyUp={handleByOnKeyUp}
- />
-
- |
+
{getMessage('stuff.search.schDispCompanyName')} |
@@ -751,8 +762,127 @@ export default function StuffSearchCondition() {
/>
|
- {getMessage('stuff.search.schSelSaleStoreId')} |
+ {getMessage('stuff.search.schAddress')} |
+
+
+ {
+ stuffSearch.schAddress = addressRef.current.value
+ setAddress(addressRef.current.value)
+ }}
+ onKeyUp={handleByOnKeyUp}
+ />
+
+ |
+
+
+ | {getMessage('stuff.search.period')} |
+
+ |
+ {getMessage('stuff.search.schTempFlgT')} |
+
+
+ |
+
+
+ | {getMessage('stuff.search.schSelSaleStoreId')} |
+
{session?.storeId === 'T01' && (
@@ -876,52 +1006,6 @@ export default function StuffSearchCondition() {
|
-
- | {getMessage('stuff.search.period')} |
-
-
- |
-
diff --git a/src/hooks/module/useModule.js b/src/hooks/module/useModule.js
index 34f3f7bd..a71744c6 100644
--- a/src/hooks/module/useModule.js
+++ b/src/hooks/module/useModule.js
@@ -26,7 +26,8 @@ export const MODULE_INSERT_TYPE = {
}
export const MODULE_ALIGN_TYPE = {
- TOP: 'top',
+ VERTICAL: 'vertical',
+ HORIZONTAL: 'horizontal',
}
export function useModule() {
@@ -83,6 +84,162 @@ export function useModule() {
}
}
}
+ const moduleMultiMove = (type, length, direction) => {
+ if (canvas.getActiveObjects().length === 0) return
+ if (canvas.getActiveObjects().length > 1) {
+ swalFire({
+ title: '여러 개의 모듈을 선택할 수 없습니다.',
+ icon: 'error',
+ type: 'alert',
+ })
+ canvas.discardActiveObject()
+ return
+ }
+ const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
+ const modules = type === 'row' ? getRowModules(activeModule) : getColumnModules(activeModule)
+ const otherModules = getOtherModules(modules)
+ const objects = getObjects()
+ const moduleSetupSurface = canvas
+ .getObjects()
+ .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0]
+ let isWarning = false
+
+ modules.forEach((module) => {
+ const { top, left } = getPosotion(module, direction, length, false)
+ module.originPos = {
+ top: module.top,
+ left: module.left,
+ fill: module.fill,
+ }
+
+ module.set({ top, left })
+ module.setCoords()
+ canvas.renderAll()
+
+ if (otherModules.length > 0) {
+ if (isOverlapOtherModules(module, otherModules) || isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) {
+ isWarning = true
+ module.set({ fill: 'red' })
+ }
+ }
+ })
+
+ canvas.renderAll()
+ if (isWarning) {
+ swalFire({
+ title: getMessage('can.not.move.module'),
+ icon: 'error',
+ type: 'alert',
+ confirmFn: () => {
+ modules.forEach((module) => {
+ module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
+ module.setCoords()
+ })
+ canvas.renderAll()
+ },
+ })
+ }
+ }
+
+ const moduleMoveAll = (length, direction) => {
+ const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
+ const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE)
+ const objects = getObjects()
+
+ let isWarning = false
+
+ modules.forEach((module) => {
+ const { top, left } = getPosotion(module, direction, length, false)
+ module.originPos = {
+ top: module.top,
+ left: module.left,
+ fill: module.fill,
+ }
+
+ module.set({ top, left })
+ module.setCoords()
+ canvas.renderAll()
+
+ if (isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) {
+ isWarning = true
+ module.set({ fill: 'red' })
+ }
+ })
+
+ canvas.renderAll()
+ if (isWarning) {
+ swalFire({
+ title: getMessage('can.not.move.module'),
+ icon: 'error',
+ type: 'alert',
+ confirmFn: () => {
+ modules.forEach((module) => {
+ module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
+ module.setCoords()
+ })
+ canvas.renderAll()
+ },
+ })
+ }
+ }
+
+ const moduleCopyAll = (length, direction) => {
+ const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
+ const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE)
+ const objects = getObjects()
+ const copyModules = []
+ let copyModule = null
+ let isWarning = false
+ let moduleLength = 0
+ if (['up', 'down'].includes(direction)) {
+ modules.sort((a, b) => a.top - b.top)
+ moduleLength = Number(modules[modules.length - 1].top) + Number(modules[modules.length - 1].height) - Number(modules[0].top)
+ } else if (['left', 'right'].includes(direction)) {
+ modules.sort((a, b) => a.left - b.left)
+ moduleLength = Number(modules[modules.length - 1].left) + Number(modules[modules.length - 1].width) - Number(modules[0].left)
+ }
+
+ modules.forEach((module) => {
+ const { top, left } = getPosotion(module, direction, Number(length) + Number(moduleLength), false)
+ module.clone((obj) => {
+ obj.set({
+ parentId: module.parentId,
+ initOptions: module.initOptions,
+ direction: module.direction,
+ arrow: module.arrow,
+ name: module.name,
+ type: module.type,
+ length: module.length,
+ points: module.points,
+ surfaceId: module.surfaceId,
+ left,
+ top,
+ id: uuidv4(),
+ })
+ copyModule = obj
+ canvas.add(obj)
+ copyModules.push(obj)
+ obj.setCoords()
+ })
+ if (isOverlapObjects(copyModule, objects) || isOutsideSurface(copyModule, moduleSetupSurface)) {
+ isWarning = true
+ copyModule.set({ fill: 'red' })
+ }
+ canvas.renderAll()
+ })
+
+ if (isWarning) {
+ swalFire({
+ title: getMessage('can.not.copy.module'),
+ icon: 'error',
+ type: 'alert',
+ confirmFn: () => {
+ canvas.remove(...copyModules)
+ canvas.renderAll()
+ },
+ })
+ }
+ }
const moduleCopy = (length, direction) => {
if (canvas.getActiveObjects().length === 0) return
@@ -144,63 +301,6 @@ export function useModule() {
}
}
- const moduleMultiMove = (type, length, direction) => {
- if (canvas.getActiveObjects().length === 0) return
- if (canvas.getActiveObjects().length > 1) {
- swalFire({
- title: '여러 개의 모듈을 선택할 수 없습니다.',
- icon: 'error',
- type: 'alert',
- })
- canvas.discardActiveObject()
- return
- }
- const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
- const modules = type === 'row' ? getRowModules(activeModule) : getColumnModules(activeModule)
- const otherModules = getOtherModules(modules)
- const objects = getObjects()
- const moduleSetupSurface = canvas
- .getObjects()
- .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0]
- let isWarning = false
-
- modules.forEach((module) => {
- const { top, left } = getPosotion(module, direction, length, false)
- module.originPos = {
- top: module.top,
- left: module.left,
- fill: module.fill,
- }
-
- module.set({ top, left })
- module.setCoords()
- canvas.renderAll()
-
- if (otherModules.length > 0) {
- if (isOverlapOtherModules(module, otherModules) || isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) {
- isWarning = true
- module.set({ fill: 'red' })
- }
- }
- })
-
- canvas.renderAll()
- if (isWarning) {
- swalFire({
- title: getMessage('can.not.move.module'),
- icon: 'error',
- type: 'alert',
- confirmFn: () => {
- modules.forEach((module) => {
- module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
- module.setCoords()
- })
- canvas.renderAll()
- },
- })
- }
- }
-
const moduleMultiCopy = (type, length, direction) => {
if (canvas.getActiveObjects().length === 0) return
if (canvas.getActiveObjects().length > 1) {
@@ -694,7 +794,68 @@ export function useModule() {
}
}
- const alignModule = (type) => {}
+ const alignModule = (type) => {
+ const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
+ const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE)
+ const objects = getObjects()
+ let [top, bottom, left, right] = [0, 0, 0, 0]
+
+ top = Math.min(...modules.map((module) => module.top))
+ bottom = Math.max(...modules.map((module) => module.top + module.height))
+ left = Math.min(...modules.map((module) => module.left))
+ right = Math.max(...modules.map((module) => module.left + module.width))
+ const moduleSurfacePos = {
+ top: Math.min(...moduleSetupSurface.points.map((point) => point.y)),
+ left: Math.min(...moduleSetupSurface.points.map((point) => point.x)),
+ }
+ const [height, width] = [bottom - top, right - left]
+ const verticalCenterLength = moduleSurfacePos.top + moduleSetupSurface.height / 2 - (top + height / 2)
+ const horizontalCenterLength = moduleSurfacePos.left + moduleSetupSurface.width / 2 - (left + width / 2)
+ let isWarning = false
+
+ canvas.discardActiveObject()
+ modules.forEach((module) => {
+ module.originPos = {
+ left: module.left,
+ top: module.top,
+ fill: module.fill,
+ }
+ if (type === MODULE_ALIGN_TYPE.VERTICAL) {
+ module.set({ top: module.top + verticalCenterLength })
+ } else if (type === MODULE_ALIGN_TYPE.HORIZONTAL) {
+ module.set({ left: module.left + horizontalCenterLength })
+ }
+
+ canvas.renderAll()
+ module.setCoords()
+ if (isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) {
+ isWarning = true
+ module.set({ fill: 'red' })
+ }
+ })
+ canvas.renderAll()
+ if (isWarning) {
+ swalFire({
+ title: getMessage('can.not.align.module'),
+ icon: 'error',
+ type: 'alert',
+ confirmFn: () => {
+ modules.forEach((module) => {
+ module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
+ module.setCoords()
+ })
+ canvas.renderAll()
+ },
+ })
+ }
+ }
+
+ const modulesRemove = () => {
+ const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
+ const modules = canvas.getObjects().filter((obj) => obj.surfaceId === activeModule.surfaceId && obj.name === POLYGON_TYPE.MODULE)
+ canvas.remove(...modules)
+ canvas.renderAll()
+ }
const isOverlapOtherModules = (module, otherModules) => {
return otherModules.some(
@@ -765,11 +926,15 @@ export function useModule() {
return {
moduleMove,
moduleMultiMove,
+ moduleMoveAll,
moduleCopy,
moduleMultiCopy,
+ moduleCopyAll,
moduleColumnRemove,
moduleRowRemove,
moduleColumnInsert,
muduleRowInsert,
+ modulesRemove,
+ alignModule,
}
}
diff --git a/src/hooks/option/useCanvasSetting.js b/src/hooks/option/useCanvasSetting.js
index 2c710708..e4c02664 100644
--- a/src/hooks/option/useCanvasSetting.js
+++ b/src/hooks/option/useCanvasSetting.js
@@ -272,7 +272,7 @@ export function useCanvasSetting() {
// 기본설정(PlacementShapeSetting) 조회 및 초기화
const fetchBasicSettings = async () => {
try {
- await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}` }).then((res) => {
+ await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/0/${correntObjectNo}` }).then((res) => {
let roofsRow = {}
let roofsArray = {}
@@ -762,7 +762,6 @@ export function useCanvasSetting() {
setCanvasSetting,
basicSetting,
setBasicSettings,
- fetchBasicSettings,
basicSettingSave,
settingsData,
setSettingsData,
diff --git a/src/hooks/roofcover/useMovementSetting.js b/src/hooks/roofcover/useMovementSetting.js
index 6e06212e..4a979438 100644
--- a/src/hooks/roofcover/useMovementSetting.js
+++ b/src/hooks/roofcover/useMovementSetting.js
@@ -5,6 +5,8 @@ import { useMessage } from '@/hooks/useMessage'
import { useEffect, useRef, useState } from 'react'
import { useEvent } from '@/hooks/useEvent'
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
+import { useSwal } from '@/hooks/useSwal'
+import { QPolygon } from '@/components/fabric/QPolygon'
import { getDegreeByChon } from '@/util/canvas-util'
//동선이동 형 올림 내림
@@ -26,6 +28,7 @@ export function useMovementSetting(id) {
]
const [type, setType] = useState(TYPE.FLOW_LINE)
const typeRef = useRef(type)
+ const { swalFire } = useSwal()
const FLOW_LINE_REF = {
POINTER_INPUT_REF: useRef(null),
@@ -69,6 +72,7 @@ export function useMovementSetting(id) {
roof.innerLines.forEach((line) => {
if (line.name === LINE_TYPE.SUBLINE.RIDGE) {
line.bringToFront()
+ line.set({ visible: true })
line.set({ selectable: true })
line.set({ strokeWidth: 4 })
line.set({ stroke: '#1083E3' })
@@ -89,7 +93,6 @@ export function useMovementSetting(id) {
canvas.renderAll()
addCanvasMouseEventListener('mouse:move', mouseMoveEvent)
addCanvasMouseEventListener('mouse:down', mouseDownEvent)
-
return () => {
initEvent()
@@ -178,6 +181,36 @@ export function useMovementSetting(id) {
updownMoveEvent(e)
}
}
+
+ function edgesIntersection(edgeA, edgeB) {
+ const den =
+ (edgeB.vertex2.y - edgeB.vertex1.y) * (edgeA.vertex2.x - edgeA.vertex1.x) -
+ (edgeB.vertex2.x - edgeB.vertex1.x) * (edgeA.vertex2.y - edgeA.vertex1.y)
+
+ if (den === 0) {
+ return null // lines are parallel or coincident
+ }
+
+ const ua =
+ ((edgeB.vertex2.x - edgeB.vertex1.x) * (edgeA.vertex1.y - edgeB.vertex1.y) -
+ (edgeB.vertex2.y - edgeB.vertex1.y) * (edgeA.vertex1.x - edgeB.vertex1.x)) /
+ den
+
+ const ub =
+ ((edgeA.vertex2.x - edgeA.vertex1.x) * (edgeA.vertex1.y - edgeB.vertex1.y) -
+ (edgeA.vertex2.y - edgeA.vertex1.y) * (edgeA.vertex1.x - edgeB.vertex1.x)) /
+ den
+
+ // Edges are not intersecting but the lines defined by them are
+ const isIntersectionOutside = ua < 0 || ub < 0 || ua > 1 || ub > 1
+
+ return {
+ x: edgeA.vertex1.x + ua * (edgeA.vertex2.x - edgeA.vertex1.x),
+ y: edgeA.vertex1.y + ua * (edgeA.vertex2.y - edgeA.vertex1.y),
+ isIntersectionOutside,
+ }
+ }
+
//동선 이동 마우스 클릭 이벤트
const saveFlowLine = (e) => {
const target = selectedObject.current
@@ -187,22 +220,23 @@ export function useMovementSetting(id) {
let newPoint = []
if (Math.sign(target.x1 - target.x2) !== 0) {
+ const sign = FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked ? 1 : -1
newPoint = [
target.x1,
- target.y1 - Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
+ target.y1 - sign * Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
target.x2,
- target.y2 - Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
+ target.y2 - sign * Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
]
} else {
+ const sign = FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked ? -1 : 1
newPoint = [
- target.x1 + Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
+ target.x1 - sign * Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
target.y1,
- target.x2 + Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
+ target.x2 - sign * Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
target.y2,
]
}
-
- clearRef()
+ newPoint = newPoint.map((point) => Math.round(point * 10) / 10)
const cloned = new fabric.Line(newPoint, {})
let currentObject = selectedObject.current
const currentX1 = currentObject.x1,
@@ -210,39 +244,94 @@ export function useMovementSetting(id) {
currentX2 = currentObject.x2,
currentY2 = currentObject.y2
+ const currentMidX = (currentX1 + currentX2) / 2
+ const currentMidY = (currentY1 + currentY2) / 2
+ const clonedMidX = (cloned.x1 + cloned.x2) / 2
+ const clonedMidY = (cloned.y1 + cloned.y2) / 2
+
const roof = canvas.getObjects().find((obj) => obj.id === currentObject.attributes.roofId)
- if (roof.separatePolygon.length > 0) {
- const separatePolygon = roof.separatePolygon
- separatePolygon
- .filter((polygon) =>
- polygon.points.some((point) => (point.x === currentX1 && point.y === currentY1) || (point.x === currentX2 && point.y === currentY2)),
- )
- .forEach((polygon) => {
- const newPoints = polygon.points.map((point) => {
- if (point.x === currentX1 && point.y === currentY1) {
- return { x: newPoint[0], y: newPoint[1] }
- } else if (point.x === currentX2 && point.y === currentY2) {
- return { x: newPoint[2], y: newPoint[3] }
- } else {
- return point
- }
- })
- polygon.set({ points: newPoints })
- polygon.setCoords()
- polygon.addLengthText()
- polygon.initLines()
- const slope = (line) => (line.x2 - line.x1 === 0 ? Infinity : (line.y2 - line.y1) / (line.x2 - line.x1))
- const currentDegree = polygon.attributes.pitch > 0 ? getDegreeByChon(polygon.attributes.pitch) : polygon.attributes.degree
- polygon.lines.forEach((line) => {
- line.attributes.planeSize = Math.round(Math.sqrt(Math.pow(line.x2 - line.x1, 2) + Math.pow(line.y2 - line.y1, 2)) * 10)
- if (currentDegree > 0 && slope(line) !== slope(currentObject)) {
- const height = Math.tan(currentDegree * (Math.PI / 180)) * line.attributes.planeSize
- line.attributes.actualSize = Math.round(Math.sqrt(Math.pow(line.attributes.planeSize, 2) + Math.pow(height, 2)))
- } else {
- line.attributes.actualSize = line.attributes.planeSize
- }
- })
+ let isOutside = false
+ roof.lines.forEach((line) => {
+ const intersection = edgesIntersection(
+ { vertex1: { x: currentMidX, y: currentMidY }, vertex2: { x: clonedMidX, y: clonedMidY } },
+ { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } },
+ )
+ if (intersection && !intersection.isIntersectionOutside) {
+ isOutside = true
+ }
+ })
+ if (isOutside) {
+ swalFire({ text: getMessage('modal.movement.flow.line.move.alert'), icon: 'error' })
+ return
+ }
+ currentObject.set({ x1: cloned.x1, y1: cloned.y1, x2: cloned.x2, y2: cloned.y2 })
+ currentObject.setCoords()
+ const otherRidges = roof.innerLines.filter((line) => line.name === LINE_TYPE.SUBLINE.RIDGE && line.id !== currentObject.id)
+ const overlapRidges = otherRidges.filter((line) => {
+ if (currentObject.x1 === currentObject.x2 && line.x1 === line.x2 && 0 < Math.abs(currentObject.x1 - line.x1) < 1) {
+ if (
+ currentObject.y1 <= line.y1 <= currentObject.y2 ||
+ currentObject.y1 >= line.y1 >= currentObject.y2 ||
+ currentObject.y1 <= line.y2 <= currentObject.y2 ||
+ currentObject.y1 >= line.y2 >= currentObject.y2
+ ) {
+ return true
+ }
+ }
+ if (currentObject.y1 === currentObject.y2 && line.y1 === line.y2 && 0 < Math.abs(currentObject.y1 - line.y1) < 1) {
+ if (
+ currentObject.x1 <= line.x1 <= currentObject.x2 ||
+ currentObject.x1 >= line.x1 >= currentObject.x2 ||
+ currentObject.x1 <= line.x2 <= currentObject.x2 ||
+ currentObject.x1 >= line.x2 >= currentObject.x2
+ ) {
+ return true
+ }
+ }
+ })
+ if (overlapRidges.length > 0) {
+ const minX = Math.min(...overlapRidges.flatMap((line) => [line.x1, line.x2]), currentObject.x1, currentObject.x2)
+ const maxX = Math.max(...overlapRidges.flatMap((line) => [line.x1, line.x2]), currentObject.x1, currentObject.x2)
+ const minY = Math.min(...overlapRidges.flatMap((line) => [line.y1, line.y2]), currentObject.y1, currentObject.y2)
+ const maxY = Math.max(...overlapRidges.flatMap((line) => [line.y1, line.y2]), currentObject.y1, currentObject.y2)
+ const newRidge = new fabric.Line([minX, minY, maxX, maxY], {
+ name: LINE_TYPE.SUBLINE.RIDGE,
+ selectable: true,
+ stroke: '#1083E3',
+ strokeWidth: 4,
+ attributes: { roofId: roof.id, currentRoof: currentObject.attributes.currentRoof },
+ })
+
+ overlapRidges.forEach((line) =>
+ line.attributes.currentRoof.forEach((id) => {
+ if (!newRidge.attributes.currentRoof.includes(id)) {
+ newRidge.attributes.currentRoof.push(id)
+ }
+ }),
+ )
+ canvas.add(newRidge)
+ newRidge.bringToFront()
+ roof.innerLines.push(newRidge)
+
+ canvas.remove(currentObject)
+ roof.innerLines.forEach((innerLine, index) => {
+ if (innerLine.id === currentObject.id) {
+ roof.innerLines.splice(index, 1)
+ }
+ })
+
+ overlapRidges.forEach((line) => {
+ canvas.remove(line)
+ roof.innerLines.forEach((innerLine, index) => {
+ if (innerLine.id === line.id) {
+ roof.innerLines.splice(index, 1)
+ }
})
+ })
+ }
+
+ if (roof.separatePolygon.length > 0) {
+ redrawSeparatePolygon(roof)
} else {
roof.innerLines
.filter((line) => currentObject !== line)
@@ -277,6 +366,390 @@ export function useMovementSetting(id) {
canvas.renderAll()
canvas.discardActiveObject()
+
+ FLOW_LINE_REF.FILLED_INPUT_REF.current.value = ''
+ }
+
+ const redrawSeparatePolygon = (roof) => {
+ roof.separatePolygon.forEach((polygon) => canvas.remove(polygon))
+ roof.separatePolygon = []
+ const roofLines = roof.lines
+ const wallLines = roof.wall.lines
+ const eaves = []
+ roofLines.forEach((currentRoof, index) => {
+ if (currentRoof.attributes?.type === LINE_TYPE.WALLLINE.EAVES) {
+ eaves.push({ index: index, roof: currentRoof, length: currentRoof.attributes.planeSize })
+ }
+ })
+ const ridges = roof.innerLines.filter((line) => line.name === LINE_TYPE.SUBLINE.RIDGE)
+ eaves.sort((a, b) => a.length - b.length)
+
+ const ridgeCount = eaves.length - 1
+ console.log('ridgeCount', ridgeCount, 'ridges', ridges.length)
+
+ const duplicatedEaves = []
+ ridges.forEach((ridge) => {
+ const positiveLines = []
+ const negativeLines = []
+ ridge.attributes.currentRoof.forEach((id) => {
+ console.log('id : ', id)
+ const eave = roofLines.find((obj) => obj.id === id)
+ console.log('roof : ', eave)
+ if (ridge.x1 === ridge.x2) {
+ if (eave.y1 < eave.y2) {
+ positiveLines.push(eave)
+ } else {
+ negativeLines.push(eave)
+ }
+ } else {
+ if (eave.x1 < eave.x2) {
+ positiveLines.push(eave)
+ } else {
+ negativeLines.push(eave)
+ }
+ }
+ })
+ if (positiveLines.length > 1) {
+ duplicatedEaves.push(positiveLines)
+ }
+ if (negativeLines.length > 1) {
+ duplicatedEaves.push(negativeLines)
+ }
+ })
+ console.log('duplicatedEaves', duplicatedEaves)
+
+ duplicatedEaves.forEach((duplicatedEave) => {
+ duplicatedEave.forEach((eave) => {
+ const index = eaves.findIndex((item) => item.roof.id === eave.id)
+ eaves.splice(index, 1)
+ })
+ })
+
+ // if (ridgeCount === ridges.length) {
+ eaves.forEach((eave, i) => {
+ const index = eave.index,
+ currentRoof = eave.roof
+ const currentWall = wallLines[index]
+ const currentRidges = ridges.filter((ridge) => ridge.attributes.currentRoof.includes(eave.roof.id))
+ let points = []
+ const signX = Math.sign(currentRoof.x1 - currentRoof.x2)
+ let currentX1 = currentRoof.x1,
+ currentY1 = currentRoof.y1,
+ currentX2 = currentRoof.x2,
+ currentY2 = currentRoof.y2
+ let changeX1 = [Math.min(currentRoof.x1, currentRoof.x2), Math.min(currentRoof.x1, currentRoof.x2)],
+ changeY1 = [Math.min(currentRoof.y1, currentRoof.y2), Math.min(currentRoof.y1, currentRoof.y2)],
+ changeX2 = [Math.max(currentRoof.x2, currentRoof.x1), Math.max(currentRoof.x2, currentRoof.x1)],
+ changeY2 = [Math.max(currentRoof.y2, currentRoof.y1), Math.max(currentRoof.y2, currentRoof.y1)]
+
+ if (signX === 0) {
+ currentY1 = Math.min(currentRoof.y1, currentRoof.y2, currentWall.y1, currentWall.y2)
+ changeY1[1] = currentY1
+ currentY2 = Math.max(currentRoof.y1, currentRoof.y2, currentWall.y1, currentWall.y2)
+ changeY2[1] = currentY2
+ } else {
+ currentX1 = Math.min(currentRoof.x1, currentRoof.x2, currentWall.x1, currentWall.x2)
+ changeX1[1] = currentX1
+ currentX2 = Math.max(currentRoof.x1, currentRoof.x2, currentWall.x1, currentWall.x2)
+ changeX2[1] = currentX2
+ }
+ points.push({ x: currentX1, y: currentY1 }, { x: currentX2, y: currentY2 })
+
+ currentRidges.forEach((ridge) => {
+ let ridgeX1 = ridge.x1,
+ ridgeY1 = ridge.y1,
+ ridgeX2 = ridge.x2,
+ ridgeY2 = ridge.y2
+ if (signX === 0) {
+ ridgeY1 = Math.min(ridge.y1, ridge.y2)
+ ridgeY2 = Math.max(ridge.y1, ridge.y2)
+ } else {
+ ridgeX1 = Math.min(ridge.x1, ridge.x2)
+ ridgeX2 = Math.max(ridge.x1, ridge.x2)
+ }
+ points.push({ x: ridgeX1, y: ridgeY1 }, { x: ridgeX2, y: ridgeY2 })
+ })
+
+ points.forEach((point) => {
+ if (point.x === changeX1[0] && changeX1[0] !== changeX1[1]) {
+ point.x = changeX1[1]
+ }
+ if (point.x === changeX2[0] && changeX2[0] !== changeX2[1]) {
+ point.x = changeX2[1]
+ }
+ if (point.y === changeY1[0] && changeY1[0] !== changeY1[1]) {
+ point.y = changeY1[1]
+ }
+ if (point.y === changeY2[0] && changeY2[0] !== changeY2[1]) {
+ point.y = changeY2[1]
+ }
+ })
+ //중복된 point 제거
+ points = points.filter((point, index, self) => index === self.findIndex((p) => p.x === point.x && p.y === point.y))
+ //point 정렬 (가장 좌측, 최상단의 점을 기준으로 삼는다.)
+ const startPoint = points
+ .filter((point) => point.x === Math.min(...points.map((point) => point.x)))
+ .reduce((prev, current) => {
+ return prev.y < current.y ? prev : current
+ })
+
+ const sortedPoints = []
+ sortedPoints.push(startPoint)
+
+ points.forEach((p, index) => {
+ if (index === 0) {
+ //시작점 다음 점 찾기, y좌표가 startPoint.y 보다 큰 점 중 x좌표가 가까운 점
+ const underStartPoint = points.filter((point) => point.y > startPoint.y)
+ const nextPoint = underStartPoint
+ .filter((point) => point.x === startPoint.x)
+ .reduce((prev, current) => {
+ if (prev === undefined) {
+ return current
+ }
+ return Math.abs(prev.y - startPoint.y) < Math.abs(current.y - startPoint.y) ? prev : current
+ }, undefined)
+ if (nextPoint) {
+ sortedPoints.push(nextPoint)
+ } else {
+ const nextPoint = underStartPoint.reduce((prev, current) => {
+ const prevHypos = Math.sqrt(Math.abs(Math.pow(prev.x - startPoint.x, 2)) + Math.abs(Math.pow(prev.y - startPoint.y, 2)))
+ const currentHypos = Math.sqrt(Math.abs(Math.pow(current.x - startPoint.x, 2)) + Math.abs(Math.pow(current.y - startPoint.y, 2)))
+ return prevHypos < currentHypos ? prev : current
+ }, undefined)
+ sortedPoints.push(nextPoint)
+ }
+ } else {
+ const lastPoint = sortedPoints[sortedPoints.length - 1]
+ console.log('lastPoint', lastPoint)
+ const prevPoint = sortedPoints[sortedPoints.length - 2]
+ const otherPoints = points.filter((point) => sortedPoints.includes(point) === false)
+ const nextPoint = otherPoints.reduce((prev, current) => {
+ if (prev === undefined) {
+ const height = Math.abs(Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))))
+ const adjacent = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
+ const hypotenuse = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))))
+
+ const angle = Math.round(
+ Math.acos((Math.pow(adjacent, 2) + Math.pow(height, 2) - Math.pow(hypotenuse, 2)) / (2 * adjacent * height)) * (180 / Math.PI),
+ )
+ if (angle === 90) {
+ return current
+ }
+ } else {
+ return prev
+ }
+ }, undefined)
+ if (nextPoint) {
+ sortedPoints.push(nextPoint)
+ } else {
+ const nextPoint = otherPoints.reduce((prev, current) => {
+ if (prev !== undefined) {
+ const height = Math.abs(
+ Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))),
+ )
+ const adjacentC = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
+ const hypotenuseC = Math.abs(
+ Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))),
+ )
+ const angleC = Math.round(
+ Math.acos((Math.pow(adjacentC, 2) + Math.pow(height, 2) - Math.pow(hypotenuseC, 2)) / (2 * adjacentC * height)) * (180 / Math.PI),
+ )
+ const adjacentP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - lastPoint.x, 2)) + Math.abs(Math.pow(prev.y - lastPoint.y, 2))))
+ const hypotenuseP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - prevPoint.x, 2)) + Math.abs(Math.pow(prev.y - prevPoint.y, 2))))
+ const angleP = Math.round(
+ Math.acos((Math.pow(adjacentP, 2) + Math.pow(height, 2) - Math.pow(hypotenuseP, 2)) / (2 * adjacentP * height)) * (180 / Math.PI),
+ )
+ if (Math.abs(90 - angleC) < Math.abs(90 - angleP)) {
+ return current
+ } else {
+ return prev
+ }
+ } else {
+ return current
+ }
+ }, undefined)
+ if (nextPoint) {
+ sortedPoints.push(nextPoint)
+ }
+ }
+ }
+ })
+
+ if (sortedPoints.length > 0) {
+ const roofPolygon = new QPolygon(sortedPoints, {
+ fill: 'transparent',
+ stroke: '#000000',
+ strokeWidth: 1,
+ selectable: false,
+ fontSize: roof.fontSize,
+ name: 'roofPolygon',
+ attributes: {
+ roofId: roof.id,
+ currentRoof: currentRoof.id,
+ pitch: currentRoof.attributes.pitch,
+ degree: currentRoof.attributes.degree,
+ direction: currentRoof.direction,
+ },
+ })
+ const currentDegree = currentRoof.attributes.pitch > 0 ? getDegreeByChon(currentRoof.attributes.pitch) : currentRoof.attributes.degree
+ //지붕 각도에 따른 실측치 조정
+ roofPolygon.lines.forEach((line) => {
+ line.attributes.planeSize = Math.round(Math.sqrt(Math.pow(line.x2 - line.x1, 2) + Math.pow(line.y2 - line.y1, 2)) * 10)
+ const slope = (line) => (line.x2 - line.x1 === 0 ? Infinity : (line.y2 - line.y1) / (line.x2 - line.x1))
+
+ if (currentDegree > 0 && slope(line) !== slope(currentRoof)) {
+ const height = Math.tan(currentDegree * (Math.PI / 180)) * line.attributes.planeSize
+ line.attributes.actualSize = Math.round(Math.sqrt(Math.pow(line.attributes.planeSize, 2) + Math.pow(height, 2)))
+ } else {
+ line.attributes.actualSize = line.attributes.planeSize
+ }
+ })
+ roof.separatePolygon.push(roofPolygon)
+ canvas.add(roofPolygon)
+ canvas.renderAll()
+ }
+ })
+
+ duplicatedEaves.forEach((duplicatedEave) => {
+ const currentRoof = duplicatedEave[0]
+ let points = []
+ duplicatedEave.forEach((eave) => {
+ points.push({ x: eave.x1, y: eave.y1 }, { x: eave.x2, y: eave.y2 })
+ const currentRidges = ridges.filter((ridge) => ridge.attributes.currentRoof.includes(eave.id))
+ currentRidges.forEach((ridge) => {
+ points.push({ x: ridge.x1, y: ridge.y1 }, { x: ridge.x2, y: ridge.y2 })
+ })
+ })
+ console.log('points', points)
+ points = points.filter((point, index, self) => index === self.findIndex((p) => p.x === point.x && p.y === point.y))
+ //point 정렬 (가장 좌측, 최상단의 점을 기준으로 삼는다.)
+
+ const startPoint = points
+ .filter((point) => point.x === Math.min(...points.map((point) => point.x)))
+ .reduce((prev, current) => {
+ return prev.y < current.y ? prev : current
+ })
+
+ const sortedPoints = []
+ sortedPoints.push(startPoint)
+
+ points.forEach((p, index) => {
+ if (index === 0) {
+ //시작점 다음 점 찾기, y좌표가 startPoint.y 보다 큰 점 중 x좌표가 가까운 점
+ const underStartPoint = points.filter((point) => point.y > startPoint.y)
+ const nextPoint = underStartPoint
+ .filter((point) => point.x === startPoint.x)
+ .reduce((prev, current) => {
+ if (prev === undefined) {
+ return current
+ }
+ return Math.abs(prev.y - startPoint.y) < Math.abs(current.y - startPoint.y) ? prev : current
+ }, undefined)
+ if (nextPoint) {
+ sortedPoints.push(nextPoint)
+ } else {
+ const nextPoint = underStartPoint.reduce((prev, current) => {
+ const prevHypos = Math.sqrt(Math.abs(Math.pow(prev.x - startPoint.x, 2)) + Math.abs(Math.pow(prev.y - startPoint.y, 2)))
+ const currentHypos = Math.sqrt(Math.abs(Math.pow(current.x - startPoint.x, 2)) + Math.abs(Math.pow(current.y - startPoint.y, 2)))
+ return prevHypos < currentHypos ? prev : current
+ }, undefined)
+ sortedPoints.push(nextPoint)
+ }
+ } else {
+ const lastPoint = sortedPoints[sortedPoints.length - 1]
+ console.log('lastPoint', lastPoint)
+ const prevPoint = sortedPoints[sortedPoints.length - 2]
+ const otherPoints = points.filter((point) => sortedPoints.includes(point) === false)
+ const nextPoint = otherPoints.reduce((prev, current) => {
+ if (prev === undefined) {
+ const height = Math.abs(Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))))
+ const adjacent = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
+ const hypotenuse = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))))
+
+ const angle = Math.round(
+ Math.acos((Math.pow(adjacent, 2) + Math.pow(height, 2) - Math.pow(hypotenuse, 2)) / (2 * adjacent * height)) * (180 / Math.PI),
+ )
+ if (angle === 90) {
+ return current
+ }
+ } else {
+ return prev
+ }
+ }, undefined)
+ if (nextPoint) {
+ sortedPoints.push(nextPoint)
+ } else {
+ const nextPoint = otherPoints.reduce((prev, current) => {
+ if (prev !== undefined) {
+ const height = Math.abs(
+ Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))),
+ )
+ const adjacentC = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
+ const hypotenuseC = Math.abs(
+ Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))),
+ )
+ const angleC = Math.round(
+ Math.acos((Math.pow(adjacentC, 2) + Math.pow(height, 2) - Math.pow(hypotenuseC, 2)) / (2 * adjacentC * height)) * (180 / Math.PI),
+ )
+ const adjacentP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - lastPoint.x, 2)) + Math.abs(Math.pow(prev.y - lastPoint.y, 2))))
+ const hypotenuseP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - prevPoint.x, 2)) + Math.abs(Math.pow(prev.y - prevPoint.y, 2))))
+ const angleP = Math.round(
+ Math.acos((Math.pow(adjacentP, 2) + Math.pow(height, 2) - Math.pow(hypotenuseP, 2)) / (2 * adjacentP * height)) * (180 / Math.PI),
+ )
+ if (Math.abs(90 - angleC) < Math.abs(90 - angleP)) {
+ return current
+ } else {
+ return prev
+ }
+ } else {
+ return current
+ }
+ }, undefined)
+ if (nextPoint) {
+ sortedPoints.push(nextPoint)
+ }
+ }
+ }
+ })
+
+ if (sortedPoints.length > 0) {
+ const roofPolygon = new QPolygon(sortedPoints, {
+ fill: 'transparent',
+ stroke: '#000000',
+ strokeWidth: 1,
+ selectable: false,
+ fontSize: roof.fontSize,
+ name: 'roofPolygon',
+ attributes: {
+ roofId: roof.id,
+ currentRoof: currentRoof.id,
+ pitch: currentRoof.attributes.pitch,
+ degree: currentRoof.attributes.degree,
+ direction: currentRoof.direction,
+ },
+ })
+ const currentDegree = currentRoof.attributes.pitch > 0 ? getDegreeByChon(currentRoof.attributes.pitch) : currentRoof.attributes.degree
+ //지붕 각도에 따른 실측치 조정
+ roofPolygon.lines.forEach((line) => {
+ line.attributes.planeSize = Math.round(Math.sqrt(Math.pow(line.x2 - line.x1, 2) + Math.pow(line.y2 - line.y1, 2)) * 10)
+ const slope = (line) => (line.x2 - line.x1 === 0 ? Infinity : (line.y2 - line.y1) / (line.x2 - line.x1))
+
+ if (currentDegree > 0 && slope(line) !== slope(currentRoof)) {
+ const height = Math.tan(currentDegree * (Math.PI / 180)) * line.attributes.planeSize
+ line.attributes.actualSize = Math.round(Math.sqrt(Math.pow(line.attributes.planeSize, 2) + Math.pow(height, 2)))
+ } else {
+ line.attributes.actualSize = line.attributes.planeSize
+ }
+ })
+ roof.separatePolygon.push(roofPolygon)
+ canvas.add(roofPolygon)
+ canvas.renderAll()
+ }
+ })
+ console.log('roof.separatePolygon : ', roof.separatePolygon)
+
+ ridges.forEach((ridge) => ridge.bringToFront())
+ console.log('ridges : ', ridges)
}
//형 올림내림 마우스 클릭 이벤트
@@ -295,18 +768,18 @@ export function useMovementSetting(id) {
if (Math.sign(target.x1 - target.x2) !== 0) {
if (targetTop > currentY) {
FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked = true
- FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(targetTop - currentY)) / 10000).toFixed(5) * 100000)
+ FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(Math.round(targetTop - currentY))) / 10000).toFixed(5) * 100000)
} else {
FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true
- FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(targetTop - currentY)) / 10000).toFixed(5) * 100000)
+ FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(Math.round(targetTop - currentY))) / 10000).toFixed(5) * 100000)
}
} else {
- if (targetLeft > currentX) {
+ if (targetLeft < currentX) {
FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked = true
- FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(currentX - targetLeft)) / 10000).toFixed(5) * 100000)
+ FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(Math.round(currentX - targetLeft))) / 10000).toFixed(5) * 100000)
} else {
FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true
- FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(currentX - targetLeft)) / 10000).toFixed(5) * 100000)
+ FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(Math.round(currentX - targetLeft))) / 10000).toFixed(5) * 100000)
}
}
diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js
index ec2d2661..0671f502 100644
--- a/src/hooks/roofcover/useRoofAllocationSetting.js
+++ b/src/hooks/roofcover/useRoofAllocationSetting.js
@@ -258,8 +258,6 @@ export function useRoofAllocationSetting(id) {
return roof
})
- newRoofList[selectedIndex].selected = true
-
setCurrentRoofList(newRoofList)
}
diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js
index 02896cb3..837c489a 100644
--- a/src/hooks/useContextMenu.js
+++ b/src/hooks/useContextMenu.js
@@ -1,7 +1,7 @@
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { canvasState, currentMenuState, currentObjectState } from '@/store/canvasAtom'
import { useEffect, useState } from 'react'
-import { MENU } from '@/common/common'
+import { MENU, POLYGON_TYPE } from '@/common/common'
import AuxiliarySize from '@/components/floor-plan/modal/auxiliary/AuxiliarySize'
import { usePopup } from '@/hooks/usePopup'
import { v4 as uuidv4 } from 'uuid'
@@ -40,6 +40,7 @@ import { useCanvasSetting } from './option/useCanvasSetting'
import { useGrid } from './common/useGrid'
import { useAdsorptionPoint } from './useAdsorptionPoint'
import { useRoofFn } from '@/hooks/common/useRoofFn'
+import { MODULE_ALIGN_TYPE, useModule } from './module/useModule'
export function useContextMenu() {
const canvas = useRecoilValue(canvasState)
@@ -66,6 +67,7 @@ export function useContextMenu() {
const commonTextFont = useRecoilValue(fontSelector('commonText'))
const { settingsData, setSettingsDataSave } = useCanvasSetting()
const { swalFire } = useSwal()
+ const { alignModule } = useModule()
const { removeRoofMaterial, removeAllRoofMaterial } = useRoofFn()
const currentMenuSetting = () => {
@@ -691,36 +693,38 @@ export function useContextMenu() {
])
break
case 'moduleSetupSurface':
- case 'dimensionLineText':
+ case 'roof':
setContextMenu([
[
{
id: 'moduleVerticalCenterAlign',
name: getMessage('contextmenu.module.vertical.align'),
+ fn: () => alignModule(MODULE_ALIGN_TYPE.VERTICAL),
},
{
id: 'moduleHorizonCenterAlign',
name: getMessage('contextmenu.module.horizon.align'),
- },
- {
- id: 'moduleLeftAlign',
- name: getMessage('contextmenu.module.left.align'),
- },
- {
- id: 'moduleRightAlign',
- name: getMessage('contextmenu.module.right.align'),
- },
- {
- id: 'moduleUpAlign',
- name: getMessage('contextmenu.module.up.align'),
- },
- {
- id: 'moduleDownAlign',
- name: getMessage('contextmenu.module.down.align'),
+ fn: () => alignModule(MODULE_ALIGN_TYPE.HORIZONTAL),
},
{
id: 'moduleRemove',
name: getMessage('contextmenu.module.remove'),
+ fn: () => {
+ const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
+ const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE)
+ canvas.remove(...modules)
+ canvas.renderAll()
+ },
+ },
+ {
+ id: 'moduleMove',
+ name: getMessage('contextmenu.module.move'),
+ component: ,
+ },
+ {
+ id: 'moduleCopy',
+ name: getMessage('contextmenu.module.copy'),
+ component: ,
},
{
id: 'moduleCircuitNumberEdit',
diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js
index 99819ad6..f463447b 100644
--- a/src/hooks/useMode.js
+++ b/src/hooks/useMode.js
@@ -1719,6 +1719,25 @@ export function useMode() {
}
const drawRoofPolygon = (wall) => {
+ const startLine = wall.lines
+ .filter((line) => line.x1 === Math.min(...wall.lines.map((line) => line.x1)))
+ .reduce((prev, current) => {
+ return prev.y1 < current.y1 ? prev : current
+ })
+
+ const beforeLine = [],
+ afterLine = []
+ let startIndex = wall.lines.findIndex((line) => line === startLine)
+ wall.lines.forEach((line, index) => {
+ if (index < startIndex) {
+ beforeLine.push(line)
+ } else {
+ afterLine.push(line)
+ }
+ })
+
+ wall.lines = afterLine.concat(beforeLine)
+
const polygon = createRoofPolygon(wall.points)
const originPolygon = new QPolygon(wall.points, { fontSize: 0 })
originPolygon.setViewLengthText(false)
diff --git a/src/locales/ja.json b/src/locales/ja.json
index 27794f3e..0fc32b81 100644
--- a/src/locales/ja.json
+++ b/src/locales/ja.json
@@ -44,6 +44,7 @@
"plan.menu.roof.cover.eaves.kerava.edit": "처마·케라바 변경",
"plan.menu.roof.cover.movement.shape.updown": "동선이동·형올림내림(JA)",
"modal.movement.flow.line.move": "銅線の移動軒",
+ "modal.movement.flow.line.move.alert": "이동 할 수 없습니다.(JA)",
"modal.movement.flow.line.updown": "型上げ・降り",
"modal.movement.flow.line.updown.info": "を選択して幅を指定してください桁の異なる辺。",
"modal.movement.flow.line.updown.up": "桁を上げる",
@@ -631,7 +632,7 @@
"stuff.detail.header.successCopy": "商品番号がコピーされました。",
"stuff.detail.header.failCopy": "存在しないものです。",
"stuff.detail.header.objectNo": "商品番号のコピーに失敗しました。",
- "stuff.detail.header.specificationConfirmDate": "仕様拡張日",
+ "stuff.detail.header.specificationConfirmDate": "仕様確認日",
"stuff.detail.header.lastEditDatetime": "更新日時",
"stuff.detail.header.createDatetime": "登録日",
"stuff.detail.required": "必須入力項目",
@@ -723,11 +724,15 @@
"stuff.search.period": "期間検索",
"stuff.search.schDateTypeU": "更新日",
"stuff.search.schDateTypeR": "登録日",
+ "stuff.search.schTempFlgT": "一時保存物",
+ "stuff.search.schTempFlg": "含む",
+ "stuff.search.schTempFlg0": "除外",
+ "stuff.search.schTempFlg1": "一時的なものだけを見る",
"stuff.search.grid.title": "商品リスト",
"stuff.search.grid.all": "全体",
"stuff.search.grid.selected": "選択",
"stuff.search.grid.schSortTypeR": "最近の登録日",
- "stuff.search.grid.schSortTypeU": "最近の更新日",
+ "stuff.search.grid.schSortTypeU": "最近修正日",
"stuff.windSelectPopup.title": "風速選択",
"stuff.windSelectPopup.table.selected": "選択",
"stuff.windSelectPopup.table.windspeed": "風速",
@@ -801,6 +806,8 @@
"main.storeName": "販売店名",
"main.objectNo": "物件番号",
"main.faq": "FAQ",
+ "main.content.objectList.noData1": "登録された商品情報はありません.",
+ "main.content.objectList.noData2": "下のボタンをクリックして商品情報を登録してください.",
"main.content.objectList": "最近の更新物件一覧",
"main.content.notice": "お知らせ",
"main.content.download1": "操作マニュアル",
@@ -817,6 +824,7 @@
"main.popup.login.btn2": "変更しない",
"main.popup.login.validate1": "入力したパスワードが異なります。",
"main.popup.login.validate2": "半角10文字以内で入力してください。",
+ "main.popup.login.validate3": "비밀번호를 입력해주세요.",
"main.popup.login.success": "パスワードが変更されました。",
"common.canvas.validate.size": "寸法を入力してください.",
"surface.shape.validate.size.1to2": "①길이는 ②보다 큰 값을 넣어주세요.",
@@ -941,5 +949,6 @@
"can.not.move.module": "모듈을 이동할 수 없습니다.(JA)",
"can.not.copy.module": "모듈을 복사할 수 없습니다.(JA)",
"can.not.remove.module": "모듈을 삭제할 수 없습니다.(JA)",
- "can.not.insert.module": "모듈을 삽입할 수 없습니다.(JA)"
+ "can.not.insert.module": "모듈을 삽입할 수 없습니다.(JA)",
+ "can.not.align.module": "모듈을 정렬할 수 없습니다.(JA)"
}
diff --git a/src/locales/ko.json b/src/locales/ko.json
index b7a64b03..6b415e88 100644
--- a/src/locales/ko.json
+++ b/src/locales/ko.json
@@ -44,6 +44,7 @@
"plan.menu.roof.cover.eaves.kerava.edit": "처마·케라바 변경",
"plan.menu.roof.cover.movement.shape.updown": "동선이동·형올림내림",
"modal.movement.flow.line.move": "동선 이동",
+ "modal.movement.flow.line.move.alert": "이동 할 수 없습니다.",
"modal.movement.flow.line.updown": "형 올림·내림",
"modal.movement.flow.line.updown.info": "자릿수가 다른 변을 선택하고 폭을 지정하십시오.",
"modal.movement.flow.line.updown.up": "자릿수를 올리다",
@@ -641,7 +642,7 @@
"stuff.detail.header.successCopy": "물건번호가 복사되었습니다.",
"stuff.detail.header.failCopy": "물건번호 복사에 실패했습니다.",
"stuff.detail.header.objectNo": "물건번호",
- "stuff.detail.header.specificationConfirmDate": "사양확장일",
+ "stuff.detail.header.specificationConfirmDate": "사양확정일",
"stuff.detail.header.lastEditDatetime": "갱신일시",
"stuff.detail.header.createDatetime": "등록일",
"stuff.detail.required": "필수 입력항목",
@@ -733,11 +734,15 @@
"stuff.search.period": "기간검색",
"stuff.search.schDateTypeU": "갱신일",
"stuff.search.schDateTypeR": "등록일",
+ "stuff.search.schTempFlgT": "임시저장 물건",
+ "stuff.search.schTempFlg": "포함",
+ "stuff.search.schTempFlg0": "제외",
+ "stuff.search.schTempFlg1": "임시물건만 조회",
"stuff.search.grid.title": "물건목록",
"stuff.search.grid.all": "전체",
"stuff.search.grid.selected": "선택",
"stuff.search.grid.schSortTypeR": "최근 등록일",
- "stuff.search.grid.schSortTypeU": "최근 갱신일",
+ "stuff.search.grid.schSortTypeU": "최근 수정일",
"stuff.windSelectPopup.title": "풍속선택",
"stuff.windSelectPopup.table.selected": "선택",
"stuff.windSelectPopup.table.windspeed": "풍속",
@@ -811,6 +816,8 @@
"main.storeName": "판매점명",
"main.objectNo": "물건번호",
"main.faq": "FAQ",
+ "main.content.objectList.noData1": "등록된 물건정보가 없습니다.",
+ "main.content.objectList.noData2": "아래 버튼을 클릭하여 물건정보를 등록하십시오.",
"main.content.objectList": "최근 갱신 물건목록",
"main.content.notice": "공지사항",
"main.content.download1": "조작메뉴얼",
@@ -827,6 +834,7 @@
"main.popup.login.btn2": "변경안함",
"main.popup.login.validate1": "입력한 패스워드가 다릅니다.",
"main.popup.login.validate2": "반각 10자 이내로 입력해주세요.",
+ "main.popup.login.validate3": "비밀번호를 입력해주세요.",
"main.popup.login.success": "비밀번호가 변경되었습니다.",
"common.canvas.validate.size": "사이즈를 입력해 주세요.",
"surface.shape.validate.size.1to2": "①길이는 ②보다 큰 값을 넣어주세요.",
@@ -951,5 +959,6 @@
"can.not.move.module": "모듈을 이동할 수 없습니다.",
"can.not.copy.module": "모듈을 복사할 수 없습니다.",
"can.not.remove.module": "모듈을 삭제할 수 없습니다.",
- "can.not.insert.module": "모듈을 삽입할 수 없습니다."
+ "can.not.insert.module": "모듈을 삽입할 수 없습니다.",
+ "can.not.align.module": "모듈을 정렬할 수 없습니다."
}
diff --git a/src/store/stuffAtom.js b/src/store/stuffAtom.js
index 06593e2b..d4e9eaad 100644
--- a/src/store/stuffAtom.js
+++ b/src/store/stuffAtom.js
@@ -17,9 +17,10 @@ export const stuffSearchState = atom({
schOtherSelSaleStoreId: '', //1차 이외 판매대리점 선택
startRow: 1,
endRow: 100,
- schSortType: 'R', //정렬조건 (R:최근등록일 U:최근수정일)
+ schSortType: 'U', //정렬조건 (R:최근등록일 U:최근수정일)
pageNo: 1,
pageSize: 100,
+ schTempFlg: '', //임시저장여부
},
dangerouslyAllowMutability: true,
})
diff --git a/src/styles/_layout.scss b/src/styles/_layout.scss
index a549ad0e..858ab351 100644
--- a/src/styles/_layout.scss
+++ b/src/styles/_layout.scss
@@ -207,6 +207,7 @@ header{
.select-box{
min-width: 165px;
margin-right: 8px;
+ height: 30px;
>div{
width: 100%;
}
diff --git a/src/styles/_main.scss b/src/styles/_main.scss
index 0733f285..5da1350d 100644
--- a/src/styles/_main.scss
+++ b/src/styles/_main.scss
@@ -155,6 +155,7 @@
.product-item-content{
margin-top: 30px;
overflow: hidden;
+ height: 100%;
.recently-list{
.recently-item{
border: 1px solid #F2F2F2;
@@ -208,6 +209,25 @@
}
}
}
+ .recently-no-data{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ h3{
+ font-size: 16px;
+ color: #101010;
+ font-weight: 600;
+ margin-bottom: 5px;
+ }
+ p{
+ font-size: 12px;
+ color: #666;
+ font-weight: 400;
+ margin-bottom: 10px;
+ }
+ }
.notice-box{
height: 100%;
overflow-y: auto;
diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js
index 63c04e89..74bc1fc2 100644
--- a/src/util/qpolygon-utils.js
+++ b/src/util/qpolygon-utils.js
@@ -317,7 +317,7 @@ export const drawGabledRoof = (roofId, canvas) => {
// 처마라인의 기본속성 입력
const eaves = []
roofLines.forEach((currentRoof, index) => {
- if (currentRoof.attributes !== undefined && currentRoof.attributes.type === LINE_TYPE.WALLLINE.EAVES) {
+ if (currentRoof.attributes?.type === LINE_TYPE.WALLLINE.EAVES) {
eaves.push({ index: index, roof: currentRoof, length: currentRoof.attributes.planeSize })
}
})
@@ -325,291 +325,147 @@ export const drawGabledRoof = (roofId, canvas) => {
const ridges = []
eaves.sort((a, b) => a.length - b.length)
- eaves.forEach((eave) => {
- if (ridges.length < ridgeCount) {
- const index = eave.index,
- currentRoof = eave.roof
- const currentWall = wallLines[index]
-
- //현재 지붕의 중심 좌표
- const midX = Math.round(((currentRoof.x1 + currentRoof.x2) / 2) * 10) / 10
- const midY = Math.round(((currentRoof.y1 + currentRoof.y2) / 2) * 10) / 10
- const deltaX = currentWall.x2 - currentWall.x1
- const deltaY = currentWall.y2 - currentWall.y1
- const length = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
- // currentWall 과 직각인 기울기 계산
- const perpendicularDeltaX = deltaY / length
- const perpendicularDeltaY = -deltaX / length
- // midX와 midY를 기준으로 직각 기울기를 사용하여 midWallX와 midWallY 계산
- const midWallX = midX + perpendicularDeltaX * length
- const midWallY = midY + perpendicularDeltaY * length
-
- const signX = Math.sign(midX - midWallX)
- const signY = Math.sign(midY - midWallY)
- const checkX = Math.round((midX - signX * checkLength) * 10) / 10
- const checkY = Math.round((midY - signY * checkLength) * 10) / 10
-
- const intersectLines = []
- // 현재 지붕의 맞은편 지붕을 찾는다.
- roofLines
- .filter((line) => line !== currentRoof)
- .forEach((line) => {
- const intersect = edgesIntersection(
- { vertex1: { x: midX, y: midY }, vertex2: { x: checkX, y: checkY } },
- { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } },
- )
- if (intersect && !intersect.isIntersectionOutside) {
- intersectLines.push({ x: intersect.x, y: intersect.y, line: line })
- }
- })
-
- // 가장 가까운 지붕을 찾는다.
- const intersect = intersectLines.reduce((prev, current) => {
- if (prev !== undefined) {
- const prevDistance = Math.sqrt(Math.pow(prev.x - midX, 2) + Math.pow(prev.y - midY, 2))
- const currentDistance = Math.sqrt(Math.pow(current.x - midX, 2) + Math.pow(current.y - midY, 2))
- return prevDistance >= currentDistance ? current : prev
- } else {
- return current
- }
- }, undefined)
-
- const linesCenterX = Math.round(((midX + intersect.x) / 2) * 10) / 10
- const linesCenterY = Math.round(((midY + intersect.y) / 2) * 10) / 10
-
- let addLength = currentRoof.attributes.planeSize / 2 / 10
-
- let centerLineX1 = Math.sign(currentRoof.x1 - currentRoof.x2) * addLength + linesCenterX
- let centerLineY1 = Math.sign(currentRoof.y1 - currentRoof.y2) * addLength + linesCenterY
- let centerLineX2 = Math.sign(currentRoof.x2 - currentRoof.x1) * addLength + linesCenterX
- let centerLineY2 = Math.sign(currentRoof.y2 - currentRoof.y1) * addLength + linesCenterY
-
- const point1Intersect = []
- const point2Intersect = []
- roofLines.forEach((line) => {
- const point1 = edgesIntersection(
- { vertex1: { x: linesCenterX, y: linesCenterY }, vertex2: { x: centerLineX1, y: centerLineY1 } },
- { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } },
- )
- if (point1 && !point1.isIntersectionOutside) {
- point1Intersect.push({ x: point1.x, y: point1.y })
- }
- const point2 = edgesIntersection(
- { vertex1: { x: linesCenterX, y: linesCenterY }, vertex2: { x: centerLineX2, y: centerLineY2 } },
- { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } },
- )
- if (point2 && !point2.isIntersectionOutside) {
- point2Intersect.push({ x: point2.x, y: point2.y })
- }
- })
- point1Intersect.reduce((prev, current) => {
- if (prev !== undefined) {
- const prevDistance = Math.sqrt(Math.pow(prev.x - linesCenterX, 2) + Math.pow(prev.y - linesCenterY, 2))
- const currentDistance = Math.sqrt(Math.pow(current.x - linesCenterX, 2) + Math.pow(current.y - linesCenterY, 2))
- return prevDistance >= currentDistance ? current : prev
- } else {
- return current
- }
- }, undefined)
- point2Intersect.reduce((prev, current) => {
- if (prev !== undefined) {
- const prevDistance = Math.sqrt(Math.pow(prev.x - linesCenterX, 2) + Math.pow(prev.y - linesCenterY, 2))
- const currentDistance = Math.sqrt(Math.pow(current.x - linesCenterX, 2) + Math.pow(current.y - linesCenterY, 2))
- return prevDistance >= currentDistance ? current : prev
- } else {
- return current
- }
- }, undefined)
-
- if (point1Intersect.length > 0) {
- centerLineX1 = point1Intersect[0].x
- centerLineY1 = point1Intersect[0].y
- }
- if (point2Intersect.length > 0) {
- centerLineX2 = point2Intersect[0].x
- centerLineY2 = point2Intersect[0].y
- }
-
- const ridge = new QLine([centerLineX1, centerLineY1, centerLineX2, centerLineY2], {
- fontSize: roof.fontSize,
- stroke: '#1083E3',
- strokeWidth: 2,
- name: LINE_TYPE.SUBLINE.RIDGE,
- attributes: { roofId: roof.id, currentRoof: currentRoof.id },
- })
- canvas.add(ridge)
- canvas.renderAll()
- ridges.push(ridge)
- roof.innerLines.push(ridge)
- }
- })
- eaves.forEach((eave) => {
+ eaves.forEach((eave, i) => {
const index = eave.index,
currentRoof = eave.roof
const currentWall = wallLines[index]
- const prevRoof = index === 0 ? roofLines[wallLines.length - 1] : roofLines[index - 1]
- const nextRoof = index === roofLines.length - 1 ? roofLines[0] : index === roofLines.length ? roofLines[1] : roofLines[index + 1]
- const midX = Math.round(((currentRoof.x1 + currentRoof.x2) / 2) * 10) / 10
- const midY = Math.round(((currentRoof.y1 + currentRoof.y2) / 2) * 10) / 10
- const deltaX = currentWall.x2 - currentWall.x1
- const deltaY = currentWall.y2 - currentWall.y1
- const length = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
- // currentWall 과 직각인 기울기 계산
- const perpendicularDeltaX = deltaY / length
- const perpendicularDeltaY = -deltaX / length
- // midX와 midY를 기준으로 직각 기울기를 사용하여 midWallX와 midWallY 계산
- const midWallX = midX + perpendicularDeltaX * length
- const midWallY = midY + perpendicularDeltaY * length
- const signX = Math.sign(midX - midWallX)
- const signY = Math.sign(midY - midWallY)
+ const oppositeLine = roofLines
+ .filter((line) => line !== currentRoof) // 현재 벽라인을 제외한 나머지 벽라인
+ .filter((line) => {
+ if (currentRoof.x1 === currentRoof.x2) {
+ const vector = Math.sign(currentRoof.y1 - currentRoof.y2)
+ const vector2 = Math.sign(currentRoof.x1 - currentWall.x1)
+ return line.x1 === line.x2 && Math.sign(line.y1 - line.y2) === -vector && Math.sign(currentRoof.x1 - line.x1) === vector2
+ }
+ if (currentRoof.y1 === currentRoof.y2) {
+ const vector = Math.sign(currentRoof.x1 - currentRoof.x2)
+ const vector2 = Math.sign(currentRoof.y1 - currentWall.y1)
+ return line.y1 === line.y2 && Math.sign(line.x1 - line.x2) === -vector && Math.sign(currentRoof.y1 - line.y1) === vector2
+ }
+ }) // 현재 벽라인과 직교하는 벽라인
+ console.log('oppositeLine', oppositeLine)
+
+ // 현재 벽라인과 직교하는 벽라인 사이에 마루를 그린다.
+ oppositeLine.forEach((line) => {
+ let points // 마루의 시작점과 끝점
+ if (currentRoof.x1 === currentRoof.x2) {
+ const currentRoofYRange = [Math.min(currentRoof.y1, currentRoof.y2), Math.max(currentRoof.y1, currentRoof.y2)]
+ const lineYRange = [Math.min(line.y1, line.y2), Math.max(line.y1, line.y2)]
+ const overlapYRange = [Math.max(currentRoofYRange[0], lineYRange[0]), Math.min(currentRoofYRange[1], lineYRange[1])]
+ if (overlapYRange[1] - overlapYRange[0] > 0) {
+ const centerX = Math.round(((currentRoof.x1 + line.x1) / 2) * 10) / 10
+ points = [centerX, overlapYRange[0], centerX, overlapYRange[1]]
+ }
+ }
+ if (currentRoof.y1 === currentRoof.y2) {
+ const currentRoofXRange = [Math.min(currentRoof.x1, currentRoof.x2), Math.max(currentRoof.x1, currentRoof.x2)]
+ const lineXRange = [Math.min(line.x1, line.x2), Math.max(line.x1, line.x2)]
+ const overlapXRange = [Math.max(currentRoofXRange[0], lineXRange[0]), Math.min(currentRoofXRange[1], lineXRange[1])]
+ if (overlapXRange[1] - overlapXRange[0] > 0) {
+ const centerY = Math.round(((currentRoof.y1 + line.y1) / 2) * 10) / 10
+ points = [overlapXRange[0], centerY, overlapXRange[1], centerY]
+ }
+ }
+ // 마루를 그린다.
+ if (points) {
+ const ridge = new QLine(points, {
+ fontSize: roof.fontSize,
+ stroke: '#1083E3',
+ strokeWidth: 1,
+ name: LINE_TYPE.SUBLINE.RIDGE,
+ attributes: { roofId: roof.id, currentRoof: [currentRoof.id] },
+ visible: false,
+ })
+ const duplicateRidge = ridges.find(
+ (ridge) => ridge.x1 === points[0] && ridge.y1 === points[1] && ridge.x2 === points[2] && ridge.y2 === points[3],
+ )
+ // 중복된 마루는 제외한다.
+ if (duplicateRidge) {
+ duplicateRidge.attributes.currentRoof.push(currentRoof.id)
+ } else {
+ canvas.add(ridge)
+ canvas.renderAll()
+ ridges.push(ridge)
+ }
+ }
+ })
+ })
+ // 처마마다 지붕 polygon 을 그린다.
+ eaves.forEach((eave, i) => {
+ const index = eave.index,
+ currentRoof = eave.roof
+ const currentWall = wallLines[index]
+ const currentRidges = ridges.filter((ridge) => ridge.attributes.currentRoof.includes(eave.roof.id))
let points = []
- const intersectRidge = []
- // 현재 roof 가 wall 보다 작을때 이전, 다음 지붕의 offset 만큼 포인트를 조정한다.
- if (currentRoof.attributes.planeSize > currentWall.attributes.planeSize) {
- points.push({ x: currentRoof.x1, y: currentRoof.y1 }, { x: currentRoof.x2, y: currentRoof.y2 })
- } else if (currentRoof.attributes.planeSize === currentWall.attributes.planeSize) {
- const deltaX = currentRoof.x2 - currentRoof.x1
- const deltaY = currentRoof.y2 - currentRoof.y1
- let x1 = currentRoof.x1,
- y1 = currentRoof.y1,
- x2 = currentRoof.x2,
- y2 = currentRoof.y2
+ const signX = Math.sign(currentRoof.x1 - currentRoof.x2)
+ let currentX1 = currentRoof.x1,
+ currentY1 = currentRoof.y1,
+ currentX2 = currentRoof.x2,
+ currentY2 = currentRoof.y2
+ let changeX1 = [Math.min(currentRoof.x1, currentRoof.x2), Math.min(currentRoof.x1, currentRoof.x2)],
+ changeY1 = [Math.min(currentRoof.y1, currentRoof.y2), Math.min(currentRoof.y1, currentRoof.y2)],
+ changeX2 = [Math.max(currentRoof.x2, currentRoof.x1), Math.max(currentRoof.x2, currentRoof.x1)],
+ changeY2 = [Math.max(currentRoof.y2, currentRoof.y1), Math.max(currentRoof.y2, currentRoof.y1)]
- if (deltaX !== 0) {
- const minX = Math.min(currentRoof.x1, currentRoof.x2, currentWall.x1, currentWall.x2)
- const maxX = Math.max(currentRoof.x1, currentRoof.x2, currentWall.x1, currentWall.x2)
- if (x1 > x2) {
- x1 = maxX
- x2 = minX
- } else {
- x1 = minX
- x2 = maxX
- }
- }
- if (deltaY !== 0) {
- const minY = Math.min(currentRoof.y1, currentRoof.y2, currentWall.y1, currentWall.y2)
- const maxY = Math.max(currentRoof.y1, currentRoof.y2, currentWall.y1, currentWall.y2)
- if (y1 > y2) {
- y1 = maxY
- y2 = minY
- } else {
- y1 = minY
- y2 = maxY
- }
- }
- points.push({ x: x1, y: y1 }, { x: x2, y: y2 })
+ if (signX === 0) {
+ currentY1 = Math.min(currentRoof.y1, currentRoof.y2, currentWall.y1, currentWall.y2)
+ changeY1[1] = currentY1
+ currentY2 = Math.max(currentRoof.y1, currentRoof.y2, currentWall.y1, currentWall.y2)
+ changeY2[1] = currentY2
} else {
- const deltaX = currentRoof.x2 - currentRoof.x1
- const deltaY = currentRoof.y2 - currentRoof.y1
- points.push(
- { x: currentRoof.x1 - Math.sign(deltaX) * prevRoof.attributes.offset, y: currentRoof.y1 - Math.sign(deltaY) * prevRoof.attributes.offset },
- { x: currentRoof.x2 + Math.sign(deltaX) * nextRoof.attributes.offset, y: currentRoof.y2 + Math.sign(deltaY) * nextRoof.attributes.offset },
- )
+ currentX1 = Math.min(currentRoof.x1, currentRoof.x2, currentWall.x1, currentWall.x2)
+ changeX1[1] = currentX1
+ currentX2 = Math.max(currentRoof.x1, currentRoof.x2, currentWall.x1, currentWall.x2)
+ changeX2[1] = currentX2
}
- ridges.forEach((ridge) => {
- const ridgeMidX = (ridge.x1 + ridge.x2) / 2
- const ridgeMidY = (ridge.y1 + ridge.y2) / 2
- if (midX === ridgeMidX || midY === ridgeMidY) {
- const intersection = edgesIntersection(
- { vertex1: { x: midX, y: midY }, vertex2: { x: ridgeMidX, y: ridgeMidY } },
- { vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } },
- )
- if (intersection && !intersection.isIntersectionOutside) {
- intersectRidge.push({ line: ridge })
- }
- }
- if (Math.sign(midX - ridgeMidX) === signX || Math.sign(midY - ridgeMidY) === signY) {
- const prevIntersect = edgesIntersection(
- { vertex1: { x: prevRoof.x1, y: prevRoof.y1 }, vertex2: { x: prevRoof.x2, y: prevRoof.y2 } },
- { vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } },
- )
- const nextIntersect = edgesIntersection(
- { vertex1: { x: nextRoof.x1, y: nextRoof.y1 }, vertex2: { x: nextRoof.x2, y: nextRoof.y2 } },
- { vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } },
- )
- if (prevIntersect && !prevIntersect.isIntersectionOutside) {
- intersectRidge.push({ line: ridge })
- }
- if (nextIntersect && !nextIntersect.isIntersectionOutside) {
- intersectRidge.push({ line: ridge })
- }
- }
- })
+ points.push({ x: currentX1, y: currentY1 }, { x: currentX2, y: currentY2 })
- intersectRidge.forEach((intersect) => {
- const line = intersect.line
- if (currentRoof.attributes.planeSize > currentWall.attributes.planeSize) {
- points.push({ x: line.x1, y: line.y1 }, { x: line.x2, y: line.y2 })
- } else if (currentRoof.attributes.planeSize === currentWall.attributes.planeSize) {
- const deltaX = currentRoof.x2 - currentRoof.x1
- const deltaY = currentRoof.y2 - currentRoof.y1
- let x1 = line.x1,
- y1 = line.y1,
- x2 = line.x2,
- y2 = line.y2
- if (deltaX !== 0) {
- const minX = Math.min(currentWall.x1, currentWall.x2, currentRoof.x1, currentRoof.x2, line.x1, line.x2)
- const maxX = Math.max(currentWall.x1, currentWall.x2, currentRoof.x1, currentRoof.x2, line.x1, line.x2)
- if (x1 > x2) {
- x1 = maxX
- x2 = minX
- } else {
- x1 = minX
- x2 = maxX
- }
- }
- if (deltaY !== 0) {
- const minY = Math.min(currentWall.y1, currentWall.y2, currentRoof.y1, currentRoof.y2, line.y1, line.y2)
- const maxY = Math.max(currentWall.y1, currentWall.y2, currentRoof.y1, currentRoof.y2, line.y1, line.y2)
- if (y1 > y2) {
- y1 = maxY
- y2 = minY
- } else {
- y1 = minY
- y2 = maxY
- }
- }
- points.push({ x: x1, y: y1 }, { x: x2, y: y2 })
+ currentRidges.forEach((ridge) => {
+ let ridgeX1 = ridge.x1,
+ ridgeY1 = ridge.y1,
+ ridgeX2 = ridge.x2,
+ ridgeY2 = ridge.y2
+ if (signX === 0) {
+ ridgeY1 = Math.min(ridge.y1, ridge.y2)
+ ridgeY2 = Math.max(ridge.y1, ridge.y2)
} else {
- let lineX1 = line.x1,
- lineY1 = line.y1,
- lineX2 = line.x2,
- lineY2 = line.y2
- const prevCheck1 = Math.sqrt(Math.pow(Math.round(lineX1 - currentRoof.x1), 2) + Math.pow(Math.round(lineY1 - currentRoof.y1), 2))
- const prevCheck2 = Math.sqrt(Math.pow(Math.round(lineX2 - currentRoof.x1), 2) + Math.pow(Math.round(lineY2 - currentRoof.y1), 2))
- const deltaX = currentRoof.x2 - currentRoof.x1
- const deltaY = currentRoof.y2 - currentRoof.y1
- if (prevCheck1 < prevCheck2) {
- lineX1 = lineX1 - Math.sign(deltaX) * prevRoof.attributes.offset
- lineY1 = lineY1 - Math.sign(deltaY) * prevRoof.attributes.offset
- lineX2 = lineX2 + Math.sign(deltaX) * nextRoof.attributes.offset
- lineY2 = lineY2 + Math.sign(deltaY) * nextRoof.attributes.offset
- } else {
- lineX1 = lineX1 + Math.sign(deltaX) * prevRoof.attributes.offset
- lineY1 = lineY1 + Math.sign(deltaY) * prevRoof.attributes.offset
- lineX2 = lineX2 - Math.sign(deltaX) * nextRoof.attributes.offset
- lineY2 = lineY2 - Math.sign(deltaY) * nextRoof.attributes.offset
- }
- points.push({ x: lineX1, y: lineY1 }, { x: lineX2, y: lineY2 })
+ ridgeX1 = Math.min(ridge.x1, ridge.x2)
+ ridgeX2 = Math.max(ridge.x1, ridge.x2)
}
-
- // canvas.remove(ridge)
- // canvas.renderAll()
+ points.push({ x: ridgeX1, y: ridgeY1 }, { x: ridgeX2, y: ridgeY2 })
})
- points = points.filter((point, index, self) => index === self.findIndex((p) => p.x === point.x && p.y === point.y))
+ points.forEach((point) => {
+ if (point.x === changeX1[0] && changeX1[0] !== changeX1[1]) {
+ point.x = changeX1[1]
+ }
+ if (point.x === changeX2[0] && changeX2[0] !== changeX2[1]) {
+ point.x = changeX2[1]
+ }
+ if (point.y === changeY1[0] && changeY1[0] !== changeY1[1]) {
+ point.y = changeY1[1]
+ }
+ if (point.y === changeY2[0] && changeY2[0] !== changeY2[1]) {
+ point.y = changeY2[1]
+ }
+ })
+ //중복된 point 제거
+ points = points.filter((point, index, self) => index === self.findIndex((p) => p.x === point.x && p.y === point.y))
+ //point 정렬 (가장 좌측, 최상단의 점을 기준으로 삼는다.)
const startPoint = points
.filter((point) => point.x === Math.min(...points.map((point) => point.x)))
.reduce((prev, current) => {
return prev.y < current.y ? prev : current
})
- const sortedPoints = [startPoint]
+
+ const sortedPoints = []
+ sortedPoints.push(startPoint)
+
points.forEach((p, index) => {
- const lastPoint = sortedPoints[sortedPoints.length - 1]
- console.log('lastPoint', lastPoint)
if (index === 0) {
+ //시작점 다음 점 찾기, y좌표가 startPoint.y 보다 큰 점 중 x좌표가 가까운 점
const underStartPoint = points.filter((point) => point.y > startPoint.y)
const nextPoint = underStartPoint
.filter((point) => point.x === startPoint.x)
@@ -630,6 +486,8 @@ export const drawGabledRoof = (roofId, canvas) => {
sortedPoints.push(nextPoint)
}
} else {
+ const lastPoint = sortedPoints[sortedPoints.length - 1]
+ console.log('lastPoint', lastPoint)
const prevPoint = sortedPoints[sortedPoints.length - 2]
const otherPoints = points.filter((point) => sortedPoints.includes(point) === false)
const nextPoint = otherPoints.reduce((prev, current) => {
@@ -656,18 +514,14 @@ export const drawGabledRoof = (roofId, canvas) => {
const height = Math.abs(Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))))
const adjacentC = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
const hypotenuseC = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))))
-
const angleC = Math.round(
Math.acos((Math.pow(adjacentC, 2) + Math.pow(height, 2) - Math.pow(hypotenuseC, 2)) / (2 * adjacentC * height)) * (180 / Math.PI),
)
-
const adjacentP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - lastPoint.x, 2)) + Math.abs(Math.pow(prev.y - lastPoint.y, 2))))
const hypotenuseP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - prevPoint.x, 2)) + Math.abs(Math.pow(prev.y - prevPoint.y, 2))))
-
const angleP = Math.round(
Math.acos((Math.pow(adjacentP, 2) + Math.pow(height, 2) - Math.pow(hypotenuseP, 2)) / (2 * adjacentP * height)) * (180 / Math.PI),
)
-
if (Math.abs(90 - angleC) < Math.abs(90 - angleP)) {
return current
} else {
@@ -683,10 +537,11 @@ export const drawGabledRoof = (roofId, canvas) => {
}
}
})
+
if (sortedPoints.length > 0) {
const roofPolygon = new QPolygon(sortedPoints, {
fill: 'transparent',
- stroke: 'blue',
+ stroke: '#1083E3',
strokeWidth: 2,
selectable: false,
fontSize: roof.fontSize,
@@ -717,6 +572,10 @@ export const drawGabledRoof = (roofId, canvas) => {
canvas.renderAll()
}
})
+
+ if (ridges.length > 0) {
+ ridges.forEach((ridge) => roof.innerLines.push(ridge))
+ }
//기준선 제거
// ridges.forEach((ridge) => canvas.remove(ridge))
}
@@ -1049,7 +908,7 @@ const isInnerLine = (prevLine, currentLine, nextLine, line) => {
* @param line2
* @returns {boolean}
*/
-const segmentsOverlap = (line1, line2) => {
+export const segmentsOverlap = (line1, line2) => {
if (line1.y1 === line1.y2 && line2.y1 === line2.y2 && line1.y1 === line2.y1) {
if ((line1.x1 <= line2.x1 && line1.x2 >= line2.x1) || (line1.x1 <= line2.x2 && line1.x2 >= line2.x2)) {
return true