leomcelroy / svg-pcb

Design PCBs in the Browser
https://www.leomcelroy.com/svg-pcb-website
GNU General Public License v3.0
64 stars 9 forks source link

Data Structures #55

Open kr15h opened 1 year ago

kr15h commented 1 year ago

Some thoughts about data structures while working on the KiCad export.

Vias vs Components

One should think a bit what is a component in the context of SvgPcb. The via data structure is different from component and the way how to indicate that difference is not obvious.

Consider the plotComponents() method in downloadKiCad.js starting line 173. I use a forEach loop to loop over all the items in the state.pcb.components list. I do that to separate vias from the rest, which I refer to components. The way to recognize a via is to check if the object has an element with a key via, which feels like a hack. If an element with the key via does not exist, I conclude it is a component.

There are a few ways how to change this for the better in my opinion.

  1. Clearly define each element type. We should think about what kind of object is a component, how it is different from via, drill, track etc. All of them are already there, but one could have a part in docs where this is clearly stated. Say the functional "features" of the board include:
    • Components
    • Traces
    • Vias
    • Drills
    • Graphics (silkscreen graphics)
    • Text (silkscreen text)
    • Outline (outline or edge cuts)
    • Cuts (we could go as far as having cuts into the board as a separate category)
  2. A simple way to avoid hackish sorting could be to add a component type field. Each of the state.pcb.components could have a type field which could be set to one of SvgPcb hardcoded component types. Maybe a better name for anything on the PCB could be PCB features. Consider this enum-like thing.

    export const PCBFeatureType = Object.freeze({
      COMPONENT: 'component',
      TRACE: 'trace',
      VIA: 'via',
      DRILL: 'drill',
    });
    
    // Usage of the above would be
    pcbFeatureA.type = PCBFeatureType.COMPONENT;
    pcbFeatureB.type = PCBFeatureType.VIA;
  3. As an alternative each of the PCB "features" could have their own list or array.
    state.pcb.features.components = [];
    state.pcb.features.vias = [];
    state.pcb.features.drills = [];
    state.pcb.features.traces = [];
  4. Furthermore, each of the feature types deserves a class which would protect the PCB "features" from being mutated accidentally during their lifetimes. It would also require less work when writing exporters such as the Gerber and KiCad one. It would also be much better for writing unit tests. The clear class or PCB feature type definitions are a part of the conceptual definition and one could allocate some team energy towards this. It would make it easier to categorize code too as methods related to via data structure could be added to the Via class as a static, public or private method. What is essential here, I think, is that we define all types or classes at once and change the code to make use of them, at once.

Footprints and SVG Strings

I see no problem with footprint definition in plain SVG in the editor mode, but when it comes to data access in the data structures later, I do not think that makes sense. I would much prefer if the SVG string shape descriptions would be converted to arrays of points as soon as possible and be kept that way until they are actually rendered in the editor.

Consider the following.

const components = state.pcb.components; 
components.forEach((comp) => {
  comp.pads.forEach((pad) => {
    pad.shape.forEach((shape) => {
      // Shapes could be also primitives such as circles and rectangles, described differently.
      // Shape classes could be useful here in that case.
      shape.points.forEach((pt) => {
        // Access to point pt.x and pt.y
      }); 
    });
  });
});

This is something I would prefer to have as an API to me as plugin or addon developer. This is just a rough sketch, but I hope you get the idea here.

Access to Footprint and RefDes Info

In the same way one could have all the PCB features and shapes neatly categorized and accessible in one place, access to initial footprint name and data is very desirable.

Consider this.

const components = state.pcb.components;
components.forEach((comp) => {
  const footprint = comp.footprint;
  const footprintName = footprint.name; // SAMD11C in const SAMD11C = footprint({"A05" ...
  const footprintPads = footprint.pads; // All other footprint information available right here now
  const compId = comp.id; // Same as RefDes or ID1 in let IC1 = ...
});

In short what I am trying to explain is, that it would be desirable to have all data accessible in one place. The same data structures could be used for rendering, exporters and other plug-ins, such as a BOM generator, for example.