Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • jllemur813/roco_electrical
1 result
Show changes
Showing
with 2097 additions and 29 deletions
#!/usr/bin/env python
import numpy as np
import ezdxf
import random
from math import sqrt
import copy
from LayoutEditor import LayoutScript
from LayoutScript import *
l=project.newLayout();
#rename a layer
layers.num(6).name="new text"
c=l.drawing.currentCell
c.cellName="test-cell-python"
c.addBox(0,0,5000,7000,5)
c.addRoundedBox(10000,0,5000,7000,500,5)
c.addChamferedBox(20000,0,5000,7000,500,5)
c.addCircleBox(point(0,10000),point(5000,17000),5)
c.addEllipse(5,point(12500,15000),2500,3500)
c.addPolygonArc(point(22500,15000),2500,3500,0,340,5)
e=c.addText(5,point(25,25000),layers.num(6).name)
e.setWidth(1000)
l.drawing.saveFile("/home/jingyan/Documents/summer_intern_lemur/roco_electrical/testout.dsn")
print("Python script completed")
\ No newline at end of file
### Jingyan Ling
### until 09/03/2019
- Testing on physical prototype
- Fabrication process
- ![](journal_media/fab_process.png)
- Result from cutter
- ![](journal_media/fab_result.png)
- Test before fully folding the robot
- ![](journal_media/test_before_fullyfold.png)
- Appearance after fully folded
- ![](journal_media/fully_folded_paperbot.png)
### 08/29/2019
- Fixing issues:
- better performance with multiple wires connecting to single pin
- changed a lot details in `drawing_processing` script:
- `pop` for endpoints at each wire will be executed before parallel traces
- `pop` and whether the point is connected to a pin is based a rule more restricted so even the wire does not connect to a pin without 0, 90 or 45 degree, it will still pop correctly
- Complete design for demo that has paperbot with an IMU, a touch sensor connecting to LED and Resistor
- ![](journal_media/demo_design.png)
- Fixing `inkscape` unit and scale issue:
- Save as svg
- Select every entities in the drawing
- Lock the width and height scale
- Times (90/96) to either height or width
### 08/28/2019
- Solving issue:
- The way mark pin as connected pin (solved)
- Changed way reading path
- Connect wire directly to pin after remove redundant small wires
- Group wires that has same connection point and same slop for branch drawing
- ![](journal_media/issue_solved828.png)
### 08/27/2019
- Solving issue:
- multiple wires connecting to single pin
- Partially solved by
- Merge paths through pin as a single path in `sesreader`
- If such path passes a pin, mark this pin as connected pin (partially working, fix needed)
- Add a filter that remove intervals inside a path which is shorter than 0.5mm
- TODO:
- Solve the way mark pin as connected pin
- Branch intersect sometimes is not draw correctly
- Issues screenshot:
- ![](journal_media/connected_pin_issue.png)
- ![](journal_media/branch_issue.png)
- ![](journal_media/pop_inter_issue.png)
- Current status:
- ![](journal_media/current_demo.png)
### 08/26/2019
- Fixed issue:
- `roco_dsn` now reads `flip` argument to get correct pin locations
- Solving issue in progress:
- When multiple wires are connecting to single pin. Isolation box is not draw correctly
- Have Done:
- Redo `sesreader` so paths will not be continued to merge if it reach one of the pin location
- ![](journal_media/same_pin_intersect.png)
### 08/22/2019
- Try to solve issues:
- `get_pin_loc` function takes `flip` parameter incorrectly
- a wiring path is connected to another path (fixed)
- The contact point cannot contain more than two path intervals
- ![](journal_media/branch_fix.png)
### 08/21/2019
- TODO:
- Find solution to deal with `inkscape` pixel scale bug
- Read prototype `csv` file
- Fabricate prototype
- Bug reported : (fixed)
- ![](journal_media/cross_bug_report.png)
#### Noticed Issue:
- If two wiring paths are connected to one pin, it might generate a open circuit
- If a wiring path is connected to another path instead of pin, an error will occur b/c it cannot find a pin connected to the tip of one of the path
- ![](journal_media/circuit_demo.png)
- Bug reported:
- get_pin_loc function in `roco_dsn` does not consider `flip` situation, pin read wrong if `filp='back'`
### 08/20/2019
- Add multiple cut to parallel traces, get outer and inner helper diagonal cut so the isolation will work well
- Making prototype cut from the output of software
- Issue reported:
- Footprint size and actual cut size not consistent
### 08/19/2019
- Remove the endpoint of a path if the last segment is inside the isolation box
- Rodo the loop dealing with parallel traces
- Add code that does isolation box for non-connected pin
- ![](journal_media/iso_para_done.png)
- When reading dwg file for dsn. It should know which is the boundary automatically.
- Changed internal boundary index finder, so user won't need to type the boundary line index manually. A value will be parsed from pre-process class to dsn writter.
- Merged and modified `dxf to path` function
- Changed function does bi-sector in post-processing so it can fits the way we do `line to path` successfully
- Whole process and pipeline works well now
- Building high-level functions
- Edit `sesreader` again and add a filter that removes redundant points
- TODO:
- put new drawings on dxf version >=12
- so the width of drawing lines can be changed
- Isolation box and parallel traces requires multiple parallel cut, changing width makes drawing easier to see
### 08/16/2019
- Record of Tips:
- changing the clearance defined in `dsn` file changes the rule of routing
- useful to change it according wire length and isolation box size
- This will output multiple path
- Redo `sesreader` so that it will merge paths those connect to each other
### 08/15/2019
- Solving issue: Connection between isolation box and parallel traces
~~~
input: endpoints of a path (each endpoints has i+1 for finding a line), iso_size, trace_width
output: intersect points*2 , draw isolation box in the process
input= contact_ept, further_ept, size, width
for pin_loc in all pin locations:
if the distance between endpoint1 and pin_loc is less than tolerance:
l=line(contact_ept,further_ept)
parallel_traces=find_offset(l,width)
iso_l_pts=isolation_box_linepts(size,pin_loc)
contact_list=[]
for l in parallel_traces:
contact=find_contact_iso_trace(l,iso_l_pts,further_ept)
contact_list.append(contact)
draw_list=[]
draw_list.append(contact_list[0])
while len(iso_boundary)!=0:
for points in iso_boundary:
find a point that is closest to last point of draw_list
if not such point is inside of two contacts:
draw_list.append(points)
iso_boundary.remove(point)
draw draw_list in order
return contact_list
~~~
- Connection between isolation and parallel traces solved!!!
- ![](journal_media/iso_with_para.png)
- TODO:
- Merge DXF to path code
- Issue exposed: after changing wire width, box still not quite correct
- `roco_ee_dwg_processing.py` line 132
### 08/14/2019
- Preparing software demo
- High level of whole project package
- ![](journal_media/roco_ee_highlvl.png)
- Pipeline of drawing changes
- ![](journal_media/dwg_structure.png)
- Package module and classes breakdown
- ![](journal_media/package_support.png)
- Structure of customized package `dsnwriter`
- ![](journal_media/dsnwriter_structure.png)
- Structure of customized package `roco_ee_dwg`
- ![](journal_media/roco_ee_dwg_structure.png)
- Demo Video at [here](https://youtu.be/HeBw4uW3Xzc)
- Solving issue: Connection between isolation box and parallel traces
### 08/13/2019
- Rearrange the package and draw the path directly on original drawing from old roco
- dsn module placement match:
- instead of getting pin locations from old roco. set pin location based on footprint when user place modules
- Reason:
- 1. no mechanical design needed for pins (especial will turn it to cross cut anyway)
- 2. make sure the electrical board design and drawings will always be consistent
- 3. easier to add new electrical components
- 4. easier to do drawing post processing (dealing with traces and isolation boxes)
- Completed: a cross cut will be drawn at pin locations and that is automatically read from circuit design. The package will only need to load module once when design circuit
- ![](journal_media/auto_read_and_cut.png)
- Draw isolation boxes and connect one edge with parallel traces without causing open circuit (fail)
- ![](journal_media/iso_trace_connect_fail.png)
- TODO:
- Connect traces to isolation box
- Merge pre-processing code
- Demo
### 08/12/2019
- Finally figure out geometry algorithm on paper
- Coding for parallel trace in following steps:
- 1. find start point and end point of a path, compute 4 points that vertical to end points based on width
- 2. find the angle bisector between each segment
- 3. Offset original path based on given width
- 4. find intersect between paths with offset and angle bisectors
- 5. connect intersect points and 4 end-points
- Separate file `paperbot_draw` to a general useful file `roco_ee_dwg_processing.py` and operations specifically for paperbot `paperbot_draw.py`
- functions and classes in `roco_ee_dwg_processing.py` will be useful for future foldable robot project.
- Finally complete the parallel trace drawing. Now any path exported from auto-router will draw parallel trace with desired width to make sure the copper type surface can conduct well.
- ![](journal_media/parallel_trace.png)
- TODO:
- Connect traces to isolation box
- Merge pre-processing code
- Clean up script
- Read trace width from Net Class
### 08/09/2019
- Potential problem:
- drawing pre-processing has two goals: 1. put different intensity cuts on different layers for accurate fabrication 2. make line to 4 nodes path for auto-router treating as obstacles.
- Two goal may conflict within single process
- potential solution: send 4 nodes path to auto-router and draw wiring paths on drawing with signed layers.
- Solving parallel traces math computation
### 08/08/2019
- `block` class in `ezdxf` generates symbol in `inkscape`. Check if it can be made to path from script
- ![](journal_media/cross_cut.png)
- Changed the way of drawing `cross-cut` to path directly instead of using inserting block class (see [paperbot_draw.py](paperbot_ee_autoroute/paperbot_draw.py) for detail)
- Parallel traces are not computed correctly
- ![](journal_media/parallel_trace_error.png)
### 08/07/2019
- Working on drawing details regarding fabrication for electrical design
- A block was created for 'cross cut' to fit pin insertions
- Parallel traces are hard to get
- A challenge that trimming isolation boxes with parallel traces occurs
### 08/06/2019
- Successfully parse the wiring information from `ses` file to array
- A little "hacky" way, not using any parsing package but going through string and looking for path section
- For `ses` file only
- Create new scripts and Re-arrange all packages
- User will be able to execute [fab_drawing.py](paperbot_ee_autoroute/fab_drawing.py) directly to get drawing for paperbot including electrical wiring design and ready to send to fabrication
- If user wants to change electrical connection, one can edit [paperbot_dsn.py](paperbot_ee_autoroute/paperbot_dsn.py)
- `dsnwriter` and `sesreader` source code are located [here](dsn_python/)
- New script:
- [paperbot_draw.py](paperbot_ee_autoroute/paperbot_draw.py) has two classes:
- `pre-process`
- process the mechanical design drawing to correct format that can be taken by `dsnwriter` and `autorouter`
- `post-process`
- process the drawing file and draw wires based on `ses` file generated from `autorouter`
- Milestone:
- Now user can generate `dsn` file from script and confirm auto-routing.
- A parser can pull information for wiring
- Able to draw such wiring back on `dxf` drawings
- ![](journal_media/draw_on_dxf_fromses.png)
- TODO:
- Merge pre drawing processing script with Daniel
- Details:
- add 'cross-cut' block in `ezdxf` for pin insertion cut
- add 'parallel-trace' block in` ezdxf` for circuit trace on copper tape
### 08/05/2019
- Working on parsing routed (wiring section) text information.
- Ref: [pyparsing](https://scipy-cookbook.readthedocs.io/items/Reading_Custom_Text_Files_with_Pyparsing.html)
- Parsing generated `dsn` file back to `DSN` class
- Fail
- Parsing generated `kicad_pcb` file back to `pykicad` package - `pcb` class
- Success
- Working on:
- debug dsn library so it can read file.
- `pykicad` uses `pyparsing` internally
- Rebuild `ses` file schema. Not working well
### 08/01/2019
- Scripting Auto-router from python
- Run `.jar` package through python
- Can open GUI with imported file
- Cannot run auto-routing function from script
- Manually click on auto-routing and save is needed (manual approval)
### 07/31/2019
- Use `dsnwriter` in RoCo
~~~
Mechanical drawings (dxf/svg)------------|
|
Module Footprints -----------------------|
|----> board design (dsn)
Electrical schematic design (netlist)----|
|
Board design details(rules,parameters)---|
----> board design (dsn)----> Auto-router (FreeRouting)----> routed board design (dsn)
----> wiring section ----> drawings with mechanical and electrical design (dxf/svg)
~~~
- The package now can auto-detect padstack information with multiple files
### 07/30/2019
- Record of Tips:
- Use `@classmethod` in class to parse information pull out from files (netlist,drawings,footprint) to original class
- Package Dependencies:
- [pykicad](https://github.com/dvc94ch/pykicad)
- numpy
- Class Footprint now can call function `from_file(path,ref)` to load footprint from a `.kicad_mod` file
- Class Padstack now can call function 'auto_detact(path)` to guess information of pads and save as padstack class
- Via information need to be defined by users. (default=None)
- Placement class can be defined after footprint is loaded and able to define the position of each component by calling `ref` of module.
- ![](journal_media/module_dsn.png)
- ![](journal_media/module_load_from_lib.png)
- Netclass is easy to write from script.
- Test auto-routing on generated `dsn`
- ![](journal_media/auto_router_from_dsn.gif)
- Test on wire width change
- ![](journal_media/wider_wire.png)
- TODO: Easier API to generate netlist.
### 07/29/2019
- Was working on 'dsn_python' Python Library.
- Latest package can be found at [personal github](https://github.com/monkalynn813/dsn_python)
- Class tree:
~~~
|--dsnwritter.py (top and second level structure)
|--dsn_module.py
|--module class
|--load module functions
|--dsn_rule.py
|--dsn_geo.py
|--boundary class
|--keepout class
|--load drawing functions
|--dsn_net.py
|--net class
|--netclass class
|--load netlist functions
~~~
- Text tree structure is done.
- Documentation and notes for code needed
- Functions are needed to help user use library.
- Function that load `dxf` file
- Function that load `footprint` file
- Function that load `netlist` file
- For board outline/footprint/netlist not loaded from file but define through this library manually, it works very well for now.
- Pull out those information from low-level file and convert it to proper text for `dsn` file
- Record of Tips:
- `Freerouting` cannot take more than one boundary. (error: exact 1 bounding expected)
- Able to use functions to load `dxf` drawings
- "internal cut issue" solved
- Treat every line individually as polygon and labeled as keepout in `dsn` library
- ![](journal_media/keepout_load.png)
- ![](journal_media/dxf_in_freerouting.png)
### 07/24/2019
- Pipeline change: (skipping `KiCAD`)
- Use (`dxf`+ `pretty` (footprint library) + `net` information ) to generate `dsn` file
- Send `dsn` file to auto-router, save as new `dsn` file
- Read `dsn` file `wiring` information and draw it back on `dxf`
- Analysis on `dsn` file format:
~~~
|--pcb
| |--parser
| |--resolution
| |--unit
| |--structure
| | |--layer 1
| | |-- ...
| | |--boundary
| | |--keepout 1
| | |-- ...
| | |--via
| | |--rule
| |--placement
| | |--component 1
| | |-- ...
| |--library
| | |--image [ref**] 1
| | | |--outline
| | | |--pin
| | |-- ...
| | |--padstack
| | |--...
| |--network
| | |--net [name] 1
| | | |--pins
| | |-- ...
| |--wiring
| | |--wire
~~~
- TODO: functions that load modules and footprints
### 07/23/2019
- Solving issue: export `.kicad_brd` file to `dsn` file for auto-router
- No known Python API so far.
- [schematic-file-converter](https://github.com/ljmljz/schematic-file-converter)
- Take `.sch` file from `KiCAD` instead of `.kicad_brd` file
- Official bug report has been requested. Not targeted in current `KiCAD` scripting version
- [bug report](https://bugs.launchpad.net/kicad/+bug/1824668)
- Potential Solutions:
- 1. Explore existing supported export API, and see if modification can be made based on existing API structure
- 2. Learn `dsn` file specification and python library to generate `dsn` file based on design information
### 07/22/2019
- Research on multiple KiCAD Python packages
- [package 3rd party list](https://github.com/xesscorp/kicad-3rd-party-tools/blob/master/README.md#footprint-library-tools)
- None can import `dxf` into `pcbnew`
- To import `dxf` into `pcbnew` automatically:
- Create a python API by myself based on the `c++` code
- Draw lines directly in `pcbnew` by using line information in `dxf`
- Create a python script serving as Python API by drawing everything on `pcbnew`
- Dependencies:
- ezdxf
- pykicad
- Successfully import `dxf` as outlines from script
- ![](journal_media/import_script.png)
### 07/18/2019
- Research on pcbnew API
- Using package [pykicad](https://github.com/dvc94ch/pykicad)
- Record of Tips:
- Do not add segments, which will route connections
- Different reference name need to be set for `dsn` export
- Able to add footprint and net list into pcbnew.
- TODO:
- Import dxf as outlines from script
- Export board as `dsn`
### 07/17/2019
- Notice that even the drawings cannot be imported onto 'wiring' layer, but can be changed manually to 'wiring' layer after importing onto 'edge.cut' layer
- `Freerouting` does not recognize wires that does not connect to any pins as obstacles.
- ![](journal_media/cutoncopper_layer.png)
- ![](journal_media/autorouter_ignore_cu_layer.png)
- Work on script doing board design
- Create New Board
- Import DXF
- Load Netlist `.net` file
- Place modules
- Export to `.dsn` file
### 07/16/2019
- Fill and Stroke (Shift + Ctrl + F)
- Stroke to Path
- Union
- Break Apart
- Remove each outer layer (manually)
- Export
- ![](journal_media/attempt5_2d.png)
- ![](journal_media/attempt5_3d.png)
- ![](journal_media/attempt5_router.png)
- Consider success when export for auto-routing manually. Huge challenge expected when doing it from script.
- Work on script doing schematic design
- *Assume symbol and footprint downloaded*
- Package Using: [skidl](https://xesscorp.github.io/skidl/docs/_site/)
- Record of Tips:
- Add custom library path that contains all symbols of electrical devices needed (`NodeMCU`)
- Use attribute `footprint` to add footprint for such symbol
- footprint syntax: 'footprint= libname.pretty: foot_print_name
- footprint directory should be under the same directory where `.lib` file is.
### 07/15/2019
- 3 potential ways to solve the issue on KiCAD with internal cut
- *Assume the position of each internal cut line is known*
- 1. Make internal cut a closed shape (original cut with thickness)
- Pro: Easy to import routed circuit back to dxf cutter file
- Con: Hard to make the cut itself a closed shape.
- 2. Make internal cut outlines a block on certain layer and treat it as obstacle in auto-router
- Pro: Easy to generate a block as obstacle in drawing
- Con: Hard to import routed circuit back to dxf cutter file
- 3. Put internal cut on different layer in KiCAD that can be read as obstacle in auto-router
- Best solution for now if the auto-router will be able to read single cut line, but cannot be edge.cut layer for sure, otherwise board outlines cannot be found by KiCAD.
- Cut lines causing issues are marked in red.
- ![](journal_media/internal_cut_marked.png)
- `Inkscape` :
- Object stroke to path can make everything looks like a bounding box
- Attempts:
- 1. Stroke every line, auto-router shows nothing, no error
- ![](journal_media/show_nothing_strokeeveryline.png)
- ![](journal_media/attempt1_3d.png)
- 2. Stroke every line, but has a larger boundary. auto-router shows nothing, error: cannot start a route inside of keepout area or boundary outlines
- ![](journal_media/show_nothing_strokewithalargerboundary.png)
- ![](journal_media/attempt2_3d.png)
- 3. Stroke every line but make the boundary outlines not closed, and draw a larger outline. Auto-router shows nothing, no error
- ![](journal_media/attempt3_2d.png)
- ![](journal_media/attempt3_3d.png)
- 4. Stroke only outline but make the boundary outlines not closed, and draw a larger outline. Auto-router shows properly. (no way to do it from script)
- ![](journal_media/attempt4_2d.png)
- ![](journal_media/attempt4_3d.png)
- ![](journal_media/attempt4_router.png)
### 07/11/2019
- Solved Error `unable to find segment with an endpoint`
- `DSN` file can only be exported for continuous closure outlines
- ![](journal_media/fail_dsn.png)
- Drawings like this drawing for paper cut is not acceptable for `dsn` file.
- Change it either to close shape or remove it when import to KiCAD
- Solving Issue: `FreeRouting` is not reading edge cut layer from `dsn`
- Work well on a sample `dsn` file
- Issue with KiCAD output
- Sample KiCAD project can output outlines properly.
- Issue found:
- KiCAD cannot take single line cut. Closed shape needed.
### 07/10/2019
##### Approach A
- Import to PCBnew issue:
- Dimension of board outlines are incorrect
- Pins does not fit in original drawings
- (solved. Microcontroller footprint was incorrect)
- pipeline confirmed:
- 1. Build symbol and footprint library for all required electrical element
- 2. Sketch schematic design
- `.sch` file
- 3. Place elements in required position
- `.dsn` file
- 4. Import `dsn` file into `FreeRouting` and do auto-routing
- `.ses` file
- 5. Import `ses` file back to `KiCAD` and export as `dxf` file
- `.dxf` file
- Manually tested pipeline till step 4
- Step 3
- ![](journal_media/sample_conn_pcbnew.png)
- Step 4
- ![](journal_media/sample_autorouting.gif)
- ISSUE:
- Board outlines are not exported correctly to `FreeRouting`
- Error: `unable to find segment with an endpoint`
- Record of Tips:
- To run `FreeRouting` from command line:
~~~
java -jar freeRouting.jar [proj.dsn]
~~~
- TODO:
- Finish with testing the pipeline manually
- Achieve steps directly from script (Python API)
### 07/09/2019
- Finish up path-finding approach (Approach B)
- Only draw the best path on `dxf` when solution is found for every route.
- ![circuit_dxf](journal_media/dxf_circuit.png)
- Throw warning once a route cannot be found
- ![fail_solution](journal_media/path_fail.gif)
- Research on Approach A
- KiCAD 5 does not have built-in auto-router
- Have to use `FreeRouting`
- `FreeRouting` does not have python API
- Parent package of `FreeRouting`, `LayoutEditor` has multiple editions
- Part of `LayoutEditor` is open- source
- A large amount of of its website are broken, source and interface are unavailable
- Other auto-routers are not open-source
##### Approach A
- 1. Use `LayoutEditor` python API to use `FreeRouting`
- 2. Use `KiCAD 5` python API to sue `FreeRouting`
- 3. Use `KiCAD 4` python API to use builtin auto-routing
###### 1
- `FreeRouting` input format: `dsn`, `lef`, `def`
- `FreeRouting` output format: `ses`, `def`
- `FreeRouting` can take arbitrary board outlines shape
- Edit `library` manually and test routing
- ![dxf_import](journal_media/dxf_import_kicad.png)
- TODO:
- If can run KiCAD 4 from python
- Check `FreeRouting` API, see if a acceptable file can be generated from things on hand
### 07/08/2019 (Mon)
- Debug multi-node path finding:
- some obstacles are ignored
- too close to each other
- Able to show the learning process:
- Trying different combination of solving order
- Try to give the best order of solving multiple path
##### Auto-routing learning process:
- ![path_learning.gif](journal_media/path_learning.gif)
- Comparison between episodes and choose best combo of paths
- ![learning_episodes.gif](journal_media/learning_episodes.gif)
##### Issues and TODO
- Path export from optimization is messed up
- Obstacles setting are incorrect
### 07/05/2019 (Fri)
- Write out algorithm for multi-node path finding
- pseudo code:
~~~~
for (episode in E):
set initial state s (choose first pair of nodes to connect randomly)
find a path
update map
while not every connection is built:
choose next connection
find a path
update map
retrieve cost (length of path)
update Q (as sum of all cost)
~~~~
- Q here represents total cost of certain choice of path finding order.
- Cost defined by length of path
- If path cannot be found, cost 1000
- Input: NX2X2 array specifies desired pin connections
- Research on KiCAD import needs and python API
### 07/03/2019 (Wed)
- dxf processing completed
- Convert dxf to matrix with resolution (270X210) (mm)
- Potential issue:
- the `pathfinding` package is based on pixel
- When round up the line's start and end point, the accuracy of pin position is low
- Apply single point to point path finding
- Able to draw the path on matrix
- Able to draw the path on original dxf file
- ![matrix](journal_media/matrix_to_img.png)
- TODO:
- Write out algorithm for multi-node path finding
- break single circuit trace to parallel traces
- solve the accuracy problem
### 07/02/2019 (Tue)
- Continue the dxf processing
- Following tasks can be completed by running the code:
- Able to detect pin center coordinate
- Able to draw arbitrary shape around the pin center
- ![isolation_circuit.png](journal_media/isolation_circuit.gif)
- - Issue & TODO
- Convert dxf image to matrix
- Explore `pathfinding` package
- `pathfinding` package solve path finding problem by shortest path algorithm, one point to another
- To solve multiple nodes problem, use concept from reinforcement learning
- Build Q function that represents total reward of choosing certain path to be solved first
- Update Q function in a loop with certain amount of episodes
- Choose the order of solving paths randomly, and add possibility of choosing it from Q function
- Exploration-exploitation method
- To solve the problem "convert dxf to matrix" for pathfinding:
- Have tried:
- Export to `png` and read file by `OpenCV`
- Resolution problem: single point does not represented as a pixel in `png`
- TODO:
- create an empty matrix and fill in numbers with the information of each lines' start and end point
### 07/01/2019 (Mon)
- Continue the dxf processing with `'graph-silhouette.dxf'`
##### Record of tips:
- Put circuit design on a new layer of dxf drawing
- [check doc about layers here](https://ezdxf.readthedocs.io/en/latest/tutorials/layers.html)
- Use block feature to draw similar pattern
- [check doc about block here](https://ezdxf.readthedocs.io/en/latest/tutorials/blocks.html)
- Blocks are `symbol` in Inkscape. Convert `symbol` to `path`
- Edit > Clone > Unlink Clone (Shift+Alt+D), and you have a group, ungroup (Object > Ungroup, or Shift+Ctrl+G) and edit
- Convert `text` to `path`
- Path combine (Ctrl+K)
- msp.delete_enetity('__') to remove existing entity
- Test fabrication with different drawing settings
- Layers can be cut separately by toggling visibility
- Set cuts with same `intensity` and `feedrate` on same layer
- Entities' layer can be changed through `Entity.dxf.layer`
### 06/29 & 06/30/2019 (Sat & Sun)
##### Approach `B`
- Potential needed functions of packages
- A package draws on DXF file through script
- A script that pulls out pins' coordinate on paper chassis
- Or a image process package (OpenCV) that reads pins' coordinate on paper chassis
- A package solves multi-node path finding problem*
##### Record of Research
- Python Pathfinding package:
- [pathfinding](https://pypi.org/project/pathfinding/#description)
- Python DXF editor:
- [ezdxf](https://pypi.org/project/ezdxf/)
- [dxfgrabber](https://pypi.org/project/dxfgrabber/)
- `Note`: able to grab simple geometry from file
- [sdxf](http://www.kellbot.com/sdxf-python-library-for-dxf/)
- Going through tutorials of `ezdxf`
- All lines on paper space`layer0`
### 06/28/2019 (Fri)
##### Connection and fabrication approach confirmed !
- Confirm that copper tape has better conductivity than aluminum sheet when attaching microcontroller pins through `H-shape` cut
- Copper tape is harder to be scratched, which provides less risk of disconnection during assembly.
- Etching on copper type isolates connections
- Research on PCB editor
- EAGLE
- EAGLE cannot import `.pcb` file
- `svg` can be exported but not imported
- Custom library needed if doing schematic design
- KiCad
- Can import `.pcb` file
- `svg` can be exported but not imported
- LayoutEditor
- support multiply file type
- `svg` can be exported with different color makers as multiple layers
- include open-sourced auto-router `freerouting`
- Auto-routing package:
- TopoR
- Python-PCB
- FreeRouting
- Approaches:
- `A`. convert SVG/DXF file to schematic/board design of PCB. Use KiCAD or EAGLE to do auto routing.
- `B`. develop algorithm on auto routing for single layer svg/dxf file. (path finding problem)
##### Approach `A`
- Use regular shape board for PCB in EAGLE/KiCAD
- image processing: divide the shape of `paperbot` to multiple rectangles (ezdxf)
- Pull required connections and place additional header pins around edges of each rectangle
- Make each connection pin to be two parallel connections so auto-router does parallel trace for each wiring.
- Etching a pair of parallel trace provides isolation, and leave the space between traces to be conductible.
- Build Library for schematic design
- Schematic design helps with router to know desired connection
- Additional header pins at each side of kink mark
### 06/27/2019 (Thur)
- Compile `OldRoCo` [repo](https://git.uclalemur.com/mehtank/oldroco)
- Record of modification:
- ++line 8 of `vstart.sh`
- --> `pip install -r requirements.txt --user`
- Export `paperbot` dxf file : `graph-silhouette.dxf` to `OnShape`
- Record of Tips:
- Onshape does not read dxf file as its own saved unit. Manual settings needed when import.
- ![onshape_dxf_unit](journal_media/onshape_dxf_unit.png)
- Draw circuit diagram as CAD on `Onshape`
- Multiple connection approaches:
- `Cross` shape of `0.039 in`
- `Cross` shape of `0.049 in`
- `Octangular` shape of `0.049 in`
- ![connection_approaches.png](journal_media/connection_approaches.png)
- ![actual_connection_cuts.JPG](journal_media/actual_connection_cut.JPG)
- Note and issue:
- `Octangular` shape is the best connection approach so far, but none of approach has stable conductivity. More research is needed.
- Scratches can be made easily when attaching microcontroller to the sheet. Potential disconnection may occur due to such scratches on metal layer.
- Export 2D CAD drawing with PCB to SVG for silhouette cameo
- Record of Tips:
- `OnShape` unit need to be consisted with unit setting in `Inkscape` (default: mm)
- Plugin `Inkscape-silhouette` cannot take multiple types of trace for cutting.
- Different trace (especially cut and etching) need to be sent separately. Use `coordinate tool` of `Inkscape` to ensure separated cuts have same origin.
- TODO:
- Cut and etching from same `Inkscape` file
# dsn_python
File added
File added
File added
File added
File added
File added
File added
from pykicad.sexpr import *
import numpy as np
class load_drawing():
def __init__(self,afile):
import ezdxf
self.dwg=ezdxf.readfile(afile)
self.msp=self.dwg.modelspace()
def load_all(self):
return [self.load_line,self.load_polygon]
def load_line(self):
startlist=[]
endlist=[]
line_list=[]
for e in self.msp.query('LINE'):
startlist.append(e.dxf.start[:2])
endlist.append(e.dxf.end[:2])
for i in range(len(startlist)):
line_list.append(startlist[i])
line_list.append(endlist[i])
line_list=np.array(line_list)
# line_list[:,1]*=-1
line_list*=1000
line_list=line_list.flatten()
line_list=list(line_list)
return line_list
def load_polygon(self):
pts_list=[]
for e in self.msp.query('LWPOLYLINE'):
pts_list.append(np.array(e.get_points()))
for i in range(len(pts_list)):
pts_list[i]=pts_list[i][:,:2]
# pts_list[i][:,1]*=-1
##Unit = um
pts_list[i]=pts_list[i]*1000
pts_list[i]=pts_list[i].flatten()
pts_list[i]=list(pts_list[i])
return pts_list
def load_line_as_polygon(self):
pts_list=self.load_polygon()
ply_list=[]
for i in range(len(pts_list)):
for j in range(len(pts_list[i])):
ply_list.append(pts_list[i][j])
return ply_list
class Boundary(AST):
tag='boundary'
schema={
'path pcb':{
'0':{
'_parser':integer,
'_attr':'brd_index'
},
'1':{
'_parser': number,
'_attr': 'path'
},
}
}
def __init__(self,path,brd_index=0):
super(Boundary,self).__init__(path=path,brd_index=brd_index)
class Keepout(AST):
tag='keepout'
schema={
'0':{
'0':{
'_parser':text,
'_attr':'name'
},
' ':{
'0': {
'_parser':text,
'_attr':'shape'
},
'1':{
'_parser':text,
'_attr':'typex'
},
'2':{
'_parser':integer,
'_attr':'brd_index'
},
'3':{
'_parser': number,
'_attr':'path'
},
},
},
}
def __init__(self,path,name='\"\"',brd_index=0,shape='polygon',typex='signal'):
super(Keepout,self).__init__(path=path,name=name,brd_index=brd_index,shape=shape,typex=typex)
\ No newline at end of file
File added
from pykicad.sexpr import *
unit_convert=1000
class Placement(AST):
tag='component'
schema={
'0':{
'_parser':text,
'_attr':'ref1',
# '_multiple':True
},
'place':{
'0':{
'_parser':text,
'_attr':'ref2',
},
'1':{
'_parser':number + number,
'_attr':'at'
},
'2':{
'_parser':text,
'_attr':'flip'
},
'3':{
'_parser':integer,
'_attr':'orientation'
},
'PN':{
'_parser':text,
'_attr':'name'
}
}
}
def __init__(self,ref1,at=[0,0],ref2=None,flip='front',orientation=0,name=None):
# at[1]=-at[1] #flip y for dsn
ref2=ref1
super(Placement,self).__init__(ref1=ref1,ref2=ref2,at=at,flip=flip,orientation=orientation,name=name)
class Outline(AST):
tag='outline'
schema={
'0':{
'path signal':{
'0':{
'_parser':integer,
'_attr':'width'
},
'1':{
'_parser':integer,
'_attr':'outline_start'
},
'2':{
'_parser':integer,
'_attr':'outline_end'
}
}
}
}
def __init__(self,width=None,outline_start=None,outline_end=None):
super(Outline,self).__init__(width=width,outline_start=outline_start,outline_end=outline_end)
class Pin(AST):
tag='pin'
schema={
'0':{
'_parser':text,
'_attr':'pin_type',
},
'1':{
'_parser':integer,
'_attr':'pin_index',
},
'2':{
'_parser':number+number,
'_attr':'pin_at',
}
}
def __init__(self,pin_index=None,pin_at=None,pin_type='Round[A]Pad_1524_um'):
super(Pin,self).__init__(pin_type=pin_type,pin_index=pin_index,pin_at=pin_at)
class Shape(AST):
tag='shape'
schema={
' ':{
'0':{
'_parser': text,
'_attr':'shape'
},
'1':{
'_parser': text,
'_attr':'layer'
},
'2':{
'_parser': integer,
'_attr': 'size'
}
}
}
def __init__(self,shape='circle',layer=None,size=1524):
super(Shape,self).__init__(shape=shape,layer=layer,size=size)
class Padstack(AST):
tag='padstack'
schema={
'0':{
'_parser': text,
'_attr': 'pin_type'
},
'1':{
'shape':{
'_parser':Shape,
'_multiple':True
},
},
'attach':{
'_parser': text
}
}
def __init__(self,pin_type='Round[A]Pad_1524_um',shape=None,attach='off'):
shape=self.init_list(shape,[])
super(Padstack,self).__init__(pin_type=pin_type,shape=shape,attach=attach)
@classmethod
def auto_detect(cls,path,attach='off'):
"""
load a module footprint file and auto detect pad info
output: padstack class
"""
from pykicad.module import Module as mod
import numpy as np
module=mod.from_file(path)
pad_types=[]
for i in range(len(module.pads)):
pad=module.pads[i]
combo=[pad.shape,pad.layers,int(pad.size[0]*unit_convert)]
if not combo in pad_types:
pad_types.append(combo)
padstack=[]
for i in range(len(pad_types)):
shape_class=[]
for layer in pad_types[i][1]:
if '*' in layer:
layer_ext=layer.split('.')[-1]
shape_class.append(Shape(pad_types[i][0],'F.'+layer_ext,pad_types[i][2]))
shape_class.append(Shape(pad_types[i][0],'B.'+layer_ext,pad_types[i][2]))
else:
shape_class.append(Shape(pad_types[i][0],layer,pad_types[i][2]))
pin_type='Round[A]Pad_'+str(int(pad_types[i][2]))+'_um'
padstack_class=cls(pin_type,shape_class,attach)
padstack.append(padstack_class)
return padstack
class Footprint(AST):
tag='image'
schema={
'0':{
'_parser':text,
'_attr':'ref',
},
'outline':{
'_parser':Outline,
'_multiple':True
},
'pin':{
'_parser':Pin,
'_multiple':True
}
}
def __init__(self,ref=None,outline=None,pin=None):
outline=self.init_list(outline,[])
pin=self.init_list(pin,[])
super(Footprint,self).__init__(ref=ref,outline=outline,pin=pin)
@classmethod
def from_file(cls,path,ref='REF**'):
"""
load module footprint from a '.kicad_mod' file
path: afile
ref: ref name of module eg. U1
output: footprint class
"""
from pykicad.module import Module as mod
import numpy as np
module=mod.from_file(path)
outlines=[]
for i in range(len(module.lines)):
outline=module.lines[i]
width=outline.width*unit_convert
outline_start=np.array(outline.start)*unit_convert
# outline_start[1]*=-1
outline_start=list(outline_start)
outline_end=np.array(outline.end)*unit_convert
# outline_end[1]*=-1
outline_end=list(outline_end)
outline_class=Outline(width,outline_start,outline_end)
outlines.append(outline_class)
pads=[]
for i in range(len(module.pads)):
pad=module.pads[i]
pin_index=int(pad.name)
pin_at=np.array(pad.at)*unit_convert
pin_at[1]*=-1
pin_at=list(pin_at)
pin_size=pad.size[0]*unit_convert
pin_type='Round[A]Pad_'+str(int(pin_size))+'_um'
pin_class=Pin(pin_index,pin_at,pin_type)
pads.append(pin_class)
return cls(ref=ref,outline=outlines,pin=pads)
from pykicad.sexpr import *
class Net(AST):
tag='net'
schema={
'0':{
'_parser': text,
'_attr': 'net_name'
},
'1':{
'pins':{
'0':{
'_parser':text +text,
'_attr':'conn_pins'
},
}
}
}
def __init__(self,net_name,conn_pins=None):
super(Net,self).__init__(net_name=net_name,conn_pins=conn_pins)
class NetClass(AST):
tag='class'
schema={
'0':{
'0':{
'_parser':text,
'_attr':'net_class_name'
},
'1':{
'_parser':text+text,
'_attr':'nets_name'
},
},
'circuit':{
'0':{
'use_via':{
'_parser':text,
'_attr':'via_name'
}
}
},
'rule':{
'width':{
'_parser':integer
},
'clearance':{
'_parser': number
}
}
}
def __init__(self,net_class_name='default',nets_name=None,
via_name='',width=3000,clearance=200.1):
super(NetClass,self).__init__(net_class_name=net_class_name,nets_name=nets_name,
via_name=via_name,width=width,clearance=clearance)
from pykicad.sexpr import *
class Clearance(AST):
tag='clearance'
schema={
'0':{
'_parser':number,
'_attr':'number'
},
'1':{
'type':{
'_parser':text,
'_attr':'typex'
},
'_optional':True
},
}
def __init__(self,number=200.1,typex=None):
super(Clearance,self).__init__(number=number,typex=typex)
class Rule(AST):
tag='rule'
schema={
'0':{
'width':{
'_parser': number
},
},
'1':{
'clearance':{
'_parser':Clearance,
'_multiple':True
},
},
}
def __init__(self,width=250,clearance=None):
clearance=self.init_list(clearance,[])
super(Rule,self).__init__(width=width,clearance=clearance)
\ No newline at end of file
#!/usr/bin/env python3
from pykicad.sexpr import *
from dsn_rule import *
from dsn_module import Placement,Footprint, Padstack
import dsn_module as module
from dsn_net import *
from dsn_geo import *
class Parser(AST):
tag = 'parser'
schema = {
'string_quote' : {
'_parser' : text,
'_attr' : 'quote_char'
},
'space_in_quoted_tokens' : {
'_parser': yes_no,
'_attr' : 'tokens_on_off'
},
'host_cad':{
'_parser': text
},
'host_version':{
'_parser':text
}
}
def __init__(self,
quote_char='\"',
tokens_on_off='on',
host_cad= "KiCad's Pcbnew",
host_version="5.1.3-ffb9f22~84~ubuntu18.04.1"):
super(Parser,self).__init__(quote_char=quote_char,
tokens_on_off=tokens_on_off,
host_cad=host_cad,
host_version=host_version)
class Layer(AST):
tag='layer'
schema={
'0':{
'_parser': text,
'_attr': 'name'
},
'type':{
'_parser': Literal('signal') | 'power' | 'mixed' | 'jumper' | 'user',
'_attr': 'typex'
},
'property':{
'index':{
'_parser':text,
'_attr':'index'
},
},
}
index_ctr=0
def __init__(self,name,typex='signal',index=None):
index=Layer.index_ctr
Layer.index_ctr+=1
super(Layer,self).__init__(name=name,typex=typex,index=index)
class Dsn(AST):
tag = 'PCB "kicad_board"'
schema = {
'0':{
'parser' : {
'_parser': Parser
},
},
'1':{
'resolution':{
'_parser': text + integer
},
},
'2':{
'unit':{
'_parser': text
},
},
'3':{
'structure':{
'0':{
'layers':{
'_parser':Layer,
'_multiple':True
},
},
'1':{
'boundary':{
'_parser':Boundary,
'_multiple':False
},
},
'2':{
'keepout':{
'_parser': Keepout,
'_multiple': True
},
},
'3':{
'via':{
'_parser': text,
'_attr': 'via_type'
},
},
'4':{
'rule':{
'_parser': Rule
}
}
},
'_optional':True
},
'4':{
'placement':{
'0':{
'placement':{
'_parser':Placement,
'_multiple':True
},
},
},
},
'5':{
'library':{
'0':{
'image':{
'_parser': Footprint,
'_multiple': True
},
},
'1':{
'_parser':Padstack,
'_multiple': True,
'_attr':'padstack'
}
}
},
'6':{
'network':{
'net':{
'_parser':Net,
'_multiple':True
},
'netclass':{
'_parser':NetClass,
'_multiple':True
}
}
},
'7':{
'wiring':{
'_parser':text, #not available before auto-routing, code can be modificed if want to set route from script manually
}
}
}
def __init__(self,
resolution=['um',10],
unit='um',
parser=None,
layers=None,
boundary=None,
keepout=None,
via_type=None,
rule=None,
placement=None,
image=None,
padstack=None,
net=None,
netclass=None,
wiring= None
):
layers=self.init_list(layers,[])
parser=self.init_list(parser,[])
boundary=self.init_list(boundary,[])
keepout=self.init_list(keepout,[])
placement=self.init_list(placement,[])
image=self.init_list(image,[])
padstack=self.init_list(padstack,[])
net=self.init_list(net,[])
net=self.init_list(netclass,[])
super(Dsn,self).__init__(
resolution=resolution,
unit=unit,
parser=parser,
layers=layers,
boundary=boundary,
keepout=keepout,
via_type=via_type,
rule=rule,
placement=placement,
image=image,
padstack=padstack,
net=net,
netclass=netclass,
wiring=wiring
)
def to_file(self, path):
if not path.endswith('.dsn'):
path += '.dsn'
with open(path, 'w', encoding='utf-8') as f:
f.write(self.to_string())
@classmethod
def from_file(cls, path):
return cls.parse(open(path, encoding='utf-8').read())
\ No newline at end of file
File added
(gui_defaults
(windows
(board_frame
visible
(bounds
351 29 1150 916
)
)
(color_manager
not_visible
(bounds
0 600 1110 134
)
)
(layer_visibility
not_visible
(bounds
0 450 359 162
)
)
(object_visibility
not_visible
(bounds
0 550 395 396
)
)
(display_miscellanious
not_visible
(bounds
0 350 241 333
)
)
(snapshots
not_visible
(bounds
0 250 230 255
)
)
(select_parameter
not_visible
(bounds
0 0 246 467
)
)
(route_parameter
not_visible
(bounds
0 100 261 542
)
)
(manual_rules
not_visible
(bounds
0 27 284 196
)
)
(route_details
not_visible
(bounds
0 27 263 240
)
)
(move_parameter
not_visible
(bounds
0 50 304 139
)
)
(clearance_matrix
not_visible
(bounds
0 150 470 257
)
)
(via_rules
not_visible
(bounds
50 150 335 450
)
)
(edit_vias
not_visible
(bounds
100 150 413 87
)
)
(edit_net_rules
not_visible
(bounds
100 200 913 103
)
)
(assign_net_rules
not_visible
(bounds
100 250 213 84
)
)
(padstack_info
not_visible
(bounds
100 30 0 0
)
)
(package_info
not_visible
(bounds
200 30 0 0
)
)
(component_info
not_visible
(bounds
300 30 0 0
)
)
(net_info
not_visible
(bounds
350 30 0 0
)
)
(incompletes_info
not_visible
(bounds
400 30 0 0
)
)
(violations_info
not_visible
(bounds
500 30 0 0
)
)
)
(colors
(background
204 204 204
)
(hilight 1.0
0 0 204
)
(incompletes 1.0
0 153 153
)
(outline
0 0 0
)
(component_front
0 0 255
)
(component_back
255 0 0
)
(violations
255 0 255
)
(length_matching 1.0
0 255 0
)
(traces 1.0
255 0 0
0 0 255
)
(fixed_traces 1.0
255 0 0
0 0 255
)
(vias 1.0
200 200 0
200 200 0
)
(fixed_vias 1.0
200 200 0
200 200 0
)
(pins 1.0
150 50 0
160 80 0
)
(conduction 1.0
0 150 0
100 100 0
)
(keepout 1.0
0 110 110
0 100 160
)
(via_keepout 1.0
100 100 100
100 100 100
)
)
(parameter
(selection_layers
all_visible
)
(selectable_items
TRACES VIAS PINS FIXED UNFIXED
)
(via_snap_to_smd_center
on
)
(route_mode
dynamic
)
(shove_enabled
on
)
(drag_components_enabled
on
)
(hilight_routing_obstacle
off
)
(pull_tight_region
2147483647
)
(pull_tight_accuracy
500
)
(clearance_compensation
off
)
(ignore_conduction_areas
on
)
(automatic_layer_dimming
0.7
)
(deselected_snapshot_attributes
)
)
)
\ No newline at end of file
(gui_defaults
(windows
(board_frame
visible
(bounds
351 29 1150 916
)
)
(color_manager
not_visible
(bounds
0 600 1110 134
)
)
(layer_visibility
not_visible
(bounds
0 450 369 162
)
)
(object_visibility
not_visible
(bounds
0 550 405 396
)
)
(display_miscellanious
not_visible
(bounds
0 350 241 333
)
)
(snapshots
not_visible
(bounds
0 250 230 255
)
)
(select_parameter
not_visible
(bounds
0 0 246 467
)
)
(route_parameter
not_visible
(bounds
0 100 261 542
)
)
(manual_rules
not_visible
(bounds
0 27 284 196
)
)
(route_details
not_visible
(bounds
0 27 263 240
)
)
(move_parameter
not_visible
(bounds
0 50 304 139
)
)
(clearance_matrix
not_visible
(bounds
0 150 470 257
)
)
(via_rules
not_visible
(bounds
50 150 335 450
)
)
(edit_vias
not_visible
(bounds
100 150 413 103
)
)
(edit_net_rules
not_visible
(bounds
100 200 913 103
)
)
(assign_net_rules
not_visible
(bounds
100 250 213 84
)
)
(padstack_info
not_visible
(bounds
100 30 0 0
)
)
(package_info
not_visible
(bounds
200 30 0 0
)
)
(component_info
not_visible
(bounds
300 30 0 0
)
)
(net_info
not_visible
(bounds
350 30 0 0
)
)
(incompletes_info
not_visible
(bounds
400 30 0 0
)
)
(violations_info
not_visible
(bounds
500 30 0 0
)
)
)
(colors
(background
204 204 204
)
(hilight 1.0
230 255 255
)
(incompletes 1.0
255 255 255
)
(outline
0 0 0
)
(component_front
0 0 255
)
(component_back
255 0 0
)
(violations
255 0 255
)
(length_matching 1.0
0 255 0
)
(traces 1.0
255 0 0
0 0 255
)
(fixed_traces 1.0
255 0 0
0 0 255
)
(vias 1.0
200 200 0
200 200 0
)
(fixed_vias 1.0
200 200 0
200 200 0
)
(pins 1.0
150 50 0
160 80 0
)
(conduction 1.0
0 150 0
100 100 0
)
(keepout 1.0
0 110 110
0 100 160
)
(via_keepout 1.0
100 100 100
100 100 100
)
)
(parameter
(selection_layers
all_visible
)
(selectable_items
TRACES VIAS PINS FIXED UNFIXED
)
(via_snap_to_smd_center
on
)
(route_mode
dynamic
)
(shove_enabled
on
)
(drag_components_enabled
on
)
(hilight_routing_obstacle
off
)
(pull_tight_region
2147483647
)
(pull_tight_accuracy
500
)
(clearance_compensation
off
)
(ignore_conduction_areas
on
)
(automatic_layer_dimming
0.7
)
(deselected_snapshot_attributes
)
)
)
\ No newline at end of file
#!/usr/bin/env python3
import copy
import numpy as np
from math import sqrt
def find_wire(file_path,pin_loc=None):
if not file_path.endswith('.ses'):
file_path+='.ses'
ses=open(file_path,'r').read().splitlines()
pathsec_list=[]
for i in range(len(ses)):
if 'path' in ses[i]:
for j in range(i,len(ses)):
if ')' in ses[j]:
pathsec=[i,j]
pathsec_list.append(pathsec)
break
path_list=[]
for sec_bry in pathsec_list:
onepath=[]
for j in range(sec_bry[0]+1,sec_bry[1]):
pts_str=ses[j].split()
ptstart=int(pts_str[0])
ptend=int(pts_str[1])
pts=[ptstart,ptend]
onepath.append(pts)
path_list.append(onepath)
pin_loc_=[]
for module in pin_loc:
for pin in module:
pin=np.array(pin)*10000
pin=pin.astype(int)
pin=pin.tolist()
pin_loc_.append(pin)
merged_path_list=[]
while len(path_list)!=0:
merged_path=path_list[0]
path_list.remove(merged_path)
flag=True
s_merge_flag=True
e_merge_flag=True
while flag:
s=merged_path[0]
e=merged_path[-1]
# m1_len=len(merged_path)
flag=False
if s in pin_loc_:
s_merge_flag=False
if e in pin_loc_:
e_merge_flag=False
to_merge_temp=[]
for restpath in path_list:
s_=restpath[0]
e_=restpath[-1]
# m2_len=len(restpath)
# if m1_len<3 or m2_len<3:
if (s==s_ or s==e_ or e==s_ or e==e_) and (s_merge_flag or e_merge_flag):
to_merge_temp.append(restpath)
if len(to_merge_temp)!=0:
dis=[]
for temp_path in to_merge_temp:
leng=len_of_path(temp_path)
dis.append(leng)
to_merge=to_merge_temp[np.argmin(dis)]
to_merge_copy=copy.deepcopy(to_merge)
s_=to_merge[0]
e_=to_merge[-1]
if s==s_ and s_merge_flag:
merged_path.remove(s)
merged_path=list(reversed(merged_path))+(to_merge_copy)
path_list.remove(to_merge)
flag=True
if s==e_ and s_merge_flag:
merged_path.remove(s)
merged_path=to_merge_copy+(merged_path)
path_list.remove(to_merge)
flag=True
if e==s_ and e_merge_flag:
merged_path.remove(e)
merged_path=(merged_path)+(to_merge_copy)
path_list.remove(to_merge)
flag=True
if e==e_ and e_merge_flag:
merged_path.remove(e)
merged_path=to_merge_copy+(list(reversed(merged_path)))
path_list.remove(to_merge)
flag=True
merged_path_list.append(merged_path)
for path in merged_path_list:
if len(path)>=3:
path_cp=copy.deepcopy(path)
for i in range(len(path_cp)-2):
pt1=path_cp[i]
pt2=path_cp[i+1]
pt3=path_cp[i+2]
x1,x2,x3=pt1[0],pt2[0],pt3[0]
y1,y2,y3=pt1[1],pt2[1],pt3[1]
if x1==x2 and x2==x3:
path.remove(pt2)
elif y1==y2 and y2==y3:
path.remove(pt2)
return merged_path_list
def len_of_path(path):
leng=0
for i in range(len(path)-1):
pt1=path[i]
pt2=path[i+1]
x1,y1=pt1[0],pt1[1]
x2,y2=pt2[0],pt2[1]
dis= sqrt((x1-x2)**2+(y1-y2)**2)
leng+=dis
return leng