Skip to content

Add automatic breadboard component placement and routing - #4323

Draft
justin-romano wants to merge 4 commits into
fritzing:developfrom
justin-romano:breadboard-autorouter-improvements
Draft

Add automatic breadboard component placement and routing#4323
justin-romano wants to merge 4 commits into
fritzing:developfrom
justin-romano:breadboard-autorouter-improvements

Conversation

@justin-romano

Copy link
Copy Markdown

Summary

Adds automatic component placement and jumper-wire routing to Fritzing's Breadboard view.

The autorouter:

  • discovers breadboard buses from actual connector topology;
  • supports mini, full-size, and multiple breadboards;
  • places compatible components while leaving peripherals off-board;
  • rejects overlaps and same-bus shorts;
  • routes external parts through breadboard connection points;
  • prioritizes completed nets, fewer jumpers, shorter jumpers, then shorter component leads;
  • provides progress and cancellation;
  • records the operation as a single Undo action.

Implementation

  • BreadboardTopology models holes and electrically connected buses.
  • BreadboardPartPolicy classifies placeable, peripheral, and ignored parts.
  • BreadboardPlacementKernel uses spatial indexing to reduce placement-search cost.
  • BreadboardRouteGraphCore provides deterministic graph routing independent of the GUI.
  • Placement ownership is reseeded after component movement.
  • Routing supports multiple target breadboards.
  • The Breadboard toolbar exposes autorouting and placement-tuning controls.

Validation

  • Added route-graph unit and conformance tests.
  • Added routing-score tests and benchmark tooling.
  • Built successfully with MSVC 2022 and Qt 6.5.3.
  • Tested with mini and multiple breadboards.
  • Tested rerouting, cancellation, Undo, peripheral wiring, and saved Fritzing sketches.
  • Verified that breadboard autorouting does not alter schematic connectivity.

Optimization priorities

  1. Complete all electrical nets.
  2. Minimize jumper count.
  3. Minimize total jumper length.
  4. Minimize component-lead length and improve lead geometry.

Limitations

Placement and routing use deterministic heuristics and do not guarantee a globally optimal result. Parts with incomplete or unusual breadboard connector geometry may remain unplaced.

Add deterministic, topology-aware component placement with spatial indexing, multi-board support, route graph optimization, progress reporting, and automated routing tests.

Update the README to mention automatic breadboard placement and routing.
@justin-romano

Copy link
Copy Markdown
Author

cc @KjellMorgenstern - I would value your guidance on whether this is the right direction for Breadboard view integration, especially given the scope of the placement/routing changes.

@KjellMorgenstern

Copy link
Copy Markdown
Member

You might want to discuss or at least analyze and explain the use case.
Is this an experiment you found interesting? Or does it solve a problem you frequently encounter? Can you reference requests similar to this from other users, open issues or existing discussions in the forum?

Disclaimer: We already have quite a number of exiting improvements and features of similar complexity, that we will hopfully manage to land in one of the next Fritzing releases.

@justin-romano

Copy link
Copy Markdown
Author

Fixing coding issues now.

justin-romano and others added 2 commits July 18, 2026 12:29
PR 4323 analysis flagged 115 issues; this clears the mechanical rules:
- S1121: no assignments inside expressions (split chained assignments,
  incl. pre-existing MainWindow initializer chains our diff touched)
- S6004: C++17 if-init declarations where a variable only feeds the if
- S995/S5350: pointer-to-const parameters and locals
- S5945: std::array instead of C-style arrays
- S6012: CTAD (QList, not QVector - alias templates lack CTAD in C++17)
- S3358: unnested conditional operator (bendable swap mode)
- S924: single break in the legacy bus Dijkstra loop
- S886: std::iota for union-find parent initialisation

No behaviour change intended; Boost suites green (5 + 12 cases).
Remaining Sonar work tracked separately: structural rules (S134, S3776,
S1820, S1448) and the C++20/Qt-idiom dismissals (S6197, S6177, S6187,
S5025).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@justin-romano

justin-romano commented Jul 18, 2026 via email

Copy link
Copy Markdown
Author

@KjellMorgenstern

Copy link
Copy Markdown
Member

The email only came through half. Again, could you describe the use case?

@KjellMorgenstern

Copy link
Copy Markdown
Member

I ran a first test

  1. Load ArduinoISP example
  2. Remove the populated breadboard, the second breadboard remains and is clean, virtual wires now mark the connections.
  3. Autoroute
image

Correctness issues:

  • switch not placed on bb
  • routing corruptions on Arduino, Switch and BB (Fritzing 1.0.7 in debug mode would turn the background red to indicate the issue, future release will show friendly bugs like in the screenshot). The checker is alreay in Fritzing since a few years. It is a debugging tool, to detect corrupted routing databases from old Fritzing sketches, broken parts, or (new?) bugs like in this case. The tool is rough. It only compares against schematic, and doesn't check breadboard vs PCB. There might be some edge cases with busses and subparts that are not yet covered by the tool.
    This is the log:

"debug connectors do"
"Connectors with id: connector3 for item: RESET1 have differing QSets. Schema{Wire1203:connector0} BB{Wire1203:connector0,Wire2356:connector0}"
"Connectors with id: connector0 for item: RESET1 have differing QSets. Schema{Wire1300:connector1} BB{Wire1300:connector1,Wire2366:connector0}"
"Connectors with id: connector1 for item: RESET1 have differing QSets. Schema{Wire2290:connector1} BB{Wire2290:connector1,Wire2367:connector0}"
"Connectors with id: connector2 for item: RESET1 have differing QSets. Schema{Wire2291:connector1} BB{Wire2291:connector1,Wire2355:connector0}"
"Connectors with id: connector55 for item: Arduino1 have differing QSets. Schema{Wire1274:connector1,Wire1747:connector0} BB{Wire1274:connector1,Wire1747:connector0,Wire2370:connector0}"
"Connectors with id: connector88 for item: Arduino1 have differing QSets. Schema{} BB{Wire2358:connector0}"
"Connectors with id: connector52 for item: Arduino1 have differing QSets. Schema{Wire1026:connector0,Wire1763:connector1} BB{Wire1026:connector0,Wire1763:connector1,Wire2374:connector0}"
"Connectors with id: connector60 for item: Arduino1 have differing QSets. Schema{} BB{Wire2376:connector0}"
"Connectors with id: connector5 for item: Arduino1 have differing QSets. Schema{} BB{Wire2375:connector0}"
"Connectors with id: connector53 for item: Arduino1 have differing QSets. Schema{Wire1080:connector0,Wire2230:connector0} BB{Wire1080:connector0,Wire2230:connector0,Wire2368:connector0}"
"Connectors with id: connector68 for item: Arduino1 have differing QSets. Schema{Wire1017:connector0,Wire1759:connector0} BB{Wire1017:connector0,Wire1759:connector0,Wire2373:connector0}"
"Connectors with id: connector51 for item: Arduino1 have differing QSets. Schema{Wire1023:connector0,Wire1761:connector0} BB{Wire1023:connector0,Wire1761:connector0,Wire2372:connector0}"
"Connectors with id: connector59 for item: Arduino1 have differing QSets. Schema{} BB{Wire2379:connector0}"
"Connectors with id: connector4 for item: Arduino1 have differing QSets. Schema{} BB{Wire2378:connector0}"
"Connectors with id: connector89 for item: Arduino1 have differing QSets. Schema{Wire1182:connector0,Wire1207:connector0,Wire1629:connector0} BB{Wire1182:connector0,Wire1207:connector0,Wire1629:connector0,Wire2359:connector0}"
"Connectors with id: connector57 for item: Arduino1 have differing QSets. Schema{} BB{Wire2357:connector0}"
"Connectors with id: connector54 for item: Arduino1 have differing QSets. Schema{Wire1275:connector1,Wire1746:connector0} BB{Wire1275:connector1,Wire1746:connector0,Wire2369:connector0}"
"Connectors with id: connector87 for item: Arduino1 have differing QSets. Schema{Wire1296:connector0,Wire1734:connector0} BB{Wire1296:connector0,Wire1734:connector0,Wire2363:connector0}"
"Connectors with id: connector56 for item: Arduino1 have differing QSets. Schema{Wire1273:connector1,Wire1748:connector0} BB{Wire1273:connector1,Wire1748:connector0,Wire2371:connector0}"
"Connectors with id: pin8A for item: Breadboard1 have differing QSets. Schema{} BB{Wire2368:connector1}"
"Connectors with id: pin15B for item: Breadboard1 have differing QSets. Schema{} BB{Wire2361:connector0}"
"Connectors with id: pin15E for item: Breadboard1 have differing QSets. Schema{ATMEGA1:connector7} BB{ATMEGA1:connector7,Wire2360:connector0}"
"Connectors with id: pin2F for item: Breadboard1 have differing QSets. Schema{} BB{Wire2378:connector1}"
"Connectors with id: pin1F for item: Breadboard1 have differing QSets. Schema{} BB{Wire2375:connector1}"
"Connectors with id: pin19J for item: Breadboard1 have differing QSets. Schema{} BB{Wire2369:connector1}"
"Connectors with id: pin14J for item: Breadboard1 have differing QSets. Schema{} BB{Wire2355:connector1}"
"Connectors with id: pin18J for item: Breadboard1 have differing QSets. Schema{} BB{Wire2370:connector1}"
"Connectors with id: pin14E for item: Breadboard1 have differing QSets. Schema{ATMEGA1:connector6} BB{ATMEGA1:connector6,Wire2364:connector1}"
"Connectors with id: pin14F for item: Breadboard1 have differing QSets. Schema{ATMEGA1:connector21} BB{ATMEGA1:connector21,Wire2360:connector1}"
"Connectors with id: pin14H for item: Breadboard1 have differing QSets. Schema{} BB{Wire2356:connector1}"
"Connectors with id: pin24A for item: Breadboard1 have differing QSets. Schema{} BB{Wire2365:connector1}"
"Connectors with id: pin16J for item: Breadboard1 have differing QSets. Schema{} BB{Wire2363:connector1}"
"Connectors with id: pin24I for item: Breadboard1 have differing QSets. Schema{} BB{Wire2379:connector1}"
"Connectors with id: pin17J for item: Breadboard1 have differing QSets. Schema{} BB{Wire2371:connector1}"
"Connectors with id: pin15C for item: Breadboard1 have differing QSets. Schema{} BB{Wire2359:connector1}"
"Connectors with id: pin14G for item: Breadboard1 have differing QSets. Schema{} BB{Wire2357:connector1}"
"Connectors with id: pin26C for item: Breadboard1 have differing QSets. Schema{} BB{Wire2362:connector1}"
"Connectors with id: pin24G for item: Breadboard1 have differing QSets. Schema{} BB{Wire2380:connector1}"
"Connectors with id: pin16A for item: Breadboard1 have differing QSets. Schema{} BB{Wire2365:connector0}"
"Connectors with id: pin22J for item: Breadboard1 have differing QSets. Schema{} BB{Wire2374:connector1}"
"Connectors with id: pin2G for item: Breadboard1 have differing QSets. Schema{} BB{Wire2380:connector0}"
"Connectors with id: pin23J for item: Breadboard1 have differing QSets. Schema{} BB{Wire2376:connector1}"
"Connectors with id: pin1H for item: Breadboard1 have differing QSets. Schema{} BB{Wire2377:connector0}"
"Connectors with id: pin23H for item: Breadboard1 have differing QSets. Schema{} BB{Wire2377:connector1}"
"Connectors with id: pin7J for item: Breadboard1 have differing QSets. Schema{} BB{Wire2373:connector1}"
"Connectors with id: pin16F for item: Breadboard1 have differing QSets. Schema{ATMEGA1:connector19} BB{ATMEGA1:connector19,Wire2364:connector0}"
"Connectors with id: pin8B for item: Breadboard1 have differing QSets. Schema{} BB{Wire2367:connector1}"
"Connectors with id: pin7E for item: Breadboard1 have differing QSets. Schema{} BB{Wire2372:connector1}"
"Connectors with id: pin25B for item: Breadboard1 have differing QSets. Schema{R8:connector1} BB{R8:connector1,Wire2361:connector1}"
"Connectors with id: pin8D for item: Breadboard1 have differing QSets. Schema{} BB{Wire2366:connector1}"
"Connectors with id: pin15D for item: Breadboard1 have differing QSets. Schema{} BB{Wire2358:connector1}"
"Connectors with id: pin17C for item: Breadboard1 have differing QSets. Schema{} BB{Wire2362:connector0}"
"debug wires do"

@justin-romano

Copy link
Copy Markdown
Author

Good catch. Just what I need to clear these issues.
The auto router relies on metrics in the parts to decide BB compatibility. So will tweak that.
Are there any good sample fzz files I can use that will really test the limits of my auto router?

@justin-romano

Copy link
Copy Markdown
Author

The email only came through half. Again, could you describe the use case?

The intended use case is:

  1. A user has created a relatively complex schematic and wants to build and test it on a breadboard before committing to a PCB design.
  2. They switch to Breadboard View and are presented with an unstructured arrangement of components and a large number of unrouted connections.
  3. They must then manually position every component and determine an efficient routing layout. This can be time-consuming, and inefficient placement increases the number of jumper wires, awkward connections, and the likelihood of wiring mistakes when assembling the physical breadboard.
  4. The user selects the breadboard autorouter, which automatically arranges the components and routes the connections into a practical breadboard layout.

The goal is to remove the most laborious part of translating a schematic into a physical breadboard prototype, while also reducing wiring complexity and the potential for assembly errors.

@KjellMorgenstern

Copy link
Copy Markdown
Member

Please strictly isolate the AI from posting here. I'll have to keep my responses to a minimum. The OP should be the human in the loop, not me.

@justin-romano

Copy link
Copy Markdown
Author

Sorry. Did Claude do that? I do not recall posting those obviously automated agent comments.
Only the use case which was me. The human version this time 😅

@justin-romano

Copy link
Copy Markdown
Author

Did you agree with the uses case? I'm knew this feature was missing years ago, and was going to do something about it but had no time. These days I'm a bit faster at writing 3000 lines of C++. Not vibed. Very steered.

@justin-titanium

Copy link
Copy Markdown

@KjellMorgenstern. I have those fixes in my clone. Ran out of time. Will push next weekend.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants