Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added CLAUDE.md
Empty file.
1 change: 1 addition & 0 deletions main/background.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<!doctype html>
<html>
<head>
<script src="util/constants.js"></script>
<script src="util/geometryutil.js"></script>
<script src="util/clipper.js"></script>
<script src="util/parallel.js"></script>
Expand Down
44 changes: 37 additions & 7 deletions main/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import { NfpCache } from '../build/nfpDb.js';
import { HullPolygon } from '../build/util/HullPolygon.js';
import { Polygon } from '../build/util/polygon.js';
import { DEFAULT_CLIPPER_SCALE } from '../build/util/constants.js';

window.onload = function () {
const { ipcRenderer } = require('electron');
Expand Down Expand Up @@ -91,9 +93,9 @@ window.onload = function () {
var clipper = new ClipperLib.Clipper();

var Ac = toClipperCoordinates(A);
ClipperLib.JS.ScaleUpPath(Ac, 10000000);
ClipperLib.JS.ScaleUpPath(Ac, DEFAULT_CLIPPER_SCALE);
var Bc = toClipperCoordinates(B);
ClipperLib.JS.ScaleUpPath(Bc, 10000000);
ClipperLib.JS.ScaleUpPath(Bc, DEFAULT_CLIPPER_SCALE);
for (let i = 0; i < Bc.length; i++) {
Bc[i].X *= -1;
Bc[i].Y *= -1;
Expand All @@ -103,7 +105,7 @@ window.onload = function () {

var largestArea = null;
for (let i = 0; i < solution.length; i++) {
var n = toNestCoordinates(solution[i], 10000000);
var n = toNestCoordinates(solution[i], DEFAULT_CLIPPER_SCALE);
var sarea = -GeometryUtil.polygonArea(n);
if (largestArea === null || largestArea < sarea) {
clipperNfp = n;
Expand Down Expand Up @@ -482,6 +484,11 @@ function toNestCoordinates(polygon, scale) {
};

function getHull(polygon) {
if (polygon instanceof Polygon) {
var hullPolygon = HullPolygon.hull(polygon);
return hullPolygon ? hullPolygon.toArray() : polygon.toArray();
}

// Convert the polygon points to proper Point objects for HullPolygon
var points = [];
for (let i = 0; i < polygon.length; i++) {
Expand All @@ -498,10 +505,33 @@ function getHull(polygon) {
return polygon;
}

return hullpoints;
return hullpoints instanceof Polygon ? hullpoints.toArray() : hullpoints;
}

function rotatePolygon(polygon, degrees) {
if (polygon instanceof Polygon) {
var rotated = polygon.rotate(degrees);
var rotatedArray = rotated.toArray();

// Preserve exact property from original points
var originalPoints = polygon.toArray();
for (let i = 0; i < rotatedArray.length && i < originalPoints.length; i++) {
if (originalPoints[i].exact) {
rotatedArray[i].exact = originalPoints[i].exact;
}
}

// Handle children if they exist
if (polygon.children && polygon.children.length > 0) {
rotatedArray.children = [];
for (let j = 0; j < polygon.children.length; j++) {
rotatedArray.children.push(rotatePolygon(polygon.children[j], degrees));
}
}

return rotatedArray;
}

var rotated = [];
var angle = degrees * Math.PI / 180;
for (let i = 0; i < polygon.length; i++) {
Expand Down Expand Up @@ -564,9 +594,9 @@ function getOuterNfp(A, B, inside) {
// console.time('clipper');

var Ac = toClipperCoordinates(A);
ClipperLib.JS.ScaleUpPath(Ac, 10000000);
ClipperLib.JS.ScaleUpPath(Ac, DEFAULT_CLIPPER_SCALE);
var Bc = toClipperCoordinates(B);
ClipperLib.JS.ScaleUpPath(Bc, 10000000);
ClipperLib.JS.ScaleUpPath(Bc, DEFAULT_CLIPPER_SCALE);
for (let i = 0; i < Bc.length; i++) {
Bc[i].X *= -1;
Bc[i].Y *= -1;
Expand All @@ -578,7 +608,7 @@ function getOuterNfp(A, B, inside) {

var largestArea = null;
for (let i = 0; i < solution.length; i++) {
var n = toNestCoordinates(solution[i], 10000000);
var n = toNestCoordinates(solution[i], DEFAULT_CLIPPER_SCALE);
var sarea = -GeometryUtil.polygonArea(n);
if (largestArea === null || largestArea < sarea) {
clipperNfp = n;
Expand Down
17 changes: 12 additions & 5 deletions main/deepnest.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@

import { Point } from '../build/util/point.js';
import { HullPolygon } from '../build/util/HullPolygon.js';
import { Polygon } from '../build/util/polygon.js';
import { DEFAULT_CLIPPER_SCALE } from '../build/util/constants.js';

const { simplifyPolygon: simplifyPoly } = require("@deepnest/svg-preprocessor");

var config = {
clipperScale: 10000000,
clipperScale: DEFAULT_CLIPPER_SCALE,
curveTolerance: 0.3,
spacing: 0,
rotations: 4,
Expand Down Expand Up @@ -119,6 +121,11 @@ export class DeepNest {
};

getHull(polygon) {
if (polygon instanceof Polygon) {
var hullPolygon = HullPolygon.hull(polygon);
return hullPolygon ? hullPolygon.toArray() : null;
}

var points = [];
for (let i = 0; i < polygon.length; i++) {
points.push({
Expand All @@ -131,7 +138,7 @@ export class DeepNest {
if (!hullpoints) {
return null;
}
return hullpoints;
return hullpoints instanceof Polygon ? hullpoints.toArray() : hullpoints;
};

// use RDP simplification, then selectively offset
Expand Down Expand Up @@ -330,9 +337,9 @@ export class DeepNest {

//if(straightened){
var Ac = toClipperCoordinates(offset);
ClipperLib.JS.ScaleUpPath(Ac, 10000000);
ClipperLib.JS.ScaleUpPath(Ac, DEFAULT_CLIPPER_SCALE);
var Bc = toClipperCoordinates(polygon);
ClipperLib.JS.ScaleUpPath(Bc, 10000000);
ClipperLib.JS.ScaleUpPath(Bc, DEFAULT_CLIPPER_SCALE);

var combined = new ClipperLib.Paths();
var clipper = new ClipperLib.Clipper();
Expand All @@ -351,7 +358,7 @@ export class DeepNest {
) {
var largestArea = null;
for (var i = 0; i < combined.length; i++) {
var n = toNestCoordinates(combined[i], 10000000);
var n = toNestCoordinates(combined[i], DEFAULT_CLIPPER_SCALE);
var sarea = -GeometryUtil.polygonArea(n);
if (largestArea === null || largestArea < sarea) {
offset = n;
Expand Down
1 change: 1 addition & 0 deletions main/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<link rel="stylesheet" type="text/css" href="style.css" />

<script src="util/pathsegpolyfill.js"></script>
<script src="util/constants.js"></script>
<script src="util/clipper.js"></script>
<script src="util/parallel.js"></script>
<script src="util/geometryutil.js"></script>
Expand Down
16 changes: 10 additions & 6 deletions main/svgparser.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import '../build/util/domparser.js';
// Dependencies
import { Matrix } from '../build/util/matrix.js';
import { Point } from '../build/util/point.js';
import { Polygon } from '../build/util/polygon.js';
import { RAD_TO_DEG, TWO_PI } from '../build/util/constants.js';

export class SvgParser {
constructor(){
Expand Down Expand Up @@ -969,7 +971,7 @@ export class SvgParser {
var tarray = transform.toArray();

// decompose affine matrix to rotate, scale components (translate is just the 3rd column)
var rotate = Math.atan2(tarray[1], tarray[3])*180/Math.PI;
var rotate = Math.atan2(tarray[1], tarray[3]) * RAD_TO_DEG;
var scale = Math.hypot(tarray[0],tarray[2]);

if(element.tagName == 'g' || element.tagName == 'svg' || element.tagName == 'defs'){
Expand Down Expand Up @@ -1404,15 +1406,15 @@ export class SvgParser {
var cy = parseFloat(element.getAttribute('cy'));

// num is the smallest number of segments required to approximate the circle to the given tolerance
var num = Math.ceil((2*Math.PI)/Math.acos(1 - (this.conf.tolerance/radius)));
var num = Math.ceil(TWO_PI / Math.acos(1 - (this.conf.tolerance/radius)));

if(num < 12){
num = 12;
}

// Ensure we create a complete polygon by going full circle
for(var i=0; i<=num; i++){
var theta = i * ( (2*Math.PI) / num);
var theta = i * (TWO_PI / num);
var point = {};
point.x = radius*Math.cos(theta) + cx;
point.y = radius*Math.sin(theta) + cy;
Expand All @@ -1429,14 +1431,14 @@ export class SvgParser {
var cx = parseFloat(element.getAttribute('cx'));
var cy = parseFloat(element.getAttribute('cy'));

var num = Math.ceil((2*Math.PI)/Math.acos(1 - (this.conf.tolerance/maxradius)));
var num = Math.ceil(TWO_PI / Math.acos(1 - (this.conf.tolerance/maxradius)));

if(num < 12){
num = 12;
}

for(var i=0; i<=num; i++){
var theta = i * ( (2*Math.PI) / num);
var theta = i * (TWO_PI / num);
var point = {};
point.x = rx*Math.cos(theta) + cx;
point.y = ry*Math.sin(theta) + cy;
Expand All @@ -1454,7 +1456,9 @@ export class SvgParser {
poly.pop();
}

return poly;
// Convert points to Point instances and create Polygon
var points = poly.map(p => new Point(p.x, p.y));
return new Polygon(points);
};

polygonifyPath(path){
Expand Down
49 changes: 34 additions & 15 deletions main/util/HullPolygon.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// based on https://d3js.org/d3-polygon/ Version 1.0.2.

import { Point } from "./point.js";
import { Polygon } from "./polygon.js";

// Type definition for a polygon (array of points)
type Polygon = Point[];
// Type definition for a polygon (array of points) - keeping for backwards compatibility
type PolygonArray = Point[];

// Type for points with index used in hull calculation
interface IndexedPoint {
Expand All @@ -19,7 +20,11 @@ export class HullPolygon {
/**
* Returns the signed area of the specified polygon.
*/
public static area(polygon: Polygon): number {
public static area(polygon: Polygon | PolygonArray): number {
if (polygon instanceof Polygon) {
return polygon.area();
}

let i = -1;
const n = polygon.length;
let a: Point;
Expand All @@ -38,7 +43,11 @@ export class HullPolygon {
/**
* Returns the centroid of the specified polygon.
*/
public static centroid(polygon: Polygon): Point {
public static centroid(polygon: Polygon | PolygonArray): Point {
if (polygon instanceof Polygon) {
return polygon.centroid();
}

let i = -1;
const n = polygon.length;
let x = 0;
Expand All @@ -62,11 +71,12 @@ export class HullPolygon {

/**
* Returns the convex hull of the specified points.
* The returned hull is represented as an array of points
* The returned hull is represented as a new Polygon
* arranged in counterclockwise order.
*/
public static hull(points: Polygon): Polygon | null {
const n = points.length;
public static hull(points: Polygon | PolygonArray): Polygon | null {
const pointArray = points instanceof Polygon ? points.points : points;
const n = pointArray.length;
if (n < 3) return null;

let i: number;
Expand All @@ -75,8 +85,8 @@ export class HullPolygon {

for (i = 0; i < n; ++i) {
sortedPoints[i] = {
x: points[i].x,
y: points[i].y,
x: pointArray[i].x,
y: pointArray[i].y,
index: i,
};
}
Expand All @@ -99,26 +109,31 @@ export class HullPolygon {
const skipRight =
lowerIndexes[lowerIndexes.length - 1] ===
upperIndexes[upperIndexes.length - 1];
const hull: Polygon = [];
const hullPoints: Point[] = [];

// Add upper hull in right-to-left order.
// Then add lower hull in left-to-right order.
for (i = upperIndexes.length - 1; i >= 0; --i)
hull.push(points[sortedPoints[upperIndexes[i]].index]);
hullPoints.push(pointArray[sortedPoints[upperIndexes[i]].index]);
for (
i = skipLeft ? 1 : 0;
i < lowerIndexes.length - (skipRight ? 1 : 0);
++i
)
hull.push(points[sortedPoints[lowerIndexes[i]].index]);
hullPoints.push(pointArray[sortedPoints[lowerIndexes[i]].index]);

return hull;
return new Polygon(hullPoints);
}

/**
* Returns true if and only if the specified point is inside the specified polygon.
*/
public static contains(polygon: Polygon, point: Point): boolean {
public static contains(polygon: Polygon | PolygonArray, point: Point): boolean {
if (polygon instanceof Polygon) {
const result = polygon.contains(point);
return result === true; // convert null to false
}

const n = polygon.length;
let p = polygon[n - 1];
const x = point.x;
Expand All @@ -145,7 +160,11 @@ export class HullPolygon {
/**
* Returns the length of the perimeter of the specified polygon.
*/
public static length(polygon: Polygon): number {
public static length(polygon: Polygon | PolygonArray): number {
if (polygon instanceof Polygon) {
return polygon.perimeter();
}

let i = -1;
const n = polygon.length;
let b = polygon[n - 1];
Expand Down
Loading
Loading