diff --git a/last_updated.log b/last_updated.log new file mode 100755 index 00000000..e7082b44 --- /dev/null +++ b/last_updated.log @@ -0,0 +1 @@ +1772531776 \ No newline at end of file diff --git a/sl b/sl new file mode 100755 index 00000000..37c17447 Binary files /dev/null and b/sl differ diff --git a/snippet.js b/snippet.js new file mode 100644 index 00000000..feed1e5f --- /dev/null +++ b/snippet.js @@ -0,0 +1,272 @@ +/** + * Renders an edge result (polygon) on the canvas + * @param {Object} res - Edge result object containing polygon vertices + * @param wallLineStart + * @param wallLineEnd + * @param {Array} res.Polygon - Array of vertex objects with X,Y coordinates + */ + const drawEdgeResult = (res, wallLineStart, wallLineEnd) => { + if (!ctx || res.Polygon.length < 2) return; + + // 삼각형 polygon인지 확인 (3개의 점으로 구성) + const isTriangle = res.Polygon.length === 3; + + if (isTriangle) { + // 삼각형인 경우 직선을 그리기 + drawStraightLineFromSkeleton(res); + return; + } + + const skelP0 = { x: res.Polygon[0].X, y: res.Polygon[0].Y }; + const skelP1 = { x: res.Polygon[1].X, y: res.Polygon[1].Y }; + + // Helper function to check if a point is on a line segment + const isPointOnSegment = (p, q, r) => { + return ( + q.x <= Math.max(p.x, r.x) && + q.x >= Math.min(p.x, r.x) && + q.y <= Math.max(p.y, r.y) && + q.y >= Math.min(p.y, r.y) + ); + }; + + // Helper function to check for collinearity + const areCollinear = (p, q, r) => { + const val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); + return Math.abs(val) < 1e-9; // Use a small tolerance for float comparison + }; + + let isOverlapping = false; + for (let i = 0; i < points.length; i++) { + const polyP1 = { x: points[i][0], y: points[i][1] }; + const polyP2 = { x: points[(i + 1) % points.length][0], y: points[(i + 1) % points.length][1] }; + + // Check if the skeleton edge is collinear with the polygon edge + // and if the skeleton points lie on the polygon edge segment. + if (areCollinear(polyP1, polyP2, skelP0) && + areCollinear(polyP1, polyP2, skelP1) && + isPointOnSegment(polyP1, skelP0, polyP2) && + isPointOnSegment(polyP1, skelP1, polyP2)) { + isOverlapping = true; + break; + } + } + + const p0 = res.Polygon[0]; + const p1 = res.Polygon[1]; + const dx = p1.X - p0.X; + const dy = p1.Y - p0.Y; + const len = Math.hypot(dx, dy); + if (len === 0) return; + + // 정규화된 방향 벡터 계산 + const dirX = dx / len; + const dirY = dy / len; + + // First pass: Create a filled polygon (transparent fill) + ctx.globalAlpha = 0.2; // Fully transparent + ctx.beginPath(); + ctx.fillStyle = 'green'; + + // Start from first vertex + ctx.moveTo(res.Polygon[0].X, res.Polygon[0].Y); + // Draw lines to each subsequent vertex + for (const v of res.Polygon) { + ctx.lineTo(v.X, v.Y); + } + ctx.closePath(); + ctx.fill(); + + // Second pass: Draw the polygon outline + ctx.globalAlpha = 1; // Fully opaque + ctx.beginPath(); + ctx.strokeStyle = isOverlapping ? 'red' : '#3C78D8'; // Blue color + ctx.lineWidth = 3; // 3px line width + + // Redraw the same polygon shape + ctx.moveTo(res.Polygon[0].X, res.Polygon[0].Y); + for (const v of res.Polygon) { + const wX = wallLineStart.X; + const wY = wallLineStart.Y; + const wEndX = wallLineEnd.X; + const wEndY = wallLineEnd.Y; + console.log("1::", v.X, v.Y); + if ((v.X === wallLineStart.X && v.Y === wallLineEnd.Y) || (v.X === wallLineEnd.X && v.Y === wallLineStart.Y)) { + console.log(v.X, v.Y); + + }else{ + ctx.lineTo(v.X, v.Y); + } + + ctx.lineTo(v.X, v.Y); + } + ctx.closePath(); + ctx.stroke(); + }; + + /** + * 삼각형 polygon 대신 직선을 그리는 함수 + * @param {Object} res - Edge result object containing polygon vertices + */ + const drawStraightLineFromSkeleton = (res) => { + if (!ctx || res.Polygon.length !== 3) return; + + // 삼각형의 세 점 + const p1 = res.Polygon[0]; + const p2 = res.Polygon[1]; + const p3 = res.Polygon[2]; + + // 다각형의 경계에 있는 점들을 찾기 (원래 다각형의 변 위에 있는 점들) + const boundaryPoints = []; + const innerPoints = []; + + [p1, p2, p3].forEach(point => { + let isOnBoundary = false; + + // 원래 다각형의 각 변과 비교 + for (let i = 0; i < points.length; i++) { + const lineStart = points[i]; + const lineEnd = points[(i + 1) % points.length]; + + // 점이 이 변 위에 있는지 확인 + if (isPointOnLine(point, lineStart, lineEnd)) { + isOnBoundary = true; + break; + } + } + + if (isOnBoundary) { + boundaryPoints.push(point); + } else { + innerPoints.push(point); + } + }); + + // 경계점이 2개이고 내부점이 1개인 경우 (일반적인 삼각형 케이스) + if (boundaryPoints.length === 2 && innerPoints.length === 1) { + const innerPoint = innerPoints[0]; + + // 내부점에서 맞은편 경계까지의 직선을 그리기 + drawExtendedLine(innerPoint, boundaryPoints); + } + }; + + /** + * 점이 선분 위에 있는지 확인하는 함수 + */ + const isPointOnLine = (point, lineStart, lineEnd) => { + const tolerance = 1; // 허용 오차 + + // 점과 선분의 두 끝점 사이의 거리 합이 선분의 길이와 같은지 확인 + const d1 = Math.hypot(point.X - lineStart[0], point.Y - lineStart[1]); + const d2 = Math.hypot(point.X - lineEnd[0], point.Y - lineEnd[1]); + const lineLength = Math.hypot(lineEnd[0] - lineStart[0], lineEnd[1] - lineStart[1]); + + return Math.abs(d1 + d2 - lineLength) < tolerance; + }; + + /** + * 내부점에서 맞은편 경계까지 직선을 연장해서 그리는 함수 + */ + const drawExtendedLine = (innerPoint, boundaryPoints) => { + if (boundaryPoints.length !== 2) return; + + // 경계점들의 중점 계산 (삼각형의 밑변 중점) + const midPoint = { + X: (boundaryPoints[0].X + boundaryPoints[1].X) / 2, + Y: (boundaryPoints[0].Y + boundaryPoints[1].Y) / 2 + }; + + // 내부점에서 중점으로의 방향 벡터 계산 + const dirX = midPoint.X - innerPoint.X; + const dirY = midPoint.Y - innerPoint.Y; + const len = Math.hypot(dirX, dirY); + + if (len === 0) return; + + // 정규화된 방향 벡터 + const normalizedDirX = dirX / len; + const normalizedDirY = dirY / len; + + // 맞은편 경계와의 교점 찾기 + const intersectionPoint = findIntersectionWithBoundary(innerPoint, normalizedDirX, normalizedDirY); + + if (intersectionPoint) { + // 직선 그리기 + ctx.beginPath(); + ctx.strokeStyle = '#3C78D8'; // 파란색 + ctx.lineWidth = 3; + ctx.moveTo(innerPoint.X, innerPoint.Y); + ctx.lineTo(intersectionPoint.X, intersectionPoint.Y); + ctx.stroke(); + } + }; + + /** + * 점에서 특정 방향으로 다각형 경계와의 교점을 찾는 함수 + */ + const findIntersectionWithBoundary = (startPoint, dirX, dirY) => { + let closestIntersection = null; + let minDistance = Infinity; + + // 모든 다각형의 변과 교점 확인 + for (let i = 0; i < points.length; i++) { + const lineStart = points[i]; + const lineEnd = points[(i + 1) % points.length]; + + // 레이와 선분의 교점 계산 + const intersection = getLineIntersection( + startPoint, + { X: startPoint.X + dirX * 1000, Y: startPoint.Y + dirY * 1000 }, // 충분히 긴 레이 + { X: lineStart[0], Y: lineStart[1] }, + { X: lineEnd[0], Y: lineEnd[1] } + ); + + if (intersection) { + // 교점이 시작점에서 올바른 방향에 있는지 확인 + const toIntersection = { + X: intersection.X - startPoint.X, + Y: intersection.Y - startPoint.Y + }; + + // 내적으로 방향 확인 (양수면 같은 방향) + const dotProduct = toIntersection.X * dirX + toIntersection.Y * dirY; + + if (dotProduct > 0) { // 올바른 방향 + const distance = Math.hypot(toIntersection.X, toIntersection.Y); + if (distance < minDistance) { + minDistance = distance; + closestIntersection = intersection; + } + } + } + } + + return closestIntersection; + }; + + /** + * 두 선분의 교점을 계산하는 함수 + */ + const getLineIntersection = (p1, p2, p3, p4) => { + const x1 = p1.X, y1 = p1.Y; + const x2 = p2.X, y2 = p2.Y; + const x3 = p3.X, y3 = p3.Y; + const x4 = p4.X, y4 = p4.Y; + + const denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); + if (Math.abs(denom) < 1e-10) return null; // 평행선 + + const t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denom; + const u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / denom; + + // 두 번째 선분(다각형의 변) 위에 교점이 있는지 확인 + if (u >= 0 && u <= 1) { + return { + X: x1 + t * (x2 - x1), + Y: y1 + t * (y2 - y1) + }; + } + + return null; + }; diff --git a/snippet2.js b/snippet2.js new file mode 100644 index 00000000..feed1e5f --- /dev/null +++ b/snippet2.js @@ -0,0 +1,272 @@ +/** + * Renders an edge result (polygon) on the canvas + * @param {Object} res - Edge result object containing polygon vertices + * @param wallLineStart + * @param wallLineEnd + * @param {Array} res.Polygon - Array of vertex objects with X,Y coordinates + */ + const drawEdgeResult = (res, wallLineStart, wallLineEnd) => { + if (!ctx || res.Polygon.length < 2) return; + + // 삼각형 polygon인지 확인 (3개의 점으로 구성) + const isTriangle = res.Polygon.length === 3; + + if (isTriangle) { + // 삼각형인 경우 직선을 그리기 + drawStraightLineFromSkeleton(res); + return; + } + + const skelP0 = { x: res.Polygon[0].X, y: res.Polygon[0].Y }; + const skelP1 = { x: res.Polygon[1].X, y: res.Polygon[1].Y }; + + // Helper function to check if a point is on a line segment + const isPointOnSegment = (p, q, r) => { + return ( + q.x <= Math.max(p.x, r.x) && + q.x >= Math.min(p.x, r.x) && + q.y <= Math.max(p.y, r.y) && + q.y >= Math.min(p.y, r.y) + ); + }; + + // Helper function to check for collinearity + const areCollinear = (p, q, r) => { + const val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); + return Math.abs(val) < 1e-9; // Use a small tolerance for float comparison + }; + + let isOverlapping = false; + for (let i = 0; i < points.length; i++) { + const polyP1 = { x: points[i][0], y: points[i][1] }; + const polyP2 = { x: points[(i + 1) % points.length][0], y: points[(i + 1) % points.length][1] }; + + // Check if the skeleton edge is collinear with the polygon edge + // and if the skeleton points lie on the polygon edge segment. + if (areCollinear(polyP1, polyP2, skelP0) && + areCollinear(polyP1, polyP2, skelP1) && + isPointOnSegment(polyP1, skelP0, polyP2) && + isPointOnSegment(polyP1, skelP1, polyP2)) { + isOverlapping = true; + break; + } + } + + const p0 = res.Polygon[0]; + const p1 = res.Polygon[1]; + const dx = p1.X - p0.X; + const dy = p1.Y - p0.Y; + const len = Math.hypot(dx, dy); + if (len === 0) return; + + // 정규화된 방향 벡터 계산 + const dirX = dx / len; + const dirY = dy / len; + + // First pass: Create a filled polygon (transparent fill) + ctx.globalAlpha = 0.2; // Fully transparent + ctx.beginPath(); + ctx.fillStyle = 'green'; + + // Start from first vertex + ctx.moveTo(res.Polygon[0].X, res.Polygon[0].Y); + // Draw lines to each subsequent vertex + for (const v of res.Polygon) { + ctx.lineTo(v.X, v.Y); + } + ctx.closePath(); + ctx.fill(); + + // Second pass: Draw the polygon outline + ctx.globalAlpha = 1; // Fully opaque + ctx.beginPath(); + ctx.strokeStyle = isOverlapping ? 'red' : '#3C78D8'; // Blue color + ctx.lineWidth = 3; // 3px line width + + // Redraw the same polygon shape + ctx.moveTo(res.Polygon[0].X, res.Polygon[0].Y); + for (const v of res.Polygon) { + const wX = wallLineStart.X; + const wY = wallLineStart.Y; + const wEndX = wallLineEnd.X; + const wEndY = wallLineEnd.Y; + console.log("1::", v.X, v.Y); + if ((v.X === wallLineStart.X && v.Y === wallLineEnd.Y) || (v.X === wallLineEnd.X && v.Y === wallLineStart.Y)) { + console.log(v.X, v.Y); + + }else{ + ctx.lineTo(v.X, v.Y); + } + + ctx.lineTo(v.X, v.Y); + } + ctx.closePath(); + ctx.stroke(); + }; + + /** + * 삼각형 polygon 대신 직선을 그리는 함수 + * @param {Object} res - Edge result object containing polygon vertices + */ + const drawStraightLineFromSkeleton = (res) => { + if (!ctx || res.Polygon.length !== 3) return; + + // 삼각형의 세 점 + const p1 = res.Polygon[0]; + const p2 = res.Polygon[1]; + const p3 = res.Polygon[2]; + + // 다각형의 경계에 있는 점들을 찾기 (원래 다각형의 변 위에 있는 점들) + const boundaryPoints = []; + const innerPoints = []; + + [p1, p2, p3].forEach(point => { + let isOnBoundary = false; + + // 원래 다각형의 각 변과 비교 + for (let i = 0; i < points.length; i++) { + const lineStart = points[i]; + const lineEnd = points[(i + 1) % points.length]; + + // 점이 이 변 위에 있는지 확인 + if (isPointOnLine(point, lineStart, lineEnd)) { + isOnBoundary = true; + break; + } + } + + if (isOnBoundary) { + boundaryPoints.push(point); + } else { + innerPoints.push(point); + } + }); + + // 경계점이 2개이고 내부점이 1개인 경우 (일반적인 삼각형 케이스) + if (boundaryPoints.length === 2 && innerPoints.length === 1) { + const innerPoint = innerPoints[0]; + + // 내부점에서 맞은편 경계까지의 직선을 그리기 + drawExtendedLine(innerPoint, boundaryPoints); + } + }; + + /** + * 점이 선분 위에 있는지 확인하는 함수 + */ + const isPointOnLine = (point, lineStart, lineEnd) => { + const tolerance = 1; // 허용 오차 + + // 점과 선분의 두 끝점 사이의 거리 합이 선분의 길이와 같은지 확인 + const d1 = Math.hypot(point.X - lineStart[0], point.Y - lineStart[1]); + const d2 = Math.hypot(point.X - lineEnd[0], point.Y - lineEnd[1]); + const lineLength = Math.hypot(lineEnd[0] - lineStart[0], lineEnd[1] - lineStart[1]); + + return Math.abs(d1 + d2 - lineLength) < tolerance; + }; + + /** + * 내부점에서 맞은편 경계까지 직선을 연장해서 그리는 함수 + */ + const drawExtendedLine = (innerPoint, boundaryPoints) => { + if (boundaryPoints.length !== 2) return; + + // 경계점들의 중점 계산 (삼각형의 밑변 중점) + const midPoint = { + X: (boundaryPoints[0].X + boundaryPoints[1].X) / 2, + Y: (boundaryPoints[0].Y + boundaryPoints[1].Y) / 2 + }; + + // 내부점에서 중점으로의 방향 벡터 계산 + const dirX = midPoint.X - innerPoint.X; + const dirY = midPoint.Y - innerPoint.Y; + const len = Math.hypot(dirX, dirY); + + if (len === 0) return; + + // 정규화된 방향 벡터 + const normalizedDirX = dirX / len; + const normalizedDirY = dirY / len; + + // 맞은편 경계와의 교점 찾기 + const intersectionPoint = findIntersectionWithBoundary(innerPoint, normalizedDirX, normalizedDirY); + + if (intersectionPoint) { + // 직선 그리기 + ctx.beginPath(); + ctx.strokeStyle = '#3C78D8'; // 파란색 + ctx.lineWidth = 3; + ctx.moveTo(innerPoint.X, innerPoint.Y); + ctx.lineTo(intersectionPoint.X, intersectionPoint.Y); + ctx.stroke(); + } + }; + + /** + * 점에서 특정 방향으로 다각형 경계와의 교점을 찾는 함수 + */ + const findIntersectionWithBoundary = (startPoint, dirX, dirY) => { + let closestIntersection = null; + let minDistance = Infinity; + + // 모든 다각형의 변과 교점 확인 + for (let i = 0; i < points.length; i++) { + const lineStart = points[i]; + const lineEnd = points[(i + 1) % points.length]; + + // 레이와 선분의 교점 계산 + const intersection = getLineIntersection( + startPoint, + { X: startPoint.X + dirX * 1000, Y: startPoint.Y + dirY * 1000 }, // 충분히 긴 레이 + { X: lineStart[0], Y: lineStart[1] }, + { X: lineEnd[0], Y: lineEnd[1] } + ); + + if (intersection) { + // 교점이 시작점에서 올바른 방향에 있는지 확인 + const toIntersection = { + X: intersection.X - startPoint.X, + Y: intersection.Y - startPoint.Y + }; + + // 내적으로 방향 확인 (양수면 같은 방향) + const dotProduct = toIntersection.X * dirX + toIntersection.Y * dirY; + + if (dotProduct > 0) { // 올바른 방향 + const distance = Math.hypot(toIntersection.X, toIntersection.Y); + if (distance < minDistance) { + minDistance = distance; + closestIntersection = intersection; + } + } + } + } + + return closestIntersection; + }; + + /** + * 두 선분의 교점을 계산하는 함수 + */ + const getLineIntersection = (p1, p2, p3, p4) => { + const x1 = p1.X, y1 = p1.Y; + const x2 = p2.X, y2 = p2.Y; + const x3 = p3.X, y3 = p3.Y; + const x4 = p4.X, y4 = p4.Y; + + const denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); + if (Math.abs(denom) < 1e-10) return null; // 평행선 + + const t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denom; + const u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / denom; + + // 두 번째 선분(다각형의 변) 위에 교점이 있는지 확인 + if (u >= 0 && u <= 1) { + return { + X: x1 + t * (x2 - x1), + Y: y1 + t * (y2 - y1) + }; + } + + return null; + }; diff --git a/src/app/sample/page.jsx b/src/app/sample/page.jsx new file mode 100644 index 00000000..f9bd14fe --- /dev/null +++ b/src/app/sample/page.jsx @@ -0,0 +1,13 @@ +'use client' +import { useContext } from 'react' +import { QcastContext } from '@/app/QcastProvider' + +export default function SamplePage() { + const { setIsGlobalLoading } = useContext(QcastContext) + setIsGlobalLoading(false) + return ( + <> +

Sample Page

+ + ) +} diff --git a/src/app/sample/sk/page.jsx b/src/app/sample/sk/page.jsx new file mode 100644 index 00000000..b2507054 --- /dev/null +++ b/src/app/sample/sk/page.jsx @@ -0,0 +1,12 @@ + +import App from './App' + +export default function SkPage() { + + return ( + <> + + + + ) +} diff --git a/src/app/sample/sk/styles.css b/src/app/sample/sk/styles.css new file mode 100644 index 00000000..3f13bfa8 --- /dev/null +++ b/src/app/sample/sk/styles.css @@ -0,0 +1,80 @@ +* { + font-family: monospace; + box-sizing: border-box; +} + +body { + margin: 0; + padding: 0; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + background-color: #f5f5f5; +} + +#root { + width: 100%; + max-width: 1000px; + margin: 0 auto; + padding: 20px; +} + +.panel { + width: 100%; + text-align: center; +} + +.controls { + margin: 16px 0; +} + +.controls button { + margin: 0 5px; + padding: 8px 16px; + border: 1px solid #aaa; + background: #fff; + border-radius: 4px; + cursor: pointer; + transition: background-color 0.2s; +} + +.controls button:hover { + background-color: #eee; +} + +.description { + margin: 10px 0; + color: #555; +} + +#wrapper { + display: flex; + justify-content: center; + width: 100%; + overflow: auto; +} + +canvas { + background: white; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); +} + +.calculator-btn { + transition: all 0.1s ease-in-out; +} +.calculator-btn:active { + transform: scale(0.95); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} +/* 키패드 나타나고 사라지는 애니메이션 */ +.keypad-container.hidden { + opacity: 0; + transform: translateY(-10px) scale(0.95); + pointer-events: none; /* 숨겨졌을 때 클릭 방지 */ +} +.keypad-container { + opacity: 1; + transform: translateY(0) scale(1); + transition: opacity 150ms ease-out, transform 150ms ease-out; +} \ No newline at end of file diff --git a/src/components/management/StuffSubHeader.jsx b/src/components/management/StuffSubHeader.jsx index b5df5411..6729405e 100644 --- a/src/components/management/StuffSubHeader.jsx +++ b/src/components/management/StuffSubHeader.jsx @@ -39,7 +39,7 @@ export default function StuffSubHeader({ type }) { if (isObjectNotEmpty(managementState)) { if (managementState?.createSaleStoreId === 'T01') { if (session?.storeId !== 'T01') { - //T01 계정이 작성한 안건 중 해당 판매점 ID가 열람 가능한 것에 한합니다. + //T01 계정이 작성한 안건 중 해당 판매점 ID가 열람 가능한 것에 한합니다.. if(session?.storeId !== managementState?.saleStoreId){ setButtonStyle('none') } diff --git a/src/hooks/option/useCanvasSetting.js b/src/hooks/option/useCanvasSetting.js index fc80fe70..11315cdf 100644 --- a/src/hooks/option/useCanvasSetting.js +++ b/src/hooks/option/useCanvasSetting.js @@ -572,7 +572,6 @@ export function useCanvasSetting(executeEffect = true) { try { // roofsData가 단일 항목인 경우, 모든 추가된 지붕재(addedRoofs)를 사용하여 다중 항목으로 확장 let roofMaterialsList = [] - if (params.roofsData && params.roofsData.length === 1) { // 단일 항목인 경우 addedRoofs의 모든 항목을 사용 if (addedRoofs && addedRoofs.length > 0) {