altium-to-circuit-json 0.0.82 → 0.0.83
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/dist/index.js +135 -25
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -5181,7 +5181,10 @@ function contourToPoints(contour) {
|
|
|
5181
5181
|
import {
|
|
5182
5182
|
AltiumFillRecord,
|
|
5183
5183
|
AltiumPolygonRecord,
|
|
5184
|
-
AltiumRegionRecord as AltiumRegionRecord3
|
|
5184
|
+
AltiumRegionRecord as AltiumRegionRecord3,
|
|
5185
|
+
getPcbContour as getPcbContour2,
|
|
5186
|
+
getPcbRecordPolygonIndex,
|
|
5187
|
+
getPcbRegionGeometry as getPcbRegionGeometry5
|
|
5185
5188
|
} from "altiumts";
|
|
5186
5189
|
|
|
5187
5190
|
// lib/pcb/copperAreas/convertCopperFill.ts
|
|
@@ -5216,8 +5219,13 @@ function convertCopperFill({
|
|
|
5216
5219
|
}
|
|
5217
5220
|
|
|
5218
5221
|
// lib/pcb/copperAreas/convertCopperPolygon.ts
|
|
5219
|
-
import {
|
|
5222
|
+
import {
|
|
5223
|
+
getPcbContour,
|
|
5224
|
+
getPcbRegionGeometry as getPcbRegionGeometry3
|
|
5225
|
+
} from "altiumts";
|
|
5226
|
+
import polygonClipping from "polygon-clipping";
|
|
5220
5227
|
function convertCopperPolygon({
|
|
5228
|
+
cutouts,
|
|
5221
5229
|
polygonIndex,
|
|
5222
5230
|
layerMap,
|
|
5223
5231
|
record,
|
|
@@ -5227,21 +5235,45 @@ function convertCopperPolygon({
|
|
|
5227
5235
|
if (!layer) return [];
|
|
5228
5236
|
const points = contourToPoints(getPcbContour(record));
|
|
5229
5237
|
if (points.length < 3) return [];
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5238
|
+
const cutoutPolygons = cutouts.map((cutout) => {
|
|
5239
|
+
const geometry = getPcbRegionGeometry3(cutout);
|
|
5240
|
+
return [geometry.outline, ...geometry.holes].map(
|
|
5241
|
+
(contour) => contourToPoints(contour).map((point) => [point.x, point.y])
|
|
5242
|
+
);
|
|
5243
|
+
});
|
|
5244
|
+
const copperPolygons = cutouts.length === 0 ? [[points]] : polygonClipping.difference(
|
|
5245
|
+
[points.map((point) => [point.x, point.y])],
|
|
5246
|
+
cutoutPolygons
|
|
5247
|
+
).map(
|
|
5248
|
+
(polygon) => polygon.map(
|
|
5249
|
+
(ring) => ring.slice(0, -1).map(([x, y]) => ({ x, y }))
|
|
5250
|
+
)
|
|
5251
|
+
);
|
|
5252
|
+
return copperPolygons.flatMap(
|
|
5253
|
+
([outerRing, ...holes], partIndex) => {
|
|
5254
|
+
if (!outerRing || outerRing.length < 3) return [];
|
|
5255
|
+
return [
|
|
5256
|
+
{
|
|
5257
|
+
type: "pcb_copper_pour",
|
|
5258
|
+
pcb_copper_pour_id: `pcb_copper_pour_altium_polygon_${polygonIndex}${partIndex === 0 ? "" : `_island_${partIndex}`}`,
|
|
5259
|
+
...sourceNetId ? { source_net_id: sourceNetId } : {},
|
|
5260
|
+
covered_with_solder_mask: true,
|
|
5261
|
+
layer,
|
|
5262
|
+
...holes.length === 0 ? { shape: "polygon", points: outerRing } : {
|
|
5263
|
+
shape: "brep",
|
|
5264
|
+
brep_shape: {
|
|
5265
|
+
outer_ring: { vertices: outerRing },
|
|
5266
|
+
inner_rings: holes.map((vertices) => ({ vertices }))
|
|
5267
|
+
}
|
|
5268
|
+
}
|
|
5269
|
+
}
|
|
5270
|
+
];
|
|
5239
5271
|
}
|
|
5240
|
-
|
|
5272
|
+
);
|
|
5241
5273
|
}
|
|
5242
5274
|
|
|
5243
5275
|
// lib/pcb/copperAreas/convertCopperRegion.ts
|
|
5244
|
-
import { getPcbRegionGeometry as
|
|
5276
|
+
import { getPcbRegionGeometry as getPcbRegionGeometry4 } from "altiumts";
|
|
5245
5277
|
function convertCopperRegion({
|
|
5246
5278
|
layerMap,
|
|
5247
5279
|
record,
|
|
@@ -5253,7 +5285,7 @@ function convertCopperRegion({
|
|
|
5253
5285
|
}
|
|
5254
5286
|
const layer = layerMap.getLayer(record.layer);
|
|
5255
5287
|
if (!layer) return [];
|
|
5256
|
-
const geometry =
|
|
5288
|
+
const geometry = getPcbRegionGeometry4(record);
|
|
5257
5289
|
const outerVertices = contourToPoints(geometry.outline);
|
|
5258
5290
|
if (outerVertices.length < 3) return [];
|
|
5259
5291
|
const innerRings = geometry.holes.map((hole) => ({ vertices: contourToPoints(hole) })).filter((ring) => ring.vertices.length >= 3);
|
|
@@ -5286,20 +5318,97 @@ function convertCopperRegion({
|
|
|
5286
5318
|
];
|
|
5287
5319
|
}
|
|
5288
5320
|
|
|
5321
|
+
// lib/pcb/copperAreas/isContourInsideContour.ts
|
|
5322
|
+
import { doesLineIntersectLine } from "@tscircuit/math-utils";
|
|
5323
|
+
function isContourInsideContour({
|
|
5324
|
+
innerContour,
|
|
5325
|
+
outerContour
|
|
5326
|
+
}) {
|
|
5327
|
+
const innerBounds = innerContour.bounds;
|
|
5328
|
+
const outerBounds = outerContour.bounds;
|
|
5329
|
+
if (!innerBounds || !outerBounds || innerBounds.minX <= outerBounds.minX || innerBounds.maxX >= outerBounds.maxX || innerBounds.minY <= outerBounds.minY || innerBounds.maxY >= outerBounds.maxY) {
|
|
5330
|
+
return false;
|
|
5331
|
+
}
|
|
5332
|
+
const innerPoints = innerContour.isExplicitlyClosed ? innerContour.points.slice(0, -1) : innerContour.points;
|
|
5333
|
+
const outerPoints = outerContour.isExplicitlyClosed ? outerContour.points.slice(0, -1) : outerContour.points;
|
|
5334
|
+
if (innerPoints.length < 3 || outerPoints.length < 3) return false;
|
|
5335
|
+
const toleranceMils = 8 * Number.EPSILON * Math.max(
|
|
5336
|
+
1,
|
|
5337
|
+
Math.abs(outerBounds.minX),
|
|
5338
|
+
Math.abs(outerBounds.maxX),
|
|
5339
|
+
Math.abs(outerBounds.minY),
|
|
5340
|
+
Math.abs(outerBounds.maxY)
|
|
5341
|
+
);
|
|
5342
|
+
for (const point of innerPoints) {
|
|
5343
|
+
let isInside = false;
|
|
5344
|
+
for (let index = 0; index < outerPoints.length; index++) {
|
|
5345
|
+
const start = outerPoints[index];
|
|
5346
|
+
const end = outerPoints[(index + 1) % outerPoints.length];
|
|
5347
|
+
if (!start || !end) continue;
|
|
5348
|
+
if (start.y > point.y !== end.y > point.y && point.x < start.x + (point.y - start.y) * (end.x - start.x) / (end.y - start.y)) {
|
|
5349
|
+
isInside = !isInside;
|
|
5350
|
+
}
|
|
5351
|
+
}
|
|
5352
|
+
if (!isInside) return false;
|
|
5353
|
+
}
|
|
5354
|
+
for (let innerIndex = 0; innerIndex < innerPoints.length; innerIndex++) {
|
|
5355
|
+
const innerStart = innerPoints[innerIndex];
|
|
5356
|
+
const innerEnd = innerPoints[(innerIndex + 1) % innerPoints.length];
|
|
5357
|
+
if (!innerStart || !innerEnd) continue;
|
|
5358
|
+
for (let outerIndex = 0; outerIndex < outerPoints.length; outerIndex++) {
|
|
5359
|
+
const outerStart = outerPoints[outerIndex];
|
|
5360
|
+
const outerEnd = outerPoints[(outerIndex + 1) % outerPoints.length];
|
|
5361
|
+
if (!outerStart || !outerEnd) continue;
|
|
5362
|
+
if (doesLineIntersectLine([innerStart, innerEnd], [outerStart, outerEnd], {
|
|
5363
|
+
lineThickness: toleranceMils
|
|
5364
|
+
})) {
|
|
5365
|
+
return false;
|
|
5366
|
+
}
|
|
5367
|
+
}
|
|
5368
|
+
}
|
|
5369
|
+
return true;
|
|
5370
|
+
}
|
|
5371
|
+
|
|
5289
5372
|
// lib/pcb/copperAreas/convertAltiumCopperAreas.ts
|
|
5290
5373
|
function convertAltiumCopperAreas(document, {
|
|
5291
5374
|
layerMap = new PcbCopperLayerMap(document),
|
|
5292
5375
|
getSourceNetId = () => void 0
|
|
5293
5376
|
} = {}) {
|
|
5294
|
-
const
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5377
|
+
const polygonsWithCopperRegions = /* @__PURE__ */ new Set();
|
|
5378
|
+
const cutoutsByPolygon = /* @__PURE__ */ new Map();
|
|
5379
|
+
const polygonContours = /* @__PURE__ */ new Map();
|
|
5380
|
+
for (const record of document.records) {
|
|
5381
|
+
if (!(record instanceof AltiumRegionRecord3) || record.recordKind !== "Region") {
|
|
5382
|
+
continue;
|
|
5383
|
+
}
|
|
5384
|
+
const polygonIndex = getPcbRecordPolygonIndex(document, record);
|
|
5385
|
+
const linkedPolygon = document.getPolygonForRecord(record);
|
|
5386
|
+
if (record.regionKind === "COPPER") {
|
|
5387
|
+
if (linkedPolygon) polygonsWithCopperRegions.add(linkedPolygon);
|
|
5388
|
+
} else if (record.regionKind === "POLYGON_CUTOUT") {
|
|
5389
|
+
const cutoutGeometry = getPcbRegionGeometry5(record);
|
|
5390
|
+
const candidatePolygons = polygonIndex === void 0 ? document.polygons : linkedPolygon ? [linkedPolygon] : [];
|
|
5391
|
+
const polygons = candidatePolygons.filter((polygon) => {
|
|
5392
|
+
if (record.layer !== polygon.layer && record.layer !== "MULTILAYER") {
|
|
5393
|
+
return false;
|
|
5394
|
+
}
|
|
5395
|
+
let polygonContour = polygonContours.get(polygon);
|
|
5396
|
+
if (!polygonContour) {
|
|
5397
|
+
polygonContour = getPcbContour2(polygon);
|
|
5398
|
+
polygonContours.set(polygon, polygonContour);
|
|
5399
|
+
}
|
|
5400
|
+
return isContourInsideContour({
|
|
5401
|
+
innerContour: cutoutGeometry.outline,
|
|
5402
|
+
outerContour: polygonContour
|
|
5403
|
+
});
|
|
5404
|
+
});
|
|
5405
|
+
for (const polygon of polygons) {
|
|
5406
|
+
const cutouts = cutoutsByPolygon.get(polygon) ?? [];
|
|
5407
|
+
cutouts.push(record);
|
|
5408
|
+
cutoutsByPolygon.set(polygon, cutouts);
|
|
5298
5409
|
}
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
})
|
|
5302
|
-
);
|
|
5410
|
+
}
|
|
5411
|
+
}
|
|
5303
5412
|
const polygonIndexes = new Map(
|
|
5304
5413
|
document.polygons.map((polygon, index) => [polygon, index])
|
|
5305
5414
|
);
|
|
@@ -5314,10 +5423,11 @@ function convertAltiumCopperAreas(document, {
|
|
|
5314
5423
|
}
|
|
5315
5424
|
if (record instanceof AltiumPolygonRecord) {
|
|
5316
5425
|
const polygonIndex = polygonIndexes.get(record);
|
|
5317
|
-
if (record.shelved === true || polygonIndex === void 0 ||
|
|
5426
|
+
if (record.shelved === true || polygonIndex === void 0 || polygonsWithCopperRegions.has(record)) {
|
|
5318
5427
|
return [];
|
|
5319
5428
|
}
|
|
5320
5429
|
return convertCopperPolygon({
|
|
5430
|
+
cutouts: cutoutsByPolygon.get(record) ?? [],
|
|
5321
5431
|
layerMap,
|
|
5322
5432
|
polygonIndex,
|
|
5323
5433
|
record,
|
|
@@ -5763,12 +5873,12 @@ function convertPcbSilkscreenLine({
|
|
|
5763
5873
|
}
|
|
5764
5874
|
|
|
5765
5875
|
// lib/pcb/silkscreen/convertPcbSilkscreenRegion.ts
|
|
5766
|
-
import { getPcbRegionGeometry as
|
|
5876
|
+
import { getPcbRegionGeometry as getPcbRegionGeometry6 } from "altiumts";
|
|
5767
5877
|
function convertPcbSilkscreenRegion({
|
|
5768
5878
|
record,
|
|
5769
5879
|
recordIndex
|
|
5770
5880
|
}) {
|
|
5771
|
-
const geometry =
|
|
5881
|
+
const geometry = getPcbRegionGeometry6(record);
|
|
5772
5882
|
const outerVertices = geometry.outline.points.map(toMillimeterPoint);
|
|
5773
5883
|
if (outerVertices.length < 3) return void 0;
|
|
5774
5884
|
const innerRings = geometry.holes.map((hole) => ({ vertices: hole.points.map(toMillimeterPoint) })).filter((ring) => ring.vertices.length >= 3);
|