How to distribute n number of points into a svg polygon javascript

46 Views Asked by At

In actual I want to create a 2d styler and I will have place n number of lights in to that. Walls of the home can be polygon and we have to place n lights in that polygon such that each of them are are evenly distributed. Current I did some work work it is not actually working because it is actually consider the enlosing rectangle of the polygon and distributing lights in that.

Here is the example.

function distributePoints(polygon, numberOfPoints) {
    const bounds = getPolygonBounds(polygon);
    const area = polygonArea(polygon);
    const spacing = Math.sqrt(area / numberOfPoints);
    const cols = Math.floor((bounds.maxX - bounds.minX) / spacing);
    const rows = Math.floor((bounds.maxY - bounds.minY) / spacing);
    const distributedPoints = [];
    for (let i = 0; i <= rows; i++) {
        for (let j = 0; j <= cols; j++) {
            const point = {
                x: bounds.minX + j * spacing,
                y: bounds.minY + i * spacing,
            };
            if (isPointInPolygon(point, polygon)) {
                distributedPoints.push(point);
            }
        }
    }
    return distributedPoints;
}
function getPolygonBounds(polygon) {
    let minX = Infinity;
    let maxX = -Infinity;
    let minY = Infinity;
    let maxY = -Infinity;
    polygon.points.forEach((point) => {
        if (point.x < minX)
            minX = point.x;
        if (point.x > maxX)
            maxX = point.x;
        if (point.y < minY)
            minY = point.y;
        if (point.y > maxY)
            maxY = point.y;
    });
    return { minX, maxX, minY, maxY };
}
function polygonArea(polygon) {
    let area = 0;
    const { points } = polygon;
    const n = points.length;
    for (let i = 0; i < n; i++) {
        const j = (i + 1) % n;
        area += points[i].x * points[j].y;
        area -= points[j].x * points[i].y;
    }
    return Math.abs(area / 2.0);
}
function isPointInPolygon(point, polygon) {
    let inside = false;
    const { x, y } = point;
    const { points } = polygon;
    const n = points.length;
    for (let i = 0, j = n - 1; i < n; j = i++) {
        const xi = points[i].x, yi = points[i].y;
        const xj = points[j].x, yj = points[j].y;
        const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
        if (intersect)
            inside = !inside;
    }
    return inside;
}
// Generate a random polygon within the bounds of the SVG
function generateRandomPolygon(numberOfVertices, maxX, maxY) {
    const points = [];
    for (let i = 0; i < numberOfVertices; i++) {
        points.push({
            x: Math.random() * maxX,
            y: Math.random() * maxY,
        });
    }
    return { points };
}
function generateRandomSimplePolygon(numberOfVertices, maxX, maxY) {
    const points = [];
    // Generate random points
    for (let i = 0; i < numberOfVertices; i++) {
        points.push({
            x: Math.random() * maxX,
            y: Math.random() * maxY,
        });
    }
    // Compute the centroid of the points
    const centroid = points.reduce((acc, point) => {
        acc.x += point.x / points.length;
        acc.y += point.y / points.length;
        return acc;
    }, { x: 0, y: 0 });
    // Sort points by angle from centroid to ensure a simple polygon
    points.sort((a, b) => {
        const angleA = Math.atan2(a.y - centroid.y, a.x - centroid.x);
        const angleB = Math.atan2(b.y - centroid.y, b.x - centroid.x);
        return angleA - angleB;
    });
    return { points };
}
const randomPolygon = generateRandomSimplePolygon(30, 700, 700);
const points = distributePoints(randomPolygon, 4);
renderVisualization(randomPolygon, points);
// Render the polygon and points on an SVG element
function renderVisualization(polygon, points) {
    const svgNS = "http://www.w3.org/2000/svg";
    const svgElement = document.createElementNS(svgNS, "svg");
    svgElement.setAttribute("width", "700");
    svgElement.setAttribute("height", "700");
    svgElement.style.border = "1px solid black";
    // Render the polygon
    const polygonElement = document.createElementNS(svgNS, "polygon");
    polygonElement.setAttribute("points", polygon.points.map((p) => `${p.x},${p.y}`).join(" "));
    polygonElement.setAttribute("stroke", "black");
    polygonElement.setAttribute("fill", "transparent");
    svgElement.appendChild(polygonElement);
    // Render the points
    points.forEach((point) => {
        const pointElement = document.createElementNS(svgNS, "circle");
        pointElement.setAttribute("cx", point.x.toString());
        pointElement.setAttribute("cy", point.y.toString());
        pointElement.setAttribute("r", "3");
        pointElement.setAttribute("fill", "red");
        svgElement.appendChild(pointElement);
    });
    document.body.appendChild(svgElement);
}

0

There are 0 best solutions below