@mark1russell7/packing 0.2.12 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.d.ts.map +1 -1
- package/build/index.js +49 -61
- package/build/index.js.map +1 -1
- package/package.json +1 -1
- package/src/maxrects.ts +44 -56
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@mark1russell7/packing",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.13",
|
|
5
5
|
"description": "Rectangle packing: shelf, guillotine and skyline strategies, push cascades and measures of a layout.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"rectangle-packing",
|
package/src/maxrects.ts
CHANGED
|
@@ -89,19 +89,41 @@ function inside(a: Box, b: Box): boolean {
|
|
|
89
89
|
*/
|
|
90
90
|
function cut(free: Box[], b: Box, minW: number, minH: number): { free: Box[]; hits: number } {
|
|
91
91
|
const kept: Box[] = [];
|
|
92
|
-
|
|
93
|
-
//
|
|
94
|
-
const
|
|
92
|
+
// A part spans the box on one axis and touches the box on the other axis. Thus a part of one side is not in a part of
|
|
93
|
+
// another side. A kept rectangle with the part in it has an edge on the same side of the box.
|
|
94
|
+
const near: Box[][] = [[], [], [], []];
|
|
95
|
+
// For each side of the box (0 left, 1 right, 2 top, 3 bottom), the parts that stay so far. Each part has five numbers
|
|
96
|
+
// in the list: its four edges and its index in the order of creation.
|
|
97
|
+
const stay: number[][] = [[], [], [], []];
|
|
98
|
+
let made = 0;
|
|
95
99
|
let hits = 0;
|
|
100
|
+
// A part stays when no other part holds more than it, and no equal part comes before it. This rule does not use an order.
|
|
101
|
+
// Thus a new part goes when a part that stays holds it. Else it removes each part that it holds.
|
|
96
102
|
const add = (side: number, x0: number, y0: number, x1: number, y1: number): void => {
|
|
97
|
-
if (x1 - x0
|
|
98
|
-
|
|
99
|
-
|
|
103
|
+
if (x1 - x0 < minW || y1 - y0 < minH) return;
|
|
104
|
+
const own = stay[side]!;
|
|
105
|
+
for (let k = 0; k < own.length; ) {
|
|
106
|
+
const qx0 = own[k]!;
|
|
107
|
+
const qy0 = own[k + 1]!;
|
|
108
|
+
const qx1 = own[k + 2]!;
|
|
109
|
+
const qy1 = own[k + 3]!;
|
|
110
|
+
if (x0 >= qx0 && y0 >= qy0 && x1 <= qx1 && y1 <= qy1) return;
|
|
111
|
+
if (qx0 >= x0 && qy0 >= y0 && qx1 <= x1 && qy1 <= y1) {
|
|
112
|
+
// The last part of the list takes the place of the removed part
|
|
113
|
+
const last = own.length - 5;
|
|
114
|
+
if (k !== last) for (let n = 0; n < 5; n++) own[k + n] = own[last + n]!;
|
|
115
|
+
own.length = last;
|
|
116
|
+
} else k += 5;
|
|
100
117
|
}
|
|
118
|
+
own.push(x0, y0, x1, y1, made++);
|
|
101
119
|
};
|
|
102
120
|
for (const f of free) {
|
|
103
121
|
if (b.x0 >= f.x1 || b.x1 <= f.x0 || b.y0 >= f.y1 || b.y1 <= f.y0) {
|
|
104
122
|
kept.push(f);
|
|
123
|
+
if (f.x1 === b.x0) near[0]!.push(f);
|
|
124
|
+
if (f.x0 === b.x1) near[1]!.push(f);
|
|
125
|
+
if (f.y1 === b.y0) near[2]!.push(f);
|
|
126
|
+
if (f.y0 === b.y1) near[3]!.push(f);
|
|
105
127
|
continue;
|
|
106
128
|
}
|
|
107
129
|
hits++;
|
|
@@ -110,62 +132,28 @@ function cut(free: Box[], b: Box, minW: number, minH: number): { free: Box[]; hi
|
|
|
110
132
|
if (b.y0 > f.y0) add(2, f.x0, f.y0, f.x1, b.y0);
|
|
111
133
|
if (b.y1 < f.y1) add(3, f.x0, b.y1, f.x1, f.y1);
|
|
112
134
|
}
|
|
113
|
-
if (
|
|
114
|
-
// Each part is in the free rectangle that it comes from. Thus
|
|
115
|
-
//
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const gone = new Uint8Array(parts.length);
|
|
128
|
-
const stay: Box[][] = [[], [], [], []];
|
|
129
|
-
for (const i of order) {
|
|
130
|
-
const p = parts[i]!;
|
|
131
|
-
const own = stay[sides[i]!]!;
|
|
132
|
-
let drop = false;
|
|
133
|
-
for (const q of own) {
|
|
134
|
-
if (inside(p, q)) {
|
|
135
|
-
drop = true;
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
if (drop) gone[i] = 1;
|
|
140
|
-
else own.push(p);
|
|
141
|
-
}
|
|
142
|
-
for (let i = 0; i < parts.length; i++) {
|
|
143
|
-
if (gone[i] === 1) continue;
|
|
144
|
-
const p = parts[i]!;
|
|
145
|
-
let drop = false;
|
|
146
|
-
for (const k of near[sides[i]!]!) {
|
|
147
|
-
if (inside(p, k)) {
|
|
148
|
-
drop = true;
|
|
149
|
-
break;
|
|
135
|
+
if (made === 0) return { free: kept, hits };
|
|
136
|
+
// Each part is in the free rectangle that it comes from. Thus no kept rectangle is in a part.
|
|
137
|
+
// The parts that stay go to the list in the order of creation.
|
|
138
|
+
const out: (Box | undefined)[] = new Array<Box | undefined>(made).fill(undefined);
|
|
139
|
+
for (let side = 0; side < 4; side++) {
|
|
140
|
+
const own = stay[side]!;
|
|
141
|
+
for (let k = 0; k < own.length; k += 5) {
|
|
142
|
+
const p: Box = { x0: own[k]!, y0: own[k + 1]!, x1: own[k + 2]!, y1: own[k + 3]! };
|
|
143
|
+
let drop = false;
|
|
144
|
+
for (const q of near[side]!) {
|
|
145
|
+
if (inside(p, q)) {
|
|
146
|
+
drop = true;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
150
149
|
}
|
|
150
|
+
if (!drop) out[own[k + 4]!] = p;
|
|
151
151
|
}
|
|
152
|
-
if (!drop) kept.push(p);
|
|
153
152
|
}
|
|
153
|
+
for (const p of out) if (p !== undefined) kept.push(p);
|
|
154
154
|
return { free: kept, hits };
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
/**
|
|
158
|
-
* This function orders two boxes. The smaller `x0` comes first, then the smaller `y0`, then the larger `x1`, then the
|
|
159
|
-
* larger `y1`. Thus a box comes before each other box in it.
|
|
160
|
-
*/
|
|
161
|
-
function byExtent(a: Box, b: Box): number {
|
|
162
|
-
if (a.x0 !== b.x0) return a.x0 < b.x0 ? -1 : 1;
|
|
163
|
-
if (a.y0 !== b.y0) return a.y0 < b.y0 ? -1 : 1;
|
|
164
|
-
if (a.x1 !== b.x1) return a.x1 > b.x1 ? -1 : 1;
|
|
165
|
-
if (a.y1 !== b.y1) return a.y1 > b.y1 ? -1 : 1;
|
|
166
|
-
return 0;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
157
|
/** The edges of the boxes on one axis: for each coordinate, the flat list of the ranges on the other axis. */
|
|
170
158
|
type Edges = Map<number, number[]>;
|
|
171
159
|
|