@tscircuit/core 0.0.1067 → 0.0.1069

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +1135 -1134
  3. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -11020,6 +11020,35 @@ var NormalComponent3 = class extends PrimitiveComponent2 {
11020
11020
  }
11021
11021
  };
11022
11022
 
11023
+ // lib/components/normal-components/Board.ts
11024
+ import {
11025
+ runAllNetlistChecks,
11026
+ runAllPlacementChecks,
11027
+ runAllRoutingChecks
11028
+ } from "@tscircuit/checks";
11029
+ import { getBoundsFromPoints as getBoundsFromPoints4 } from "@tscircuit/math-utils";
11030
+ import { boardProps } from "@tscircuit/props";
11031
+ import { compose as compose7, translate as translate7 } from "transformation-matrix";
11032
+
11033
+ // lib/utils/autorouting/getAncestorSubcircuitIds.ts
11034
+ var getDescendantSubcircuitIds = (db, root_subcircuit_id) => {
11035
+ const groups = db.source_group.list();
11036
+ const result = [];
11037
+ const findDescendants = (parentId) => {
11038
+ const children = groups.filter(
11039
+ (group) => group.parent_subcircuit_id === parentId
11040
+ );
11041
+ for (const child of children) {
11042
+ if (child.subcircuit_id) {
11043
+ result.push(child.subcircuit_id);
11044
+ findDescendants(child.subcircuit_id);
11045
+ }
11046
+ }
11047
+ };
11048
+ findDescendants(root_subcircuit_id);
11049
+ return result;
11050
+ };
11051
+
11023
11052
  // lib/utils/boards/get-board-center-from-anchor.ts
11024
11053
  var getBoardCenterFromAnchor = ({
11025
11054
  boardAnchorPosition,
@@ -11070,311 +11099,817 @@ var getBoardCenterFromAnchor = ({
11070
11099
  return { x: cx, y: cy };
11071
11100
  };
11072
11101
 
11073
- // lib/components/normal-components/Board.ts
11074
- import { boardProps } from "@tscircuit/props";
11075
-
11076
- // lib/components/primitive-components/Group/Group.ts
11077
- import { convertSrjToGraphicsObject } from "@tscircuit/capacity-autorouter";
11078
- import { getBoundsFromPoints as getBoundsFromPoints3 } from "@tscircuit/math-utils";
11079
- import {
11080
- groupProps
11081
- } from "@tscircuit/props";
11082
- import {
11083
- distance as distance8
11084
- } from "circuit-json";
11085
- import Debug13 from "debug";
11086
-
11087
- // lib/utils/autorouting/CapacityMeshAutorouter.ts
11088
- import "@tscircuit/capacity-autorouter";
11089
-
11090
- // lib/solvers.ts
11091
- import { PackSolver2 } from "calculate-packing";
11092
- import {
11093
- AutoroutingPipelineSolver,
11094
- AssignableAutoroutingPipeline2,
11095
- AutoroutingPipeline1_OriginalUnravel,
11096
- AssignableAutoroutingPipeline3
11097
- } from "@tscircuit/capacity-autorouter";
11098
- import { CopperPourPipelineSolver } from "@tscircuit/copper-pour-solver";
11099
- var SOLVERS = {
11100
- PackSolver2,
11101
- AutoroutingPipelineSolver,
11102
- AssignableAutoroutingPipeline2,
11103
- AssignableAutoroutingPipeline3,
11104
- AutoroutingPipeline1_OriginalUnravel,
11105
- CopperPourPipelineSolver
11106
- };
11102
+ // lib/utils/circuit-json/inflate-circuit-json.ts
11103
+ import { cju } from "@tscircuit/circuit-json-util";
11107
11104
 
11108
- // lib/utils/autorouting/CapacityMeshAutorouter.ts
11109
- var TscircuitAutorouter = class {
11110
- input;
11111
- isRouting = false;
11112
- solver;
11113
- eventHandlers = {
11114
- complete: [],
11115
- error: [],
11116
- progress: []
11105
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflatePcbBoard.ts
11106
+ function inflatePcbBoard(pcbBoard, inflatorContext) {
11107
+ const { subcircuit } = inflatorContext;
11108
+ if (subcircuit.lowercaseComponentName === "board" || subcircuit.lowercaseComponentName === "mountedboard") {
11109
+ return;
11110
+ }
11111
+ if (subcircuit.parent?.lowercaseComponentName === "board") {
11112
+ return;
11113
+ }
11114
+ const boardProps2 = {
11115
+ name: "inflated_board"
11117
11116
  };
11118
- cycleCount = 0;
11119
- stepDelay;
11120
- timeoutId;
11121
- constructor(input, options = {}) {
11122
- this.input = input;
11123
- const {
11124
- capacityDepth,
11125
- targetMinCapacity,
11126
- stepDelay = 0,
11127
- useAssignableSolver = false,
11128
- useAutoJumperSolver = false,
11129
- autorouterVersion: autorouterVersion2,
11130
- effort,
11131
- onSolverStarted
11132
- } = options;
11133
- let solverName;
11134
- if (autorouterVersion2 === "v1") {
11135
- solverName = "AutoroutingPipeline1_OriginalUnravel";
11136
- } else if (useAutoJumperSolver) {
11137
- solverName = "AssignableAutoroutingPipeline3";
11138
- } else if (useAssignableSolver) {
11139
- solverName = "AssignableAutoroutingPipeline2";
11140
- } else {
11141
- solverName = "AutoroutingPipelineSolver";
11142
- }
11143
- const SolverClass = SOLVERS[solverName];
11144
- this.solver = new SolverClass(input, {
11145
- capacityDepth,
11146
- targetMinCapacity,
11147
- cacheProvider: null,
11148
- effort
11149
- });
11150
- onSolverStarted?.({
11151
- solverName,
11152
- solverParams: {
11153
- input,
11154
- options: {
11155
- capacityDepth,
11156
- targetMinCapacity,
11157
- cacheProvider: null,
11158
- effort
11159
- }
11160
- }
11161
- });
11162
- this.stepDelay = stepDelay;
11117
+ if (pcbBoard.width) boardProps2.width = pcbBoard.width;
11118
+ if (pcbBoard.height) boardProps2.height = pcbBoard.height;
11119
+ if (pcbBoard.center) {
11120
+ boardProps2.pcbX = pcbBoard.center.x;
11121
+ boardProps2.pcbY = pcbBoard.center.y;
11163
11122
  }
11164
- /**
11165
- * Start the autorouting process asynchronously
11166
- * This will emit progress events during routing and a complete event when done
11167
- */
11168
- start() {
11169
- if (this.isRouting) return;
11170
- this.isRouting = true;
11171
- this.cycleCount = 0;
11172
- this.runCycleAndQueueNextCycle();
11123
+ if (pcbBoard.outline) boardProps2.outline = pcbBoard.outline;
11124
+ if (pcbBoard.thickness) boardProps2.thickness = pcbBoard.thickness;
11125
+ if (pcbBoard.material) boardProps2.material = pcbBoard.material;
11126
+ const board = new Board(boardProps2);
11127
+ board.pcb_board_id = pcbBoard.pcb_board_id;
11128
+ subcircuit.add(board);
11129
+ return board;
11130
+ }
11131
+
11132
+ // lib/components/normal-components/Capacitor.ts
11133
+ import { capacitorProps } from "@tscircuit/props";
11134
+ import { formatSiUnit } from "format-si-unit";
11135
+ var Capacitor = class extends NormalComponent3 {
11136
+ _adjustSilkscreenTextAutomatically = true;
11137
+ get config() {
11138
+ return {
11139
+ componentName: "Capacitor",
11140
+ schematicSymbolName: this.props.polarized ? "capacitor_polarized" : this.props.symbolName ?? "capacitor",
11141
+ zodProps: capacitorProps,
11142
+ sourceFtype: FTYPE.simple_capacitor
11143
+ };
11173
11144
  }
11174
- /**
11175
- * Execute the next routing step and schedule the following one if needed
11176
- */
11177
- runCycleAndQueueNextCycle() {
11178
- if (!this.isRouting) return;
11179
- try {
11180
- if (this.solver.solved || this.solver.failed) {
11181
- if (this.solver.failed) {
11182
- this.emitEvent({
11183
- type: "error",
11184
- error: new AutorouterError(this.solver.error || "Routing failed")
11185
- });
11186
- } else {
11187
- this.emitEvent({
11188
- type: "complete",
11189
- traces: this.solver.getOutputSimpleRouteJson().traces || []
11190
- });
11145
+ initPorts() {
11146
+ if (typeof this.props.footprint === "string") {
11147
+ super.initPorts({
11148
+ additionalAliases: {
11149
+ pin1: ["anode", "pos"],
11150
+ pin2: ["cathode", "neg"]
11191
11151
  }
11192
- this.isRouting = false;
11193
- return;
11194
- }
11195
- const startTime = Date.now();
11196
- const startIterations = this.solver.iterations;
11197
- while (Date.now() - startTime < 250 && !this.solver.failed && !this.solver.solved) {
11198
- this.solver.step();
11199
- }
11200
- const iterationsPerSecond = (this.solver.iterations - startIterations) / (Date.now() - startTime) * 1e3;
11201
- this.cycleCount++;
11202
- const debugGraphics = this.solver?.preview() || void 0;
11203
- const progress = this.solver.progress;
11204
- this.emitEvent({
11205
- type: "progress",
11206
- steps: this.cycleCount,
11207
- iterationsPerSecond,
11208
- progress,
11209
- phase: this.solver.getCurrentPhase(),
11210
- debugGraphics
11211
- });
11212
- if (this.stepDelay > 0) {
11213
- this.timeoutId = setTimeout(
11214
- () => this.runCycleAndQueueNextCycle(),
11215
- this.stepDelay
11216
- );
11217
- } else {
11218
- this.timeoutId = setTimeout(
11219
- () => this.runCycleAndQueueNextCycle(),
11220
- 0
11221
- );
11222
- }
11223
- } catch (error) {
11224
- this.emitEvent({
11225
- type: "error",
11226
- error: error instanceof Error ? new AutorouterError(error.message) : new AutorouterError(String(error))
11227
11152
  });
11228
- this.isRouting = false;
11153
+ } else {
11154
+ super.initPorts();
11229
11155
  }
11230
11156
  }
11231
- /**
11232
- * Stop the routing process if it's in progress
11233
- */
11234
- stop() {
11235
- if (!this.isRouting) return;
11236
- this.isRouting = false;
11237
- if (this.timeoutId !== void 0) {
11238
- clearTimeout(this.timeoutId);
11239
- this.timeoutId = void 0;
11157
+ _getSchematicSymbolDisplayValue() {
11158
+ const inputCapacitance = this.props.capacitance;
11159
+ const capacitanceDisplay = typeof inputCapacitance === "string" ? inputCapacitance : `${formatSiUnit(this._parsedProps.capacitance)}F`;
11160
+ if (this._parsedProps.schShowRatings && this._parsedProps.maxVoltageRating) {
11161
+ return `${capacitanceDisplay}/${formatSiUnit(this._parsedProps.maxVoltageRating)}V`;
11240
11162
  }
11163
+ return capacitanceDisplay;
11241
11164
  }
11242
- on(event, callback) {
11243
- if (event === "complete") {
11244
- this.eventHandlers.complete.push(
11245
- callback
11165
+ doInitialCreateNetsFromProps() {
11166
+ this._createNetsFromProps([
11167
+ this.props.decouplingFor,
11168
+ this.props.decouplingTo,
11169
+ ...this._getNetsFromConnectionsProp()
11170
+ ]);
11171
+ }
11172
+ doInitialCreateTracesFromProps() {
11173
+ if (this.props.decouplingFor && this.props.decouplingTo) {
11174
+ this.add(
11175
+ new Trace3({
11176
+ from: `${this.getSubcircuitSelector()} > port.1`,
11177
+ to: this.props.decouplingFor
11178
+ })
11246
11179
  );
11247
- } else if (event === "error") {
11248
- this.eventHandlers.error.push(
11249
- callback
11250
- );
11251
- } else if (event === "progress") {
11252
- this.eventHandlers.progress.push(
11253
- callback
11180
+ this.add(
11181
+ new Trace3({
11182
+ from: `${this.getSubcircuitSelector()} > port.2`,
11183
+ to: this.props.decouplingTo
11184
+ })
11254
11185
  );
11255
11186
  }
11187
+ this._createTracesFromConnectionsProp();
11256
11188
  }
11257
- /**
11258
- * Emit an event to all registered handlers
11259
- */
11260
- emitEvent(event) {
11261
- if (event.type === "complete") {
11262
- for (const handler of this.eventHandlers.complete) {
11263
- handler(event);
11264
- }
11265
- } else if (event.type === "error") {
11266
- for (const handler of this.eventHandlers.error) {
11267
- handler(event);
11268
- }
11269
- } else if (event.type === "progress") {
11270
- for (const handler of this.eventHandlers.progress) {
11271
- handler(event);
11272
- }
11273
- }
11274
- }
11275
- /**
11276
- * Solve the routing problem synchronously
11277
- * @returns Array of routed traces
11278
- */
11279
- solveSync() {
11280
- this.solver.solve();
11281
- if (this.solver.failed) {
11282
- throw new AutorouterError(this.solver.error || "Routing failed");
11283
- }
11284
- return this.solver.getOutputSimpleRouteJson().traces || [];
11285
- }
11286
- /**
11287
- * Get the mapping of obstacle IDs to root connection names that were
11288
- * connected via off-board paths (e.g., interconnects).
11289
- * Only available when using AssignableAutoroutingPipeline2.
11290
- */
11291
- getConnectedOffboardObstacles() {
11292
- if ("getConnectedOffboardObstacles" in this.solver) {
11293
- return this.solver.getConnectedOffboardObstacles();
11294
- }
11295
- return {};
11189
+ doInitialSourceRender() {
11190
+ const { db } = this.root;
11191
+ const { _parsedProps: props } = this;
11192
+ const source_component = db.source_component.insert({
11193
+ ftype: "simple_capacitor",
11194
+ name: this.name,
11195
+ manufacturer_part_number: props.manufacturerPartNumber ?? props.mfn,
11196
+ supplier_part_numbers: props.supplierPartNumbers,
11197
+ capacitance: props.capacitance,
11198
+ max_voltage_rating: props.maxVoltageRating,
11199
+ max_decoupling_trace_length: props.maxDecouplingTraceLength,
11200
+ display_capacitance: this._getSchematicSymbolDisplayValue(),
11201
+ are_pins_interchangeable: !props.polarized,
11202
+ display_name: props.displayName
11203
+ });
11204
+ this.source_component_id = source_component.source_component_id;
11296
11205
  }
11297
11206
  };
11298
11207
 
11299
- // lib/utils/autorouting/createSourceTracesFromOffboardConnections.ts
11300
- var createSourceTracesFromOffboardConnections = ({
11208
+ // lib/utils/extractPcbPrimitivesFromCircuitJson.ts
11209
+ import { transformPCBElements } from "@tscircuit/circuit-json-util";
11210
+ import { compose as compose5, inverse, rotate as rotate2, translate as translate4 } from "transformation-matrix";
11211
+ var extractPcbPrimitivesFromCircuitJson = ({
11212
+ pcbComponent,
11301
11213
  db,
11302
- connectedOffboardObstacles,
11303
- simpleRouteJson,
11304
- subcircuit_id
11214
+ componentName
11305
11215
  }) => {
11306
- if (Object.keys(connectedOffboardObstacles).length === 0) return;
11307
- const pcbElementIdToSourcePortId = /* @__PURE__ */ new Map();
11308
- for (const pcbPort of db.pcb_port.list()) {
11309
- if (pcbPort.source_port_id) {
11310
- const smtpad = db.pcb_smtpad.getWhere({
11311
- pcb_port_id: pcbPort.pcb_port_id
11312
- });
11313
- if (smtpad) {
11314
- pcbElementIdToSourcePortId.set(
11315
- smtpad.pcb_smtpad_id,
11316
- pcbPort.source_port_id
11317
- );
11318
- }
11319
- const platedHole = db.pcb_plated_hole.getWhere({
11320
- pcb_port_id: pcbPort.pcb_port_id
11321
- });
11322
- if (platedHole) {
11323
- pcbElementIdToSourcePortId.set(
11324
- platedHole.pcb_plated_hole_id,
11325
- pcbPort.source_port_id
11326
- );
11327
- }
11216
+ const componentCenter = pcbComponent.center || { x: 0, y: 0 };
11217
+ const componentRotation = pcbComponent.rotation || 0;
11218
+ const absoluteToComponentRelativeTransform = inverse(
11219
+ compose5(
11220
+ translate4(componentCenter.x, componentCenter.y),
11221
+ rotate2(componentRotation * Math.PI / 180)
11222
+ )
11223
+ );
11224
+ const relativeElements = db.toArray().filter(
11225
+ (elm) => "pcb_component_id" in elm && elm.pcb_component_id === pcbComponent.pcb_component_id
11226
+ );
11227
+ const clonedRelativeElements = structuredClone(relativeElements);
11228
+ transformPCBElements(
11229
+ clonedRelativeElements,
11230
+ absoluteToComponentRelativeTransform
11231
+ );
11232
+ const components = createComponentsFromCircuitJson(
11233
+ {
11234
+ componentName,
11235
+ componentRotation: "0deg"
11236
+ },
11237
+ clonedRelativeElements
11238
+ );
11239
+ return components;
11240
+ };
11241
+
11242
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflateFootprintComponent.ts
11243
+ var inflateFootprintComponent = (pcbElm, inflatorContext) => {
11244
+ const { injectionDb, normalComponent } = inflatorContext;
11245
+ if (!normalComponent) return null;
11246
+ const primitives = extractPcbPrimitivesFromCircuitJson({
11247
+ pcbComponent: pcbElm,
11248
+ db: injectionDb,
11249
+ componentName: normalComponent.name
11250
+ });
11251
+ if (primitives.length === 0) return null;
11252
+ const footprint = new Footprint({});
11253
+ footprint.addAll(primitives);
11254
+ return footprint;
11255
+ };
11256
+
11257
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceCapacitor.ts
11258
+ function inflateSourceCapacitor(sourceElm, inflatorContext) {
11259
+ const { injectionDb, subcircuit, groupsMap } = inflatorContext;
11260
+ const pcbElm = injectionDb.pcb_component.getWhere({
11261
+ source_component_id: sourceElm.source_component_id
11262
+ });
11263
+ const cadElm = injectionDb.cad_component.getWhere({
11264
+ source_component_id: sourceElm.source_component_id
11265
+ });
11266
+ const capacitor = new Capacitor({
11267
+ name: sourceElm.name,
11268
+ capacitance: sourceElm.capacitance,
11269
+ layer: pcbElm?.layer,
11270
+ pcbX: pcbElm?.center?.x,
11271
+ pcbY: pcbElm?.center?.y,
11272
+ pcbRotation: pcbElm?.rotation,
11273
+ doNotPlace: pcbElm?.do_not_place,
11274
+ obstructsWithinBounds: pcbElm?.obstructs_within_bounds
11275
+ });
11276
+ if (pcbElm) {
11277
+ const footprint = inflateFootprintComponent(pcbElm, {
11278
+ ...inflatorContext,
11279
+ normalComponent: capacitor
11280
+ });
11281
+ if (footprint) {
11282
+ capacitor.add(footprint);
11328
11283
  }
11329
11284
  }
11330
- const obstacleById = /* @__PURE__ */ new Map();
11331
- for (const obstacle of simpleRouteJson.obstacles) {
11332
- if (obstacle.obstacleId) {
11333
- obstacleById.set(obstacle.obstacleId, obstacle);
11334
- }
11285
+ if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
11286
+ const group = groupsMap.get(sourceElm.source_group_id);
11287
+ group.add(capacitor);
11288
+ } else {
11289
+ subcircuit.add(capacitor);
11335
11290
  }
11336
- const connectionGroups = /* @__PURE__ */ new Map();
11337
- for (const [obstacleId, rootConnectionName] of Object.entries(
11338
- connectedOffboardObstacles
11339
- )) {
11340
- if (!connectionGroups.has(rootConnectionName)) {
11341
- connectionGroups.set(rootConnectionName, []);
11342
- }
11343
- connectionGroups.get(rootConnectionName).push(obstacleId);
11291
+ }
11292
+
11293
+ // lib/components/normal-components/Chip.ts
11294
+ import { chipProps as chipProps2 } from "@tscircuit/props";
11295
+ import { pcb_component_invalid_layer_error as pcb_component_invalid_layer_error2 } from "circuit-json";
11296
+ var Chip = class extends NormalComponent3 {
11297
+ schematicBoxDimensions = null;
11298
+ constructor(props) {
11299
+ super(props);
11344
11300
  }
11345
- for (const [rootConnectionName, obstacleIds] of connectionGroups) {
11346
- const sourcePortIds = /* @__PURE__ */ new Set();
11347
- for (const obstacleId of obstacleIds) {
11348
- const obstacle = obstacleById.get(obstacleId);
11349
- if (!obstacle) continue;
11350
- for (const connectedId of obstacle.connectedTo) {
11351
- const sourcePortId = pcbElementIdToSourcePortId.get(connectedId);
11352
- if (sourcePortId) {
11353
- sourcePortIds.add(sourcePortId);
11301
+ get config() {
11302
+ return {
11303
+ componentName: "Chip",
11304
+ zodProps: chipProps2,
11305
+ shouldRenderAsSchematicBox: true
11306
+ };
11307
+ }
11308
+ initPorts(opts = {}) {
11309
+ super.initPorts(opts);
11310
+ const { _parsedProps: props } = this;
11311
+ if (props.externallyConnectedPins) {
11312
+ const requiredPorts = /* @__PURE__ */ new Set();
11313
+ for (const [pin1, pin2] of props.externallyConnectedPins) {
11314
+ requiredPorts.add(pin1);
11315
+ requiredPorts.add(pin2);
11316
+ }
11317
+ for (const pinIdentifier of requiredPorts) {
11318
+ const existingPort = this.children.find(
11319
+ (child) => child instanceof Port && child.isMatchingAnyOf([pinIdentifier])
11320
+ );
11321
+ if (!existingPort) {
11322
+ const pinMatch = pinIdentifier.match(/^pin(\d+)$/);
11323
+ if (pinMatch) {
11324
+ const pinNumber = parseInt(pinMatch[1]);
11325
+ this.add(
11326
+ new Port({
11327
+ pinNumber,
11328
+ aliases: [pinIdentifier]
11329
+ })
11330
+ );
11331
+ } else {
11332
+ this.add(
11333
+ new Port({
11334
+ name: pinIdentifier,
11335
+ aliases: [pinIdentifier]
11336
+ })
11337
+ );
11338
+ }
11354
11339
  }
11355
11340
  }
11356
11341
  }
11357
- if (sourcePortIds.size < 2) continue;
11358
- const sourcePortIdArray = Array.from(sourcePortIds);
11359
- const existingTraces = db.source_trace.list();
11360
- const alreadyConnected = existingTraces.some((trace) => {
11361
- const tracePortIds = new Set(trace.connected_source_port_ids);
11362
- return sourcePortIdArray.every((id) => tracePortIds.has(id));
11363
- });
11364
- if (alreadyConnected) continue;
11365
- db.source_trace.insert({
11366
- connected_source_port_ids: sourcePortIdArray,
11367
- connected_source_net_ids: [],
11368
- subcircuit_id: subcircuit_id ?? void 0,
11369
- display_name: `offboard_${rootConnectionName}`
11370
- });
11371
11342
  }
11372
- };
11373
-
11374
- // lib/utils/autorouting/getPresetAutoroutingConfig.ts
11375
- function getPresetAutoroutingConfig(autorouterConfig) {
11376
- const defaults = {
11377
- serverUrl: "https://registry-api.tscircuit.com",
11343
+ doInitialSchematicComponentRender() {
11344
+ const { _parsedProps: props } = this;
11345
+ if (props?.noSchematicRepresentation === true) return;
11346
+ super.doInitialSchematicComponentRender();
11347
+ }
11348
+ doInitialSourceRender() {
11349
+ const { db } = this.root;
11350
+ const { _parsedProps: props } = this;
11351
+ const source_component = db.source_component.insert({
11352
+ ftype: "simple_chip",
11353
+ name: this.name,
11354
+ manufacturer_part_number: props.manufacturerPartNumber,
11355
+ supplier_part_numbers: props.supplierPartNumbers,
11356
+ display_name: props.displayName
11357
+ });
11358
+ this.source_component_id = source_component.source_component_id;
11359
+ }
11360
+ doInitialPcbComponentRender() {
11361
+ if (this.root?.pcbDisabled) return;
11362
+ const { db } = this.root;
11363
+ const { _parsedProps: props } = this;
11364
+ const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
11365
+ const componentLayer = props.layer ?? "top";
11366
+ if (componentLayer !== "top" && componentLayer !== "bottom") {
11367
+ const subcircuit = this.getSubcircuit();
11368
+ const error = pcb_component_invalid_layer_error2.parse({
11369
+ type: "pcb_component_invalid_layer_error",
11370
+ message: `Component cannot be placed on layer '${componentLayer}'. Components can only be placed on 'top' or 'bottom' layers.`,
11371
+ source_component_id: this.source_component_id,
11372
+ layer: componentLayer,
11373
+ subcircuit_id: subcircuit.subcircuit_id ?? void 0
11374
+ });
11375
+ db.pcb_component_invalid_layer_error.insert(error);
11376
+ }
11377
+ const pcb_component = db.pcb_component.insert({
11378
+ center: { x: pcbX, y: pcbY },
11379
+ width: 2,
11380
+ // Default width, adjust as needed
11381
+ height: 3,
11382
+ // Default height, adjust as needed
11383
+ layer: componentLayer === "top" || componentLayer === "bottom" ? componentLayer : "top",
11384
+ rotation: props.pcbRotation ?? 0,
11385
+ source_component_id: this.source_component_id,
11386
+ subcircuit_id: this.getSubcircuit().subcircuit_id ?? void 0,
11387
+ do_not_place: props.doNotPlace ?? false,
11388
+ obstructs_within_bounds: props.obstructsWithinBounds ?? true,
11389
+ is_allowed_to_be_off_board: props.allowOffBoard ?? false,
11390
+ metadata: props.kicadFootprintMetadata ? { kicad_footprint: props.kicadFootprintMetadata } : void 0
11391
+ });
11392
+ this.pcb_component_id = pcb_component.pcb_component_id;
11393
+ }
11394
+ doInitialCreateTracesFromProps() {
11395
+ const { _parsedProps: props } = this;
11396
+ if (props.externallyConnectedPins) {
11397
+ for (const [pin1, pin2] of props.externallyConnectedPins) {
11398
+ this.add(
11399
+ new Trace3({
11400
+ from: `${this.getSubcircuitSelector()} > port.${pin1}`,
11401
+ to: `${this.getSubcircuitSelector()} > port.${pin2}`
11402
+ })
11403
+ );
11404
+ }
11405
+ }
11406
+ this._createTracesFromConnectionsProp();
11407
+ }
11408
+ doInitialSimulationRender() {
11409
+ const { db } = this.root;
11410
+ const { pinAttributes } = this.props;
11411
+ if (!pinAttributes) return;
11412
+ let powerPort = null;
11413
+ let groundPort = null;
11414
+ let voltage;
11415
+ const ports = this.selectAll("port");
11416
+ for (const port of ports) {
11417
+ for (const alias of port.getNameAndAliases()) {
11418
+ if (pinAttributes[alias]) {
11419
+ const attributes = pinAttributes[alias];
11420
+ if (attributes.providesPower) {
11421
+ powerPort = port;
11422
+ voltage = attributes.providesVoltage;
11423
+ }
11424
+ if (attributes.providesGround) {
11425
+ groundPort = port;
11426
+ }
11427
+ }
11428
+ }
11429
+ }
11430
+ if (!powerPort || !groundPort || voltage === void 0) {
11431
+ return;
11432
+ }
11433
+ const powerSourcePort = db.source_port.get(powerPort.source_port_id);
11434
+ if (!powerSourcePort?.subcircuit_connectivity_map_key) return;
11435
+ const groundSourcePort = db.source_port.get(groundPort.source_port_id);
11436
+ if (!groundSourcePort?.subcircuit_connectivity_map_key) return;
11437
+ const powerNet = db.source_net.getWhere({
11438
+ subcircuit_connectivity_map_key: powerSourcePort.subcircuit_connectivity_map_key
11439
+ });
11440
+ const groundNet = db.source_net.getWhere({
11441
+ subcircuit_connectivity_map_key: groundSourcePort.subcircuit_connectivity_map_key
11442
+ });
11443
+ if (!powerNet || !groundNet) {
11444
+ return;
11445
+ }
11446
+ ;
11447
+ db.simulation_voltage_source.insert({
11448
+ type: "simulation_voltage_source",
11449
+ positive_source_port_id: powerPort.source_port_id,
11450
+ positive_source_net_id: powerNet.source_net_id,
11451
+ negative_source_port_id: groundPort.source_port_id,
11452
+ negative_source_net_id: groundNet.source_net_id,
11453
+ voltage
11454
+ });
11455
+ }
11456
+ };
11457
+
11458
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceChip.ts
11459
+ var mapInternallyConnectedSourcePortIdsToPinLabels = (sourcePortIds, inflatorContext) => {
11460
+ if (!sourcePortIds || sourcePortIds.length === 0) return void 0;
11461
+ const { injectionDb } = inflatorContext;
11462
+ const mapped = sourcePortIds.map(
11463
+ (group) => group.map((sourcePortId) => {
11464
+ const port = injectionDb.source_port.get(
11465
+ sourcePortId
11466
+ );
11467
+ if (!port) return null;
11468
+ if (port.pin_number !== void 0 && port.pin_number !== null) {
11469
+ return `pin${port.pin_number}`;
11470
+ }
11471
+ return port.name;
11472
+ }).filter((value) => value !== null)
11473
+ ).filter((group) => group.length > 0);
11474
+ return mapped.length > 0 ? mapped : void 0;
11475
+ };
11476
+ var inflateSourceChip = (sourceElm, inflatorContext) => {
11477
+ const { injectionDb, subcircuit, groupsMap } = inflatorContext;
11478
+ const pcbElm = injectionDb.pcb_component.getWhere({
11479
+ source_component_id: sourceElm.source_component_id
11480
+ });
11481
+ const schematicElm = injectionDb.schematic_component.getWhere({
11482
+ source_component_id: sourceElm.source_component_id
11483
+ });
11484
+ const cadElm = injectionDb.cad_component.getWhere({
11485
+ source_component_id: sourceElm.source_component_id
11486
+ });
11487
+ const internallyConnectedPins = mapInternallyConnectedSourcePortIdsToPinLabels(
11488
+ sourceElm.internally_connected_source_port_ids,
11489
+ inflatorContext
11490
+ );
11491
+ const footprinterString = cadElm?.footprinter_string ?? null;
11492
+ const chip = new Chip({
11493
+ name: sourceElm.name,
11494
+ manufacturerPartNumber: sourceElm.manufacturer_part_number,
11495
+ supplierPartNumbers: sourceElm.supplier_part_numbers ?? void 0,
11496
+ pinLabels: schematicElm?.port_labels ?? void 0,
11497
+ schWidth: schematicElm?.size?.width,
11498
+ schHeight: schematicElm?.size?.height,
11499
+ schPinSpacing: schematicElm?.pin_spacing,
11500
+ schX: schematicElm?.center?.x,
11501
+ schY: schematicElm?.center?.y,
11502
+ layer: pcbElm?.layer,
11503
+ pcbX: pcbElm?.center?.x,
11504
+ pcbY: pcbElm?.center?.y,
11505
+ pcbRotation: pcbElm?.rotation,
11506
+ doNotPlace: pcbElm?.do_not_place,
11507
+ obstructsWithinBounds: pcbElm?.obstructs_within_bounds,
11508
+ internallyConnectedPins
11509
+ });
11510
+ if (footprinterString) {
11511
+ Object.assign(chip.props, { footprint: footprinterString });
11512
+ Object.assign(chip._parsedProps, { footprint: footprinterString });
11513
+ }
11514
+ if (pcbElm) {
11515
+ const footprint = inflateFootprintComponent(pcbElm, {
11516
+ ...inflatorContext,
11517
+ normalComponent: chip
11518
+ });
11519
+ if (footprint) {
11520
+ chip.add(footprint);
11521
+ }
11522
+ }
11523
+ if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
11524
+ const group = groupsMap.get(sourceElm.source_group_id);
11525
+ group.add(chip);
11526
+ } else {
11527
+ subcircuit.add(chip);
11528
+ }
11529
+ };
11530
+
11531
+ // lib/components/normal-components/Diode.ts
11532
+ import { diodeProps } from "@tscircuit/props";
11533
+ var Diode = class extends NormalComponent3 {
11534
+ get config() {
11535
+ const symbolMap = {
11536
+ schottky: "schottky_diode",
11537
+ avalanche: "avalanche_diode",
11538
+ zener: "zener_diode",
11539
+ photodiode: "photodiode"
11540
+ };
11541
+ const variantSymbol = this.props.schottky ? "schottky" : this.props.avalanche ? "avalanche" : this.props.zener ? "zener" : this.props.photo ? "photodiode" : null;
11542
+ return {
11543
+ schematicSymbolName: variantSymbol ? symbolMap[variantSymbol] : this.props.symbolName ?? "diode",
11544
+ componentName: "Diode",
11545
+ zodProps: diodeProps,
11546
+ sourceFtype: "simple_diode"
11547
+ };
11548
+ }
11549
+ initPorts() {
11550
+ super.initPorts({
11551
+ additionalAliases: {
11552
+ pin1: ["anode", "pos", "left"],
11553
+ pin2: ["cathode", "neg", "right"]
11554
+ }
11555
+ });
11556
+ }
11557
+ doInitialSourceRender() {
11558
+ const { db } = this.root;
11559
+ const { _parsedProps: props } = this;
11560
+ const source_component = db.source_component.insert({
11561
+ ftype: "simple_diode",
11562
+ name: this.name,
11563
+ manufacturer_part_number: props.manufacturerPartNumber ?? props.mfn,
11564
+ supplier_part_numbers: props.supplierPartNumbers,
11565
+ are_pins_interchangeable: false,
11566
+ display_name: props.displayName
11567
+ });
11568
+ this.source_component_id = source_component.source_component_id;
11569
+ }
11570
+ pos = this.portMap.pin1;
11571
+ anode = this.portMap.pin1;
11572
+ neg = this.portMap.pin2;
11573
+ cathode = this.portMap.pin2;
11574
+ };
11575
+
11576
+ // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceDiode.ts
11577
+ function inflateSourceDiode(sourceElm, inflatorContext) {
11578
+ const { injectionDb, subcircuit, groupsMap } = inflatorContext;
11579
+ const pcbElm = injectionDb.pcb_component.getWhere({
11580
+ source_component_id: sourceElm.source_component_id
11581
+ });
11582
+ const cadElm = injectionDb.cad_component.getWhere({
11583
+ source_component_id: sourceElm.source_component_id
11584
+ });
11585
+ const diode = new Diode({
11586
+ name: sourceElm.name,
11587
+ layer: pcbElm?.layer,
11588
+ pcbX: pcbElm?.center?.x,
11589
+ pcbY: pcbElm?.center?.y,
11590
+ pcbRotation: pcbElm?.rotation,
11591
+ doNotPlace: pcbElm?.do_not_place,
11592
+ obstructsWithinBounds: pcbElm?.obstructs_within_bounds
11593
+ });
11594
+ if (pcbElm) {
11595
+ const footprint = inflateFootprintComponent(pcbElm, {
11596
+ ...inflatorContext,
11597
+ normalComponent: diode
11598
+ });
11599
+ if (footprint) {
11600
+ diode.add(footprint);
11601
+ }
11602
+ }
11603
+ if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
11604
+ const group = groupsMap.get(sourceElm.source_group_id);
11605
+ group.add(diode);
11606
+ } else {
11607
+ subcircuit.add(diode);
11608
+ }
11609
+ }
11610
+
11611
+ // lib/components/primitive-components/Group/Group.ts
11612
+ import { convertSrjToGraphicsObject } from "@tscircuit/capacity-autorouter";
11613
+ import { getBoundsFromPoints as getBoundsFromPoints3 } from "@tscircuit/math-utils";
11614
+ import {
11615
+ groupProps
11616
+ } from "@tscircuit/props";
11617
+ import {
11618
+ distance as distance8
11619
+ } from "circuit-json";
11620
+ import Debug13 from "debug";
11621
+
11622
+ // lib/utils/autorouting/CapacityMeshAutorouter.ts
11623
+ import "@tscircuit/capacity-autorouter";
11624
+
11625
+ // lib/solvers.ts
11626
+ import { PackSolver2 } from "calculate-packing";
11627
+ import {
11628
+ AutoroutingPipelineSolver,
11629
+ AssignableAutoroutingPipeline2,
11630
+ AutoroutingPipeline1_OriginalUnravel,
11631
+ AssignableAutoroutingPipeline3
11632
+ } from "@tscircuit/capacity-autorouter";
11633
+ import { CopperPourPipelineSolver } from "@tscircuit/copper-pour-solver";
11634
+ var SOLVERS = {
11635
+ PackSolver2,
11636
+ AutoroutingPipelineSolver,
11637
+ AssignableAutoroutingPipeline2,
11638
+ AssignableAutoroutingPipeline3,
11639
+ AutoroutingPipeline1_OriginalUnravel,
11640
+ CopperPourPipelineSolver
11641
+ };
11642
+
11643
+ // lib/utils/autorouting/CapacityMeshAutorouter.ts
11644
+ var TscircuitAutorouter = class {
11645
+ input;
11646
+ isRouting = false;
11647
+ solver;
11648
+ eventHandlers = {
11649
+ complete: [],
11650
+ error: [],
11651
+ progress: []
11652
+ };
11653
+ cycleCount = 0;
11654
+ stepDelay;
11655
+ timeoutId;
11656
+ constructor(input, options = {}) {
11657
+ this.input = input;
11658
+ const {
11659
+ capacityDepth,
11660
+ targetMinCapacity,
11661
+ stepDelay = 0,
11662
+ useAssignableSolver = false,
11663
+ useAutoJumperSolver = false,
11664
+ autorouterVersion: autorouterVersion2,
11665
+ effort,
11666
+ onSolverStarted
11667
+ } = options;
11668
+ let solverName;
11669
+ if (autorouterVersion2 === "v1") {
11670
+ solverName = "AutoroutingPipeline1_OriginalUnravel";
11671
+ } else if (useAutoJumperSolver) {
11672
+ solverName = "AssignableAutoroutingPipeline3";
11673
+ } else if (useAssignableSolver) {
11674
+ solverName = "AssignableAutoroutingPipeline2";
11675
+ } else {
11676
+ solverName = "AutoroutingPipelineSolver";
11677
+ }
11678
+ const SolverClass = SOLVERS[solverName];
11679
+ this.solver = new SolverClass(input, {
11680
+ capacityDepth,
11681
+ targetMinCapacity,
11682
+ cacheProvider: null,
11683
+ effort
11684
+ });
11685
+ onSolverStarted?.({
11686
+ solverName,
11687
+ solverParams: {
11688
+ input,
11689
+ options: {
11690
+ capacityDepth,
11691
+ targetMinCapacity,
11692
+ cacheProvider: null,
11693
+ effort
11694
+ }
11695
+ }
11696
+ });
11697
+ this.stepDelay = stepDelay;
11698
+ }
11699
+ /**
11700
+ * Start the autorouting process asynchronously
11701
+ * This will emit progress events during routing and a complete event when done
11702
+ */
11703
+ start() {
11704
+ if (this.isRouting) return;
11705
+ this.isRouting = true;
11706
+ this.cycleCount = 0;
11707
+ this.runCycleAndQueueNextCycle();
11708
+ }
11709
+ /**
11710
+ * Execute the next routing step and schedule the following one if needed
11711
+ */
11712
+ runCycleAndQueueNextCycle() {
11713
+ if (!this.isRouting) return;
11714
+ try {
11715
+ if (this.solver.solved || this.solver.failed) {
11716
+ if (this.solver.failed) {
11717
+ this.emitEvent({
11718
+ type: "error",
11719
+ error: new AutorouterError(this.solver.error || "Routing failed")
11720
+ });
11721
+ } else {
11722
+ this.emitEvent({
11723
+ type: "complete",
11724
+ traces: this.solver.getOutputSimpleRouteJson().traces || []
11725
+ });
11726
+ }
11727
+ this.isRouting = false;
11728
+ return;
11729
+ }
11730
+ const startTime = Date.now();
11731
+ const startIterations = this.solver.iterations;
11732
+ while (Date.now() - startTime < 250 && !this.solver.failed && !this.solver.solved) {
11733
+ this.solver.step();
11734
+ }
11735
+ const iterationsPerSecond = (this.solver.iterations - startIterations) / (Date.now() - startTime) * 1e3;
11736
+ this.cycleCount++;
11737
+ const debugGraphics = this.solver?.preview() || void 0;
11738
+ const progress = this.solver.progress;
11739
+ this.emitEvent({
11740
+ type: "progress",
11741
+ steps: this.cycleCount,
11742
+ iterationsPerSecond,
11743
+ progress,
11744
+ phase: this.solver.getCurrentPhase(),
11745
+ debugGraphics
11746
+ });
11747
+ if (this.stepDelay > 0) {
11748
+ this.timeoutId = setTimeout(
11749
+ () => this.runCycleAndQueueNextCycle(),
11750
+ this.stepDelay
11751
+ );
11752
+ } else {
11753
+ this.timeoutId = setTimeout(
11754
+ () => this.runCycleAndQueueNextCycle(),
11755
+ 0
11756
+ );
11757
+ }
11758
+ } catch (error) {
11759
+ this.emitEvent({
11760
+ type: "error",
11761
+ error: error instanceof Error ? new AutorouterError(error.message) : new AutorouterError(String(error))
11762
+ });
11763
+ this.isRouting = false;
11764
+ }
11765
+ }
11766
+ /**
11767
+ * Stop the routing process if it's in progress
11768
+ */
11769
+ stop() {
11770
+ if (!this.isRouting) return;
11771
+ this.isRouting = false;
11772
+ if (this.timeoutId !== void 0) {
11773
+ clearTimeout(this.timeoutId);
11774
+ this.timeoutId = void 0;
11775
+ }
11776
+ }
11777
+ on(event, callback) {
11778
+ if (event === "complete") {
11779
+ this.eventHandlers.complete.push(
11780
+ callback
11781
+ );
11782
+ } else if (event === "error") {
11783
+ this.eventHandlers.error.push(
11784
+ callback
11785
+ );
11786
+ } else if (event === "progress") {
11787
+ this.eventHandlers.progress.push(
11788
+ callback
11789
+ );
11790
+ }
11791
+ }
11792
+ /**
11793
+ * Emit an event to all registered handlers
11794
+ */
11795
+ emitEvent(event) {
11796
+ if (event.type === "complete") {
11797
+ for (const handler of this.eventHandlers.complete) {
11798
+ handler(event);
11799
+ }
11800
+ } else if (event.type === "error") {
11801
+ for (const handler of this.eventHandlers.error) {
11802
+ handler(event);
11803
+ }
11804
+ } else if (event.type === "progress") {
11805
+ for (const handler of this.eventHandlers.progress) {
11806
+ handler(event);
11807
+ }
11808
+ }
11809
+ }
11810
+ /**
11811
+ * Solve the routing problem synchronously
11812
+ * @returns Array of routed traces
11813
+ */
11814
+ solveSync() {
11815
+ this.solver.solve();
11816
+ if (this.solver.failed) {
11817
+ throw new AutorouterError(this.solver.error || "Routing failed");
11818
+ }
11819
+ return this.solver.getOutputSimpleRouteJson().traces || [];
11820
+ }
11821
+ /**
11822
+ * Get the mapping of obstacle IDs to root connection names that were
11823
+ * connected via off-board paths (e.g., interconnects).
11824
+ * Only available when using AssignableAutoroutingPipeline2.
11825
+ */
11826
+ getConnectedOffboardObstacles() {
11827
+ if ("getConnectedOffboardObstacles" in this.solver) {
11828
+ return this.solver.getConnectedOffboardObstacles();
11829
+ }
11830
+ return {};
11831
+ }
11832
+ };
11833
+
11834
+ // lib/utils/autorouting/createSourceTracesFromOffboardConnections.ts
11835
+ var createSourceTracesFromOffboardConnections = ({
11836
+ db,
11837
+ connectedOffboardObstacles,
11838
+ simpleRouteJson,
11839
+ subcircuit_id
11840
+ }) => {
11841
+ if (Object.keys(connectedOffboardObstacles).length === 0) return;
11842
+ const pcbElementIdToSourcePortId = /* @__PURE__ */ new Map();
11843
+ for (const pcbPort of db.pcb_port.list()) {
11844
+ if (pcbPort.source_port_id) {
11845
+ const smtpad = db.pcb_smtpad.getWhere({
11846
+ pcb_port_id: pcbPort.pcb_port_id
11847
+ });
11848
+ if (smtpad) {
11849
+ pcbElementIdToSourcePortId.set(
11850
+ smtpad.pcb_smtpad_id,
11851
+ pcbPort.source_port_id
11852
+ );
11853
+ }
11854
+ const platedHole = db.pcb_plated_hole.getWhere({
11855
+ pcb_port_id: pcbPort.pcb_port_id
11856
+ });
11857
+ if (platedHole) {
11858
+ pcbElementIdToSourcePortId.set(
11859
+ platedHole.pcb_plated_hole_id,
11860
+ pcbPort.source_port_id
11861
+ );
11862
+ }
11863
+ }
11864
+ }
11865
+ const obstacleById = /* @__PURE__ */ new Map();
11866
+ for (const obstacle of simpleRouteJson.obstacles) {
11867
+ if (obstacle.obstacleId) {
11868
+ obstacleById.set(obstacle.obstacleId, obstacle);
11869
+ }
11870
+ }
11871
+ const connectionGroups = /* @__PURE__ */ new Map();
11872
+ for (const [obstacleId, rootConnectionName] of Object.entries(
11873
+ connectedOffboardObstacles
11874
+ )) {
11875
+ if (!connectionGroups.has(rootConnectionName)) {
11876
+ connectionGroups.set(rootConnectionName, []);
11877
+ }
11878
+ connectionGroups.get(rootConnectionName).push(obstacleId);
11879
+ }
11880
+ for (const [rootConnectionName, obstacleIds] of connectionGroups) {
11881
+ const sourcePortIds = /* @__PURE__ */ new Set();
11882
+ for (const obstacleId of obstacleIds) {
11883
+ const obstacle = obstacleById.get(obstacleId);
11884
+ if (!obstacle) continue;
11885
+ for (const connectedId of obstacle.connectedTo) {
11886
+ const sourcePortId = pcbElementIdToSourcePortId.get(connectedId);
11887
+ if (sourcePortId) {
11888
+ sourcePortIds.add(sourcePortId);
11889
+ }
11890
+ }
11891
+ }
11892
+ if (sourcePortIds.size < 2) continue;
11893
+ const sourcePortIdArray = Array.from(sourcePortIds);
11894
+ const existingTraces = db.source_trace.list();
11895
+ const alreadyConnected = existingTraces.some((trace) => {
11896
+ const tracePortIds = new Set(trace.connected_source_port_ids);
11897
+ return sourcePortIdArray.every((id) => tracePortIds.has(id));
11898
+ });
11899
+ if (alreadyConnected) continue;
11900
+ db.source_trace.insert({
11901
+ connected_source_port_ids: sourcePortIdArray,
11902
+ connected_source_net_ids: [],
11903
+ subcircuit_id: subcircuit_id ?? void 0,
11904
+ display_name: `offboard_${rootConnectionName}`
11905
+ });
11906
+ }
11907
+ };
11908
+
11909
+ // lib/utils/autorouting/getPresetAutoroutingConfig.ts
11910
+ function getPresetAutoroutingConfig(autorouterConfig) {
11911
+ const defaults = {
11912
+ serverUrl: "https://registry-api.tscircuit.com",
11378
11913
  serverMode: "job",
11379
11914
  serverCacheEnabled: true
11380
11915
  };
@@ -11567,7 +12102,7 @@ var applyEditEventsToManualEditsFile = ({
11567
12102
 
11568
12103
  // lib/utils/edit-events/apply-edit-events-to-circuit-json.ts
11569
12104
  import { transformPCBElement } from "@tscircuit/circuit-json-util";
11570
- import { translate as translate4 } from "transformation-matrix";
12105
+ import { translate as translate5 } from "transformation-matrix";
11571
12106
 
11572
12107
  // lib/utils/edit-events/apply-trace-hint-edit-event.ts
11573
12108
  import { su as su3 } from "@tscircuit/circuit-json-util";
@@ -11612,7 +12147,7 @@ var applyEditEvents = ({
11612
12147
  );
11613
12148
  const needsMovement = !component || component.center.x !== editEvent.new_center.x || component.center.y !== editEvent.new_center.y;
11614
12149
  if (needsMovement && editEvent.original_center) {
11615
- const mat = translate4(
12150
+ const mat = translate5(
11616
12151
  editEvent.new_center.x - editEvent.original_center.x,
11617
12152
  editEvent.new_center.y - editEvent.original_center.y
11618
12153
  );
@@ -11642,27 +12177,6 @@ import { su as su4 } from "@tscircuit/circuit-json-util";
11642
12177
  import {
11643
12178
  getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson3
11644
12179
  } from "circuit-json-to-connectivity-map";
11645
-
11646
- // lib/utils/autorouting/getAncestorSubcircuitIds.ts
11647
- var getDescendantSubcircuitIds = (db, root_subcircuit_id) => {
11648
- const groups = db.source_group.list();
11649
- const result = [];
11650
- const findDescendants = (parentId) => {
11651
- const children = groups.filter(
11652
- (group) => group.parent_subcircuit_id === parentId
11653
- );
11654
- for (const child of children) {
11655
- if (child.subcircuit_id) {
11656
- result.push(child.subcircuit_id);
11657
- findDescendants(child.subcircuit_id);
11658
- }
11659
- }
11660
- };
11661
- findDescendants(root_subcircuit_id);
11662
- return result;
11663
- };
11664
-
11665
- // lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts
11666
12180
  var getSimpleRouteJsonFromCircuitJson = ({
11667
12181
  db,
11668
12182
  circuitJson,
@@ -13175,9 +13689,9 @@ var applyComponentConstraintClusters = (group, packInput) => {
13175
13689
  };
13176
13690
 
13177
13691
  // lib/components/primitive-components/Group/Group_doInitialPcbLayoutPack/applyPackOutput.ts
13178
- import { translate as translate5, rotate as rotate2, compose as compose5 } from "transformation-matrix";
13692
+ import { translate as translate6, rotate as rotate3, compose as compose6 } from "transformation-matrix";
13179
13693
  import {
13180
- transformPCBElements
13694
+ transformPCBElements as transformPCBElements2
13181
13695
  } from "@tscircuit/circuit-json-util";
13182
13696
  import { normalizeDegrees as normalizeDegrees2 } from "@tscircuit/math-utils";
13183
13697
  var updateCadRotation = ({
@@ -13230,16 +13744,16 @@ var applyPackOutput = (group, packOutput, clusterMap) => {
13230
13744
  const member = db.pcb_component.get(memberId);
13231
13745
  if (!member) continue;
13232
13746
  const originalCenter2 = member.center;
13233
- const transformMatrix2 = compose5(
13747
+ const transformMatrix2 = compose6(
13234
13748
  group._computePcbGlobalTransformBeforeLayout(),
13235
- translate5(center.x + rotatedRel.x, center.y + rotatedRel.y),
13236
- rotate2(angleRad),
13237
- translate5(-originalCenter2.x, -originalCenter2.y)
13749
+ translate6(center.x + rotatedRel.x, center.y + rotatedRel.y),
13750
+ rotate3(angleRad),
13751
+ translate6(-originalCenter2.x, -originalCenter2.y)
13238
13752
  );
13239
13753
  const related = db.toArray().filter(
13240
13754
  (elm) => "pcb_component_id" in elm && elm.pcb_component_id === memberId
13241
13755
  );
13242
- transformPCBElements(related, transformMatrix2);
13756
+ transformPCBElements2(related, transformMatrix2);
13243
13757
  updateCadRotation({
13244
13758
  db,
13245
13759
  pcbComponentId: memberId,
@@ -13264,16 +13778,16 @@ var applyPackOutput = (group, packOutput, clusterMap) => {
13264
13778
  }
13265
13779
  const originalCenter2 = pcbComponent.center;
13266
13780
  const rotationDegrees2 = ccwRotationDegrees ?? ccwRotationOffset ?? 0;
13267
- const transformMatrix2 = compose5(
13781
+ const transformMatrix2 = compose6(
13268
13782
  group._computePcbGlobalTransformBeforeLayout(),
13269
- translate5(center.x, center.y),
13270
- rotate2(rotationDegrees2 * Math.PI / 180),
13271
- translate5(-originalCenter2.x, -originalCenter2.y)
13783
+ translate6(center.x, center.y),
13784
+ rotate3(rotationDegrees2 * Math.PI / 180),
13785
+ translate6(-originalCenter2.x, -originalCenter2.y)
13272
13786
  );
13273
13787
  const related = db.toArray().filter(
13274
13788
  (elm) => "pcb_component_id" in elm && elm.pcb_component_id === componentId
13275
13789
  );
13276
- transformPCBElements(related, transformMatrix2);
13790
+ transformPCBElements2(related, transformMatrix2);
13277
13791
  updateCadRotation({
13278
13792
  db,
13279
13793
  pcbComponentId: componentId,
@@ -13286,11 +13800,11 @@ var applyPackOutput = (group, packOutput, clusterMap) => {
13286
13800
  if (!pcbGroup) continue;
13287
13801
  const originalCenter = pcbGroup.center;
13288
13802
  const rotationDegrees = ccwRotationDegrees ?? ccwRotationOffset ?? 0;
13289
- const transformMatrix = compose5(
13803
+ const transformMatrix = compose6(
13290
13804
  group._computePcbGlobalTransformBeforeLayout(),
13291
- translate5(center.x, center.y),
13292
- rotate2(rotationDegrees * Math.PI / 180),
13293
- translate5(-originalCenter.x, -originalCenter.y)
13805
+ translate6(center.x, center.y),
13806
+ rotate3(rotationDegrees * Math.PI / 180),
13807
+ translate6(-originalCenter.x, -originalCenter.y)
13294
13808
  );
13295
13809
  const relatedElements = db.toArray().filter((elm) => {
13296
13810
  if ("source_group_id" in elm && elm.source_group_id) {
@@ -13337,7 +13851,7 @@ var applyPackOutput = (group, packOutput, clusterMap) => {
13337
13851
  });
13338
13852
  }
13339
13853
  }
13340
- transformPCBElements(relatedElements, transformMatrix);
13854
+ transformPCBElements2(relatedElements, transformMatrix);
13341
13855
  db.pcb_group.update(pcbGroup.pcb_group_id, { center });
13342
13856
  }
13343
13857
  };
@@ -16532,7 +17046,8 @@ var Group6 = class extends NormalComponent3 {
16532
17046
  const debug11 = Debug13("tscircuit:core:doInitialPcbTraceRender");
16533
17047
  if (!this.isSubcircuit) return;
16534
17048
  if (this.root?.pcbDisabled) return;
16535
- if (this.getInheritedProperty("routingDisabled")) return;
17049
+ if (this.root?.pcbRoutingDisabled || this.getInheritedProperty("routingDisabled"))
17050
+ return;
16536
17051
  if (this._isInflatedFromCircuitJson) return;
16537
17052
  if (this._shouldUseTraceByTraceRouting()) return;
16538
17053
  if (!this._areChildSubcircuitsRouted()) {
@@ -16784,718 +17299,210 @@ var Group6 = class extends NormalComponent3 {
16784
17299
  this._doInitialPcbLayoutGrid();
16785
17300
  } else if (pcbLayoutMode === "pack") {
16786
17301
  this._doInitialPcbLayoutPack();
16787
- } else if (pcbLayoutMode === "flex") {
16788
- this._doInitialPcbLayoutFlex();
16789
- }
16790
- }
16791
- _doInitialPcbLayoutGrid() {
16792
- Group_doInitialPcbLayoutGrid(this);
16793
- }
16794
- _doInitialPcbLayoutPack() {
16795
- Group_doInitialPcbLayoutPack(this);
16796
- }
16797
- _doInitialPcbLayoutFlex() {
16798
- Group_doInitialPcbLayoutFlex(this);
16799
- }
16800
- _insertSchematicBorder() {
16801
- if (this.root?.schematicDisabled) return;
16802
- const { db } = this.root;
16803
- const props = this._parsedProps;
16804
- if (!props.border) return;
16805
- let width = typeof props.schWidth === "number" ? props.schWidth : void 0;
16806
- let height = typeof props.schHeight === "number" ? props.schHeight : void 0;
16807
- const paddingGeneral = typeof props.schPadding === "number" ? props.schPadding : 0;
16808
- const paddingLeft = typeof props.schPaddingLeft === "number" ? props.schPaddingLeft : paddingGeneral;
16809
- const paddingRight = typeof props.schPaddingRight === "number" ? props.schPaddingRight : paddingGeneral;
16810
- const paddingTop = typeof props.schPaddingTop === "number" ? props.schPaddingTop : paddingGeneral;
16811
- const paddingBottom = typeof props.schPaddingBottom === "number" ? props.schPaddingBottom : paddingGeneral;
16812
- const schematicGroup = this.schematic_group_id ? db.schematic_group.get(this.schematic_group_id) : null;
16813
- if (schematicGroup) {
16814
- if (width === void 0 && typeof schematicGroup.width === "number") {
16815
- width = schematicGroup.width;
16816
- }
16817
- if (height === void 0 && typeof schematicGroup.height === "number") {
16818
- height = schematicGroup.height;
16819
- }
16820
- }
16821
- if (width === void 0 || height === void 0) return;
16822
- const center = schematicGroup?.center ?? this._getGlobalSchematicPositionBeforeLayout();
16823
- const left = center.x - width / 2 - paddingLeft;
16824
- const bottom = center.y - height / 2 - paddingBottom;
16825
- const finalWidth = width + paddingLeft + paddingRight;
16826
- const finalHeight = height + paddingTop + paddingBottom;
16827
- db.schematic_box.insert({
16828
- width: finalWidth,
16829
- height: finalHeight,
16830
- x: left,
16831
- y: bottom,
16832
- is_dashed: props.border?.dashed ?? false
16833
- });
16834
- }
16835
- _determineSideFromPosition(port, component) {
16836
- if (!port.center || !component.center) return "left";
16837
- const dx = port.center.x - component.center.x;
16838
- const dy = port.center.y - component.center.y;
16839
- if (Math.abs(dx) > Math.abs(dy)) {
16840
- return dx > 0 ? "right" : "left";
16841
- }
16842
- return dy > 0 ? "bottom" : "top";
16843
- }
16844
- _calculateSchematicBounds(boxes) {
16845
- if (boxes.length === 0) {
16846
- return { minX: 0, maxX: 0, minY: 0, maxY: 0 };
16847
- }
16848
- let minX = Infinity;
16849
- let maxX = -Infinity;
16850
- let minY = Infinity;
16851
- let maxY = -Infinity;
16852
- for (const box of boxes) {
16853
- minX = Math.min(minX, box.centerX);
16854
- maxX = Math.max(maxX, box.centerX);
16855
- minY = Math.min(minY, box.centerY);
16856
- maxY = Math.max(maxY, box.centerY);
16857
- }
16858
- const padding = 2;
16859
- return {
16860
- minX: minX - padding,
16861
- maxX: maxX + padding,
16862
- minY: minY - padding,
16863
- maxY: maxY + padding
16864
- };
16865
- }
16866
- _getAutorouterConfig() {
16867
- const autorouter = this._parsedProps.autorouter || this.getInheritedProperty("autorouter");
16868
- return getPresetAutoroutingConfig(autorouter);
16869
- }
16870
- _isLaserPrefabAutorouter(autorouterConfig = this._getAutorouterConfig()) {
16871
- const autorouterProp = this.props.autorouter;
16872
- const normalize = (value) => value?.replace(/-/g, "_") ?? value;
16873
- if (autorouterConfig.preset === "laser_prefab") return true;
16874
- if (typeof autorouterProp === "string") {
16875
- return normalize(autorouterProp) === "laser_prefab";
16876
- }
16877
- if (typeof autorouterProp === "object" && autorouterProp) {
16878
- return normalize(autorouterProp.preset) === "laser_prefab";
16879
- }
16880
- return false;
16881
- }
16882
- _isAutoJumperAutorouter(autorouterConfig = this._getAutorouterConfig()) {
16883
- const autorouterProp = this.props.autorouter;
16884
- const normalize = (value) => value?.replace(/-/g, "_") ?? value;
16885
- if (autorouterConfig.preset === "auto_jumper") return true;
16886
- if (typeof autorouterProp === "string") {
16887
- return normalize(autorouterProp) === "auto_jumper";
16888
- }
16889
- if (typeof autorouterProp === "object" && autorouterProp) {
16890
- return normalize(autorouterProp.preset) === "auto_jumper";
16891
- }
16892
- return false;
16893
- }
16894
- _getSubcircuitLayerCount() {
16895
- const layers = this.getInheritedProperty("layers");
16896
- return typeof layers === "number" ? layers : 2;
16897
- }
16898
- /**
16899
- * Trace-by-trace autorouting is where each trace routes itself in a well-known
16900
- * order. It's the most deterministic way to autoroute, because a new trace
16901
- * is generally ordered last.
16902
- *
16903
- * This method will return false if using an external service for autorouting
16904
- * or if using a "fullview" or "rip and replace" autorouting mode
16905
- */
16906
- _shouldUseTraceByTraceRouting() {
16907
- const autorouter = this._getAutorouterConfig();
16908
- return autorouter.groupMode === "sequential-trace";
16909
- }
16910
- doInitialPcbDesignRuleChecks() {
16911
- if (this.root?.pcbDisabled) return;
16912
- if (this.getInheritedProperty("routingDisabled")) return;
16913
- const { db } = this.root;
16914
- if (this.isSubcircuit) {
16915
- const subcircuitComponentsByName = /* @__PURE__ */ new Map();
16916
- for (const child of this.children) {
16917
- if (child.isSubcircuit) continue;
16918
- if (child._parsedProps.name) {
16919
- const components = subcircuitComponentsByName.get(child._parsedProps.name) || [];
16920
- components.push(child);
16921
- subcircuitComponentsByName.set(child._parsedProps.name, components);
16922
- }
16923
- }
16924
- for (const [name, components] of subcircuitComponentsByName.entries()) {
16925
- if (components.length > 1) {
16926
- db.pcb_trace_error.insert({
16927
- error_type: "pcb_trace_error",
16928
- message: `Multiple components found with name "${name}" in subcircuit "${this.name || "unnamed"}". Component names must be unique within a subcircuit.`,
16929
- source_trace_id: "",
16930
- pcb_trace_id: "",
16931
- pcb_component_ids: components.map((c) => c.pcb_component_id).filter(Boolean),
16932
- pcb_port_ids: []
16933
- });
16934
- }
16935
- }
16936
- }
16937
- }
16938
- doInitialSchematicReplaceNetLabelsWithSymbols() {
16939
- if (this.root?.schematicDisabled) return;
16940
- if (!this.isSubcircuit) return;
16941
- const { db } = this.root;
16942
- const subtree = db;
16943
- for (const nl of subtree.schematic_net_label.list()) {
16944
- const net = subtree.source_net.get(nl.source_net_id);
16945
- const text = nl.text || net?.name || "";
16946
- if (nl.anchor_side === "top" && /^gnd/i.test(text)) {
16947
- subtree.schematic_net_label.update(nl.schematic_net_label_id, {
16948
- symbol_name: "rail_down"
16949
- });
16950
- continue;
16951
- }
16952
- if (nl.anchor_side === "bottom" && /^v/i.test(text)) {
16953
- subtree.schematic_net_label.update(nl.schematic_net_label_id, {
16954
- symbol_name: "rail_up"
16955
- });
16956
- }
16957
- }
16958
- }
16959
- doInitialSimulationSpiceEngineRender() {
16960
- Group_doInitialSimulationSpiceEngineRender(this);
16961
- }
16962
- /**
16963
- * Override anchor alignment to handle group-specific logic
16964
- */
16965
- doInitialPcbComponentAnchorAlignment() {
16966
- Group_doInitialPcbComponentAnchorAlignment(this);
16967
- }
16968
- updatePcbComponentAnchorAlignment() {
16969
- this.doInitialPcbComponentAnchorAlignment();
16970
- }
16971
- doInitialPcbCalcPlacementResolution() {
16972
- Group_doInitialPcbCalcPlacementResolution(this);
16973
- }
16974
- updatePcbCalcPlacementResolution() {
16975
- this.doInitialPcbCalcPlacementResolution();
16976
- }
16977
- /**
16978
- * Get the minimum flex container size for this group on PCB
16979
- */
16980
- _getMinimumFlexContainerSize() {
16981
- return super._getMinimumFlexContainerSize();
16982
- }
16983
- /**
16984
- * Reposition this group on the PCB to the specified coordinates
16985
- */
16986
- _repositionOnPcb(position) {
16987
- return super._repositionOnPcb(position);
16988
- }
16989
- };
16990
-
16991
- // lib/utils/circuit-json/inflate-circuit-json.ts
16992
- import { cju } from "@tscircuit/circuit-json-util";
16993
-
16994
- // lib/components/primitive-components/Group/Subcircuit/inflators/inflatePcbBoard.ts
16995
- function inflatePcbBoard(pcbBoard, inflatorContext) {
16996
- const { subcircuit } = inflatorContext;
16997
- if (subcircuit.lowercaseComponentName === "board" || subcircuit.lowercaseComponentName === "mountedboard") {
16998
- return;
16999
- }
17000
- if (subcircuit.parent?.lowercaseComponentName === "board") {
17001
- return;
17002
- }
17003
- const boardProps2 = {
17004
- name: "inflated_board"
17005
- };
17006
- if (pcbBoard.width) boardProps2.width = pcbBoard.width;
17007
- if (pcbBoard.height) boardProps2.height = pcbBoard.height;
17008
- if (pcbBoard.center) {
17009
- boardProps2.pcbX = pcbBoard.center.x;
17010
- boardProps2.pcbY = pcbBoard.center.y;
17011
- }
17012
- if (pcbBoard.outline) boardProps2.outline = pcbBoard.outline;
17013
- if (pcbBoard.thickness) boardProps2.thickness = pcbBoard.thickness;
17014
- if (pcbBoard.material) boardProps2.material = pcbBoard.material;
17015
- const board = new Board(boardProps2);
17016
- board.pcb_board_id = pcbBoard.pcb_board_id;
17017
- subcircuit.add(board);
17018
- return board;
17019
- }
17020
-
17021
- // lib/components/normal-components/Capacitor.ts
17022
- import { capacitorProps } from "@tscircuit/props";
17023
- import { formatSiUnit } from "format-si-unit";
17024
- var Capacitor = class extends NormalComponent3 {
17025
- _adjustSilkscreenTextAutomatically = true;
17026
- get config() {
17027
- return {
17028
- componentName: "Capacitor",
17029
- schematicSymbolName: this.props.polarized ? "capacitor_polarized" : this.props.symbolName ?? "capacitor",
17030
- zodProps: capacitorProps,
17031
- sourceFtype: FTYPE.simple_capacitor
17032
- };
17033
- }
17034
- initPorts() {
17035
- if (typeof this.props.footprint === "string") {
17036
- super.initPorts({
17037
- additionalAliases: {
17038
- pin1: ["anode", "pos"],
17039
- pin2: ["cathode", "neg"]
17040
- }
17041
- });
17042
- } else {
17043
- super.initPorts();
17302
+ } else if (pcbLayoutMode === "flex") {
17303
+ this._doInitialPcbLayoutFlex();
17044
17304
  }
17045
17305
  }
17046
- _getSchematicSymbolDisplayValue() {
17047
- const inputCapacitance = this.props.capacitance;
17048
- const capacitanceDisplay = typeof inputCapacitance === "string" ? inputCapacitance : `${formatSiUnit(this._parsedProps.capacitance)}F`;
17049
- if (this._parsedProps.schShowRatings && this._parsedProps.maxVoltageRating) {
17050
- return `${capacitanceDisplay}/${formatSiUnit(this._parsedProps.maxVoltageRating)}V`;
17051
- }
17052
- return capacitanceDisplay;
17306
+ _doInitialPcbLayoutGrid() {
17307
+ Group_doInitialPcbLayoutGrid(this);
17053
17308
  }
17054
- doInitialCreateNetsFromProps() {
17055
- this._createNetsFromProps([
17056
- this.props.decouplingFor,
17057
- this.props.decouplingTo,
17058
- ...this._getNetsFromConnectionsProp()
17059
- ]);
17309
+ _doInitialPcbLayoutPack() {
17310
+ Group_doInitialPcbLayoutPack(this);
17060
17311
  }
17061
- doInitialCreateTracesFromProps() {
17062
- if (this.props.decouplingFor && this.props.decouplingTo) {
17063
- this.add(
17064
- new Trace3({
17065
- from: `${this.getSubcircuitSelector()} > port.1`,
17066
- to: this.props.decouplingFor
17067
- })
17068
- );
17069
- this.add(
17070
- new Trace3({
17071
- from: `${this.getSubcircuitSelector()} > port.2`,
17072
- to: this.props.decouplingTo
17073
- })
17074
- );
17075
- }
17076
- this._createTracesFromConnectionsProp();
17312
+ _doInitialPcbLayoutFlex() {
17313
+ Group_doInitialPcbLayoutFlex(this);
17077
17314
  }
17078
- doInitialSourceRender() {
17315
+ _insertSchematicBorder() {
17316
+ if (this.root?.schematicDisabled) return;
17079
17317
  const { db } = this.root;
17080
- const { _parsedProps: props } = this;
17081
- const source_component = db.source_component.insert({
17082
- ftype: "simple_capacitor",
17083
- name: this.name,
17084
- manufacturer_part_number: props.manufacturerPartNumber ?? props.mfn,
17085
- supplier_part_numbers: props.supplierPartNumbers,
17086
- capacitance: props.capacitance,
17087
- max_voltage_rating: props.maxVoltageRating,
17088
- max_decoupling_trace_length: props.maxDecouplingTraceLength,
17089
- display_capacitance: this._getSchematicSymbolDisplayValue(),
17090
- are_pins_interchangeable: !props.polarized,
17091
- display_name: props.displayName
17318
+ const props = this._parsedProps;
17319
+ if (!props.border) return;
17320
+ let width = typeof props.schWidth === "number" ? props.schWidth : void 0;
17321
+ let height = typeof props.schHeight === "number" ? props.schHeight : void 0;
17322
+ const paddingGeneral = typeof props.schPadding === "number" ? props.schPadding : 0;
17323
+ const paddingLeft = typeof props.schPaddingLeft === "number" ? props.schPaddingLeft : paddingGeneral;
17324
+ const paddingRight = typeof props.schPaddingRight === "number" ? props.schPaddingRight : paddingGeneral;
17325
+ const paddingTop = typeof props.schPaddingTop === "number" ? props.schPaddingTop : paddingGeneral;
17326
+ const paddingBottom = typeof props.schPaddingBottom === "number" ? props.schPaddingBottom : paddingGeneral;
17327
+ const schematicGroup = this.schematic_group_id ? db.schematic_group.get(this.schematic_group_id) : null;
17328
+ if (schematicGroup) {
17329
+ if (width === void 0 && typeof schematicGroup.width === "number") {
17330
+ width = schematicGroup.width;
17331
+ }
17332
+ if (height === void 0 && typeof schematicGroup.height === "number") {
17333
+ height = schematicGroup.height;
17334
+ }
17335
+ }
17336
+ if (width === void 0 || height === void 0) return;
17337
+ const center = schematicGroup?.center ?? this._getGlobalSchematicPositionBeforeLayout();
17338
+ const left = center.x - width / 2 - paddingLeft;
17339
+ const bottom = center.y - height / 2 - paddingBottom;
17340
+ const finalWidth = width + paddingLeft + paddingRight;
17341
+ const finalHeight = height + paddingTop + paddingBottom;
17342
+ db.schematic_box.insert({
17343
+ width: finalWidth,
17344
+ height: finalHeight,
17345
+ x: left,
17346
+ y: bottom,
17347
+ is_dashed: props.border?.dashed ?? false
17092
17348
  });
17093
- this.source_component_id = source_component.source_component_id;
17094
17349
  }
17095
- };
17096
-
17097
- // lib/utils/extractPcbPrimitivesFromCircuitJson.ts
17098
- import { transformPCBElements as transformPCBElements2 } from "@tscircuit/circuit-json-util";
17099
- import { compose as compose6, inverse, rotate as rotate3, translate as translate6 } from "transformation-matrix";
17100
- var extractPcbPrimitivesFromCircuitJson = ({
17101
- pcbComponent,
17102
- db,
17103
- componentName
17104
- }) => {
17105
- const componentCenter = pcbComponent.center || { x: 0, y: 0 };
17106
- const componentRotation = pcbComponent.rotation || 0;
17107
- const absoluteToComponentRelativeTransform = inverse(
17108
- compose6(
17109
- translate6(componentCenter.x, componentCenter.y),
17110
- rotate3(componentRotation * Math.PI / 180)
17111
- )
17112
- );
17113
- const relativeElements = db.toArray().filter(
17114
- (elm) => "pcb_component_id" in elm && elm.pcb_component_id === pcbComponent.pcb_component_id
17115
- );
17116
- const clonedRelativeElements = structuredClone(relativeElements);
17117
- transformPCBElements2(
17118
- clonedRelativeElements,
17119
- absoluteToComponentRelativeTransform
17120
- );
17121
- const components = createComponentsFromCircuitJson(
17122
- {
17123
- componentName,
17124
- componentRotation: "0deg"
17125
- },
17126
- clonedRelativeElements
17127
- );
17128
- return components;
17129
- };
17130
-
17131
- // lib/components/primitive-components/Group/Subcircuit/inflators/inflateFootprintComponent.ts
17132
- var inflateFootprintComponent = (pcbElm, inflatorContext) => {
17133
- const { injectionDb, normalComponent } = inflatorContext;
17134
- if (!normalComponent) return null;
17135
- const primitives = extractPcbPrimitivesFromCircuitJson({
17136
- pcbComponent: pcbElm,
17137
- db: injectionDb,
17138
- componentName: normalComponent.name
17139
- });
17140
- if (primitives.length === 0) return null;
17141
- const footprint = new Footprint({});
17142
- footprint.addAll(primitives);
17143
- return footprint;
17144
- };
17145
-
17146
- // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceCapacitor.ts
17147
- function inflateSourceCapacitor(sourceElm, inflatorContext) {
17148
- const { injectionDb, subcircuit, groupsMap } = inflatorContext;
17149
- const pcbElm = injectionDb.pcb_component.getWhere({
17150
- source_component_id: sourceElm.source_component_id
17151
- });
17152
- const cadElm = injectionDb.cad_component.getWhere({
17153
- source_component_id: sourceElm.source_component_id
17154
- });
17155
- const capacitor = new Capacitor({
17156
- name: sourceElm.name,
17157
- capacitance: sourceElm.capacitance,
17158
- layer: pcbElm?.layer,
17159
- pcbX: pcbElm?.center?.x,
17160
- pcbY: pcbElm?.center?.y,
17161
- pcbRotation: pcbElm?.rotation,
17162
- doNotPlace: pcbElm?.do_not_place,
17163
- obstructsWithinBounds: pcbElm?.obstructs_within_bounds
17164
- });
17165
- if (pcbElm) {
17166
- const footprint = inflateFootprintComponent(pcbElm, {
17167
- ...inflatorContext,
17168
- normalComponent: capacitor
17169
- });
17170
- if (footprint) {
17171
- capacitor.add(footprint);
17350
+ _determineSideFromPosition(port, component) {
17351
+ if (!port.center || !component.center) return "left";
17352
+ const dx = port.center.x - component.center.x;
17353
+ const dy = port.center.y - component.center.y;
17354
+ if (Math.abs(dx) > Math.abs(dy)) {
17355
+ return dx > 0 ? "right" : "left";
17172
17356
  }
17357
+ return dy > 0 ? "bottom" : "top";
17173
17358
  }
17174
- if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
17175
- const group = groupsMap.get(sourceElm.source_group_id);
17176
- group.add(capacitor);
17177
- } else {
17178
- subcircuit.add(capacitor);
17179
- }
17180
- }
17181
-
17182
- // lib/components/normal-components/Chip.ts
17183
- import { chipProps as chipProps2 } from "@tscircuit/props";
17184
- import { pcb_component_invalid_layer_error as pcb_component_invalid_layer_error2 } from "circuit-json";
17185
- var Chip = class extends NormalComponent3 {
17186
- schematicBoxDimensions = null;
17187
- constructor(props) {
17188
- super(props);
17189
- }
17190
- get config() {
17359
+ _calculateSchematicBounds(boxes) {
17360
+ if (boxes.length === 0) {
17361
+ return { minX: 0, maxX: 0, minY: 0, maxY: 0 };
17362
+ }
17363
+ let minX = Infinity;
17364
+ let maxX = -Infinity;
17365
+ let minY = Infinity;
17366
+ let maxY = -Infinity;
17367
+ for (const box of boxes) {
17368
+ minX = Math.min(minX, box.centerX);
17369
+ maxX = Math.max(maxX, box.centerX);
17370
+ minY = Math.min(minY, box.centerY);
17371
+ maxY = Math.max(maxY, box.centerY);
17372
+ }
17373
+ const padding = 2;
17191
17374
  return {
17192
- componentName: "Chip",
17193
- zodProps: chipProps2,
17194
- shouldRenderAsSchematicBox: true
17375
+ minX: minX - padding,
17376
+ maxX: maxX + padding,
17377
+ minY: minY - padding,
17378
+ maxY: maxY + padding
17195
17379
  };
17196
17380
  }
17197
- initPorts(opts = {}) {
17198
- super.initPorts(opts);
17199
- const { _parsedProps: props } = this;
17200
- if (props.externallyConnectedPins) {
17201
- const requiredPorts = /* @__PURE__ */ new Set();
17202
- for (const [pin1, pin2] of props.externallyConnectedPins) {
17203
- requiredPorts.add(pin1);
17204
- requiredPorts.add(pin2);
17205
- }
17206
- for (const pinIdentifier of requiredPorts) {
17207
- const existingPort = this.children.find(
17208
- (child) => child instanceof Port && child.isMatchingAnyOf([pinIdentifier])
17209
- );
17210
- if (!existingPort) {
17211
- const pinMatch = pinIdentifier.match(/^pin(\d+)$/);
17212
- if (pinMatch) {
17213
- const pinNumber = parseInt(pinMatch[1]);
17214
- this.add(
17215
- new Port({
17216
- pinNumber,
17217
- aliases: [pinIdentifier]
17218
- })
17219
- );
17220
- } else {
17221
- this.add(
17222
- new Port({
17223
- name: pinIdentifier,
17224
- aliases: [pinIdentifier]
17225
- })
17226
- );
17227
- }
17228
- }
17229
- }
17381
+ _getAutorouterConfig() {
17382
+ const autorouter = this._parsedProps.autorouter || this.getInheritedProperty("autorouter");
17383
+ return getPresetAutoroutingConfig(autorouter);
17384
+ }
17385
+ _isLaserPrefabAutorouter(autorouterConfig = this._getAutorouterConfig()) {
17386
+ const autorouterProp = this.props.autorouter;
17387
+ const normalize = (value) => value?.replace(/-/g, "_") ?? value;
17388
+ if (autorouterConfig.preset === "laser_prefab") return true;
17389
+ if (typeof autorouterProp === "string") {
17390
+ return normalize(autorouterProp) === "laser_prefab";
17391
+ }
17392
+ if (typeof autorouterProp === "object" && autorouterProp) {
17393
+ return normalize(autorouterProp.preset) === "laser_prefab";
17394
+ }
17395
+ return false;
17396
+ }
17397
+ _isAutoJumperAutorouter(autorouterConfig = this._getAutorouterConfig()) {
17398
+ const autorouterProp = this.props.autorouter;
17399
+ const normalize = (value) => value?.replace(/-/g, "_") ?? value;
17400
+ if (autorouterConfig.preset === "auto_jumper") return true;
17401
+ if (typeof autorouterProp === "string") {
17402
+ return normalize(autorouterProp) === "auto_jumper";
17403
+ }
17404
+ if (typeof autorouterProp === "object" && autorouterProp) {
17405
+ return normalize(autorouterProp.preset) === "auto_jumper";
17230
17406
  }
17407
+ return false;
17231
17408
  }
17232
- doInitialSchematicComponentRender() {
17233
- const { _parsedProps: props } = this;
17234
- if (props?.noSchematicRepresentation === true) return;
17235
- super.doInitialSchematicComponentRender();
17409
+ _getSubcircuitLayerCount() {
17410
+ const layers = this.getInheritedProperty("layers");
17411
+ return typeof layers === "number" ? layers : 2;
17236
17412
  }
17237
- doInitialSourceRender() {
17238
- const { db } = this.root;
17239
- const { _parsedProps: props } = this;
17240
- const source_component = db.source_component.insert({
17241
- ftype: "simple_chip",
17242
- name: this.name,
17243
- manufacturer_part_number: props.manufacturerPartNumber,
17244
- supplier_part_numbers: props.supplierPartNumbers,
17245
- display_name: props.displayName
17246
- });
17247
- this.source_component_id = source_component.source_component_id;
17413
+ /**
17414
+ * Trace-by-trace autorouting is where each trace routes itself in a well-known
17415
+ * order. It's the most deterministic way to autoroute, because a new trace
17416
+ * is generally ordered last.
17417
+ *
17418
+ * This method will return false if using an external service for autorouting
17419
+ * or if using a "fullview" or "rip and replace" autorouting mode
17420
+ */
17421
+ _shouldUseTraceByTraceRouting() {
17422
+ const autorouter = this._getAutorouterConfig();
17423
+ return autorouter.groupMode === "sequential-trace";
17248
17424
  }
17249
- doInitialPcbComponentRender() {
17425
+ doInitialPcbDesignRuleChecks() {
17250
17426
  if (this.root?.pcbDisabled) return;
17427
+ if (this.root?.pcbRoutingDisabled || this.getInheritedProperty("routingDisabled"))
17428
+ return;
17251
17429
  const { db } = this.root;
17252
- const { _parsedProps: props } = this;
17253
- const { pcbX, pcbY } = this.getResolvedPcbPositionProp();
17254
- const componentLayer = props.layer ?? "top";
17255
- if (componentLayer !== "top" && componentLayer !== "bottom") {
17256
- const subcircuit = this.getSubcircuit();
17257
- const error = pcb_component_invalid_layer_error2.parse({
17258
- type: "pcb_component_invalid_layer_error",
17259
- message: `Component cannot be placed on layer '${componentLayer}'. Components can only be placed on 'top' or 'bottom' layers.`,
17260
- source_component_id: this.source_component_id,
17261
- layer: componentLayer,
17262
- subcircuit_id: subcircuit.subcircuit_id ?? void 0
17263
- });
17264
- db.pcb_component_invalid_layer_error.insert(error);
17265
- }
17266
- const pcb_component = db.pcb_component.insert({
17267
- center: { x: pcbX, y: pcbY },
17268
- width: 2,
17269
- // Default width, adjust as needed
17270
- height: 3,
17271
- // Default height, adjust as needed
17272
- layer: componentLayer === "top" || componentLayer === "bottom" ? componentLayer : "top",
17273
- rotation: props.pcbRotation ?? 0,
17274
- source_component_id: this.source_component_id,
17275
- subcircuit_id: this.getSubcircuit().subcircuit_id ?? void 0,
17276
- do_not_place: props.doNotPlace ?? false,
17277
- obstructs_within_bounds: props.obstructsWithinBounds ?? true,
17278
- is_allowed_to_be_off_board: props.allowOffBoard ?? false,
17279
- metadata: props.kicadFootprintMetadata ? { kicad_footprint: props.kicadFootprintMetadata } : void 0
17280
- });
17281
- this.pcb_component_id = pcb_component.pcb_component_id;
17282
- }
17283
- doInitialCreateTracesFromProps() {
17284
- const { _parsedProps: props } = this;
17285
- if (props.externallyConnectedPins) {
17286
- for (const [pin1, pin2] of props.externallyConnectedPins) {
17287
- this.add(
17288
- new Trace3({
17289
- from: `${this.getSubcircuitSelector()} > port.${pin1}`,
17290
- to: `${this.getSubcircuitSelector()} > port.${pin2}`
17291
- })
17292
- );
17430
+ if (this.isSubcircuit) {
17431
+ const subcircuitComponentsByName = /* @__PURE__ */ new Map();
17432
+ for (const child of this.children) {
17433
+ if (child.isSubcircuit) continue;
17434
+ if (child._parsedProps.name) {
17435
+ const components = subcircuitComponentsByName.get(child._parsedProps.name) || [];
17436
+ components.push(child);
17437
+ subcircuitComponentsByName.set(child._parsedProps.name, components);
17438
+ }
17293
17439
  }
17294
- }
17295
- this._createTracesFromConnectionsProp();
17296
- }
17297
- doInitialSimulationRender() {
17298
- const { db } = this.root;
17299
- const { pinAttributes } = this.props;
17300
- if (!pinAttributes) return;
17301
- let powerPort = null;
17302
- let groundPort = null;
17303
- let voltage;
17304
- const ports = this.selectAll("port");
17305
- for (const port of ports) {
17306
- for (const alias of port.getNameAndAliases()) {
17307
- if (pinAttributes[alias]) {
17308
- const attributes = pinAttributes[alias];
17309
- if (attributes.providesPower) {
17310
- powerPort = port;
17311
- voltage = attributes.providesVoltage;
17312
- }
17313
- if (attributes.providesGround) {
17314
- groundPort = port;
17315
- }
17440
+ for (const [name, components] of subcircuitComponentsByName.entries()) {
17441
+ if (components.length > 1) {
17442
+ db.pcb_trace_error.insert({
17443
+ error_type: "pcb_trace_error",
17444
+ message: `Multiple components found with name "${name}" in subcircuit "${this.name || "unnamed"}". Component names must be unique within a subcircuit.`,
17445
+ source_trace_id: "",
17446
+ pcb_trace_id: "",
17447
+ pcb_component_ids: components.map((c) => c.pcb_component_id).filter(Boolean),
17448
+ pcb_port_ids: []
17449
+ });
17316
17450
  }
17317
17451
  }
17318
17452
  }
17319
- if (!powerPort || !groundPort || voltage === void 0) {
17320
- return;
17321
- }
17322
- const powerSourcePort = db.source_port.get(powerPort.source_port_id);
17323
- if (!powerSourcePort?.subcircuit_connectivity_map_key) return;
17324
- const groundSourcePort = db.source_port.get(groundPort.source_port_id);
17325
- if (!groundSourcePort?.subcircuit_connectivity_map_key) return;
17326
- const powerNet = db.source_net.getWhere({
17327
- subcircuit_connectivity_map_key: powerSourcePort.subcircuit_connectivity_map_key
17328
- });
17329
- const groundNet = db.source_net.getWhere({
17330
- subcircuit_connectivity_map_key: groundSourcePort.subcircuit_connectivity_map_key
17331
- });
17332
- if (!powerNet || !groundNet) {
17333
- return;
17334
- }
17335
- ;
17336
- db.simulation_voltage_source.insert({
17337
- type: "simulation_voltage_source",
17338
- positive_source_port_id: powerPort.source_port_id,
17339
- positive_source_net_id: powerNet.source_net_id,
17340
- negative_source_port_id: groundPort.source_port_id,
17341
- negative_source_net_id: groundNet.source_net_id,
17342
- voltage
17343
- });
17344
17453
  }
17345
- };
17346
-
17347
- // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceChip.ts
17348
- var mapInternallyConnectedSourcePortIdsToPinLabels = (sourcePortIds, inflatorContext) => {
17349
- if (!sourcePortIds || sourcePortIds.length === 0) return void 0;
17350
- const { injectionDb } = inflatorContext;
17351
- const mapped = sourcePortIds.map(
17352
- (group) => group.map((sourcePortId) => {
17353
- const port = injectionDb.source_port.get(
17354
- sourcePortId
17355
- );
17356
- if (!port) return null;
17357
- if (port.pin_number !== void 0 && port.pin_number !== null) {
17358
- return `pin${port.pin_number}`;
17454
+ doInitialSchematicReplaceNetLabelsWithSymbols() {
17455
+ if (this.root?.schematicDisabled) return;
17456
+ if (!this.isSubcircuit) return;
17457
+ const { db } = this.root;
17458
+ const subtree = db;
17459
+ for (const nl of subtree.schematic_net_label.list()) {
17460
+ const net = subtree.source_net.get(nl.source_net_id);
17461
+ const text = nl.text || net?.name || "";
17462
+ if (nl.anchor_side === "top" && /^gnd/i.test(text)) {
17463
+ subtree.schematic_net_label.update(nl.schematic_net_label_id, {
17464
+ symbol_name: "rail_down"
17465
+ });
17466
+ continue;
17467
+ }
17468
+ if (nl.anchor_side === "bottom" && /^v/i.test(text)) {
17469
+ subtree.schematic_net_label.update(nl.schematic_net_label_id, {
17470
+ symbol_name: "rail_up"
17471
+ });
17359
17472
  }
17360
- return port.name;
17361
- }).filter((value) => value !== null)
17362
- ).filter((group) => group.length > 0);
17363
- return mapped.length > 0 ? mapped : void 0;
17364
- };
17365
- var inflateSourceChip = (sourceElm, inflatorContext) => {
17366
- const { injectionDb, subcircuit, groupsMap } = inflatorContext;
17367
- const pcbElm = injectionDb.pcb_component.getWhere({
17368
- source_component_id: sourceElm.source_component_id
17369
- });
17370
- const schematicElm = injectionDb.schematic_component.getWhere({
17371
- source_component_id: sourceElm.source_component_id
17372
- });
17373
- const cadElm = injectionDb.cad_component.getWhere({
17374
- source_component_id: sourceElm.source_component_id
17375
- });
17376
- const internallyConnectedPins = mapInternallyConnectedSourcePortIdsToPinLabels(
17377
- sourceElm.internally_connected_source_port_ids,
17378
- inflatorContext
17379
- );
17380
- const footprinterString = cadElm?.footprinter_string ?? null;
17381
- const chip = new Chip({
17382
- name: sourceElm.name,
17383
- manufacturerPartNumber: sourceElm.manufacturer_part_number,
17384
- supplierPartNumbers: sourceElm.supplier_part_numbers ?? void 0,
17385
- pinLabels: schematicElm?.port_labels ?? void 0,
17386
- schWidth: schematicElm?.size?.width,
17387
- schHeight: schematicElm?.size?.height,
17388
- schPinSpacing: schematicElm?.pin_spacing,
17389
- schX: schematicElm?.center?.x,
17390
- schY: schematicElm?.center?.y,
17391
- layer: pcbElm?.layer,
17392
- pcbX: pcbElm?.center?.x,
17393
- pcbY: pcbElm?.center?.y,
17394
- pcbRotation: pcbElm?.rotation,
17395
- doNotPlace: pcbElm?.do_not_place,
17396
- obstructsWithinBounds: pcbElm?.obstructs_within_bounds,
17397
- internallyConnectedPins
17398
- });
17399
- if (footprinterString) {
17400
- Object.assign(chip.props, { footprint: footprinterString });
17401
- Object.assign(chip._parsedProps, { footprint: footprinterString });
17402
- }
17403
- if (pcbElm) {
17404
- const footprint = inflateFootprintComponent(pcbElm, {
17405
- ...inflatorContext,
17406
- normalComponent: chip
17407
- });
17408
- if (footprint) {
17409
- chip.add(footprint);
17410
17473
  }
17411
17474
  }
17412
- if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
17413
- const group = groupsMap.get(sourceElm.source_group_id);
17414
- group.add(chip);
17415
- } else {
17416
- subcircuit.add(chip);
17475
+ doInitialSimulationSpiceEngineRender() {
17476
+ Group_doInitialSimulationSpiceEngineRender(this);
17417
17477
  }
17418
- };
17419
-
17420
- // lib/components/normal-components/Diode.ts
17421
- import { diodeProps } from "@tscircuit/props";
17422
- var Diode = class extends NormalComponent3 {
17423
- get config() {
17424
- const symbolMap = {
17425
- schottky: "schottky_diode",
17426
- avalanche: "avalanche_diode",
17427
- zener: "zener_diode",
17428
- photodiode: "photodiode"
17429
- };
17430
- const variantSymbol = this.props.schottky ? "schottky" : this.props.avalanche ? "avalanche" : this.props.zener ? "zener" : this.props.photo ? "photodiode" : null;
17431
- return {
17432
- schematicSymbolName: variantSymbol ? symbolMap[variantSymbol] : this.props.symbolName ?? "diode",
17433
- componentName: "Diode",
17434
- zodProps: diodeProps,
17435
- sourceFtype: "simple_diode"
17436
- };
17478
+ /**
17479
+ * Override anchor alignment to handle group-specific logic
17480
+ */
17481
+ doInitialPcbComponentAnchorAlignment() {
17482
+ Group_doInitialPcbComponentAnchorAlignment(this);
17483
+ }
17484
+ updatePcbComponentAnchorAlignment() {
17485
+ this.doInitialPcbComponentAnchorAlignment();
17437
17486
  }
17438
- initPorts() {
17439
- super.initPorts({
17440
- additionalAliases: {
17441
- pin1: ["anode", "pos", "left"],
17442
- pin2: ["cathode", "neg", "right"]
17443
- }
17444
- });
17487
+ doInitialPcbCalcPlacementResolution() {
17488
+ Group_doInitialPcbCalcPlacementResolution(this);
17445
17489
  }
17446
- doInitialSourceRender() {
17447
- const { db } = this.root;
17448
- const { _parsedProps: props } = this;
17449
- const source_component = db.source_component.insert({
17450
- ftype: "simple_diode",
17451
- name: this.name,
17452
- manufacturer_part_number: props.manufacturerPartNumber ?? props.mfn,
17453
- supplier_part_numbers: props.supplierPartNumbers,
17454
- are_pins_interchangeable: false,
17455
- display_name: props.displayName
17456
- });
17457
- this.source_component_id = source_component.source_component_id;
17490
+ updatePcbCalcPlacementResolution() {
17491
+ this.doInitialPcbCalcPlacementResolution();
17458
17492
  }
17459
- pos = this.portMap.pin1;
17460
- anode = this.portMap.pin1;
17461
- neg = this.portMap.pin2;
17462
- cathode = this.portMap.pin2;
17463
- };
17464
-
17465
- // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceDiode.ts
17466
- function inflateSourceDiode(sourceElm, inflatorContext) {
17467
- const { injectionDb, subcircuit, groupsMap } = inflatorContext;
17468
- const pcbElm = injectionDb.pcb_component.getWhere({
17469
- source_component_id: sourceElm.source_component_id
17470
- });
17471
- const cadElm = injectionDb.cad_component.getWhere({
17472
- source_component_id: sourceElm.source_component_id
17473
- });
17474
- const diode = new Diode({
17475
- name: sourceElm.name,
17476
- layer: pcbElm?.layer,
17477
- pcbX: pcbElm?.center?.x,
17478
- pcbY: pcbElm?.center?.y,
17479
- pcbRotation: pcbElm?.rotation,
17480
- doNotPlace: pcbElm?.do_not_place,
17481
- obstructsWithinBounds: pcbElm?.obstructs_within_bounds
17482
- });
17483
- if (pcbElm) {
17484
- const footprint = inflateFootprintComponent(pcbElm, {
17485
- ...inflatorContext,
17486
- normalComponent: diode
17487
- });
17488
- if (footprint) {
17489
- diode.add(footprint);
17490
- }
17493
+ /**
17494
+ * Get the minimum flex container size for this group on PCB
17495
+ */
17496
+ _getMinimumFlexContainerSize() {
17497
+ return super._getMinimumFlexContainerSize();
17491
17498
  }
17492
- if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) {
17493
- const group = groupsMap.get(sourceElm.source_group_id);
17494
- group.add(diode);
17495
- } else {
17496
- subcircuit.add(diode);
17499
+ /**
17500
+ * Reposition this group on the PCB to the specified coordinates
17501
+ */
17502
+ _repositionOnPcb(position) {
17503
+ return super._repositionOnPcb(position);
17497
17504
  }
17498
- }
17505
+ };
17499
17506
 
17500
17507
  // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceGroup.ts
17501
17508
  function inflateSourceGroup(sourceGroup, inflatorContext) {
@@ -18039,100 +18046,6 @@ var inflateCircuitJson = (target, circuitJson, children) => {
18039
18046
  inflateStandalonePcbPrimitives(inflationCtx);
18040
18047
  };
18041
18048
 
18042
- // lib/components/normal-components/Board.ts
18043
- import {
18044
- checkEachPcbPortConnectedToPcbTraces,
18045
- checkEachPcbTraceNonOverlapping,
18046
- checkPcbComponentsOutOfBoard,
18047
- checkPcbTracesOutOfBoard,
18048
- checkDifferentNetViaSpacing,
18049
- checkSameNetViaSpacing,
18050
- checkPcbComponentOverlap,
18051
- checkPinMustBeConnected
18052
- } from "@tscircuit/checks";
18053
- import { getBoundsFromPoints as getBoundsFromPoints4 } from "@tscircuit/math-utils";
18054
- import { compose as compose7, translate as translate7 } from "transformation-matrix";
18055
-
18056
- // lib/components/primitive-components/Group/Subcircuit_getSubcircuitPropHash.ts
18057
- var EXCLUDED_PROPS = /* @__PURE__ */ new Set([
18058
- "name",
18059
- "key",
18060
- "pcbX",
18061
- "pcbY",
18062
- "schX",
18063
- "schY",
18064
- "pcbLeftEdgeX",
18065
- "pcbRightEdgeX",
18066
- "pcbTopEdgeY",
18067
- "pcbBottomEdgeY",
18068
- "pcbRotation",
18069
- "schRotation"
18070
- ]);
18071
- function safeSerialize(value, seen = /* @__PURE__ */ new WeakSet()) {
18072
- if (value === null) return "null";
18073
- if (value === void 0) return "undefined";
18074
- const type = typeof value;
18075
- if (type === "string") return `"${value}"`;
18076
- if (type === "number" || type === "boolean") return String(value);
18077
- if (type === "function") return "[function]";
18078
- if (type === "symbol") return "[symbol]";
18079
- if (type === "object") {
18080
- if (seen.has(value)) return "[circular]";
18081
- seen.add(value);
18082
- if (value.$$typeof !== void 0) {
18083
- const elementType = typeof value.type === "string" ? value.type : value.type?.name || "[component]";
18084
- const propsStr = value.props ? safeSerialize(value.props, seen) : "{}";
18085
- return `ReactElement(${elementType},${propsStr})`;
18086
- }
18087
- if (Array.isArray(value)) {
18088
- const items = value.map((v) => safeSerialize(v, seen)).join(",");
18089
- return `[${items}]`;
18090
- }
18091
- const keys = Object.keys(value).sort();
18092
- const pairs3 = keys.map((k) => `${k}:${safeSerialize(value[k], seen)}`);
18093
- return `{${pairs3.join(",")}}`;
18094
- }
18095
- return String(value);
18096
- }
18097
- function getHashableProps(props) {
18098
- const result = {};
18099
- const keys = Object.keys(props).sort();
18100
- for (const key of keys) {
18101
- if (!EXCLUDED_PROPS.has(key) && props[key] !== void 0) {
18102
- result[key] = props[key];
18103
- }
18104
- }
18105
- return result;
18106
- }
18107
- function getChildrenHashData(children) {
18108
- return children.map((child) => ({
18109
- componentName: child.componentName,
18110
- props: getHashableProps(child.props ?? {}),
18111
- children: getChildrenHashData(child.children)
18112
- }));
18113
- }
18114
- function fnv1aHash(str) {
18115
- let hash = 2166136261;
18116
- for (let i = 0; i < str.length; i++) {
18117
- hash ^= str.charCodeAt(i);
18118
- hash = Math.imul(hash, 16777619);
18119
- }
18120
- return hash >>> 0;
18121
- }
18122
- function computeHash(data) {
18123
- const serialized = safeSerialize(data);
18124
- const hash1 = fnv1aHash(serialized);
18125
- const hash2 = fnv1aHash(serialized + hash1.toString());
18126
- return hash1.toString(16).padStart(8, "0") + hash2.toString(16).padStart(8, "0");
18127
- }
18128
- function Subcircuit_getSubcircuitPropHash(subcircuit) {
18129
- const hashableData = {
18130
- props: getHashableProps(subcircuit.props ?? {}),
18131
- children: getChildrenHashData(subcircuit.children)
18132
- };
18133
- return computeHash(hashableData);
18134
- }
18135
-
18136
18049
  // lib/IsolatedCircuit.ts
18137
18050
  import { su as su5 } from "@tscircuit/circuit-json-util";
18138
18051
  import Debug14 from "debug";
@@ -18143,7 +18056,7 @@ import { identity as identity5 } from "transformation-matrix";
18143
18056
  var package_default = {
18144
18057
  name: "@tscircuit/core",
18145
18058
  type: "module",
18146
- version: "0.0.1066",
18059
+ version: "0.0.1068",
18147
18060
  types: "dist/index.d.ts",
18148
18061
  main: "dist/index.js",
18149
18062
  module: "dist/index.js",
@@ -18176,8 +18089,8 @@ var package_default = {
18176
18089
  "@resvg/resvg-js": "^2.6.2",
18177
18090
  "@tscircuit/alphabet": "0.0.18",
18178
18091
  "@tscircuit/capacity-autorouter": "^0.0.299",
18179
- "@tscircuit/checks": "^0.0.91",
18180
- "@tscircuit/circuit-json-util": "^0.0.77",
18092
+ "@tscircuit/checks": "0.0.95",
18093
+ "@tscircuit/circuit-json-util": "^0.0.80",
18181
18094
  "@tscircuit/common": "^0.0.20",
18182
18095
  "@tscircuit/copper-pour-solver": "^0.0.20",
18183
18096
  "@tscircuit/footprinter": "^0.0.316",
@@ -18187,7 +18100,7 @@ var package_default = {
18187
18100
  "@tscircuit/math-utils": "^0.0.29",
18188
18101
  "@tscircuit/miniflex": "^0.0.4",
18189
18102
  "@tscircuit/ngspice-spice-engine": "^0.0.8",
18190
- "@tscircuit/props": "^0.0.484",
18103
+ "@tscircuit/props": "^0.0.485",
18191
18104
  "@tscircuit/schematic-match-adapt": "^0.0.16",
18192
18105
  "@tscircuit/schematic-trace-solver": "^v0.0.45",
18193
18106
  "@tscircuit/solver-utils": "^0.0.3",
@@ -18207,7 +18120,7 @@ var package_default = {
18207
18120
  "circuit-json-to-gltf": "^0.0.73",
18208
18121
  "circuit-json-to-simple-3d": "^0.0.9",
18209
18122
  "circuit-json-to-spice": "^0.0.34",
18210
- "circuit-to-svg": "^0.0.331",
18123
+ "circuit-to-svg": "^0.0.333",
18211
18124
  concurrently: "^9.1.2",
18212
18125
  "connectivity-map": "^1.0.0",
18213
18126
  debug: "^4.3.6",
@@ -18321,6 +18234,7 @@ var IsolatedCircuit = class {
18321
18234
  this.platform = platform;
18322
18235
  this.projectUrl = projectUrl;
18323
18236
  this.pcbDisabled = platform?.pcbDisabled ?? false;
18237
+ this.pcbRoutingDisabled = platform?.routingDisabled ?? false;
18324
18238
  this.cachedSubcircuits = cachedSubcircuits;
18325
18239
  this.pendingSubcircuitRenders = pendingSubcircuitRenders;
18326
18240
  this.root = this;
@@ -18339,6 +18253,12 @@ var IsolatedCircuit = class {
18339
18253
  ...this.platform,
18340
18254
  ...platform
18341
18255
  };
18256
+ if (platform.pcbDisabled !== void 0) {
18257
+ this.pcbDisabled = platform.pcbDisabled;
18258
+ }
18259
+ if (platform.routingDisabled !== void 0) {
18260
+ this.pcbRoutingDisabled = platform.routingDisabled;
18261
+ }
18342
18262
  }
18343
18263
  /**
18344
18264
  * Get the main board for this Circuit.
@@ -18593,6 +18513,86 @@ function Subcircuit_doInitialRenderIsolatedSubcircuits(subcircuit) {
18593
18513
  });
18594
18514
  }
18595
18515
 
18516
+ // lib/components/primitive-components/Group/Subcircuit_getSubcircuitPropHash.ts
18517
+ var EXCLUDED_PROPS = /* @__PURE__ */ new Set([
18518
+ "name",
18519
+ "key",
18520
+ "pcbX",
18521
+ "pcbY",
18522
+ "schX",
18523
+ "schY",
18524
+ "pcbLeftEdgeX",
18525
+ "pcbRightEdgeX",
18526
+ "pcbTopEdgeY",
18527
+ "pcbBottomEdgeY",
18528
+ "pcbRotation",
18529
+ "schRotation"
18530
+ ]);
18531
+ function safeSerialize(value, seen = /* @__PURE__ */ new WeakSet()) {
18532
+ if (value === null) return "null";
18533
+ if (value === void 0) return "undefined";
18534
+ const type = typeof value;
18535
+ if (type === "string") return `"${value}"`;
18536
+ if (type === "number" || type === "boolean") return String(value);
18537
+ if (type === "function") return "[function]";
18538
+ if (type === "symbol") return "[symbol]";
18539
+ if (type === "object") {
18540
+ if (seen.has(value)) return "[circular]";
18541
+ seen.add(value);
18542
+ if (value.$$typeof !== void 0) {
18543
+ const elementType = typeof value.type === "string" ? value.type : value.type?.name || "[component]";
18544
+ const propsStr = value.props ? safeSerialize(value.props, seen) : "{}";
18545
+ return `ReactElement(${elementType},${propsStr})`;
18546
+ }
18547
+ if (Array.isArray(value)) {
18548
+ const items = value.map((v) => safeSerialize(v, seen)).join(",");
18549
+ return `[${items}]`;
18550
+ }
18551
+ const keys = Object.keys(value).sort();
18552
+ const pairs3 = keys.map((k) => `${k}:${safeSerialize(value[k], seen)}`);
18553
+ return `{${pairs3.join(",")}}`;
18554
+ }
18555
+ return String(value);
18556
+ }
18557
+ function getHashableProps(props) {
18558
+ const result = {};
18559
+ const keys = Object.keys(props).sort();
18560
+ for (const key of keys) {
18561
+ if (!EXCLUDED_PROPS.has(key) && props[key] !== void 0) {
18562
+ result[key] = props[key];
18563
+ }
18564
+ }
18565
+ return result;
18566
+ }
18567
+ function getChildrenHashData(children) {
18568
+ return children.map((child) => ({
18569
+ componentName: child.componentName,
18570
+ props: getHashableProps(child.props ?? {}),
18571
+ children: getChildrenHashData(child.children)
18572
+ }));
18573
+ }
18574
+ function fnv1aHash(str) {
18575
+ let hash = 2166136261;
18576
+ for (let i = 0; i < str.length; i++) {
18577
+ hash ^= str.charCodeAt(i);
18578
+ hash = Math.imul(hash, 16777619);
18579
+ }
18580
+ return hash >>> 0;
18581
+ }
18582
+ function computeHash(data) {
18583
+ const serialized = safeSerialize(data);
18584
+ const hash1 = fnv1aHash(serialized);
18585
+ const hash2 = fnv1aHash(serialized + hash1.toString());
18586
+ return hash1.toString(16).padStart(8, "0") + hash2.toString(16).padStart(8, "0");
18587
+ }
18588
+ function Subcircuit_getSubcircuitPropHash(subcircuit) {
18589
+ const hashableData = {
18590
+ props: getHashableProps(subcircuit.props ?? {}),
18591
+ children: getChildrenHashData(subcircuit.children)
18592
+ };
18593
+ return computeHash(hashableData);
18594
+ }
18595
+
18596
18596
  // lib/components/normal-components/Board.ts
18597
18597
  var MIN_EFFECTIVE_BORDER_RADIUS_MM = 0.01;
18598
18598
  var getRoundedRectOutline = (width, height, radius) => {
@@ -18653,6 +18653,7 @@ var Board = class extends Group6 {
18653
18653
  pcb_board_id = null;
18654
18654
  source_board_id = null;
18655
18655
  _drcChecksComplete = false;
18656
+ _drcChecksInProgress = false;
18656
18657
  _connectedSchematicPortPairs = /* @__PURE__ */ new Set();
18657
18658
  _panelPositionOffset = null;
18658
18659
  get isSubcircuit() {
@@ -18967,53 +18968,53 @@ var Board = class extends Group6 {
18967
18968
  }
18968
18969
  doInitialPcbDesignRuleChecks() {
18969
18970
  if (this.root?.pcbDisabled) return;
18970
- if (this.getInheritedProperty("routingDisabled")) return;
18971
18971
  super.doInitialPcbDesignRuleChecks();
18972
+ this.updatePcbDesignRuleChecks();
18972
18973
  }
18973
18974
  updatePcbDesignRuleChecks() {
18974
- if (this.root?.pcbDisabled) return;
18975
- if (this.getInheritedProperty("routingDisabled")) return;
18976
18975
  const { db } = this.root;
18977
- if (!this._areChildSubcircuitsRouted()) return;
18978
- if (this._drcChecksComplete) return;
18979
- const runDrcChecks = (circuitJson) => {
18980
- const pcbTraceOverlappingErrors = checkEachPcbTraceNonOverlapping(circuitJson);
18981
- for (const error of pcbTraceOverlappingErrors) {
18982
- db.pcb_trace_error.insert(error);
18983
- }
18984
- const pcbPortNotConnectedErrors = checkEachPcbPortConnectedToPcbTraces(circuitJson);
18985
- for (const error of pcbPortNotConnectedErrors) {
18986
- db.pcb_port_not_connected_error.insert(error);
18987
- }
18988
- const pcbComponentOutsideErrors = checkPcbComponentsOutOfBoard(circuitJson);
18989
- for (const error of pcbComponentOutsideErrors) {
18990
- db.pcb_component_outside_board_error.insert(error);
18991
- }
18992
- const pcbTracesOutOfBoardErrors = checkPcbTracesOutOfBoard(circuitJson);
18993
- for (const error of pcbTracesOutOfBoardErrors) {
18994
- db.pcb_trace_error.insert(error);
18995
- }
18996
- const differentNetViaErrors = checkDifferentNetViaSpacing(circuitJson);
18997
- for (const error of differentNetViaErrors) {
18998
- db.pcb_via_clearance_error.insert(error);
18999
- }
19000
- const sameNetViaErrors = checkSameNetViaSpacing(circuitJson);
19001
- for (const error of sameNetViaErrors) {
19002
- db.pcb_via_clearance_error.insert(error);
18976
+ const routingDisabled = this.root?.pcbRoutingDisabled || this.getInheritedProperty("routingDisabled");
18977
+ const pcbDisabled = this.root?.pcbDisabled;
18978
+ const shouldRunNetlistChecks = true;
18979
+ const shouldRunPlacementChecks = !pcbDisabled;
18980
+ const shouldRunRoutingChecks = !pcbDisabled && !routingDisabled;
18981
+ if (shouldRunRoutingChecks && this._hasIncompleteAsyncEffectsInSubtreeForPhase("PcbTraceRender"))
18982
+ return;
18983
+ const hasTracesToRoute = this._hasTracesToRoute();
18984
+ if (shouldRunRoutingChecks && hasTracesToRoute && !this._areChildSubcircuitsRouted())
18985
+ return;
18986
+ if (this._drcChecksComplete || this._drcChecksInProgress) return;
18987
+ const runDrcChecks = async (circuitJson) => {
18988
+ const checksToRun = [];
18989
+ if (shouldRunRoutingChecks) {
18990
+ checksToRun.push(
18991
+ runAllRoutingChecks(circuitJson)
18992
+ );
19003
18993
  }
19004
- const pcbComponentOverlapErrors = checkPcbComponentOverlap(circuitJson);
19005
- for (const error of pcbComponentOverlapErrors) {
19006
- db.pcb_footprint_overlap_error.insert(error);
18994
+ if (shouldRunPlacementChecks) {
18995
+ checksToRun.push(
18996
+ runAllPlacementChecks(circuitJson)
18997
+ );
19007
18998
  }
19008
- const sourcePinMustBeConnectedErrors = checkPinMustBeConnected(circuitJson);
19009
- for (const error of sourcePinMustBeConnectedErrors) {
19010
- db.source_pin_must_be_connected_error.insert(error);
18999
+ if (shouldRunNetlistChecks) {
19000
+ checksToRun.push(
19001
+ runAllNetlistChecks(circuitJson)
19002
+ );
19011
19003
  }
19004
+ const checkResults = await Promise.all(checksToRun);
19005
+ db.insertAll(checkResults.flat());
19012
19006
  };
19013
19007
  const subcircuit = db.subtree({ subcircuit_id: this.subcircuit_id });
19014
19008
  const subcircuitCircuitJson = subcircuit.toArray();
19015
- runDrcChecks(subcircuitCircuitJson);
19016
- this._drcChecksComplete = true;
19009
+ this._drcChecksInProgress = true;
19010
+ this._queueAsyncEffect("board:drc-checks", async () => {
19011
+ try {
19012
+ await runDrcChecks(subcircuitCircuitJson);
19013
+ this._drcChecksComplete = true;
19014
+ } finally {
19015
+ this._drcChecksInProgress = false;
19016
+ }
19017
+ });
19017
19018
  }
19018
19019
  _emitRenderLifecycleEvent(phase, startOrEnd) {
19019
19020
  super._emitRenderLifecycleEvent(phase, startOrEnd);