Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Drill Map in PCB Print #733

Open
nguyen-v opened this issue Nov 22, 2024 · 8 comments
Open

[FEATURE] Drill Map in PCB Print #733

nguyen-v opened this issue Nov 22, 2024 · 8 comments
Assignees
Labels
enhancement New feature or request

Comments

@nguyen-v
Copy link

nguyen-v commented Nov 22, 2024

Is your feature request related to a problem? Please describe.
In my fabrication documents, I like to add a drill map drawing, which is aligned with the PCB Print outputs of the other pages

image

On the page, I add both the Drill Map and a table with more information on the types of holes, as well as their associated symbol

Describe the solution you'd like
A way to automate the creation of that type of document (inclusion of Drill Map drawing in PCB Print, as well as associated table with symbols). The Drill Map drawing could be included in a similar way to the Include Image feature, but as a vectorized graphics (e.g. DXF). Maybe there could be an option to either use a group as a position, or to automatically position the drill map to be aligned with the PCB (with parametrized scaling).

For the table, it might be possible to create a CSV file to be included with Include Table, but extracting and positioning the symbols might be tricky

Ideally the Table would be similar to Altium:
image

Describe alternatives you've considered
Currently, I manually import the Drill Map as a DXF, remove the texts and then manually modify the table.

@nguyen-v nguyen-v added the enhancement New feature or request label Nov 22, 2024
@set-soft
Copy link
Member

Here we should solve the table first, make the report produce more detailed information.

@set-soft
Copy link
Member

Hole type: in KiCad we have circular and oval, no more
Pad shape: seems to be unrelated to the drill

@nguyen-v
Copy link
Author

Hole type: in KiCad we have circular and oval, no more Pad shape: seems to be unrelated to the drill

Yes pad shape is probably unnecessary. For hole type probably 'Round' and 'Slot' is fine

@nguyen-v
Copy link
Author

nguyen-v commented Dec 20, 2024

Any updates on this? I had a quick look and it does look quite involved, would need a reimplementation of
https://gitlab.com/kicad/code/kicad/-/blob/master/pcbnew/exporters/gendrill_file_writer_base.cpp
To get the CSV report table with the correct ordering/layer pairs etc. (and most importantly the m_holeListBuffer list of holes). Once the ordering is correct (i.e. similar to KiCad ordering), each unique group of holes would be assigned to specific drill marks.

For the drill marks that would be fairly straightforward to implement:
https://gitlab.com/kicad/code/kicad/-/blob/master/common/plotters/plotter.cpp

Using these rough functions:

def draw_arc(g, x, y, radius, angle_start, angle_end, layer, line_w=10000):

    arc = pcbnew.PCB_SHAPE(GS.board)
    arc.SetShape(pcbnew.SHAPE_T_ARC)

    # Set the arc's center
    center = arc.GetCenter()
    center.x = x
    center.y = y
    arc.SetCenter(center)

    start_point = arc.GetStart()
    # Calculate the start point using the start angle
    start_point.x = int(x + radius * math.cos(math.radians(angle_start)))
    start_point.y = int(y + radius * math.sin(math.radians(angle_start)))
    arc.SetStart(start_point)

    # Calculate the sweep angle and set it
    sweep_angle = pcbnew.EDA_ANGLE(angle_end - angle_start, pcbnew.DEGREES_T)
    arc.SetArcAngleAndEnd(sweep_angle, True)  # KiCad uses deci-degrees internally

    # Set the arc's layer and width
    arc.SetLayer(layer)
    arc.SetWidth(line_w)

    # Add the arc to the graphics context and board
    g.AddItem(arc)
    GS.board.Add(arc)

def draw_marker_square(g, x, y, radius, layer, line_w=10000):
    r = round(radius / 1.4142)  # Calculate the side's half-length from the radius.
    w = 2 * r  # The width and height of the square.
    draw_rect(g, x - r, y - r, w, w, layer, filled, line_w)

def draw_marker_circle(g, x, y, radius, layer, line_w=10000):
    draw_arc(g, x, y, radius, 0, 360, layer, line_w=10000)

def draw_marker_lozenge(g, x, y, radius, layer, line_w=10000):
    points = [
        (x, y + radius),  # Top
        (x + radius, y),  # Right
        (x, y - radius),  # Bottom
        (x - radius, y),  # Left
    ]
    draw_poly(g, points, layer, filled, line_w)
    
def draw_marker_hbar(g, x, y, radius, layer, line_w=10000):
    draw_line(g, x - radius, y, x + radius, y, layer, line_w)

def draw_marker_slash(g, x, y, radius, layer, line_w=10000):
    draw_line(g, x - radius, y - radius, x + radius, y + radius, layer, line_w)

def draw_marker_backslash(g, x, y, radius, layer, line_w=10000):
    draw_line(g, x + radius, y - radius, x - radius, y + radius, layer, line_w)

def draw_marker_vbar(g, x, y, radius, layer, line_w=10000):
    draw_line(g, x, y - radius, x, y + radius, layer, line_w)

Then, it might be possible to simply iterate through the holes list m_holeListBuffer, and match them against the CSV report table to choose the correct symbol.

Including it in the Include Table preflight might make things simpler, with a is_drill_table option for the IncTableOutputOptions and if it is set to True, we automatically draw the Drill Map Drawing on the same layer in a new group (e.g. kibot_drill_map), aligned with the PCB.

@set-soft
Copy link
Member

No news about it, I don't have much time and higher priority issues poped-up

@nguyen-v
Copy link
Author

Got it, I will be working on that on my side

@nguyen-v
Copy link
Author

nguyen-v commented Dec 26, 2024

I've made some progress on this
https://github.com/INTI-CMNB/KiBot/compare/dev...nguyen-v:KiBot:feat_drill_map?expand=1

Features:

  • New output in excellon, which allows to generate CSV drill tables for each unique drill layer pair. The name/order of columns can be changed. By default the grouping is similar to KiCad, but I've also added the option to separate by hole shape (i.e. slot vs circle) even if the tool diameter is the same.
    Just an example of configuration
outputs:
- name: @NAME@
  comment: '@COMMENT@'
  type: excellon
  category: '@DIR@'
  dir: '@DIR@'
  options:
    generate_drill_files: false
    table:
      pth_and_npth_single_file: @PTH_NPTH@
      group_slots_and_round_holes: @GROUP_ROUND_SLOTS@
      columns:
        - field: Count
          name: Number of holes
        - field: Hole Size
          name: Size

When columns is not specified, we get the default list of columns
Default behavior:
image
Separating by hole shape:
image

Now, I need some guidance on how to implement these functions in the PCB Print. The issue is that there might be one or multiple outputs, depending on whether the user decides to separate PTH/NPTH holes and also if there are more than one layer drill pairs.

I'm not very familiar with the intricacies of PCB Print or how this feature would be best implemented in KiBot, but I will throw some ideas:

  • Have something similar to repeat_layer but would allow to specify a preflight to iterate on, with a start index, increment and end index. In this case the preflight could be something like Include Table and the end index would be the number of unique layer pairs. For the drill map drawing maybe in Include Table automatically draw it alongside the drill table if the output is set as is_drill_table = True in the outputs option of the preflight . The is_drill_table could be a special case where it draws the drill symbols next to the leftmost cells (or in empty cells appended on the left)
  • Reserve one user layer per unique drill layer pair on the PCB and manually input different indexes in the group names. I don't really like this approach because it wastes some of the user layers and would need to know in advance the number of layer pairs

@set-soft
Copy link
Member

set-soft commented Dec 27, 2024

Hi @nguyen-v !

I think we should create some virtual layers, lets say we use a prefix _Drill.. Then we encode the filter here. I.e. _Drill.LAYERPAIR_PTHCASE. Lets say _Drill.F.Cu#B.Cu#NPTH will mean drill holes that are through hole and aren't plated, _Drill.F.Cu#B.Cu might be for plated and not plated, _Drill.all might be for all drill "layers" merging plated and non-plated, _Drill.all#PTH all plated "layers", _Drill.all#all like all but separating plated style, etc.

So then for the layer you use one of these names, and then you use repeat_for_layer and repeat_layers in the same way you use them for F.Cu.

This virtual layer is just the drawing marks plus the reference table. The reference table might use a mechanism that is similar to the Include Table mechanism.

Options to fine tune the details might be some drill_options in the page level, some dict containing options to customize the process.

One tricky detail here is that we should make the Layer class be aware of the valid names. Perhaps a derived class? With members to store the layer pair, PTH/NPTH/Both and the all wildcards?

Another thing: should we move the PTH/NPTH/Both selection to the drill_options? This will simplify the layer specification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants