X-Authentication-Warning: delorie.com: mail set sender to geda-user-bounces using -f X-Recipient: geda-user AT delorie DOT com X-Original-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type:content-transfer-encoding; bh=GiKnFfTDPI/mUfM1MQNPuFz2BJQBNNItM3WhcGzPsHM=; b=VczdWxT9+QdtL0EEcnLh3r8PdPOzRR7CbN4B3rTxt3f1QKQ6jctIG1QffkN37ICojs qYzxvokC/Xy5PALkNIg4wqx620JpwTGuJUfR0s7Ci8hUakKM0DLhXV8Jij07SOJUE+g3 dAUNagC6vBZHWE6wPfNzjvIhKdpc8BmmuGldqEmXrn3THRRuK68DeH4X4QUUOhGaaOAJ h+/8P/oEDhDEXUb3p84ZtBMboSQlUEuzFKgB+hGQyXE5tlYEpEoaEvYLdVxVtf9ZuDWH +ZYXD6F4i+zs4Pbc2C4E/a16SAao3ZLaCXr7Y8S7gjPXH6TWObLImBIadShvLD9ZRGBI D9qg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:date :message-id:subject:from:to:content-type:content-transfer-encoding; bh=GiKnFfTDPI/mUfM1MQNPuFz2BJQBNNItM3WhcGzPsHM=; b=ZAu/vCgqwqY7UFVP8/CXtdvvHw8KDQxF7vbJx5rXG2xs+Iv+ZPZBES8KOm7P2V32CN 4w1wCp9GEaOWC8EKroRge18AKjWnyO+jiM4DftZJRmIZNbfDTYZ2uNb6xdRYac11/J8Q 5YAtDRVPZMZPsyaXfrQD8osv9dHAWUj5rrZiYKHODEN7zZpJO4d8suhWxEoub2NF/ub8 k+IMuZHj9pn5ajgaf2DPL5X94JX4v4BnhIaOhCD3totfOJC8S+DFE/Y+qBzjnP5SzI5C Kxz0p0sKboIuuB44fWttmlbO2PLztrvwfhjxS5s9TlYCEaX2Y1luOY5Ws3Op25ssRtht v4Ow== X-Gm-Message-State: AG10YOTjkP9Qtd8DyrVz7foTjzTs4jS3I8SqlgQSD2ciXq5neOax01ak5lfxlai1p/ipWQgd7daIqHgAz5UThQ== MIME-Version: 1.0 X-Received: by 10.194.6.98 with SMTP id z2mr1553947wjz.101.1453448588253; Thu, 21 Jan 2016 23:43:08 -0800 (PST) In-Reply-To: References: <1512221837 DOT AA25291 AT ivan DOT Harhan DOT ORG> <20160106133049 DOT 5A0E9809D79B AT turkos DOT aspodata DOT se> <20160106143629 DOT 4D39D809D79B AT turkos DOT aspodata DOT se> <20160106164022 DOT D0D4E809D79B AT turkos DOT aspodata DOT se> <20160106180912 DOT 42ddf4079d91384f206b7c35 AT gmail DOT com> <20160106191433 DOT 5dc5cb59 AT jive DOT levalinux DOT org> <20160106202817 DOT 56197b2c539d426a1b724c9e AT gmail DOT com> <568E09ED DOT 1080508 AT m0n5t3r DOT info> <568E6354 DOT 80302 AT m0n5t3r DOT info> <20160108002640 DOT 03233b24 AT jive DOT levalinux DOT org> <20160108175259 DOT 127a3f073616758434f7edff AT gmail DOT com> <20160109020345 DOT 1e07cb84 AT jive> <20160109112851 DOT 1129dc38 AT wind DOT levalinux DOT org> Date: Thu, 21 Jan 2016 22:43:08 -0900 Message-ID: Subject: Re: [geda-user] PCB data structures (was: features: layers stack, padstack/vias) From: "Britton Kerin (britton DOT kerin AT gmail DOT com) [via geda-user AT delorie DOT com]" To: geda-user AT delorie DOT com Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from quoted-printable to 8bit by delorie.com id u0M7hEse012660 Reply-To: geda-user AT delorie DOT com Errors-To: nobody AT delorie DOT com X-Mailing-List: geda-user AT delorie DOT com X-Unsubscribes-To: listserv AT delorie DOT com Precedence: bulk On Thu, Jan 21, 2016 at 12:26 PM, Roland Lutz wrote: > > On Sat, 9 Jan 2016, Britton Kerin (britton DOT kerin AT gmail DOT com) [via geda-user AT delorie DOT com] wrote: >> >> First the existing parser needs to get separated from the innards of pcb. > > > I agree. > >> As things stand now there's no single data structure that corresponds >> one-to-one with the format. Once this is done other equivalent formats >> could be implemented. > > > So let's start with that! :-) I translated the PCB file format definition into a set of C structs which you find below. The rationale behind this data structures is as follows: I'm a little unclear where you intend the below stuff to be used. As an alteration of current pcb data structures it's a huge refactor, and I guess this isn't what you're proposing. As an additional set of structures, it's got a lot of overlap with the existing PCBType. I guess these are intended as part of an API, of which existing_pcb_internals would be one consumer (it would translate the below to it's native format)? In other words, the justifcation for the significant restatement below would be the cleaner API provided not just to the existing internals, but to other potential consumers as well? Keepint this in sync with existing_pcb_internals would be challenging if existing_pcb_internals changed much, but then they generally don't. > - An "object" should be something that is located at some position on the board, and which makes sense to manipulate as an entity (e.g., both an "element instance" and a "pad" are objects, but an attribute is not). Seems reasonble. > - The location of an object in the hierarchy should be independent from the actual data which makes up the object (i.e., there are no pointers to child objects in the data structures; the hierarchy is managed separately and points to each object's data). I don't understand this, given the below. It appears that the structures you define have other objects as referenced children, and unless "object" is meant to referr to something irreducible I don't see how else it could work. > > - The data structure should be semantic; any value should have an explicit field, explicit type, and explicit meaning. Attributes are implemented as fields in a struct so they are semantically accessible to other users of the data structure. > > - All code operating on these data structures should be in the main repository, so if some change to the data structure is necessary, it can be performed without having to worry about breaking code elsewhere. > - The data structure should not contain any fields that are internal to the PCB implementation. So all access is meant to go through an API. Including access from pcb itself? > How the in-memory object hierarchy should look like is actually a non-trivial question. I think it's generally a good idea to have the state of the object tree represent something on which you can do a meaningful undo/redo: for schematics, for example, this would be each referenced or embedded symbol, and the schematic itself. But a PCB file consists of four different kinds of things: the PCB layout, the imported netlist, the elements in the layout, and the stroke font. There are also some settings that are saved with each layout, and override the defaults (from ~/.pcb/preferences or so) for that board. As far as gettign the in-memory representation "right", I'm not sure it's possible to do that in general. It's going to depend what you want to do. Therefore, an API may be overkill: it's likely you'll just need to rephrase the data anyway, so what matters is how easily you can do that, and an API may make that cumbersome. However, choosing a basic structure that gracefully supports undo/redo is reasonable, since that's required everywhere. > The netlist is a bit different in that it doesn't have a geometric structure; it's not "objects" in the definition above. The stroke font symbols are obvious candidates for separate object trees. The hard question is whether to treat an element as a "group object" which contains a bunch of element line/arc, pin, and pad objects, or to treat it as an instantiation of an embedded element definition (a.k.a. footprint). > > I think from a logical perspective it makes more sense to treat it as an instantiation (you might want to update an embedded footprint, or to not embed but reference a footprint in the future), but the way elements are currently used suggests a group object notion, too (for example changing the sizes of individual pads/pins in an existing element). Since I had to choose, I finally went with treating them as an instantiation (this is at least consistent with the way we treat symbols in gEDA/gaf). I don't understand you here. > ### Object hierarchy ### > > A PCB file contains a PCB layout, an arbitrary number of footprints, and (usually) 94 symbols. And some settings (as mentioned previously). > > The PCB layout has an object of type pcb_layout as the root object, which can contain an arbitrary number of pcb_layer objects--which in turn contain the geometric primitives--and pcb_element objects which aren't associated with a layer. Objects of type pcb_polygon can have child objects of type pcb_polygon_hole: > > pcb_layout > +- pcb_layer > +- pcb_arc > +- pcb_line > +- pcb_pad > +- pcb_pin > +- pcb_polygon > +- pcb_polygon_hole > +- pcb_rat > +- pcb_text > +- pcb_via > +- pcb_element Sounds reasonable, and similar to what we have now but with much cleaned up naming and hierarchy. > A footprint (element definition) has a pcb_footprint object as the root object which can only contain objects of the types pcb_element_arc, pcb_element_line, pcb_pad, and pcb_pin: > > pcb_footprint > +- pcb_element_arc > +- pcb_element_line > +- pcb_pad > +- pcb_pin > > A symbol definition has a pcb_symbol object as the root object which can contain pcb_symbol_line objects: > > pcb_symbol > +- pcb_symbol_line > > > ### Struct definitions ### > > I'm using double coordinates here. This is not a meant as a statement regarding integer vs. floating-point values; you can simply replace "double" with your favorite kind of "int". > > The "flags" field gave me a bit of trouble since it is a kind of general-purpose field which contains a lot of unrelated information. Most of this is only valid for certain object types, though, so I moved these flags to the appropriate type structs. What remained is five flags which apply to most geometric objects: > > /* Helper struct > used by arc, line, pad, pin, rat, text, via, element, and element text */ > > struct pcb_flags { > bool found; > bool selected; > bool failed_drc; > bool locked; > bool connected; > }; > > It may make sense to move some of this information (found and selected objects, DRC result) to a different place later since it represents a set of objects, not a state of an individual object. > > There are some directives (Grid, PolyArea, Thermal, DRC, Styles) which relate to the PCB file as a whole and can't be used more than once, so I grouped them into the pcb_layout data structure: > > struct pcb_layout { > struct string name; > struct string name; > struct double2d size; > struct { > double step; > struct double2d offset; > bool visible; > } grid; > struct { > double area; > } poly_area; > struct { > double scale; > } thermal; > struct { > double bloat; > double shrink; > double line; > double silk; > double drill; > double ring; > } drc; > struct { > bool showdrc; > bool rubberband; > bool nameonpcb; > bool autodrc; > /* ... flags ... */ > } flags; > struct string groups; > struct { > struct string name; > double thickness; > double diameter; > double drill; > double keepaway; > } styles[4]; > struct { > bool grid_imperial; > double grid_size; > /* ... attributes ... */ > } attributes; >}; > >I probably missed some flags and attributes because I couldn't find a list in the documentation and guessed from an example file. strflags.c has tables showing all the flags and which are valid for each object type. I've only looked briefly at the rest of this. My impression is that it's reasonable, though I'd have to look much more closely to feel sure. My questions about exactly how it's intended to be used remain however. When I originally referred to creating a new structure, I had a more humble goal in mind: I just wanted something like PCBType, minus all fields that don't go in a pcb file (e.g. the rtree), plus everything not reachable from PCBType that does go in a pcb file (e.g. the grid stuff from Settings). I've since become even more humble and decided it might be better to just try to add a little bit to PCBType such that it consists of a superset of what goes in a pcb_file. This would be a slightl improvement over the existing situation (which is that PCBType is neither superset nor identical set). I think you have slightly different purpose in mind of creating a foundation for a pcb API. I don't like the idea of an API based off PCBType either, but my present goal is a bit more modest than a full API, so I'm not sure I want to tackle that at the moment. It it does materialize I'll be happy to use it as a basis for an on-disc format though :). Britton >There isn't much data associated with a layer, just the number and a name: > >struct pcb_layer { > int number; > struct string name; >}; > >The geometric objects contain a "flags" field (except for pcb_polygon). Some flags which are only valid for certain object types are defined directly in the object's data structure, and pcb_element contains two sets of flags, one for the element itself and one for its text label: > >struct pcb_arc { > struct double2d pos; > struct double2d radius; > double thickness; > double clearance; > int startangle; > int deltaangle; > bool clear_polygons; > struct pcb_flags flags; >}; > >struct pcb_element { > struct pcb_flags flags; > struct string desc; > struct string name; > struct string value; > struct double2d mark; > struct double2d text; > int tdir; > double tscale; > bool hide_element_name; > bool show_pin_names; > bool onsolder; > struct pcb_flags tflags; > struct pointer footprint; >}; > >struct pcb_line { > struct double2d pos[2]; > double thickness; > double clearance; > bool clear_polygons; > bool autorouted; > struct pcb_flags flags; >}; > >struct pcb_pad { > struct double2d pos[2]; > double thickness; > double clearance; > double mask; > struct string name; > struct string number; > bool nopaste; > bool onsolder; > bool square; > bool warn; > bool edge2; > struct pcb_flags flags; >}; > >struct pcb_pin { > struct double2d pos; > double thickness; > double clearance; > double mask; > double drill; > struct string name; > struct string number; > bool hole; > bool square; > bool warn; > bool octagon; > bool edge2; > struct pcb_flags flags; >}; > >struct pcb_polygon { > struct double2d_list vertices; > bool clear; > bool full; >}; > >struct pcb_polygon_hole { > struct double2d_list vertices; >}; > >struct pcb_rat { > struct double2d pos[2]; > int group[2]; > struct pcb_flags flags; >}; > >struct pcb_text { > struct double2d pos; > int direction; > double scale; > struct string string; > struct pcb_flags flags; >}; > >struct pcb_via { > struct double2d pos; > double thickness; > double clearance; > double mask; > double drill; > struct string name; > bool hole; > bool autorouted; > bool warn; > bool octagon; > struct pcb_flags flags; >}; > >The pcb_footprint structure has much duplication with pcb_element. Some of this can probably be removed since some fields only make sense for an element instance and others for a footprint, but since I'm not too familiar with the way PCB works, I thought it would be safer to keep them for now: > >struct pcb_footprint { > struct string desc; > struct string name; > struct string value; > struct double2d mark; > struct double2d text; > int tdir; > double tscale; > bool hide_element_name; > bool show_pin_names; > bool onsolder; > struct { > struct string device; > struct string manufacturer; > struct string manufacturer_part_number; > struct string vendor; > struct string vendor_part_number; > /* ... attributes ... */ > } attributes; >}; > >As with the PCB file, I guessed the attributes from an example file and probably missed some. > >struct pcb_element_arc { > struct double2d pos; > struct double2d radius; > int startangle; > int deltaangle; > double thickness; >}; > >struct pcb_element_line { > struct double2d pos[2]; > double thickness; >}; > >Finally, symbol definitions: > >struct pcb_symbol { > wchar_t ch; > double delta; >}; > >struct pcb_symbol_line { > struct double2d pos[2]; > double thickness; >};