Skip to content

Commit 32e324a

Browse files
committed
feat: add self-intersection detection for polygons in SvgParser
1 parent 19f0de5 commit 32e324a

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

main/svgparser.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,7 +1507,88 @@ export class SvgParser {
15071507
// Record the start of a subpath
15081508
if (command=='M' || command=='m') x0=x, y0=y;
15091509
}
1510+
console.log("for path:", path);
1511+
// After generating the polygon points, check for self-intersection.
1512+
if (poly.length > 0) {
1513+
let uniquePolyForCheck = poly.slice();
1514+
console.log('1:uniquePolyForCheck.length', uniquePolyForCheck.length);
1515+
// Remove duplicate last point if it's the same as the first (for closed paths)
1516+
if (uniquePolyForCheck.length > 1 && GeometryUtil.almostEqualPoints(uniquePolyForCheck[0], uniquePolyForCheck[uniquePolyForCheck.length - 1], this.conf.toleranceSvg)) {
1517+
uniquePolyForCheck.pop();
1518+
}
1519+
1520+
console.log('2:uniquePolyForCheck.length', uniquePolyForCheck.length);
1521+
console.log('uniquePolyForCheck', uniquePolyForCheck);
1522+
console.log('this.isPolygonSelfIntersecting', this.isPolygonSelfIntersecting(uniquePolyForCheck));
1523+
if (uniquePolyForCheck.length >= 3 && this.isPolygonSelfIntersecting(uniquePolyForCheck)) {
1524+
console.warn('SVG Import: Path was skipped due to self-intersection. Source path d:', path.getAttribute('d') || 'N/A');
1525+
return []; // Return an empty array to indicate this path should be skipped
1526+
}
1527+
}
15101528

15111529
return poly;
15121530
};
15131531
}
1532+
1533+
SvgParser.prototype.isPolygonSelfIntersecting = function(uniquePolygonPoints) {
1534+
const n = uniquePolygonPoints.length;
1535+
// console.log('[isPolygonSelfIntersecting] Checking polygon with points:', JSON.parse(JSON.stringify(uniquePolygonPoints)));
1536+
// A simple polygon needs at least 4 vertices to self-intersect.
1537+
// Triangles (n=3) cannot self-intersect in this context.
1538+
if (n < 4) {
1539+
// console.log('[isPolygonSelfIntersecting] Polygon has less than 4 points, cannot self-intersect.');
1540+
return false;
1541+
}
1542+
1543+
for (let i = 0; i < n; i++) {
1544+
const p1 = uniquePolygonPoints[i];
1545+
const p2 = uniquePolygonPoints[(i + 1) % n]; // End of the first segment
1546+
1547+
// Iterate over subsequent segments for comparison
1548+
// Start j from i + 1 to get unique pairs of segments.
1549+
// The adjacency check will filter out immediate neighbors.
1550+
for (let j = i + 1; j < n; j++) {
1551+
const p3 = uniquePolygonPoints[j];
1552+
const p4 = uniquePolygonPoints[(j + 1) % n]; // End of the second segment
1553+
1554+
// console.log(`[isPolygonSelfIntersecting] Comparing segment ${i}-${(i + 1) % n} [(${p1.x},${p1.y})-(${p2.x},${p2.y})] with segment ${j}-${(j + 1) % n} [(${p3.x},${p3.y})-(${p4.x},${p4.y})]`);
1555+
1556+
// Avoid checking adjacent segments.
1557+
if (((i + 1) % n === j) || (i === (j + 1) % n)) {
1558+
// console.log(`[isPolygonSelfIntersecting] Segments ${i}-${(i + 1) % n} and ${j}-${(j + 1) % n} are adjacent. Skipping.`);
1559+
continue;
1560+
}
1561+
1562+
const intersection = GeometryUtil.lineIntersect(p1, p2, p3, p4, false);
1563+
1564+
if (intersection) {
1565+
console.log(`[isPolygonSelfIntersecting] Raw intersection found between segment ${i}-${(i+1)%n} and ${j}-${(j+1)%n}:`, JSON.parse(JSON.stringify(intersection)), 'P1,P2:', JSON.parse(JSON.stringify(p1)), JSON.parse(JSON.stringify(p2)), 'P3,P4:', JSON.parse(JSON.stringify(p3)), JSON.parse(JSON.stringify(p4)));
1566+
1567+
const tol = this.conf.toleranceSvg || 0.01;
1568+
1569+
// Check if the intersection point is an endpoint of the first segment
1570+
let isEndpointForSeg1 = GeometryUtil.almostEqualPoints(intersection, p1, tol) ||
1571+
GeometryUtil.almostEqualPoints(intersection, p2, tol);
1572+
1573+
// Check if the intersection point is an endpoint of the second segment
1574+
let isEndpointForSeg2 = GeometryUtil.almostEqualPoints(intersection, p3, tol) ||
1575+
GeometryUtil.almostEqualPoints(intersection, p4, tol);
1576+
1577+
console.log(`[isPolygonSelfIntersecting] Endpoint checks for intersection: isEndpointForSeg1=${isEndpointForSeg1}, isEndpointForSeg2=${isEndpointForSeg2}`);
1578+
1579+
// A true self-intersection occurs if the intersection is NOT a shared vertex for both segments.
1580+
// If it's an endpoint for one segment but lies in the interior of the other (or vice-versa),
1581+
// or if it's in the interior of both, it's a self-intersection.
1582+
// It's NOT a self-intersection if it's an endpoint of seg1 AND an endpoint of seg2 (segments touch at a common vertex).
1583+
if (!(isEndpointForSeg1 && isEndpointForSeg2)) {
1584+
console.warn('[isPolygonSelfIntersecting] Self-intersecting path segment DETECTED. Intersection at:', JSON.parse(JSON.stringify(intersection)), 'Segments:', {i, p1: JSON.parse(JSON.stringify(p1)), p2: JSON.parse(JSON.stringify(p2))}, {j, p3: JSON.parse(JSON.stringify(p3)), p4: JSON.parse(JSON.stringify(p4))});
1585+
return true; // Found a true self-intersection
1586+
} else {
1587+
console.log('[isPolygonSelfIntersecting] Intersection is a shared vertex (endpoint of both segments). Not a self-intersection in this context. Details:', {i, j, p1: JSON.parse(JSON.stringify(p1)), p2: JSON.parse(JSON.stringify(p2)), p3: JSON.parse(JSON.stringify(p3)), p4: JSON.parse(JSON.stringify(p4)), intersection: JSON.parse(JSON.stringify(intersection))});
1588+
}
1589+
}
1590+
}
1591+
}
1592+
// console.log('[isPolygonSelfIntersecting] No self-intersection detected for polygon:', JSON.parse(JSON.stringify(uniquePolygonPoints)));
1593+
return false; // No self-intersections found
1594+
};

0 commit comments

Comments
 (0)