@tscircuit/pcb-viewer 1.11.434 → 1.11.436

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 CHANGED
@@ -10132,7 +10132,7 @@ var useMeasure_default = isBrowser && typeof window.ResizeObserver !== "undefine
10132
10132
  };
10133
10133
 
10134
10134
  // src/PCBViewer.tsx
10135
- import { compose as compose10, scale as scale6, translate as translate14 } from "transformation-matrix";
10135
+ import { compose as compose11, scale as scale6, translate as translate15 } from "transformation-matrix";
10136
10136
 
10137
10137
  // node_modules/use-mouse-matrix-transform/dist/chunk-TGYMZPTI.js
10138
10138
  import { compose as compose3, translate as translate7, scale } from "transformation-matrix";
@@ -10641,6 +10641,14 @@ var getFullConnectivityMapFromCircuitJson = (circuitJson) => {
10641
10641
  return new ConnectivityMap(netMap);
10642
10642
  };
10643
10643
 
10644
+ // src/lib/convert-element-to-primitive.ts
10645
+ import {
10646
+ applyToPoint as applyToPoint3,
10647
+ compose as compose5,
10648
+ rotateDEG as rotateDEG2,
10649
+ translate as translate9
10650
+ } from "transformation-matrix";
10651
+
10644
10652
  // src/lib/util/expand-stroke.ts
10645
10653
  function getExpandedStroke(strokeInput, defaultWidth) {
10646
10654
  if (strokeInput.length < 2) {
@@ -11335,6 +11343,7 @@ var convertElementToPrimitives = (element, allElements, metadataIndex) => {
11335
11343
  const {
11336
11344
  x,
11337
11345
  y,
11346
+ ccw_rotation,
11338
11347
  pad_outline,
11339
11348
  hole_shape,
11340
11349
  hole_diameter,
@@ -11346,17 +11355,20 @@ var convertElementToPrimitives = (element, allElements, metadataIndex) => {
11346
11355
  } = element;
11347
11356
  const parsed_hole_offset_x = distance.parse(hole_offset_x ?? 0);
11348
11357
  const parsed_hole_offset_y = distance.parse(hole_offset_y ?? 0);
11349
- const pcb_outline = pad_outline;
11358
+ const transformPadLocalToBoard = compose5(
11359
+ translate9(x, y),
11360
+ rotateDEG2(ccw_rotation ?? 0)
11361
+ );
11350
11362
  const padPrimitives = [];
11351
- if (pcb_outline && Array.isArray(pcb_outline)) {
11352
- const translatedPoints = normalizePolygonPoints(pcb_outline).map(
11353
- (p) => ({ x: p.x + x, y: p.y + y })
11363
+ if (Array.isArray(pad_outline)) {
11364
+ const points = normalizePolygonPoints(pad_outline).map(
11365
+ (p) => applyToPoint3(transformPadLocalToBoard, p)
11354
11366
  );
11355
11367
  for (const layer of layers || ["top", "bottom"]) {
11356
11368
  padPrimitives.push({
11357
11369
  _pcb_drawing_object_id: `polygon_${globalPcbDrawingObjectCount++}`,
11358
11370
  pcb_drawing_type: "polygon",
11359
- points: translatedPoints,
11371
+ points,
11360
11372
  layer,
11361
11373
  _element: element,
11362
11374
  _parent_pcb_component,
@@ -11365,10 +11377,10 @@ var convertElementToPrimitives = (element, allElements, metadataIndex) => {
11365
11377
  });
11366
11378
  }
11367
11379
  }
11368
- const holeCenter = {
11369
- x: x + parsed_hole_offset_x,
11370
- y: y + parsed_hole_offset_y
11371
- };
11380
+ const holeCenter = applyToPoint3(transformPadLocalToBoard, {
11381
+ x: parsed_hole_offset_x,
11382
+ y: parsed_hole_offset_y
11383
+ });
11372
11384
  const holePrimitives = [];
11373
11385
  if (hole_shape === "circle") {
11374
11386
  holePrimitives.push({
@@ -11390,6 +11402,7 @@ var convertElementToPrimitives = (element, allElements, metadataIndex) => {
11390
11402
  y: holeCenter.y,
11391
11403
  rX: (hole_width ?? 0) / 2,
11392
11404
  rY: (hole_height ?? 0) / 2,
11405
+ ccw_rotation,
11393
11406
  layer: "drill",
11394
11407
  _element: element,
11395
11408
  _parent_pcb_component,
@@ -11407,7 +11420,7 @@ var convertElementToPrimitives = (element, allElements, metadataIndex) => {
11407
11420
  _element: element,
11408
11421
  _parent_pcb_component,
11409
11422
  _parent_source_component,
11410
- ccw_rotation: element.ccw_rotation
11423
+ ccw_rotation
11411
11424
  });
11412
11425
  }
11413
11426
  return [...padPrimitives, ...holePrimitives];
@@ -11474,6 +11487,162 @@ function drawCopperPourElementsForLayer({
11474
11487
  drawer.drawElements(copperPourElements, { layers });
11475
11488
  }
11476
11489
 
11490
+ // src/lib/get-trace-overlay-text.ts
11491
+ var getNonEmptyName = (name) => name?.trim() || null;
11492
+ function createTraceOverlayElementIndex(elements) {
11493
+ const sourceNetById = /* @__PURE__ */ new Map();
11494
+ const sourceTraceById = /* @__PURE__ */ new Map();
11495
+ for (const element of elements) {
11496
+ if (element.type === "source_net") {
11497
+ sourceNetById.set(element.source_net_id, element);
11498
+ } else if (element.type === "source_trace") {
11499
+ sourceTraceById.set(element.source_trace_id, element);
11500
+ }
11501
+ }
11502
+ return { sourceNetById, sourceTraceById };
11503
+ }
11504
+ function getAssociatedTraceName({
11505
+ primitiveElement,
11506
+ traceOverlayElementIndex
11507
+ }) {
11508
+ const sourceElementId = primitiveElement.source_trace_id;
11509
+ if (!sourceElementId) return null;
11510
+ const sourceTrace = traceOverlayElementIndex.sourceTraceById.get(sourceElementId);
11511
+ const sourceTraceName = getNonEmptyName(sourceTrace?.name);
11512
+ if (sourceTraceName) return sourceTraceName;
11513
+ const sourceNet = traceOverlayElementIndex.sourceNetById.get(sourceElementId);
11514
+ const sourceNetName = getNonEmptyName(sourceNet?.name);
11515
+ if (sourceNetName) return sourceNetName;
11516
+ for (const sourceNetId of sourceTrace?.connected_source_net_ids ?? []) {
11517
+ const connectedSourceNetName = getNonEmptyName(
11518
+ traceOverlayElementIndex.sourceNetById.get(sourceNetId)?.name
11519
+ );
11520
+ if (connectedSourceNetName) return connectedSourceNetName;
11521
+ }
11522
+ return null;
11523
+ }
11524
+ function getTraceOverlayInfo({
11525
+ primitiveElement,
11526
+ traceOverlayElementIndex
11527
+ }) {
11528
+ const sourceTraceId = primitiveElement.source_trace_id;
11529
+ const trace = sourceTraceId ? traceOverlayElementIndex.sourceTraceById.get(sourceTraceId) : void 0;
11530
+ const traceLength = primitiveElement.trace_length;
11531
+ const hasTraceLength = typeof traceLength === "number";
11532
+ const maxLength = trace?.max_length;
11533
+ const text = hasTraceLength ? `${traceLength.toFixed(3)}${typeof maxLength === "number" ? ` / ${maxLength}` : ""} mm` : "";
11534
+ const name = getAssociatedTraceName({
11535
+ primitiveElement,
11536
+ traceOverlayElementIndex
11537
+ }) ?? getNonEmptyName(trace?.display_name);
11538
+ if (!text && !name) return null;
11539
+ const isOverLength = Boolean(
11540
+ hasTraceLength && typeof maxLength === "number" && traceLength > maxLength
11541
+ );
11542
+ return {
11543
+ text,
11544
+ name,
11545
+ isOverLength
11546
+ };
11547
+ }
11548
+
11549
+ // src/lib/x-ray-net.ts
11550
+ function getElementNetId(element, connectivityMap) {
11551
+ if (!element) return;
11552
+ const ids = [];
11553
+ for (const key of [
11554
+ `${element.type}_id`,
11555
+ "pcb_port_id",
11556
+ "pcb_trace_id",
11557
+ "source_trace_id",
11558
+ "source_net_id"
11559
+ ]) {
11560
+ const value = element[key];
11561
+ if (typeof value === "string") ids.push(value);
11562
+ }
11563
+ for (const id of ids) {
11564
+ const net = connectivityMap.getNetConnectedToId(id);
11565
+ if (net) return net;
11566
+ }
11567
+ if ("source_net_id" in element) return element.source_net_id;
11568
+ }
11569
+ function isXRayCopper(element) {
11570
+ return element && [
11571
+ "pcb_trace",
11572
+ "pcb_smtpad",
11573
+ "pcb_plated_hole",
11574
+ "pcb_via",
11575
+ "pcb_copper_pour"
11576
+ ].includes(element.type);
11577
+ }
11578
+ function getXRayDisplayName(element, elements, connectivityMap) {
11579
+ const traceOverlayElementIndex = createTraceOverlayElementIndex(elements);
11580
+ const directName = element.type === "pcb_trace" ? getAssociatedTraceName({
11581
+ primitiveElement: element,
11582
+ traceOverlayElementIndex
11583
+ }) : null;
11584
+ if (directName) return directName;
11585
+ const netId = getElementNetId(element, connectivityMap);
11586
+ const connected = netId ? elements.filter(
11587
+ (candidate) => getElementNetId(candidate, connectivityMap) === netId
11588
+ ) : [];
11589
+ for (const type of ["source_net", "source_trace"]) {
11590
+ for (const candidate of connected) {
11591
+ if (candidate.type === type && "name" in candidate && typeof candidate.name === "string" && candidate.name.trim())
11592
+ return candidate.name.trim();
11593
+ }
11594
+ }
11595
+ if (element.type === "pcb_trace") {
11596
+ const label = getTraceOverlayInfo({
11597
+ primitiveElement: element,
11598
+ traceOverlayElementIndex
11599
+ })?.name;
11600
+ if (label) return label;
11601
+ }
11602
+ for (const candidate of connected) {
11603
+ if (candidate.type === "source_trace" && candidate.display_name?.trim())
11604
+ return candidate.display_name.trim();
11605
+ }
11606
+ return "Net";
11607
+ }
11608
+ function getXRayGroups(netId, elements, connectivityMap) {
11609
+ return elements.flatMap((element) => {
11610
+ if (element.type !== "source_bus") return [];
11611
+ const netIds = [
11612
+ ...new Set(
11613
+ element.source_trace_ids.flatMap((id) => {
11614
+ const net = connectivityMap.getNetConnectedToId(id);
11615
+ return net ? [net] : [];
11616
+ })
11617
+ )
11618
+ ];
11619
+ if (!netIds.includes(netId)) return [];
11620
+ return [
11621
+ {
11622
+ id: element.source_bus_id,
11623
+ name: element.name?.trim() || "Bus",
11624
+ netIds
11625
+ }
11626
+ ];
11627
+ });
11628
+ }
11629
+
11630
+ // src/lib/get-highlighted-copper-pour-ids.ts
11631
+ function getHighlightedCopperPourIds(elements, highlightedNetElementIds, connectivityMap) {
11632
+ if (highlightedNetElementIds.length === 0) return [];
11633
+ const netIds = new Set(
11634
+ highlightedNetElementIds.flatMap((id) => {
11635
+ const netId = connectivityMap.getNetConnectedToId(id);
11636
+ return netId ? [netId] : [];
11637
+ })
11638
+ );
11639
+ return elements.flatMap((element) => {
11640
+ if (element.type !== "pcb_copper_pour") return [];
11641
+ const netId = getElementNetId(element, connectivityMap);
11642
+ return netId && netIds.has(netId) ? [element.pcb_copper_pour_id] : [];
11643
+ });
11644
+ }
11645
+
11477
11646
  // src/lib/util/get-primitive-bounding-box.ts
11478
11647
  var mergeNumber = (a, b, fn) => fn(a, b);
11479
11648
  var rotatePoint = (x, y, centerX, centerY, rotationDeg) => {
@@ -11560,11 +11729,16 @@ var getPrimitiveBoundingBox = (primitive) => {
11560
11729
  };
11561
11730
  }
11562
11731
  case "oval": {
11732
+ const ccwRotationRadians = (primitive.ccw_rotation ?? 0) * Math.PI / 180;
11733
+ const cos = Math.cos(ccwRotationRadians);
11734
+ const sin = Math.sin(ccwRotationRadians);
11735
+ const halfWidth = Math.hypot(primitive.rX * cos, primitive.rY * sin);
11736
+ const halfHeight = Math.hypot(primitive.rX * sin, primitive.rY * cos);
11563
11737
  return {
11564
- minX: primitive.x - primitive.rX,
11565
- maxX: primitive.x + primitive.rX,
11566
- minY: primitive.y - primitive.rY,
11567
- maxY: primitive.y + primitive.rY
11738
+ minX: primitive.x - halfWidth,
11739
+ maxX: primitive.x + halfWidth,
11740
+ minY: primitive.y - halfHeight,
11741
+ maxY: primitive.y + halfHeight
11568
11742
  };
11569
11743
  }
11570
11744
  case "pill": {
@@ -11758,7 +11932,7 @@ function addInteractionMetadataToPrimitives({
11758
11932
  import {
11759
11933
  getBoundsFromPoints as getBoundsFromPoints2
11760
11934
  } from "@tscircuit/math-utils";
11761
- import { compose as compose5, scale as scale3, translate as translate9 } from "transformation-matrix";
11935
+ import { compose as compose6, scale as scale3, translate as translate10 } from "transformation-matrix";
11762
11936
  var buildErrorPreviewElementIndexes = (elements) => {
11763
11937
  const tracesById = /* @__PURE__ */ new Map();
11764
11938
  const portsById = /* @__PURE__ */ new Map();
@@ -12049,10 +12223,10 @@ var createTransformForBounds = ({
12049
12223
  const targetWidth = Math.max(bounds.maxX - bounds.minX, 0.8) + 1.4;
12050
12224
  const targetHeight = Math.max(bounds.maxY - bounds.minY, 0.8) + 1.4;
12051
12225
  const scaleFactor = Math.min(width / targetWidth, height / targetHeight, 240) * 0.92;
12052
- return compose5(
12053
- translate9(width / 2, height / 2),
12226
+ return compose6(
12227
+ translate10(width / 2, height / 2),
12054
12228
  scale3(scaleFactor, -scaleFactor, 0, 0),
12055
- translate9(-center.x, -center.y)
12229
+ translate10(-center.x, -center.y)
12056
12230
  );
12057
12231
  };
12058
12232
  var getRelatedIdsForError = (error) => {
@@ -12145,149 +12319,9 @@ var animateTransform = ({
12145
12319
  return animationFrameId;
12146
12320
  };
12147
12321
 
12148
- // src/lib/get-trace-overlay-text.ts
12149
- var getNonEmptyName = (name) => name?.trim() || null;
12150
- function createTraceOverlayElementIndex(elements) {
12151
- const sourceNetById = /* @__PURE__ */ new Map();
12152
- const sourceTraceById = /* @__PURE__ */ new Map();
12153
- for (const element of elements) {
12154
- if (element.type === "source_net") {
12155
- sourceNetById.set(element.source_net_id, element);
12156
- } else if (element.type === "source_trace") {
12157
- sourceTraceById.set(element.source_trace_id, element);
12158
- }
12159
- }
12160
- return { sourceNetById, sourceTraceById };
12161
- }
12162
- function getAssociatedTraceName({
12163
- primitiveElement,
12164
- traceOverlayElementIndex
12165
- }) {
12166
- const sourceElementId = primitiveElement.source_trace_id;
12167
- if (!sourceElementId) return null;
12168
- const sourceTrace = traceOverlayElementIndex.sourceTraceById.get(sourceElementId);
12169
- const sourceTraceName = getNonEmptyName(sourceTrace?.name);
12170
- if (sourceTraceName) return sourceTraceName;
12171
- const sourceNet = traceOverlayElementIndex.sourceNetById.get(sourceElementId);
12172
- const sourceNetName = getNonEmptyName(sourceNet?.name);
12173
- if (sourceNetName) return sourceNetName;
12174
- for (const sourceNetId of sourceTrace?.connected_source_net_ids ?? []) {
12175
- const connectedSourceNetName = getNonEmptyName(
12176
- traceOverlayElementIndex.sourceNetById.get(sourceNetId)?.name
12177
- );
12178
- if (connectedSourceNetName) return connectedSourceNetName;
12179
- }
12180
- return null;
12181
- }
12182
- function getTraceOverlayInfo({
12183
- primitiveElement,
12184
- traceOverlayElementIndex
12185
- }) {
12186
- const sourceTraceId = primitiveElement.source_trace_id;
12187
- const trace = sourceTraceId ? traceOverlayElementIndex.sourceTraceById.get(sourceTraceId) : void 0;
12188
- const traceLength = primitiveElement.trace_length;
12189
- const hasTraceLength = typeof traceLength === "number";
12190
- const maxLength = trace?.max_length;
12191
- const text = hasTraceLength ? `${traceLength.toFixed(3)}${typeof maxLength === "number" ? ` / ${maxLength}` : ""} mm` : "";
12192
- const name = getAssociatedTraceName({
12193
- primitiveElement,
12194
- traceOverlayElementIndex
12195
- }) ?? getNonEmptyName(trace?.display_name);
12196
- if (!text && !name) return null;
12197
- const isOverLength = Boolean(
12198
- hasTraceLength && typeof maxLength === "number" && traceLength > maxLength
12199
- );
12200
- return {
12201
- text,
12202
- name,
12203
- isOverLength
12204
- };
12205
- }
12206
-
12207
- // src/lib/x-ray-net.ts
12208
- function getElementNetId(element, connectivityMap) {
12209
- if (!element) return;
12210
- const ids = [];
12211
- for (const key of [
12212
- `${element.type}_id`,
12213
- "pcb_port_id",
12214
- "pcb_trace_id",
12215
- "source_trace_id",
12216
- "source_net_id"
12217
- ]) {
12218
- const value = element[key];
12219
- if (typeof value === "string") ids.push(value);
12220
- }
12221
- for (const id of ids) {
12222
- const net = connectivityMap.getNetConnectedToId(id);
12223
- if (net) return net;
12224
- }
12225
- if ("source_net_id" in element) return element.source_net_id;
12226
- }
12227
- function isXRayCopper(element) {
12228
- return element && [
12229
- "pcb_trace",
12230
- "pcb_smtpad",
12231
- "pcb_plated_hole",
12232
- "pcb_via",
12233
- "pcb_copper_pour"
12234
- ].includes(element.type);
12235
- }
12236
- function getXRayDisplayName(element, elements, connectivityMap) {
12237
- const traceOverlayElementIndex = createTraceOverlayElementIndex(elements);
12238
- const directName = element.type === "pcb_trace" ? getAssociatedTraceName({
12239
- primitiveElement: element,
12240
- traceOverlayElementIndex
12241
- }) : null;
12242
- if (directName) return directName;
12243
- const netId = getElementNetId(element, connectivityMap);
12244
- const connected = netId ? elements.filter(
12245
- (candidate) => getElementNetId(candidate, connectivityMap) === netId
12246
- ) : [];
12247
- for (const type of ["source_net", "source_trace"]) {
12248
- for (const candidate of connected) {
12249
- if (candidate.type === type && "name" in candidate && typeof candidate.name === "string" && candidate.name.trim())
12250
- return candidate.name.trim();
12251
- }
12252
- }
12253
- if (element.type === "pcb_trace") {
12254
- const label = getTraceOverlayInfo({
12255
- primitiveElement: element,
12256
- traceOverlayElementIndex
12257
- })?.name;
12258
- if (label) return label;
12259
- }
12260
- for (const candidate of connected) {
12261
- if (candidate.type === "source_trace" && candidate.display_name?.trim())
12262
- return candidate.display_name.trim();
12263
- }
12264
- return "Net";
12265
- }
12266
- function getXRayGroups(netId, elements, connectivityMap) {
12267
- return elements.flatMap((element) => {
12268
- if (element.type !== "source_bus") return [];
12269
- const netIds = [
12270
- ...new Set(
12271
- element.source_trace_ids.flatMap((id) => {
12272
- const net = connectivityMap.getNetConnectedToId(id);
12273
- return net ? [net] : [];
12274
- })
12275
- )
12276
- ];
12277
- if (!netIds.includes(netId)) return [];
12278
- return [
12279
- {
12280
- id: element.source_bus_id,
12281
- name: element.name?.trim() || "Bus",
12282
- netIds
12283
- }
12284
- ];
12285
- });
12286
- }
12287
-
12288
12322
  // src/components/CanvasElementsRenderer.tsx
12289
12323
  import { useCallback as useCallback11, useEffect as useEffect20, useMemo as useMemo15, useRef as useRef16, useState as useState13 } from "react";
12290
- import { applyToPoint as applyToPoint21, inverse as inverse6 } from "transformation-matrix";
12324
+ import { applyToPoint as applyToPoint22, inverse as inverse6 } from "transformation-matrix";
12291
12325
 
12292
12326
  // src/lib/get-pad-component.ts
12293
12327
  var getPadComponent = (pad, elements) => {
@@ -12314,11 +12348,11 @@ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer17 } from "circuit-to-can
12314
12348
  // src/lib/Drawer.ts
12315
12349
  import colorParser from "color";
12316
12350
  import {
12317
- applyToPoint as applyToPoint3,
12318
- compose as compose6,
12351
+ applyToPoint as applyToPoint4,
12352
+ compose as compose7,
12319
12353
  identity as identity3,
12320
12354
  inverse,
12321
- translate as translate10
12355
+ translate as translate11
12322
12356
  } from "transformation-matrix";
12323
12357
 
12324
12358
  // src/lib/colors.ts
@@ -12640,7 +12674,7 @@ var Drawer = class {
12640
12674
  );
12641
12675
  this.transform = identity3();
12642
12676
  this.transform.d *= -1;
12643
- this.transform = compose6(this.transform, translate10(0, -500));
12677
+ this.transform = compose7(this.transform, translate11(0, -500));
12644
12678
  this.lastPoint = { x: 0, y: 0 };
12645
12679
  this.equip({});
12646
12680
  }
@@ -12663,8 +12697,8 @@ var Drawer = class {
12663
12697
  }
12664
12698
  drawMeshPattern(x, y, width, height, spacing, angle = 45) {
12665
12699
  const ctx = this.getLayerCtx();
12666
- const [x1, y1] = applyToPoint3(this.transform, [x, y]);
12667
- const [x2, y2] = applyToPoint3(this.transform, [x + width, y + height]);
12700
+ const [x1, y1] = applyToPoint4(this.transform, [x, y]);
12701
+ const [x2, y2] = applyToPoint4(this.transform, [x + width, y + height]);
12668
12702
  const spacing$ = scaleOnly(this.transform, spacing);
12669
12703
  ctx.lineWidth = 1;
12670
12704
  ctx.strokeStyle = this.aperture.color;
@@ -12694,8 +12728,8 @@ var Drawer = class {
12694
12728
  stroke_width,
12695
12729
  roundness
12696
12730
  }) {
12697
- const [x1$, y1$] = applyToPoint3(this.transform, [x - w / 2, y - h / 2]);
12698
- const [x2$, y2$] = applyToPoint3(this.transform, [x + w / 2, y + h / 2]);
12731
+ const [x1$, y1$] = applyToPoint4(this.transform, [x - w / 2, y - h / 2]);
12732
+ const [x2$, y2$] = applyToPoint4(this.transform, [x + w / 2, y + h / 2]);
12699
12733
  this.applyAperture();
12700
12734
  const ctx = this.getLayerCtx();
12701
12735
  const radius$ = roundness ? scaleOnly(this.transform, roundness) : 0;
@@ -12765,11 +12799,11 @@ var Drawer = class {
12765
12799
  rotatedRect(x, y, w, h, ccw_rotation, roundness, mesh_fill) {
12766
12800
  const ctx = this.getLayerCtx();
12767
12801
  this.applyAperture();
12768
- const [x1$, y1$] = applyToPoint3(this.transform, [x - w / 2, y - h / 2]);
12769
- const [x2$, y2$] = applyToPoint3(this.transform, [x + w / 2, y + h / 2]);
12802
+ const [x1$, y1$] = applyToPoint4(this.transform, [x - w / 2, y - h / 2]);
12803
+ const [x2$, y2$] = applyToPoint4(this.transform, [x + w / 2, y + h / 2]);
12770
12804
  const radius$ = roundness ? scaleOnly(this.transform, roundness) : 0;
12771
12805
  ctx.save();
12772
- const [centerX, centerY] = applyToPoint3(this.transform, [x, y]);
12806
+ const [centerX, centerY] = applyToPoint4(this.transform, [x, y]);
12773
12807
  ctx.translate(centerX, centerY);
12774
12808
  const cw_rotation = 360 - ccw_rotation;
12775
12809
  if (ccw_rotation) ctx.rotate(cw_rotation * Math.PI / 180);
@@ -12805,7 +12839,7 @@ var Drawer = class {
12805
12839
  const ctx = this.getLayerCtx();
12806
12840
  this.applyAperture();
12807
12841
  ctx.save();
12808
- const [centerX, centerY] = applyToPoint3(this.transform, [x, y]);
12842
+ const [centerX, centerY] = applyToPoint4(this.transform, [x, y]);
12809
12843
  ctx.translate(centerX, centerY);
12810
12844
  const cw_rotation = 360 - ccw_rotation;
12811
12845
  if (ccw_rotation) ctx.rotate(cw_rotation * Math.PI / 180);
@@ -12815,7 +12849,7 @@ var Drawer = class {
12815
12849
  }
12816
12850
  circle(x, y, r, mesh_fill, is_filled = true) {
12817
12851
  const r$ = scaleOnly(this.transform, r);
12818
- const [x$, y$] = applyToPoint3(this.transform, [x, y]);
12852
+ const [x$, y$] = applyToPoint4(this.transform, [x, y]);
12819
12853
  this.applyAperture();
12820
12854
  const ctx = this.getLayerCtx();
12821
12855
  if (mesh_fill) {
@@ -12834,19 +12868,26 @@ var Drawer = class {
12834
12868
  ctx.fill();
12835
12869
  }
12836
12870
  }
12837
- oval(x, y, rx, ry) {
12871
+ oval({
12872
+ x,
12873
+ y,
12874
+ rx,
12875
+ ry,
12876
+ ccwRotationDegrees = 0
12877
+ }) {
12838
12878
  const rx$ = scaleOnly(this.transform, rx);
12839
12879
  const ry$ = scaleOnly(this.transform, ry);
12840
- const [x$, y$] = applyToPoint3(this.transform, [x, y]);
12880
+ const [x$, y$] = applyToPoint4(this.transform, [x, y]);
12841
12881
  this.applyAperture();
12842
12882
  const ctx = this.getLayerCtx();
12843
12883
  ctx.beginPath();
12844
- ctx.ellipse(x$, y$, rx$, ry$, 0, 0, 2 * Math.PI);
12884
+ const cwRotationRadians = -ccwRotationDegrees * Math.PI / 180;
12885
+ ctx.ellipse(x$, y$, rx$, ry$, cwRotationRadians, 0, 2 * Math.PI);
12845
12886
  ctx.fill();
12846
12887
  ctx.closePath();
12847
12888
  }
12848
12889
  pill(x, y, w, h) {
12849
- const [x$, y$] = applyToPoint3(this.transform, [x - w / 2, y + h / 2]);
12890
+ const [x$, y$] = applyToPoint4(this.transform, [x - w / 2, y + h / 2]);
12850
12891
  const width$ = scaleOnly(this.transform, w);
12851
12892
  const height$ = scaleOnly(this.transform, h);
12852
12893
  const radius = Math.min(width$, height$) / 2;
@@ -12873,7 +12914,7 @@ var Drawer = class {
12873
12914
  this.applyAperture();
12874
12915
  const ctx = this.getLayerCtx();
12875
12916
  const transformedPoints = points.map(
12876
- (point2) => applyToPoint3(this.transform, [point2.x, point2.y])
12917
+ (point2) => applyToPoint4(this.transform, [point2.x, point2.y])
12877
12918
  );
12878
12919
  ctx.beginPath();
12879
12920
  ctx.moveTo(transformedPoints[0][0], transformedPoints[0][1]);
@@ -12890,7 +12931,7 @@ var Drawer = class {
12890
12931
  }
12891
12932
  /* NOTE: This is not gerber compatible */
12892
12933
  debugText(text, x, y) {
12893
- const [x$, y$] = applyToPoint3(this.transform, [x, y]);
12934
+ const [x$, y$] = applyToPoint4(this.transform, [x, y]);
12894
12935
  this.applyAperture();
12895
12936
  const ctx = this.getLayerCtx();
12896
12937
  ctx.font = "10px sans-serif";
@@ -12999,11 +13040,11 @@ var Drawer = class {
12999
13040
  this.lastPoint = { x, y };
13000
13041
  }
13001
13042
  lineTo(x, y) {
13002
- const [x$, y$] = applyToPoint3(this.transform, [x, y]);
13043
+ const [x$, y$] = applyToPoint4(this.transform, [x, y]);
13003
13044
  const { size, shape, mode } = this.aperture;
13004
13045
  const size$ = scaleOnly(this.transform, size);
13005
13046
  const { lastPoint } = this;
13006
- const lastPoint$ = applyToPoint3(this.transform, lastPoint);
13047
+ const lastPoint$ = applyToPoint4(this.transform, lastPoint);
13007
13048
  this.applyAperture();
13008
13049
  const ctx = this.getLayerCtx();
13009
13050
  if (shape === "square")
@@ -13027,7 +13068,7 @@ var Drawer = class {
13027
13068
  const processRing = (ring) => {
13028
13069
  if (ring.vertices.length === 0) return;
13029
13070
  const startPoint = ring.vertices[0];
13030
- const t_start_point = applyToPoint3(this.transform, [
13071
+ const t_start_point = applyToPoint4(this.transform, [
13031
13072
  startPoint.x,
13032
13073
  startPoint.y
13033
13074
  ]);
@@ -13041,7 +13082,7 @@ var Drawer = class {
13041
13082
  const dy = p2.y - p1.y;
13042
13083
  const chord = Math.sqrt(dx * dx + dy * dy);
13043
13084
  if (chord < 1e-9) {
13044
- const t_p2 = applyToPoint3(this.transform, [p2.x, p2.y]);
13085
+ const t_p2 = applyToPoint4(this.transform, [p2.x, p2.y]);
13045
13086
  ctx.lineTo(t_p2[0], t_p2[1]);
13046
13087
  continue;
13047
13088
  }
@@ -13065,7 +13106,7 @@ var Drawer = class {
13065
13106
  } else if (bulge < 0 && endAngle > startAngle) {
13066
13107
  endAngle -= 2 * Math.PI;
13067
13108
  }
13068
- const t_center = applyToPoint3(this.transform, [cx, cy]);
13109
+ const t_center = applyToPoint4(this.transform, [cx, cy]);
13069
13110
  const t_radius = scaleOnly(this.transform, radius);
13070
13111
  ctx.arc(
13071
13112
  t_center[0],
@@ -13076,7 +13117,7 @@ var Drawer = class {
13076
13117
  bulge > 0
13077
13118
  );
13078
13119
  } else {
13079
- const t_p2 = applyToPoint3(this.transform, [p2.x, p2.y]);
13120
+ const t_p2 = applyToPoint4(this.transform, [p2.x, p2.y]);
13080
13121
  ctx.lineTo(t_p2[0], t_p2[1]);
13081
13122
  }
13082
13123
  }
@@ -13607,24 +13648,24 @@ function drawPlatedHolePads({
13607
13648
  }
13608
13649
 
13609
13650
  // src/lib/util/rotate-text.ts
13610
- import { compose as compose7, translate as translate11, rotate as rotate2, applyToPoint as applyToPoint4 } from "transformation-matrix";
13651
+ import { compose as compose8, translate as translate12, rotate as rotate2, applyToPoint as applyToPoint5 } from "transformation-matrix";
13611
13652
  function rotateText(rotateTextParams) {
13612
13653
  const { lines, anchorPoint, ccwRotation } = rotateTextParams;
13613
13654
  if (!ccwRotation) return lines;
13614
13655
  const rad = ccwRotation * Math.PI / 180;
13615
13656
  const rotationMatrix = rotate2(rad);
13616
- const transform = compose7(
13617
- translate11(anchorPoint.x, anchorPoint.y),
13657
+ const transform = compose8(
13658
+ translate12(anchorPoint.x, anchorPoint.y),
13618
13659
  rotationMatrix,
13619
- translate11(-anchorPoint.x, -anchorPoint.y)
13660
+ translate12(-anchorPoint.x, -anchorPoint.y)
13620
13661
  );
13621
- applyToPoint4(transform, anchorPoint);
13662
+ applyToPoint5(transform, anchorPoint);
13622
13663
  return lines.map((line2) => ({
13623
13664
  ...line2,
13624
- x1: applyToPoint4(transform, { x: line2.x1, y: line2.y1 }).x,
13625
- y1: applyToPoint4(transform, { x: line2.x1, y: line2.y1 }).y,
13626
- x2: applyToPoint4(transform, { x: line2.x2, y: line2.y2 }).x,
13627
- y2: applyToPoint4(transform, { x: line2.x2, y: line2.y2 }).y
13665
+ x1: applyToPoint5(transform, { x: line2.x1, y: line2.y1 }).x,
13666
+ y1: applyToPoint5(transform, { x: line2.x1, y: line2.y1 }).y,
13667
+ x2: applyToPoint5(transform, { x: line2.x2, y: line2.y2 }).x,
13668
+ y2: applyToPoint5(transform, { x: line2.x2, y: line2.y2 }).y
13628
13669
  }));
13629
13670
  }
13630
13671
 
@@ -13940,7 +13981,13 @@ var drawOval = (drawer, oval) => {
13940
13981
  color: getColor(oval),
13941
13982
  layer: oval.layer
13942
13983
  });
13943
- drawer.oval(oval.x, oval.y, oval.rX, oval.rY);
13984
+ drawer.oval({
13985
+ x: oval.x,
13986
+ y: oval.y,
13987
+ rx: oval.rX,
13988
+ ry: oval.rY,
13989
+ ccwRotationDegrees: oval.ccw_rotation
13990
+ });
13944
13991
  };
13945
13992
  var drawPill = (drawer, pill) => {
13946
13993
  drawer.equip({
@@ -14696,7 +14743,7 @@ var pngSignature = Uint8Array.of(137, 80, 78, 71, 13, 10, 26, 10);
14696
14743
  var latin1Decoder = new TextDecoder("latin1");
14697
14744
 
14698
14745
  // node_modules/graphics-debug/dist/chunk-FLFF6QXL.js
14699
- import { applyToPoint as applyToPoint5, inverse as inverse2 } from "transformation-matrix";
14746
+ import { applyToPoint as applyToPoint6, inverse as inverse2 } from "transformation-matrix";
14700
14747
  var EPSILON = 1e-9;
14701
14748
  var isWithin = (value, min, max) => {
14702
14749
  return value >= min - EPSILON && value <= max + EPSILON;
@@ -14766,10 +14813,10 @@ function clipInfiniteLineToBounds(infiniteLine, bounds) {
14766
14813
  function getViewportBoundsFromMatrix(matrix2, width, height) {
14767
14814
  const screenToReal = inverse2(matrix2);
14768
14815
  const corners = [
14769
- applyToPoint5(screenToReal, { x: 0, y: 0 }),
14770
- applyToPoint5(screenToReal, { x: width, y: 0 }),
14771
- applyToPoint5(screenToReal, { x: 0, y: height }),
14772
- applyToPoint5(screenToReal, { x: width, y: height })
14816
+ applyToPoint6(screenToReal, { x: 0, y: 0 }),
14817
+ applyToPoint6(screenToReal, { x: width, y: 0 }),
14818
+ applyToPoint6(screenToReal, { x: 0, y: height }),
14819
+ applyToPoint6(screenToReal, { x: width, y: height })
14773
14820
  ];
14774
14821
  return {
14775
14822
  minX: Math.min(...corners.map((p) => p.x)),
@@ -14784,7 +14831,7 @@ var FONT_SIZE_WIDTH_RATIO = 0.6;
14784
14831
  var FONT_SIZE_HEIGHT_RATIO = 1;
14785
14832
 
14786
14833
  // node_modules/graphics-debug/dist/chunk-MLQPMI4V.js
14787
- import { applyToPoint as applyToPoint6 } from "transformation-matrix";
14834
+ import { applyToPoint as applyToPoint7 } from "transformation-matrix";
14788
14835
  var getDistanceBetweenPoints = (a, b) => {
14789
14836
  return Math.hypot(a.x - b.x, a.y - b.y);
14790
14837
  };
@@ -14833,9 +14880,9 @@ var getRectCornersWithAngle = (rect, angleRadians) => {
14833
14880
  };
14834
14881
  var getProjectedRectGeometry = (rect, matrix2) => {
14835
14882
  const corners = getRectCornersForMatrix(rect, matrix2).map(
14836
- (point2) => applyToPoint6(matrix2, point2)
14883
+ (point2) => applyToPoint7(matrix2, point2)
14837
14884
  );
14838
- const center = applyToPoint6(matrix2, rect.center);
14885
+ const center = applyToPoint7(matrix2, rect.center);
14839
14886
  const width = getDistanceBetweenPoints(corners[0], corners[1]);
14840
14887
  const height = getDistanceBetweenPoints(corners[1], corners[2]);
14841
14888
  const angleRadians = corners.length >= 2 ? Math.atan2(corners[1].y - corners[0].y, corners[1].x - corners[0].x) : 0;
@@ -15013,10 +15060,10 @@ function getInlineLabelLayout(shaftStart, shaftEnd, {
15013
15060
 
15014
15061
  // node_modules/graphics-debug/dist/chunk-TKCBDTT7.js
15015
15062
  import {
15016
- applyToPoint as applyToPoint7,
15017
- compose as compose8,
15063
+ applyToPoint as applyToPoint8,
15064
+ compose as compose9,
15018
15065
  scale as scale4,
15019
- translate as translate12
15066
+ translate as translate13
15020
15067
  } from "transformation-matrix";
15021
15068
  var defaultColors = [
15022
15069
  "rgba(239, 68, 68, 0.8)",
@@ -15078,10 +15125,10 @@ function computeTransformFromViewbox(viewbox, canvasWidth, canvasHeight, options
15078
15125
  (canvasWidth - 2 * padding) / width,
15079
15126
  (canvasHeight - 2 * padding) / height
15080
15127
  );
15081
- return compose8(
15082
- translate12(canvasWidth / 2, canvasHeight / 2),
15128
+ return compose9(
15129
+ translate13(canvasWidth / 2, canvasHeight / 2),
15083
15130
  scale4(scale_factor, yFlip ? -scale_factor : scale_factor),
15084
- translate12(-(bounds.minX + width / 2), -(bounds.minY + height / 2))
15131
+ translate13(-(bounds.minX + width / 2), -(bounds.minY + height / 2))
15085
15132
  );
15086
15133
  }
15087
15134
  function getBounds(graphics) {
@@ -15207,7 +15254,7 @@ function drawGraphicsToCanvas(graphics, target, options = {}) {
15207
15254
  }
15208
15255
  if (graphics.circles && graphics.circles.length > 0) {
15209
15256
  graphics.circles.forEach((circle2) => {
15210
- const projected = applyToPoint7(matrix2, circle2.center);
15257
+ const projected = applyToPoint8(matrix2, circle2.center);
15211
15258
  const scaledRadius = circle2.radius * Math.abs(matrix2.a);
15212
15259
  ctx.beginPath();
15213
15260
  ctx.arc(projected.x, projected.y, scaledRadius, 0, 2 * Math.PI);
@@ -15225,7 +15272,7 @@ function drawGraphicsToCanvas(graphics, target, options = {}) {
15225
15272
  graphics.polygons.forEach((polygon2) => {
15226
15273
  if (polygon2.points.length === 0) return;
15227
15274
  const projectedPoints = polygon2.points.map(
15228
- (point2) => applyToPoint7(matrix2, point2)
15275
+ (point2) => applyToPoint8(matrix2, point2)
15229
15276
  );
15230
15277
  ctx.beginPath();
15231
15278
  ctx.moveTo(projectedPoints[0].x, projectedPoints[0].y);
@@ -15249,8 +15296,8 @@ function drawGraphicsToCanvas(graphics, target, options = {}) {
15249
15296
  if (graphics.arrows && graphics.arrows.length > 0) {
15250
15297
  graphics.arrows.forEach((arrow, arrowIndex) => {
15251
15298
  const geometry = getArrowGeometry(arrow);
15252
- const shaftStart = applyToPoint7(matrix2, geometry.shaftStart);
15253
- const shaftEnd = applyToPoint7(matrix2, geometry.shaftEnd);
15299
+ const shaftStart = applyToPoint8(matrix2, geometry.shaftStart);
15300
+ const shaftEnd = applyToPoint8(matrix2, geometry.shaftEnd);
15254
15301
  const color9 = arrow.color || defaultColors[arrowIndex % defaultColors.length];
15255
15302
  const scaleFactor = Math.hypot(matrix2.a, matrix2.b);
15256
15303
  ctx.strokeStyle = color9;
@@ -15263,9 +15310,9 @@ function drawGraphicsToCanvas(graphics, target, options = {}) {
15263
15310
  ctx.lineTo(shaftEnd.x, shaftEnd.y);
15264
15311
  ctx.stroke();
15265
15312
  geometry.heads.forEach((head) => {
15266
- const tip = applyToPoint7(matrix2, head.tip);
15267
- const leftWing = applyToPoint7(matrix2, head.leftWing);
15268
- const rightWing = applyToPoint7(matrix2, head.rightWing);
15313
+ const tip = applyToPoint8(matrix2, head.tip);
15314
+ const leftWing = applyToPoint8(matrix2, head.leftWing);
15315
+ const rightWing = applyToPoint8(matrix2, head.rightWing);
15269
15316
  ctx.beginPath();
15270
15317
  ctx.moveTo(tip.x, tip.y);
15271
15318
  ctx.lineTo(leftWing.x, leftWing.y);
@@ -15316,10 +15363,10 @@ function drawGraphicsToCanvas(graphics, target, options = {}) {
15316
15363
  ).forEach(({ line: line2, originalIndex: lineIndex }) => {
15317
15364
  if (line2.points.length === 0) return;
15318
15365
  ctx.beginPath();
15319
- const firstPoint = applyToPoint7(matrix2, line2.points[0]);
15366
+ const firstPoint = applyToPoint8(matrix2, line2.points[0]);
15320
15367
  ctx.moveTo(firstPoint.x, firstPoint.y);
15321
15368
  for (let i = 1; i < line2.points.length; i++) {
15322
- const projected = applyToPoint7(matrix2, line2.points[i]);
15369
+ const projected = applyToPoint8(matrix2, line2.points[i]);
15323
15370
  ctx.lineTo(projected.x, projected.y);
15324
15371
  }
15325
15372
  ctx.strokeStyle = line2.strokeColor || defaultColors[lineIndex % defaultColors.length];
@@ -15358,8 +15405,8 @@ function drawGraphicsToCanvas(graphics, target, options = {}) {
15358
15405
  const segment2 = clipInfiniteLineToBounds(line2, viewportBounds);
15359
15406
  if (!segment2) return;
15360
15407
  const [start, end] = segment2;
15361
- const projectedStart = applyToPoint7(matrix2, start);
15362
- const projectedEnd = applyToPoint7(matrix2, end);
15408
+ const projectedStart = applyToPoint8(matrix2, start);
15409
+ const projectedEnd = applyToPoint8(matrix2, end);
15363
15410
  ctx.beginPath();
15364
15411
  ctx.moveTo(projectedStart.x, projectedStart.y);
15365
15412
  ctx.lineTo(projectedEnd.x, projectedEnd.y);
@@ -15387,7 +15434,7 @@ function drawGraphicsToCanvas(graphics, target, options = {}) {
15387
15434
  }
15388
15435
  if (graphics.texts && graphics.texts.length > 0) {
15389
15436
  graphics.texts.forEach((text) => {
15390
- const projected = applyToPoint7(matrix2, { x: text.x, y: text.y });
15437
+ const projected = applyToPoint8(matrix2, { x: text.x, y: text.y });
15391
15438
  ctx.fillStyle = text.color || "black";
15392
15439
  ctx.font = `${(text.fontSize ?? 12) * Math.abs(matrix2.a)}px sans-serif`;
15393
15440
  const anchor = text.anchorSide ?? "center";
@@ -15420,7 +15467,7 @@ function drawGraphicsToCanvas(graphics, target, options = {}) {
15420
15467
  }
15421
15468
  if (graphics.points && graphics.points.length > 0) {
15422
15469
  graphics.points.forEach((point2, pointIndex) => {
15423
- const projected = applyToPoint7(matrix2, point2);
15470
+ const projected = applyToPoint8(matrix2, point2);
15424
15471
  ctx.beginPath();
15425
15472
  ctx.arc(projected.x, projected.y, 3, 0, 2 * Math.PI);
15426
15473
  ctx.fillStyle = point2.color || defaultColors[pointIndex % defaultColors.length];
@@ -15436,15 +15483,15 @@ function drawGraphicsToCanvas(graphics, target, options = {}) {
15436
15483
  }
15437
15484
 
15438
15485
  // node_modules/graphics-debug/dist/chunk-5XG5QE5Z.js
15439
- import { applyToPoint as applyToPoint8 } from "transformation-matrix";
15486
+ import { applyToPoint as applyToPoint9 } from "transformation-matrix";
15440
15487
 
15441
15488
  // node_modules/graphics-debug/dist/chunk-WDTSQY35.js
15442
15489
  var import_svgson = __toESM(require_svgson_umd(), 1);
15443
15490
  import {
15444
- applyToPoint as applyToPoint9,
15445
- compose as compose9,
15491
+ applyToPoint as applyToPoint10,
15492
+ compose as compose10,
15446
15493
  scale as scale5,
15447
- translate as translate13
15494
+ translate as translate14
15448
15495
  } from "transformation-matrix";
15449
15496
 
15450
15497
  // src/components/DebugGraphicsOverlay.tsx
@@ -15500,7 +15547,7 @@ var DebugGraphicsOverlay = ({
15500
15547
 
15501
15548
  // src/components/DimensionOverlay.tsx
15502
15549
  import { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo5, useRef as useRef5, useState as useState4 } from "react";
15503
- import { applyToPoint as applyToPoint11, identity as identity4, inverse as inverse3 } from "transformation-matrix";
15550
+ import { applyToPoint as applyToPoint12, identity as identity4, inverse as inverse3 } from "transformation-matrix";
15504
15551
 
15505
15552
  // src/hooks/useDiagonalLabel.ts
15506
15553
  import { useMemo as useMemo3 } from "react";
@@ -15694,7 +15741,10 @@ var getPrimitiveSnapPoints = (primitive) => {
15694
15741
  anchor: "oval_bottom",
15695
15742
  point: { x: primitive.x, y: primitive.y + primitive.rY }
15696
15743
  }
15697
- ];
15744
+ ].map(({ anchor, point: point2 }) => ({
15745
+ anchor,
15746
+ point: rotatePoint3(point2, primitive, primitive.ccw_rotation ?? 0)
15747
+ }));
15698
15748
  }
15699
15749
  case "line": {
15700
15750
  const midPoint = {
@@ -15725,7 +15775,7 @@ var getPrimitiveSnapPoints = (primitive) => {
15725
15775
  };
15726
15776
 
15727
15777
  // src/lib/get-screen-snapping-points.ts
15728
- import { applyToPoint as applyToPoint10 } from "transformation-matrix";
15778
+ import { applyToPoint as applyToPoint11 } from "transformation-matrix";
15729
15779
  var EMPTY_SCREEN_SNAPPING_POINTS = [];
15730
15780
  function getScreenSnappingPoints({
15731
15781
  snappingPoints,
@@ -15736,7 +15786,7 @@ function getScreenSnappingPoints({
15736
15786
  return snappingPoints.map((snap, index) => ({
15737
15787
  ...snap,
15738
15788
  id: `${index}-${snap.anchor}`,
15739
- screenPoint: applyToPoint10(realToScreenTransform, snap.point)
15789
+ screenPoint: applyToPoint11(realToScreenTransform, snap.point)
15740
15790
  }));
15741
15791
  }
15742
15792
 
@@ -15936,7 +15986,7 @@ var DimensionOverlay = ({
15936
15986
  if (screenSnappingPoints.length === 0) {
15937
15987
  return { point: rwPoint, id: null };
15938
15988
  }
15939
- const screenPoint = applyToPoint11(transform, rwPoint);
15989
+ const screenPoint = applyToPoint12(transform, rwPoint);
15940
15990
  let bestMatch = null;
15941
15991
  for (const snap of screenSnappingPoints) {
15942
15992
  const dx = snap.screenPoint.x - screenPoint.x;
@@ -16023,10 +16073,10 @@ var DimensionOverlay = ({
16023
16073
  disarmBounds,
16024
16074
  findSnap
16025
16075
  ]);
16026
- const screenDStart = applyToPoint11(transform, dStart);
16027
- const screenDEnd = applyToPoint11(transform, dEnd);
16028
- const screenBoundsStart = applyToPoint11(transform, boundsStart);
16029
- const screenBoundsEnd = applyToPoint11(transform, boundsEnd);
16076
+ const screenDStart = applyToPoint12(transform, dStart);
16077
+ const screenDEnd = applyToPoint12(transform, dEnd);
16078
+ const screenBoundsStart = applyToPoint12(transform, boundsStart);
16079
+ const screenBoundsEnd = applyToPoint12(transform, boundsEnd);
16030
16080
  const selectedBounds = {
16031
16081
  minX: Math.min(boundsStart.x, boundsEnd.x),
16032
16082
  minY: Math.min(boundsStart.y, boundsEnd.y),
@@ -16117,7 +16167,7 @@ var DimensionOverlay = ({
16117
16167
  const rect = e.currentTarget.getBoundingClientRect();
16118
16168
  const x = e.clientX - rect.left;
16119
16169
  const y = e.clientY - rect.top;
16120
- const rwPoint = applyToPoint11(inverse3(transform), { x, y });
16170
+ const rwPoint = applyToPoint12(inverse3(transform), { x, y });
16121
16171
  mousePosRef.current.x = rwPoint.x;
16122
16172
  mousePosRef.current.y = rwPoint.y;
16123
16173
  if (dimensionToolStretching) {
@@ -16135,7 +16185,7 @@ var DimensionOverlay = ({
16135
16185
  const rect = e.currentTarget.getBoundingClientRect();
16136
16186
  const x = e.clientX - rect.left;
16137
16187
  const y = e.clientY - rect.top;
16138
- const rwPoint = applyToPoint11(inverse3(transform), { x, y });
16188
+ const rwPoint = applyToPoint12(inverse3(transform), { x, y });
16139
16189
  if (boundsToolArmed) {
16140
16190
  e.preventDefault();
16141
16191
  e.stopPropagation();
@@ -16166,7 +16216,7 @@ var DimensionOverlay = ({
16166
16216
  const rect = e.currentTarget.getBoundingClientRect();
16167
16217
  const x = e.clientX - rect.left;
16168
16218
  const y = e.clientY - rect.top;
16169
- const rwPoint = applyToPoint11(inverse3(transform), { x, y });
16219
+ const rwPoint = applyToPoint12(inverse3(transform), { x, y });
16170
16220
  const end = { x: rwPoint.x, y: rwPoint.y };
16171
16221
  e.preventDefault();
16172
16222
  e.stopPropagation();
@@ -16423,7 +16473,7 @@ var DimensionOverlay = ({
16423
16473
 
16424
16474
  // src/components/EditPlacementOverlay.tsx
16425
16475
  import { useRef as useRef6, useState as useState5 } from "react";
16426
- import { applyToPoint as applyToPoint12, identity as identity5, inverse as inverse4 } from "transformation-matrix";
16476
+ import { applyToPoint as applyToPoint13, identity as identity5, inverse as inverse4 } from "transformation-matrix";
16427
16477
  import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
16428
16478
  var isInsideOf = (pcb_component, point2, padding = 0) => {
16429
16479
  const halfWidth = pcb_component.width / 2;
@@ -16468,7 +16518,7 @@ var EditPlacementOverlay = ({
16468
16518
  const x = e.clientX - rect.left;
16469
16519
  const y = e.clientY - rect.top;
16470
16520
  if (Number.isNaN(x) || Number.isNaN(y)) return;
16471
- const rwMousePoint = applyToPoint12(inverse4(transform), { x, y });
16521
+ const rwMousePoint = applyToPoint13(inverse4(transform), { x, y });
16472
16522
  let foundActiveComponent = false;
16473
16523
  for (const e2 of soup) {
16474
16524
  if (e2.type === "pcb_component" && isInsideOf(e2, rwMousePoint, 10 / transform.a)) {
@@ -16510,7 +16560,7 @@ var EditPlacementOverlay = ({
16510
16560
  const x = e.clientX - rect.left;
16511
16561
  const y = e.clientY - rect.top;
16512
16562
  if (Number.isNaN(x) || Number.isNaN(y)) return;
16513
- const rwMousePoint = applyToPoint12(inverse4(transform), { x, y });
16563
+ const rwMousePoint = applyToPoint13(inverse4(transform), { x, y });
16514
16564
  setDragState({
16515
16565
  ...dragState,
16516
16566
  dragEnd: rwMousePoint
@@ -16539,7 +16589,7 @@ var EditPlacementOverlay = ({
16539
16589
  children,
16540
16590
  !disabled && soup.filter((e) => e.type === "pcb_component").map((e) => {
16541
16591
  if (!e?.center) return null;
16542
- const projectedCenter = applyToPoint12(transform, e.center);
16592
+ const projectedCenter = applyToPoint13(transform, e.center);
16543
16593
  return /* @__PURE__ */ jsx7(
16544
16594
  "div",
16545
16595
  {
@@ -16602,7 +16652,7 @@ var getPopupPosition = (errorCenter, containerRef) => {
16602
16652
 
16603
16653
  // src/components/ErrorOverlay.tsx
16604
16654
  import { Fragment as Fragment2, useMemo as useMemo6, useRef as useRef7 } from "react";
16605
- import { applyToPoint as applyToPoint13, identity as identity6 } from "transformation-matrix";
16655
+ import { applyToPoint as applyToPoint14, identity as identity6 } from "transformation-matrix";
16606
16656
 
16607
16657
  // src/components/FocusMarkerSVG.tsx
16608
16658
  import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
@@ -16807,7 +16857,7 @@ var ErrorOverlay = ({
16807
16857
  if (!focusCenter || typeof focusCenter.x !== "number" || typeof focusCenter.y !== "number") {
16808
16858
  return null;
16809
16859
  }
16810
- const screenCenter = applyToPoint13(transform, focusCenter);
16860
+ const screenCenter = applyToPoint14(transform, focusCenter);
16811
16861
  if (Number.isNaN(screenCenter.x) || Number.isNaN(screenCenter.y)) {
16812
16862
  return null;
16813
16863
  }
@@ -17005,7 +17055,7 @@ var ErrorOverlay = ({
17005
17055
  if (pcbComp && pcbComp.type === "pcb_component")
17006
17056
  center = pcbComp.center || { x: 0, y: 0 };
17007
17057
  }
17008
- const screenCenter = applyToPoint13(transform, center);
17058
+ const screenCenter = applyToPoint14(transform, center);
17009
17059
  if (Number.isNaN(screenCenter.x) || Number.isNaN(screenCenter.y))
17010
17060
  return null;
17011
17061
  const scale7 = Math.abs(transform.a);
@@ -17132,7 +17182,7 @@ var ErrorOverlay = ({
17132
17182
 
17133
17183
  // src/components/FocusedPcbComponentOverlay.tsx
17134
17184
  import { useEffect as useEffect9 } from "react";
17135
- import { applyToPoint as applyToPoint14 } from "transformation-matrix";
17185
+ import { applyToPoint as applyToPoint15 } from "transformation-matrix";
17136
17186
 
17137
17187
  // src/lib/get-pcb-component-focus.ts
17138
17188
  var getPcbComponentFocus = (elements, pcbComponentId, width, height) => {
@@ -17166,8 +17216,8 @@ var FocusedPcbComponentOverlay = ({
17166
17216
  }, [focusRequest, layer, selectLayer]);
17167
17217
  if (!focus || !transform) return null;
17168
17218
  const { bounds } = focus;
17169
- const a = applyToPoint14(transform, { x: bounds.minX, y: bounds.minY });
17170
- const b = applyToPoint14(transform, { x: bounds.maxX, y: bounds.maxY });
17219
+ const a = applyToPoint15(transform, { x: bounds.minX, y: bounds.minY });
17220
+ const b = applyToPoint15(transform, { x: bounds.maxX, y: bounds.maxY });
17171
17221
  return /* @__PURE__ */ jsx10(
17172
17222
  "div",
17173
17223
  {
@@ -17200,10 +17250,10 @@ function ifSetsMatchExactly(set1, set2) {
17200
17250
 
17201
17251
  // src/components/MouseElementTracker.tsx
17202
17252
  import { useEffect as useEffect11, useMemo as useMemo8, useState as useState7 } from "react";
17203
- import { applyToPoint as applyToPoint17, inverse as inverse5 } from "transformation-matrix";
17253
+ import { applyToPoint as applyToPoint18, inverse as inverse5 } from "transformation-matrix";
17204
17254
 
17205
17255
  // src/components/AnchorOffsetOverlay/AnchorOffsetOverlay.tsx
17206
- import { applyToPoint as applyToPoint15 } from "transformation-matrix";
17256
+ import { applyToPoint as applyToPoint16 } from "transformation-matrix";
17207
17257
 
17208
17258
  // src/components/AnchorOffsetOverlay/common/constants.ts
17209
17259
  var VISUAL_CONFIG = {
@@ -17248,7 +17298,7 @@ var AnchorOffsetOverlay = ({
17248
17298
  const anchorScreens = /* @__PURE__ */ new Map();
17249
17299
  targets.forEach((target) => {
17250
17300
  if (!anchorScreens.has(target.anchor_id)) {
17251
- const screenPoint = applyToPoint15(transform, target.anchor);
17301
+ const screenPoint = applyToPoint16(transform, target.anchor);
17252
17302
  anchorScreens.set(target.anchor_id, screenPoint);
17253
17303
  }
17254
17304
  });
@@ -17282,7 +17332,7 @@ var AnchorOffsetOverlay = ({
17282
17332
  const anchorKey = target.anchor_id;
17283
17333
  const targetCenter = target.target;
17284
17334
  const anchorMarkerScreen = anchorScreens.get(anchorKey);
17285
- const targetScreen = applyToPoint15(transform, targetCenter);
17335
+ const targetScreen = applyToPoint16(transform, targetCenter);
17286
17336
  const offsetX = targetCenter.x - anchorPosition.x;
17287
17337
  const offsetY = targetCenter.y - anchorPosition.y;
17288
17338
  const xLineLength = Math.abs(targetScreen.x - anchorMarkerScreen.x);
@@ -17660,7 +17710,7 @@ var GroupAnchorOffsetOverlay = ({
17660
17710
  };
17661
17711
 
17662
17712
  // src/components/AnchorOffsetOverlay/ComponentBoundingBoxOverlay.tsx
17663
- import { applyToPoint as applyToPoint16 } from "transformation-matrix";
17713
+ import { applyToPoint as applyToPoint17 } from "transformation-matrix";
17664
17714
  import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
17665
17715
  var calculateComponentBoundingBox = (component, elements) => {
17666
17716
  const componentId = component.pcb_component_id;
@@ -17724,11 +17774,11 @@ var ComponentBoundingBoxOverlay = ({
17724
17774
  width: containerWidth,
17725
17775
  height: containerHeight,
17726
17776
  children: renderData.map(({ component, bbox, group }) => {
17727
- const topLeft = applyToPoint16(transform, {
17777
+ const topLeft = applyToPoint17(transform, {
17728
17778
  x: bbox.minX,
17729
17779
  y: bbox.maxY
17730
17780
  });
17731
- const bottomRight = applyToPoint16(transform, {
17781
+ const bottomRight = applyToPoint17(transform, {
17732
17782
  x: bbox.maxX,
17733
17783
  y: bbox.minY
17734
17784
  });
@@ -17742,7 +17792,7 @@ var ComponentBoundingBoxOverlay = ({
17742
17792
  x: (bbox.minX + bbox.maxX) / 2,
17743
17793
  y: (bbox.minY + bbox.maxY) / 2
17744
17794
  };
17745
- const componentCenterScreen = applyToPoint16(transform, componentCenter);
17795
+ const componentCenterScreen = applyToPoint17(transform, componentCenter);
17746
17796
  return /* @__PURE__ */ jsxs9("g", { children: [
17747
17797
  /* @__PURE__ */ jsx14(
17748
17798
  "rect",
@@ -18232,8 +18282,9 @@ var getPrimitivesUnderPoint = ({
18232
18282
  w = primitive.r * 2;
18233
18283
  h = primitive.r * 2;
18234
18284
  } else if ("rX" in primitive && "rY" in primitive) {
18235
- w = primitive.rX * 2;
18236
- h = primitive.rY * 2;
18285
+ const bounds = getPrimitiveBoundingBox(primitive);
18286
+ w = bounds.maxX - bounds.minX;
18287
+ h = bounds.maxY - bounds.minY;
18237
18288
  } else {
18238
18289
  continue;
18239
18290
  }
@@ -18301,7 +18352,7 @@ var MouseElementTracker = ({
18301
18352
  h = "h" in primitive ? primitive.h : "r" in primitive ? primitive.r * 2 : "rX" in primitive && "rY" in primitive ? primitive.rY * 2 : 0;
18302
18353
  }
18303
18354
  if (!basePoint) continue;
18304
- const screenPos = applyToPoint17(transform, basePoint);
18355
+ const screenPos = applyToPoint18(transform, basePoint);
18305
18356
  const screenSize = {
18306
18357
  w: w * transform.a,
18307
18358
  h: h * transform.a
@@ -18330,7 +18381,7 @@ var MouseElementTracker = ({
18330
18381
  }) => {
18331
18382
  const { x, y } = screenPoint;
18332
18383
  setMousePos({ x, y });
18333
- const rwPoint = applyToPoint17(inverse5(transform2), { x, y });
18384
+ const rwPoint = applyToPoint18(inverse5(transform2), { x, y });
18334
18385
  const nearbyPrimitives = getPrimitivesNearPoint({
18335
18386
  point: rwPoint,
18336
18387
  realToScreenScale: transform2.a,
@@ -18433,7 +18484,7 @@ var MouseElementTracker = ({
18433
18484
 
18434
18485
  // src/components/PcbGroupOverlay.tsx
18435
18486
  import { useEffect as useEffect12, useMemo as useMemo9, useRef as useRef8 } from "react";
18436
- import { applyToPoint as applyToPoint18 } from "transformation-matrix";
18487
+ import { applyToPoint as applyToPoint19 } from "transformation-matrix";
18437
18488
  import { identity as identity7 } from "transformation-matrix";
18438
18489
  import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
18439
18490
  var GROUP_COLORS = [
@@ -18603,10 +18654,10 @@ var PcbGroupOverlay = ({
18603
18654
  minY -= totalPadding;
18604
18655
  maxY += totalPadding;
18605
18656
  }
18606
- const topLeft = applyToPoint18(transform, { x: minX, y: maxY });
18607
- const topRight = applyToPoint18(transform, { x: maxX, y: maxY });
18608
- const bottomLeft = applyToPoint18(transform, { x: minX, y: minY });
18609
- const bottomRight = applyToPoint18(transform, { x: maxX, y: minY });
18657
+ const topLeft = applyToPoint19(transform, { x: minX, y: maxY });
18658
+ const topRight = applyToPoint19(transform, { x: maxX, y: maxY });
18659
+ const bottomLeft = applyToPoint19(transform, { x: minX, y: minY });
18660
+ const bottomRight = applyToPoint19(transform, { x: maxX, y: minY });
18610
18661
  const groupColor = GROUP_COLORS[groupIndex % GROUP_COLORS.length];
18611
18662
  ctx.strokeStyle = groupColor;
18612
18663
  ctx.lineWidth = 2;
@@ -18656,7 +18707,7 @@ var PcbGroupOverlay = ({
18656
18707
  x: group.anchor_position[0] ?? 0,
18657
18708
  y: group.anchor_position[1] ?? 0
18658
18709
  } : { x: group.anchor_position.x, y: group.anchor_position.y };
18659
- const anchorScreenPos = applyToPoint18(transform, anchorPositionValue);
18710
+ const anchorScreenPos = applyToPoint19(transform, anchorPositionValue);
18660
18711
  ctx.strokeStyle = "white";
18661
18712
  ctx.lineWidth = 1.5;
18662
18713
  ctx.setLineDash([]);
@@ -18710,7 +18761,7 @@ var PcbGroupOverlay = ({
18710
18761
  };
18711
18762
 
18712
18763
  // src/components/RatsNestOverlay.tsx
18713
- import { applyToPoint as applyToPoint19, identity as identity8 } from "transformation-matrix";
18764
+ import { applyToPoint as applyToPoint20, identity as identity8 } from "transformation-matrix";
18714
18765
  import { useMemo as useMemo10 } from "react";
18715
18766
  import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
18716
18767
  var RatsNestOverlay = ({
@@ -18793,8 +18844,8 @@ var RatsNestOverlay = ({
18793
18844
  zIndex: zIndexMap.ratsNestOverlay
18794
18845
  },
18795
18846
  children: ratsNestLines.map(({ key, startPoint, endPoint, isInNet }) => {
18796
- const transformedStart = applyToPoint19(transform, startPoint);
18797
- const transformedEnd = applyToPoint19(transform, endPoint);
18847
+ const transformedStart = applyToPoint20(transform, startPoint);
18848
+ const transformedEnd = applyToPoint20(transform, endPoint);
18798
18849
  return /* @__PURE__ */ jsx19(
18799
18850
  "line",
18800
18851
  {
@@ -18920,7 +18971,7 @@ import {
18920
18971
  // package.json
18921
18972
  var package_default = {
18922
18973
  name: "@tscircuit/pcb-viewer",
18923
- version: "1.11.433",
18974
+ version: "1.11.435",
18924
18975
  main: "dist/index.js",
18925
18976
  type: "module",
18926
18977
  repository: {
@@ -20736,7 +20787,7 @@ var getPcbWarningHighlightLabel = (warning) => {
20736
20787
 
20737
20788
  // src/components/WarningGraphicsOverlay.tsx
20738
20789
  import { useEffect as useEffect18, useMemo as useMemo13, useRef as useRef14 } from "react";
20739
- import { applyToPoint as applyToPoint20, identity as identity9 } from "transformation-matrix";
20790
+ import { applyToPoint as applyToPoint21, identity as identity9 } from "transformation-matrix";
20740
20791
  import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
20741
20792
  var WarningGraphicsOverlay = ({
20742
20793
  children,
@@ -20774,7 +20825,7 @@ var WarningGraphicsOverlay = ({
20774
20825
  const component = pcbComponentById.get(warning.pcb_component_id);
20775
20826
  if (!component) return;
20776
20827
  const { width: width2, height: height2, center } = component;
20777
- const transformedCenter = applyToPoint20(transform, center);
20828
+ const transformedCenter = applyToPoint21(transform, center);
20778
20829
  const scaledWidth = width2 * Math.abs(transform.a);
20779
20830
  const scaledHeight = height2 * Math.abs(transform.d);
20780
20831
  const boxPadding = 0.1 * Math.abs(transform.a);
@@ -20880,16 +20931,17 @@ function WebGpuElementsRenderer(props) {
20880
20931
  const showCourtyards = useGlobalStore((s) => s.is_showing_courtyards);
20881
20932
  const highlightedElementIds = useMemo14(
20882
20933
  () => [
20883
- ...new Set(
20884
- primitives.flatMap((p) => {
20934
+ .../* @__PURE__ */ new Set([
20935
+ ...props.highlightedCopperPourIds ?? [],
20936
+ ...primitives.flatMap((p) => {
20885
20937
  if (!p.is_mouse_over && !p.is_in_highlighted_net) return [];
20886
20938
  const element = p._element;
20887
20939
  const id = element?.[`${element.type}_id`];
20888
20940
  return id ? [id] : [];
20889
20941
  })
20890
- )
20942
+ ])
20891
20943
  ],
20892
- [primitives]
20944
+ [primitives, props.highlightedCopperPourIds]
20893
20945
  );
20894
20946
  const xRayElementIds = useMemo14(
20895
20947
  () => (props.xRayElements ?? []).map(
@@ -21109,7 +21161,7 @@ function getHitTestCandidates({
21109
21161
  transform
21110
21162
  }) {
21111
21163
  if (!transform) return null;
21112
- const realWorldPoint = applyToPoint21(inverse6(transform), screenPoint);
21164
+ const realWorldPoint = applyToPoint22(inverse6(transform), screenPoint);
21113
21165
  return {
21114
21166
  primitives: getPrimitivesNearPoint({
21115
21167
  point: realWorldPoint,
@@ -21213,7 +21265,7 @@ var CanvasElementsRenderer = (props) => {
21213
21265
  if (isShowingCopperPours && copperPourOpacity > 0) {
21214
21266
  for (const pour of getCopperPoursUnderPoint(
21215
21267
  elementsToRender,
21216
- applyToPoint21(inverse6(transform), point2),
21268
+ applyToPoint22(inverse6(transform), point2),
21217
21269
  selectedLayer
21218
21270
  ).reverse()) {
21219
21271
  const net = getElementNetId(pour, connectivityMap);
@@ -21247,6 +21299,14 @@ var CanvasElementsRenderer = (props) => {
21247
21299
  drawingObjectIdsWithMouseOver: /* @__PURE__ */ new Set(),
21248
21300
  primitiveIdsInMousedOverNet: []
21249
21301
  });
21302
+ const highlightedCopperPourIds = useMemo15(
21303
+ () => xRayNetIds.length > 0 ? [] : getHighlightedCopperPourIds(
21304
+ elementsToRender,
21305
+ hoverState.primitiveIdsInMousedOverNet,
21306
+ connectivityMap
21307
+ ),
21308
+ [elementsToRender, hoverState, connectivityMap, xRayNetIds]
21309
+ );
21250
21310
  const [hoveredComponentIds, setHoveredComponentIds] = useState13([]);
21251
21311
  const currentTransformRef = useRef16(transform ?? null);
21252
21312
  const zoomAnimationFrameRef = useRef16(null);
@@ -21445,6 +21505,7 @@ var CanvasElementsRenderer = (props) => {
21445
21505
  ) : /* @__PURE__ */ jsx26(
21446
21506
  WebGpuElementsRenderer,
21447
21507
  {
21508
+ highlightedCopperPourIds,
21448
21509
  transform,
21449
21510
  primitives,
21450
21511
  elements,
@@ -21503,7 +21564,7 @@ function useAnimationFrameTransformState(initialTransform) {
21503
21564
 
21504
21565
  // src/PCBViewer.tsx
21505
21566
  import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
21506
- var defaultTransform = compose10(translate14(400, 300), scale6(40, -40));
21567
+ var defaultTransform = compose11(translate15(400, 300), scale6(40, -40));
21507
21568
  var getPreferredRenderer = () => {
21508
21569
  const stored = getStoredString(STORAGE_KEYS.RENDERING_ENGINE, "webgpu");
21509
21570
  return stored === "canvas" || stored === "webgpu" ? stored : "webgpu";
@@ -21598,10 +21659,10 @@ var PCBViewer = ({
21598
21659
  (elmBounds.height ?? 0) / height2,
21599
21660
  100
21600
21661
  ) * 0.75;
21601
- const targetTransform = compose10(
21602
- translate14((elmBounds.width ?? 0) / 2, (elmBounds.height ?? 0) / 2),
21662
+ const targetTransform = compose11(
21663
+ translate15((elmBounds.width ?? 0) / 2, (elmBounds.height ?? 0) / 2),
21603
21664
  scale6(scaleFactor, -scaleFactor, 0, 0),
21604
- translate14(-center.x, -center.y)
21665
+ translate15(-center.x, -center.y)
21605
21666
  );
21606
21667
  setTransform(targetTransform);
21607
21668
  return;