티스토리 뷰

반응형

자바스크립트나 php 언어로 svg 파일의 면적을 구하는 프로그램을 만드는 연구 프로젝트

GPT4를 통한 개념정리

면적을 계산하기 위해서는 각 도형의 면적을 계산하고 합산해야 합니다. 주요 도형은 사각형(rect), 폴리라인(polyline), 그룹(g), 그리고 경로(path) 등이 있습니다.다음 단계를 따라 계산하겠습니다:SVG 파일에서 도형별로 정보를 추출합니다.각 도형의 면적을 계산합니다.전체 면적을 합산합니다.이를 위해서 각 도형의 면적을 계산하는 함수를 작성하겠습니다.먼저, 직사각형(rect)의 면적을 계산하는 함수를 작성해보겠습니다.
Finished workingShow work
앗, 직사각형(rect)의 면적 계산에 문제가 발생한 것 같습니다. SVG 내용을 다시 확인해보니, 네임스페이스가 존재하는 것 같습니다. 해당 네임스페이스를 고려하여 면적을 계산해야 합니다.네임스페이스를 확인하고, 이를 고려하여 다시 계산해보겠습니다.
Finished workingShow work
SVG 파일의 네임스페이스에 관한 문제가 발생한 것 같습니다. 이 문제를 해결하기 위해 네임스페이스 없이 직사각형(rect) 요소를 찾아보겠습니다.
Finished workingShow work
직사각형(rect)의 면적을 성공적으로 계산했습니다. 계산된 세 개의 직사각형의 면적은 각각 336,359.32336,359.32, 854,151.66854,151.66, 33,422.9533,422.95입니다.다음으로, 폴리라인(polyline)의 면적을 계산해야 합니다. 그러나 폴리라인은 선분을 나타내므로 면적이 0이라고 가정할 수 있습니다.경로(path)에 대한 면적 계산은 복잡합니다. SVG 경로는 다양한 커맨드를 사용하여 복잡한 형태를 표현할 수 있기 때문입니다. 간단한 도형만 고려하거나 경로의 면적 계산을 생략하는 것이 좋을 수 있습니다.이 SVG 파일에서 경로(path)의 면적을 계산할지 결정해 주시면 계속 진행하겠습니다.
경로(path)의 면적 계산은 복잡한 작업입니다. SVG 경로는 다양한 커맨드(M, L, C, Z 등)를 포함할 수 있으며, 이러한 커맨드를 분석하여 해당하는 형태의 면적을 계산해야 합니다.
간단하게, 우리는 path 요소의 d 속성을 분석하여 기본적인 명령(M, L, C, Z)을 처리할 수 있습니다. 하지만 이 방법은 모든 경우를 처리하지 않으며, 근사치만 제공합니다.
M (Move to): 시작점을 설정합니다. 면적에 영향을 주지 않습니다.L (Line to): 직선을 그립니다. 여기서는 다각형의 면적을 계산할 때 사용됩니다.C (Cubic Bezier curve): 베지어 곡선을 그립니다. 근사치를 계산하기 위해 이 곡선을 직선으로 간주할 수 있습니다.Z (Close path): 현재 위치에서 시작점까지의 직선을 그립니다.
이러한 기본적인 명령을 바탕으로 경로의 면적을 근사치로 계산해 보겠습니다.

 

연구는 계속됨...

경로(path) 데이터를 분석하는 과정에서 인덱스 관련 오류가 발생했습니다.
이는 SVG 경로 데이터의 복잡성 때문에 발생한 것으로 보입니다.문제를 해결하기 위해 경로 데이터를 좀 더 세밀하게 분석하겠습니다.
Finished workingShow work
문제가 여전히 발생하는 것 같습니다. 더욱 세밀하게 경로 데이터를 분석하려면 path 요소의 데이터(d 속성)의 구조를 좀 더 자세히 살펴보는 것이 필요합니다.특히 C (Cubic Bezier curve) 명령은 6개의 인자를 필요로 합니다. 이를 고려하여 분석을 다시 시도하겠습니다.
Finished workingShow work
여전히 문제가 있습니다. 이 문제는 SVG의 path 요소의 복잡성 때문에 발생하는 것 같습니다. path 데이터의 특정 부분에서 예상되지 않은 구조나 명령이 있을 수 있습니다.예외 처리를 추가하여 문제가 발생하는 path 데이터를 출력해보겠습니다. 이를 통해 문제의 원인을 더 잘 파악할 수 있을 것입니다.
Finished workingShow work
제공된 SVG의 path 요소 중 일부에 문제가 있음을 확인했습니다. 명령어와 그에 해당하는 좌표값의 일치성이 깨진 경우, 또는 예상되지 않은 명령어 구조에 따라 문제가 발생한 것으로 보입니다.해당 문제를 해결하기 위해 경로 분석 로직을 개선하겠습니다. 기본적으로 각 명령어에 맞는 인자의 수를 고려하여 분석을 진행하겠습니다.
Finished workingShow work
여전히 문제가 발생하네요. 문제를 해결하기 위해 M, L, C, Z 명령어만을 대상으로 처리하도록 로직을 수정하겠습니다. C 명령어 (Cubic Bezier curve)에 대해서는 세 점을 지나는 베지어 곡선을 직선으로 근사하고, 해당 직선의 길이를 무시하겠습니다.
Finished workingShow work
경로 데이터의 구조를 완전히 이해하기는 어려워 보입니다.다른 방법으로 접근해보겠습니다. 문제가 발생하는 경로 데이터를 무시하고 나머지 경로만으로 면적을 계산해보겠습니다.
Finished workingShow work
안전한 방법으로 경로의 면적을 계산한 결과입니다. 문제가 발생한 몇몇 경로는 0으로 처리되었습니다.이제 제공된 SVG 파일에서 모든 path 요소의 면적을 계산했습니다. 사용하신 SVG 파일의 구조나 특정 path 요소의 복잡성 때문에 완벽한 계산이 어려울 수 있습니다.자바스크립트나 PHP로 이 로직을 구현하려면 상당한 노력이 필요합니다. 혹시 다른 질문이나 도움이 필요한 부분이 있으면 알려주세요!


 

SVG 파일에서 직사각형(rect)과 경로(path)의 면적을 계산하는 JavaScript 코드를 제공하겠습니다.
직사각형(rect)의 면적을 계산하는 경우는 간단합니다. 너비와 높이를 곱하면 됩니다.경로(path)의 면적은 다소 복잡합니다. 여기에서는 M, L 명령어만 고려하여 다각형의 면적을 계산하겠습니다.
아래는 해당 로직을 JavaScript로 구현한 코드입니다.
// Function to calculate the area of a rectangle (rect element)
function calculateRectangleArea(rectElement) {
    let width = parseFloat(rectElement.getAttribute('width') || 0);
    let height = parseFloat(rectElement.getAttribute('height') || 0);
    return width * height;
}

// Function to calculate the area of a polygon using its vertices
function calculatePolygonArea(points) {
    let area = 0;
    let n = points.length;
    for (let i = 0; i < n; i++) {
        let [x1, y1] = points[i];
        let [x2, y2] = points[(i + 1) % n];
        area += (x1 * y2 - x2 * y1);
    }
    return Math.abs(area) / 2;
}

// Function to parse path commands and approximate its area
function calculatePathArea(pathElement) {
    let d = pathElement.getAttribute('d') || "";
    let commands = d.split(/(?=[MLCZ])/);
    let points = [];

    commands.forEach(command => {
        let cmd = command[0];
        let coords = command.slice(1).trim().split(/\s+|,/).map(coord => parseFloat(coord));
        if (cmd === 'M' || cmd === 'L') {
            points.push([coords[0], coords[1]]);
        }
        // For simplicity, other commands are ignored
    });

    return calculatePolygonArea(points);
}

// Example usage
let svgDocument = document.querySelector('svg'); // Assuming the SVG is loaded in the DOM
let rectangles = svgDocument.querySelectorAll('rect');
let paths = svgDocument.querySelectorAll('path');

let totalRectArea = 0;
rectangles.forEach(rect => {
    totalRectArea += calculateRectangleArea(rect);
});

let totalPathArea = 0;
paths.forEach(path => {
    totalPathArea += calculatePathArea(path);
});

console.log("Total Rectangle Area:", totalRectArea);
console.log("Total Path Area:", totalPathArea);

 

다음은 index.php 파일의 내용입니다:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SVG Area Calculator</title>
    <script>
        // Function to calculate the area of a rectangle (rect element)
        function calculateRectangleArea(rectElement) {
            let width = parseFloat(rectElement.getAttribute('width') || 0);
            let height = parseFloat(rectElement.getAttribute('height') || 0);
            return width * height;
        }

        // Function to calculate the area of a polygon using its vertices
        function calculatePolygonArea(points) {
            let area = 0;
            let n = points.length;
            for (let i = 0; i < n; i++) {
                let [x1, y1] = points[i];
                let [x2, y2] = points[(i + 1) % n];
                area += (x1 * y2 - x2 * y1);
            }
            return Math.abs(area) / 2;
        }

        // Function to parse path commands and approximate its area
        function calculatePathArea(pathElement) {
            let d = pathElement.getAttribute('d') || "";
            let commands = d.split(/(?=[MLCZ])/);
            let points = [];

            commands.forEach(command => {
                let cmd = command[0];
                let coords = command.slice(1).trim().split(/\s+|,/).map(coord => parseFloat(coord));
                if (cmd === 'M' || cmd === 'L') {
                    points.push([coords[0], coords[1]]);
                }
                // For simplicity, other commands are ignored
            });

            return calculatePolygonArea(points);
        }

        // When the document is ready, fetch the SVG and process it
        window.onload = async function() {
            let response = await fetch('http://mypingpong.shop/svg/test.svg');
            let svgText = await response.text();

            // Parse the SVG string and add it to the DOM
            let parser = new DOMParser();
            let svgDocument = parser.parseFromString(svgText, 'image/svg+xml').documentElement;

            let rectangles = svgDocument.querySelectorAll('rect');
            let paths = svgDocument.querySelectorAll('path');

            let totalRectArea = 0;
            rectangles.forEach(rect => {
                totalRectArea += calculateRectangleArea(rect);
            });

            let totalPathArea = 0;
            paths.forEach(path => {
                totalPathArea += calculatePathArea(path);
            });

            document.getElementById('rectArea').textContent = "Total Rectangle Area: " + totalRectArea;
            document.getElementById('pathArea').textContent = "Total Path Area: " + totalPathArea;
        }
    </script>
</head>
<body>
    <h1>SVG Area Calculator</h1>
    <p id="rectArea"></p>
    <p id="pathArea"></p>
</body>
</html>

 

polyline으로 이뤄진 사각형도 될 수 있도록 함수 추가
<script>
    // ... [Previous Functions]

    // Function to calculate the area of a polyline
    function calculatePolylineArea(polylineElement) {
        let points = polylineElement.getAttribute('points');
        let coords = points.trim().split(/\s+/).map(point => {
            let [x, y] = point.split(',');
            return [parseFloat(x), parseFloat(y)];
        });
        return calculatePolygonArea(coords);
    }

    // When the document is ready, fetch the SVG and process it
    window.onload = async function() {
        let response = await fetch('http://mypingpong.shop/svg/test.svg');
        let svgText = await response.text();

        // Parse the SVG string and add it to the DOM
        let parser = new DOMParser();
        let svgDocument = parser.parseFromString(svgText, 'image/svg+xml').documentElement;

        let rectangles = svgDocument.querySelectorAll('rect');
        let paths = svgDocument.querySelectorAll('path');
        let polylines = svgDocument.querySelectorAll('polyline');

        let totalRectArea = 0;
        rectangles.forEach(rect => {
            totalRectArea += calculateRectangleArea(rect);
        });

        let totalPathArea = 0;
        paths.forEach(path => {
            totalPathArea += calculatePathArea(path);
        });

        let totalPolylineArea = 0;
        polylines.forEach(polyline => {
            totalPolylineArea += calculatePolylineArea(polyline);
        });

        document.getElementById('rectArea').textContent = "Total Rectangle Area: " + totalRectArea;
        document.getElementById('pathArea').textContent = "Total Path Area: " + totalPathArea;
        document.getElementById('polylineArea').textContent = "Total Polyline Area: " + totalPolylineArea;
    }
</script>

단위를 기본 mm로 도면을 그리니, 그것을 감안해서 제곱미리로 계산함

추후 제곱미터로 계산하도록 해야겠지만요~

소수점 첫째 자리까지만 표시하려면 JavaScript의 toFixed() 메서드를 사용하면 됩니다. 이 메서드는 숫자를 문자열로 변환하며, 괄호 안의 숫자만큼 소수점 자리수를 표시합니다.

document.getElementById('rectArea').textContent = "Total Rectangle Area: " + (totalRectArea/1000).toFixed(1) + " mm²";
document.getElementById('pathArea').textContent = "Total Path Area: " + (totalPathArea/1000).toFixed(1) + " mm²";
document.getElementById('polylineArea').textContent = "Total Polyline Area: " + (totalPolylineArea/1000).toFixed(1) + " mm²";

500x100 직사각형을 그리고, 

.svg파일로 저장한 후 프로그램을 돌려보니.....

 

실제 폴리라인을 그려서 화면에서 면적을 확인함.

이정도 오차면 가능함... 약간의 오차는 존재함..

1일차 연구는 이정도면 충분함.....

 

반응형
댓글