Skip to content

Commit 7d8bb20

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

File tree

1 file changed

+79
-0
lines changed

1 file changed

+79
-0
lines changed

main/svgparser.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,6 +1508,85 @@ export class SvgParser {
15081508
if (command=='M' || command=='m') x0=x, y0=y;
15091509
}
15101510

1511+
// After generating the polygon points, check for self-intersection.
1512+
if (poly.length > 0) {
1513+
let uniquePolyForCheck = poly.slice();
1514+
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+
if (uniquePolyForCheck.length >= 3 && this.isPolygonSelfIntersecting(uniquePolyForCheck)) {
1521+
console.warn('SVG Import: Path was skipped due to self-intersection. Source path d:', path.getAttribute('d') || 'N/A');
1522+
console.trace();
1523+
return []; // Return an empty array to indicate this path should be skipped
1524+
}
1525+
}
1526+
15111527
return poly;
15121528
};
15131529
}
1530+
1531+
SvgParser.prototype.isPolygonSelfIntersecting = function(uniquePolygonPoints) {
1532+
const n = uniquePolygonPoints.length;
1533+
// console.log('[isPolygonSelfIntersecting] Checking polygon with points:', JSON.parse(JSON.stringify(uniquePolygonPoints)));
1534+
// A simple polygon needs at least 4 vertices to self-intersect.
1535+
// Triangles (n=3) cannot self-intersect in this context.
1536+
if (n < 4) {
1537+
// console.log('[isPolygonSelfIntersecting] Polygon has less than 4 points, cannot self-intersect.');
1538+
return false;
1539+
}
1540+
1541+
for (let i = 0; i < n; i++) {
1542+
const p1 = uniquePolygonPoints[i];
1543+
const p2 = uniquePolygonPoints[(i + 1) % n]; // End of the first segment
1544+
1545+
// Iterate over subsequent segments for comparison
1546+
// Start j from i + 1 to get unique pairs of segments.
1547+
// The adjacency check will filter out immediate neighbors.
1548+
for (let j = i + 1; j < n; j++) {
1549+
const p3 = uniquePolygonPoints[j];
1550+
const p4 = uniquePolygonPoints[(j + 1) % n]; // End of the second segment
1551+
1552+
// 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})]`);
1553+
1554+
// Avoid checking adjacent segments.
1555+
if (((i + 1) % n === j) || (i === (j + 1) % n)) {
1556+
// console.log(`[isPolygonSelfIntersecting] Segments ${i}-${(i + 1) % n} and ${j}-${(j + 1) % n} are adjacent. Skipping.`);
1557+
continue;
1558+
}
1559+
1560+
const intersection = GeometryUtil.lineIntersect(p1, p2, p3, p4, false);
1561+
1562+
if (intersection) {
1563+
//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)));
1564+
1565+
const tol = this.conf.toleranceSvg || 0.01;
1566+
1567+
// Check if the intersection point is an endpoint of the first segment
1568+
let isEndpointForSeg1 = GeometryUtil.almostEqualPoints(intersection, p1, tol) ||
1569+
GeometryUtil.almostEqualPoints(intersection, p2, tol);
1570+
1571+
// Check if the intersection point is an endpoint of the second segment
1572+
let isEndpointForSeg2 = GeometryUtil.almostEqualPoints(intersection, p3, tol) ||
1573+
GeometryUtil.almostEqualPoints(intersection, p4, tol);
1574+
1575+
//console.log(`[isPolygonSelfIntersecting] Endpoint checks for intersection: isEndpointForSeg1=${isEndpointForSeg1}, isEndpointForSeg2=${isEndpointForSeg2}`);
1576+
1577+
// A true self-intersection occurs if the intersection is NOT a shared vertex for both segments.
1578+
// If it's an endpoint for one segment but lies in the interior of the other (or vice-versa),
1579+
// or if it's in the interior of both, it's a self-intersection.
1580+
// It's NOT a self-intersection if it's an endpoint of seg1 AND an endpoint of seg2 (segments touch at a common vertex).
1581+
if (!(isEndpointForSeg1 && isEndpointForSeg2)) {
1582+
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))});
1583+
return true; // Found a true self-intersection
1584+
} /* else {
1585+
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))});
1586+
} */
1587+
}
1588+
}
1589+
}
1590+
// console.log('[isPolygonSelfIntersecting] No self-intersection detected for polygon:', JSON.parse(JSON.stringify(uniquePolygonPoints)));
1591+
return false; // No self-intersections found
1592+
};

0 commit comments

Comments
 (0)