diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index e1f7377b..2c7a36ca 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -204,7 +204,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { this.canvas = canvas }, fillCell(cell = { width: 50, height: 100, padding: 10 }) { - const points = this.getCurrentPoints() + const points = this.points const minX = Math.min(...points.map((p) => p.x)) const maxX = Math.max(...points.map((p) => p.x)) @@ -231,8 +231,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { for (let i = 0; i < cols; i++) { for (let j = 0; j < rows; j++) { - const rectLeft = minX + i * (rectWidth + cell.padding) + tmpWidth - const rectTop = minY + j * (rectHeight + cell.padding) + tmpHeight + const rectLeft = minX + i * (rectWidth + cell.padding) + const rectTop = minY + j * (rectHeight + cell.padding) const rectPoints = [ { x: rectLeft, y: rectTop }, @@ -240,6 +240,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { { x: rectLeft, y: rectTop + rectHeight }, { x: rectLeft + rectWidth, y: rectTop + rectHeight }, ] + const allPointsInside = rectPoints.every((point) => this.inPolygon(point)) if (allPointsInside) { @@ -272,6 +273,102 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { this.cells = drawCellsArray return drawCellsArray }, + fillCellABTemplate(cell = { width: 50, height: 100, padding: 5, parallelPoint: undefined, startX: 0, startY: 0 }) { + const points = this.points + + const minX = Math.min(...points.map((p) => p.x)) //왼쪽 + const maxX = Math.max(...points.map((p) => p.x)) //오른쪽 + const minY = Math.min(...points.map((p) => p.y)) //위 + const maxY = Math.max(...points.map((p) => p.y)) //아래 + + const boundingBoxWidth = maxX - minX + const boundingBoxHeight = maxY - minY + + const rectWidth = cell.width + const rectHeight = cell.height + + const cols = Math.floor((boundingBoxWidth + cell.padding) / (rectWidth + cell.padding)) + const rows = Math.floor((boundingBoxHeight + cell.padding) / (rectHeight + cell.padding)) + + //전체 높이에서 패딩을 포함하고 rows를 곱해서 여백길이를 계산 후에 2로 나누면 반높이를 넣어서 중간으로 정렬 + const tmpHeight = (boundingBoxHeight - (rectHeight + cell.padding) * rows) / 2 + //센터 정렬시에 쓴다 체크박스가 존재함 TODO: if문 추가해서 정렬해야함 + const tmpWidth = (boundingBoxWidth - (rectWidth + cell.padding) * cols) / 2 + + const drawCellsArray = [] //그려진 셀의 배열 + + let idx = 1 + + if (cell.parallelPoint > -1) { + //4각형 이상이면 각 꼭지점에서 위, 아래로 이동하면서 채움 + //앞에서 -1로 선언함 + if (cell.parallelPoint === 1 || cell.parallelPoint === 2) { + //ㄴ자 역ㄱ자 + //밑에서 위로 올라가야하면 + cell.startY = cell.startY - (rectHeight + cell.padding) * rows + if (cell.parallelPoint === 2) { + cell.startX = cell.startX - (rectWidth + cell.padding) * cols + } + } else { + if (cell.parallelPoint === 5) { + cell.startX = cell.startX - (rectWidth + cell.padding) * cols + } + } + } + + let startXPos, startYPos + + for (let i = 0; i < cols; i++) { + for (let j = 0; j < rows; j++) { + if (cell.parallelPoint > -1) { + startXPos = cell.startX + i * (rectWidth + cell.padding) + startYPos = cell.startY + j * (rectHeight + cell.padding) + } else { + startXPos = minX + i * (rectWidth + cell.padding) + startYPos = minY + j * (rectHeight + cell.padding) + } + + const rectPoints = [] + + rectPoints.push( + { x: startXPos, y: startYPos }, + { x: startXPos + rectWidth, y: startYPos }, + { x: startXPos, y: startYPos + rectHeight }, + { x: startXPos + rectWidth, y: startYPos + rectHeight }, + ) + + const allPointsInside = rectPoints.every((point) => this.inPolygon(point)) + + if (allPointsInside) { + const rect = new fabric.Rect({ + left: startXPos, + top: startYPos, + width: rectWidth, + height: rectHeight, + fill: '#BFFD9F', + stroke: 'black', + selectable: true, // 선택 가능하게 설정 + // lockMovementX: true, // X 축 이동 잠금 + // lockMovementY: true, // Y 축 이동 잠금 + // lockRotation: true, // 회전 잠금 + // lockScalingX: true, // X 축 크기 조정 잠금 + // lockScalingY: true, // Y 축 크기 조정 잠금 + opacity: 0.8, + name: 'cell', + idx: idx, + }) + + idx++ + drawCellsArray.push(rect) //배열에 넣어서 반환한다 + this.canvas.add(rect) + } + } + } + this.canvas?.renderAll() + this.cells = drawCellsArray + return drawCellsArray + }, + inPolygon(point) { const vertices = this.points let intersects = 0 @@ -295,7 +392,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { } let xInt = ((point.y - vertex1.y) * (vertex2.x - vertex1.x)) / (vertex2.y - vertex1.y) + vertex1.x - if (xInt < point.x) { + if (xInt <= point.x) { intersects++ } } diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index bd3bbd94..da7b8bf7 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -510,7 +510,7 @@ export function useMode() { * 마우스로 그린 점 기준으로 외벽선을 완성시켜준다. * makePolygon 함수에 포함되어있던 내용을 다른 템플릿 적용에서도 사용할수 있도록 함수로 대체 */ - const drawWallPolygon = () => { + const drawWallPolygon = (sort = true) => { const firstPoint = historyPoints.current[0] const lastPoint = historyPoints.current[historyPoints.current.length - 1] historyPoints.current.forEach((point) => { @@ -521,7 +521,7 @@ export function useMode() { historyPoints.current = [] // handleOuterlines() - const wall = makePolygon() + const wall = makePolygon(null, sort) wall.set({ name: 'wall' }) setWall(wall) @@ -638,7 +638,7 @@ export function useMode() { canvas?.renderAll() } - const makePolygon = (otherLines) => { + const makePolygon = (otherLines, sort = true) => { // 캔버스에서 모든 라인 객체를 찾습니다. const lines = otherLines || historyLines.current @@ -685,6 +685,7 @@ export function useMode() { fill: 'transparent', viewLengthText: true, fontSize: fontSize, + sort: sort, }, canvas, ) @@ -1087,7 +1088,7 @@ export function useMode() { offsetPoints.push(offsetPoint) } - return makePolygon(offsetPoints) + return makePolygon(offsetPoints, false) } /** @@ -1146,7 +1147,7 @@ export function useMode() { const applyTemplateA = () => { changeMode(canvas, Mode.EDIT) - const polygon = drawWallPolygon() + const polygon = drawWallPolygon(false) handleClear() if (polygon.lines.length === 4) { @@ -1895,12 +1896,7 @@ export function useMode() { //작은 지붕쪽 높이 길이를 구하는 로직 let secondVertCenterPoint = (lastLine.x1 + lastLine.x2) / 2 - secondVertCenterLine = new QLine([secondVertCenterPoint, middleSubLine.y1, secondVertCenterPoint, middleSubLine.y2 + edge], { - stroke: 'blue', - strokeWidth: 4, - property: 'centerLine', - fontSize: 14, - }) + secondVertCenterLine = new QLine([secondVertCenterPoint, middleSubLine.y1, secondVertCenterPoint, middleSubLine.y2 + edge], centerLineOpt) canvas.add(secondVertCenterLine) outLines.push(secondVertCenterLine) @@ -2085,38 +2081,10 @@ export function useMode() { return tmpArray } - // 외적을 계산하는 함수 - function crossProduct(p1, p2, p3) { - const dx1 = p2.x - p1.x - const dy1 = p2.y - p1.y - const dx2 = p3.x - p2.x - const dy2 = p3.y - p2.y - return dx1 * dy2 - dy1 * dx2 - } - - let concaveIndices = [] //볼록한 부분 인덱스 배열 - let concavePointIndices = [] //오목한 부분 인덱스 배열 - - // 오목한 부분 찾기 - function findConcavePointIndices(points) { - let concaveIndices = [] - for (let i = 0; i < points.length; i++) { - const p1 = points[i] - const p2 = points[(i + 1) % points.length] - const p3 = points[(i + 2) % points.length] - const cross = crossProduct(p1, p2, p3) - if (cross < 0) { - concaveIndices.push((i + 1) % points.length) - } else { - concavePointIndices.push((i + 1) % points.length) - } - } - return concaveIndices - } - // 오목한 부분 인덱스 찾기 - concaveIndices = findConcavePointIndices(points) //오목한 부분을 제외한 인덱스 - const concavePoints = concaveIndices.map((index) => points[index]) + const concaveIndicesObj = findConcavePointIndices(points) //오목한 부분을 제외한 인덱스 + let concavePointIndices = concaveIndicesObj.concavePointIndices + const concaveLine = { index: concavePointIndices[0], line: lines[concavePointIndices[0]], @@ -2168,7 +2136,7 @@ export function useMode() { offsetPoints.push(offsetPoint) } - const outlinePolygon = makePolygon(offsetPoints) + const outlinePolygon = makePolygon(offsetPoints, false) outlinePolygon.setViewLengthText(false) // 아웃라인 폴리곤의 각 변을 선으로 생성 @@ -2178,7 +2146,7 @@ export function useMode() { const line = new QLine([start.x, start.y, end.x, end.y], { stroke: 'blue', - strokeWidth: 2, + strokeWidth: 1, property: 'normal', fontSize: 14, idx: i, @@ -2607,7 +2575,7 @@ export function useMode() { */ const applyTemplateB = () => { changeMode(canvas, Mode.EDIT) - const polygon = drawWallPolygon() + const polygon = drawWallPolygon(false) const params = { eaves: 50, edge: 20, @@ -3149,7 +3117,7 @@ export function useMode() { ctx.scale(ratio, ratio) if (mode === 'cell') { - ctx.fillStyle = 'rgba(0, 0, 0, 0.3)' + ctx.fillStyle = 'rgba(0, 0, 0, 0.1)' ctx.fillRect(0, 0, patternSize.width * 2, patternSize.height * 2) } @@ -3286,7 +3254,9 @@ export function useMode() { canvas?.renderAll() } - const pattern = getRoofPattern(roofStyle, 'cell') + const pattern = getRoofPattern(roofStyle, 'cell') //셀모드 배경색을 칠한다 + + polygons.sort((a, b) => a.lines.length > b.lines.length) //무조건 잴 긴거 정렬 // 외각선을 안쪽으로 그려 가대선을 그린다. polygons.forEach((polygon, index) => { @@ -3312,9 +3282,6 @@ export function useMode() { trestlePolygon.on('mousedown', function () { toggleSelection(trestlePolygon) }) - - console.log('polygon', polygon) - polygon.set({ fill: pattern }) }) @@ -3349,7 +3316,7 @@ export function useMode() { } } - const inputCellSize = { width: 172, height: 113 } + const inputCellSize = { width: 172, height: 113 } //추후 입력받는 값으로 변경 const cellSize = { ...inputCellSize } //기본으로 가로형으로 넣고 if (templateType === 2) { @@ -3357,7 +3324,25 @@ export function useMode() { } selectedCellRoofArray.forEach((polygon, index) => { - const drawCells = polygon.fillCell({ width: cellSize.width, height: cellSize.height, padding: 10 }) + let parallelPoint = -1 //오목한 부분의 반대 꼭지점 //없는 애들도 있어서 -1 + const startPoint = {} //도형의 시작점을 찾기 위해 + + if (polygon.lines.length > 4) { + const concave = findConcavePointIndices(polygon.points) //오목한 부분기준으로 시작점을 찾으려 계산 + parallelPoint = parseInt(concave.concavePointIndices[0] + 3) % polygon.points.length //시작점을 찾기 위해 적용 + startPoint.x = polygon.points[parallelPoint].x + startPoint.y = polygon.points[parallelPoint].y + } + + const drawCells = polygon.fillCellABTemplate({ + width: cellSize.width, + height: cellSize.height, + padding: 10, + parallelPoint: parallelPoint, + startX: startPoint.x, + startY: startPoint.y, + }) + // const drawCells = polygon.fillCell({ width: cellSize.width, height: cellSize.height, padding: 10 }) drawCellsArray.push({ roofIndex: polygon.customIndex, drawCells: drawCells }) }) @@ -3411,6 +3396,32 @@ export function useMode() { setDrewRoofCells(roofCells) } + // 외적을 계산하는 함수 + const crossProduct = (p1, p2, p3) => { + const dx1 = p2.x - p1.x + const dy1 = p2.y - p1.y + const dx2 = p3.x - p2.x + const dy2 = p3.y - p2.y + return dx1 * dy2 - dy1 * dx2 + } + // 오목한 부분 찾기 + const findConcavePointIndices = (points) => { + let concaveIndices = [] + let concavePointIndices = [] + for (let i = 0; i < points.length; i++) { + const p1 = points[i] + const p2 = points[(i + 1) % points.length] + const p3 = points[(i + 2) % points.length] + const cross = crossProduct(p1, p2, p3) + if (cross < 0) { + concaveIndices.push((i + 1) % points.length) + } else { + concavePointIndices.push((i + 1) % points.length) + } + } + return { concaveIndices: concaveIndices, concavePointIndices: concavePointIndices } + } + return { mode, setMode,