@tscircuit/pcb-viewer 1.5.0 → 1.7.0

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
@@ -13390,7 +13390,7 @@ var import_soup2 = __toESM(require_dist());
13390
13390
  // package.json
13391
13391
  var package_default = {
13392
13392
  name: "@tscircuit/pcb-viewer",
13393
- version: "1.4.6",
13393
+ version: "1.6.0",
13394
13394
  main: "dist/index.js",
13395
13395
  repository: "tscircuit/pcb-viewer",
13396
13396
  license: "MIT",
@@ -14004,7 +14004,7 @@ var HotkeyActionMenu = function(param) {
14004
14004
  };
14005
14005
  // src/components/EditTraceHintOverlay.tsx
14006
14006
  var import_jsx_runtime10 = require("react/jsx-runtime");
14007
- var isInsideOf2 = function(elm, point) {
14007
+ var isInsideOfSmtpad = function(elm, point) {
14008
14008
  var padding = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : 0;
14009
14009
  if (elm.shape === "circle") {
14010
14010
  return false;
@@ -14017,6 +14017,21 @@ var isInsideOf2 = function(elm, point) {
14017
14017
  var bottom = elm.y + halfHeight + padding;
14018
14018
  return point.x > left && point.x < right && point.y > top && point.y < bottom;
14019
14019
  };
14020
+ var isInsideOfPlatedHole = function(hole, point) {
14021
+ var padding = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : 0;
14022
+ if (hole.shape === "circle") {
14023
+ var distance = Math.sqrt(Math.pow(point.x - hole.x, 2) + Math.pow(point.y - hole.y, 2));
14024
+ return distance <= hole.outer_diameter / 2 + padding;
14025
+ } else {
14026
+ var halfWidth = hole.hole_width / 2;
14027
+ var halfHeight = hole.hole_height / 2;
14028
+ var left = hole.x - halfWidth - padding;
14029
+ var right = hole.x + halfWidth + padding;
14030
+ var top = hole.y - halfHeight - padding;
14031
+ var bottom = hole.y + halfHeight + padding;
14032
+ return point.x > left && point.x < right && point.y > top && point.y < bottom;
14033
+ }
14034
+ };
14020
14035
  var EditTraceHintOverlay = function(param) {
14021
14036
  var children = param.children, disabledProp = param.disabled, transform = param.transform, soup = param.soup, cancelPanDrag = param.cancelPanDrag, onCreateEditEvent = param.onCreateEditEvent, onModifyEditEvent = param.onModifyEditEvent;
14022
14037
  var _containerRef_current;
@@ -14072,7 +14087,7 @@ var EditTraceHintOverlay = function(param) {
14072
14087
  try {
14073
14088
  for(var _iterator = soup[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
14074
14089
  var e2 = _step.value;
14075
- if (e2.type === "pcb_smtpad" && isInsideOf2(e2, rwMousePoint, 10 / transform.a)) {
14090
+ if (e2.type === "pcb_smtpad" && isInsideOfSmtpad(e2, rwMousePoint, 10 / transform.a) || e2.type === "pcb_plated_hole" && isInsideOfPlatedHole(e2, rwMousePoint, 10 / transform.a)) {
14076
14091
  setSelectedElement(e2);
14077
14092
  setShouldCreateAsVia(false);
14078
14093
  setDragState({
@@ -14243,48 +14258,57 @@ var EditTraceHintOverlay = function(param) {
14243
14258
  var route = e.route;
14244
14259
  var pcb_port = (0, import_soup_util2.su)(soup).pcb_port.get(e.pcb_port_id);
14245
14260
  var pcb_port_screen = (0, import_transformation_matrix6.applyToPoint)(transform, pcb_port);
14246
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react13.Fragment, {
14261
+ var strokeInput = [
14262
+ {
14263
+ x: pcb_port_screen.x,
14264
+ y: pcb_port_screen.y,
14265
+ trace_width: 0.5
14266
+ }
14267
+ ].concat(// Start with a small width
14268
+ _to_consumable_array(route.map(function(r) {
14269
+ if (r === void 0) {
14270
+ throw new Error("route contains undefined point");
14271
+ }
14272
+ return {
14273
+ x: (0, import_transformation_matrix6.applyToPoint)(transform, r).x,
14274
+ y: (0, import_transformation_matrix6.applyToPoint)(transform, r).y,
14275
+ trace_width: r.trace_width
14276
+ };
14277
+ })));
14278
+ var expandedStroke = getExpandedStroke(strokeInput, 0.5);
14279
+ var expandedPath = expandedStroke.map(function(point, index) {
14280
+ return "".concat(index === 0 ? "M" : "L", " ").concat(point.x, ",").concat(point.y);
14281
+ }).join(" ") + " Z";
14282
+ var originalPath = strokeInput.map(function(point, index) {
14283
+ return "".concat(index === 0 ? "M" : "L", " ").concat(point.x, ",").concat(point.y);
14284
+ }).join(" ");
14285
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("g", {
14247
14286
  children: [
14248
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("rect", {
14249
- x: pcb_port_screen.x - 10,
14250
- y: pcb_port_screen.y - 10,
14251
- width: 20,
14252
- height: 20,
14287
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", {
14288
+ d: expandedPath,
14289
+ fill: "red"
14290
+ }, "expanded-path-".concat(e.pcb_port_id)),
14291
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", {
14292
+ d: originalPath,
14293
+ style: {
14294
+ mixBlendMode: "difference"
14295
+ },
14253
14296
  stroke: "red"
14254
- }, "rect-".concat(e.pcb_port_id)),
14255
- route.map(function(r, index) {
14256
- var start = index === 0 ? pcb_port_screen : (0, import_transformation_matrix6.applyToPoint)(transform, route[index - 1]);
14257
- var end = (0, import_transformation_matrix6.applyToPoint)(transform, r);
14258
- var width = r === null || r === void 0 ? void 0 : r.trace_width;
14259
- var angle = Math.atan2(end.y - start.y, end.x - start.x);
14260
- var dx = width !== null && width !== void 0 ? width : 0.5 * Math.sin(angle);
14261
- var dy = width !== null && width !== void 0 ? width : 0.5 * -Math.cos(angle);
14262
- var topLeft = "".concat(start.x - dx, ",").concat(start.y - dy);
14263
- var topRight = "".concat(end.x - dx, ",").concat(end.y - dy);
14264
- var bottomRight = "".concat(end.x + dx, ",").concat(end.y + dy);
14265
- var bottomLeft = "".concat(start.x + dx, ",").concat(start.y + dy);
14266
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", {
14267
- fill: "red",
14268
- d: "M ".concat(topLeft, " L ").concat(topRight, " L ").concat(bottomRight, " L ").concat(bottomLeft, " Z")
14269
- }, "path-".concat(e.pcb_port_id, "-").concat(index));
14270
- }),
14271
- route.map(function(r) {
14272
- return _object_spread({}, r, (0, import_transformation_matrix6.applyToPoint)(transform, r));
14273
- }).map(function(r, i) {
14274
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react13.Fragment, {
14297
+ }, "original-path-".concat(e.pcb_port_id)),
14298
+ strokeInput.map(function(r, i) {
14299
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("g", {
14275
14300
  children: [
14276
14301
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("circle", {
14277
14302
  cx: r.x,
14278
14303
  cy: r.y,
14279
- r: 8,
14304
+ r: r.trace_width ? r.trace_width / 2 : 8,
14280
14305
  stroke: "red"
14281
14306
  }),
14282
14307
  r.via && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("circle", {
14283
14308
  cx: r.x,
14284
14309
  cy: r.y,
14285
- r: 16,
14286
- stroke: "red",
14287
- fill: "transparent"
14310
+ r: r.trace_width ? r.trace_width / 2 : 8,
14311
+ stroke: "red"
14288
14312
  })
14289
14313
  ]
14290
14314
  }, i);
@@ -14314,6 +14338,83 @@ var EditTraceHintOverlay = function(param) {
14314
14338
  ]
14315
14339
  });
14316
14340
  };
14341
+ function getExpandedStroke(strokeInput, defaultWidth) {
14342
+ if (strokeInput.length < 2) {
14343
+ throw new Error("Stroke must have at least two points");
14344
+ }
14345
+ var stroke = strokeInput.map(function(point) {
14346
+ if (Array.isArray(point)) {
14347
+ return {
14348
+ x: point[0],
14349
+ y: point[1]
14350
+ };
14351
+ }
14352
+ return point;
14353
+ });
14354
+ var leftSide = [];
14355
+ var rightSide = [];
14356
+ function getNormal(p1, p2) {
14357
+ var dx = p2.x - p1.x;
14358
+ var dy = p2.y - p1.y;
14359
+ var length = Math.sqrt(dx * dx + dy * dy);
14360
+ return {
14361
+ x: -dy / length,
14362
+ y: dx / length
14363
+ };
14364
+ }
14365
+ function addPoint(point, normal, factor, width) {
14366
+ var halfWidth = width / 2;
14367
+ var newPoint = {
14368
+ x: point.x + normal.x * halfWidth * factor,
14369
+ y: point.y + normal.y * halfWidth * factor
14370
+ };
14371
+ if (factor > 0) {
14372
+ leftSide.push(newPoint);
14373
+ } else {
14374
+ rightSide.unshift(newPoint);
14375
+ }
14376
+ }
14377
+ var firstNormal = getNormal(stroke[0], stroke[1]);
14378
+ var _stroke__trace_width;
14379
+ var firstWidth = (_stroke__trace_width = stroke[0].trace_width) !== null && _stroke__trace_width !== void 0 ? _stroke__trace_width : defaultWidth;
14380
+ addPoint(stroke[0], firstNormal, 1, firstWidth);
14381
+ addPoint(stroke[0], firstNormal, -1, firstWidth);
14382
+ for(var i = 1; i < stroke.length - 1; i++){
14383
+ var prev = stroke[i - 1];
14384
+ var current = stroke[i];
14385
+ var next = stroke[i + 1];
14386
+ var normalPrev = getNormal(prev, current);
14387
+ var normalNext = getNormal(current, next);
14388
+ var miterX = normalPrev.x + normalNext.x;
14389
+ var miterY = normalPrev.y + normalNext.y;
14390
+ var miterLength = Math.sqrt(miterX * miterX + miterY * miterY);
14391
+ var _current_trace_width;
14392
+ var currentWidth = (_current_trace_width = current.trace_width) !== null && _current_trace_width !== void 0 ? _current_trace_width : defaultWidth;
14393
+ var miterLimit = 2;
14394
+ if (miterLength / 2 > miterLimit * (currentWidth / 2)) {
14395
+ addPoint(current, normalPrev, 1, currentWidth);
14396
+ addPoint(current, normalNext, 1, currentWidth);
14397
+ addPoint(current, normalPrev, -1, currentWidth);
14398
+ addPoint(current, normalNext, -1, currentWidth);
14399
+ } else {
14400
+ var scale2 = 1 / miterLength;
14401
+ addPoint(current, {
14402
+ x: miterX * scale2,
14403
+ y: miterY * scale2
14404
+ }, 1, currentWidth);
14405
+ addPoint(current, {
14406
+ x: miterX * scale2,
14407
+ y: miterY * scale2
14408
+ }, -1, currentWidth);
14409
+ }
14410
+ }
14411
+ var lastNormal = getNormal(stroke[stroke.length - 2], stroke[stroke.length - 1]);
14412
+ var _stroke__trace_width1;
14413
+ var lastWidth = (_stroke__trace_width1 = stroke[stroke.length - 1].trace_width) !== null && _stroke__trace_width1 !== void 0 ? _stroke__trace_width1 : defaultWidth;
14414
+ addPoint(stroke[stroke.length - 1], lastNormal, 1, lastWidth);
14415
+ addPoint(stroke[stroke.length - 1], lastNormal, -1, lastWidth);
14416
+ return _to_consumable_array(leftSide).concat(_to_consumable_array(rightSide));
14417
+ }
14317
14418
  // src/components/RatsNestOverlay.tsx
14318
14419
  var import_transformation_matrix7 = require("transformation-matrix");
14319
14420
  var import_soup_util3 = __toESM(require_dist2());