KiCommand discussion and development - Easy pcbnew command line; 4.07 & 5.1.5/.6

Major update to KiCommand to include net and netclass commands. I haven’t tested the set* commands, but the get* commands work well.

I’ve tried to standardize on get* command using an argument, while commands that are nouns (like netnamemap, netcodemap, tracks, etc) retrieve board-wide lists/maps of objects. To do this, a few commands have changed, and there are perhaps a few holdover commands that still need updating.

Through all of this, one command seemed out of place: matchreference was renamed to filterrefregex (filter reference regular expression) and a corresponding filtervalregex added to complement. The filter* commands filter the objectlist provided as an argument based on matching criteria also provided as an argument.

Development continues, and comments, discussion, or questions are welcome.

In my attempt to be very flexible in handling lists, where functions operate seamlessly on the elements of a list, I’ve run into an ambiguity. I’ve recently extended call and callargs to work on lists where you can supply a list of objects and/or a list of arguments and/or a list of functions, and it works well. For example:

  • netclassmap Default sindex GetClearance,GetTrackWidth,GetViaDiameter,GetViaDrill,GetuViaDiameter,GetuViaDrill,GetDiffPairWidth,GetDiffPairGap split call - return as a list, each of the listed values from the netclassptr object.

The detection of a list is determined by identifying an iterator. If it is an iterator, it is considered a list. With this detection, a dictionary is identified as a ‘list’ because it has an iterator. This makes it more difficult to directly call dictionary functions, such as keys() or values().

The solution is either to surround the dictionary with list and delist to get past the detection mechanism, or to redefine the new call and callargs functions into call. and callargs., which indicate an element-by-element function. Then redefine the call and callargs to not operate on lists element by element.

I’m trying to keep in mind that KiCommand is primarily an interactive command line and determine what is most useful in that context.

While I decide how to proceed, comments are welcome.

Edit: Maybe I could add calld and callargsd to indicate “direct”, where I ignore the iterator status of the objectlist. My main problem is that I like the ease of use of handling lists automatically, and I want that to be the “default” for unadorned functions.

Hi @HiGreg, i wonder if i can use your KiCommand to highlight all “equal” components in PCBnew?
So for example if i wanted to highlight all resistors with value 1k and 0603 package could i use something like

show all r 1k 0603 

or can i alter specific attributes of a footprint with it like the “lock” with something like

lock all fp

I’ve read the wiki and your read.me but you talk a lot about data types and stuff but it’s not quite clear to me if and how i could achieve the two examples from above.
If this is off topic, tell me and i open a new thread.

This is exactly on topic. First thing to note is that KiCommand is stack based, so arguments occur before the command. You can get all 1k resistors by using either a regular expression or a string match. Let’s walk through the demo board available in the kicad install directory (share/kicad/demos/complex_hierarchy). Load that board then try the following:

  • modules getvaltext print - this will print the value text of all modules

on the demo board, I see:

[u’CONN_2’, u’CONN_2’, u’CONN_2’, u’CONN_2’, u’CONN_2’, u’CONN_2’, u’1N4148’, u’1N4148’, u’1N4148’, u’1N4148’, u’1N4148’, u’1N4148’, u’1N4148’, u’1N4148’, u’1N4007’, u’15nF’, u’4.7nF’, u’150nF’, u’150nF’, u’820pF’, u’15nF’, u’4.7nF’, u’820pF’, u’LM358N’, u’ICL7660’, u’LM358N’, u’5,6K’, u’220K’, u’1K’, u’1K’, u’47’, u’220K’, u’47’, u’220K’, u’47’, u’220K’, u’470’, u’4,7K’, u’22K’, u’22K’, u’1K’, u’1K’, u’5,6K’, u’4,7K’, u’220K’, u’470’, u’220K’, u’47’, u’22K’, u’1K’, u’22K’, u’1K’, u’47uF’, u’47uF/20V’, u’47uF/63V’, u’10uF’, u’10uF’, u’MPAS92’, u’MPAS42’, u’MPAS92’, u’MPAS42’, u’MPAS92’, u’MPAS42’, u’MPAS92’, u’MPAS42’, u’4,7K’, u’4,7K’, u’78L05’]

  • modules getreftext print - print the reference text of all modules

Result:

[u’P5’, u’P6’, u’P3’, u’P4’, u’P2’, u’P1’, u’D9’, u’D4’, u’D6’, u’D7’, u’D3’, u’D2’, u’D8’, u’D5’, u’D1’, u’C3’, u’C4’, u’C14’, u’C12’, u’C5’, u’C6’, u’C7’, u’C8’, u’U3’, u’U1’, u’U4’, u’R20’, u’R22’, u’R23’, u’R24’, u’R25’, u’R26’, u’R27’, u’R28’, u’R5’, u’R4’, u’R3’, u’R21’, u’R17’, u’R7’, u’R8’, u’R9’, u’R10’, u’R11’, u’R12’, u’R13’, u’R14’, u’R15’, u’R16’, u’R18’, u’R6’, u’R19’, u’C1’, u’C2’, u’C9’, u’C10’, u’C11’, u’Q1’, u’Q2’, u’Q3’, u’Q4’, u’Q5’, u’Q6’, u’Q7’, u’Q8’, u’RV1’, u’RV2’, u’U2’]

The next one is a little tricky. Getting the path of the footprint. Try this:

  • clear modules GetFPID call GetLibItemName call '__str__ call print - get the name of the footprint

One of the items here is named “R_Axial_DIN0204_L3.6mm_D1.6mm_P7.62mm_Horizontal”, which seems to indicate its size (but it’s not guaranteed).

Now that we know a little bit about the board, we can start to hone our command to get only the desired modules.

Using some commands to filter on the name and value, assuming resistors start with “R”:

  • modules R.* filterrefregex 1K filtervalregex print - filter on modules with reference beginning with R and value of 1K

But we want to make sure we get the 0603, so let’s assume that string is in the footprint path.

  • copy GetFPID call GetLibItemName call '__str__ call - get the library name

We’ll call the following command string the module selection command. It’s a combination of all the above:

clear modules R.* filterrefregex 1K filtervalregex copy GetFPID call GetLibItemName call '__str__ call .*0204.* regex filter

That’s the command we’ll use to find the modules. You’ll want to change that to 0603 instead of 0204. Then we need to get or set their Lock status. There’s not a built in KiCommand to lock a footprint, but we can drop into the python function.

Execute the above module selection command to get all the modules desired. Then execute only one of the following.

Execute the module selection command, then:

  • IsLocked call - get the Locked status of modules

Execute the module selection command, then:

  • true SetLocked callargs - set the Locked status of modules

Finally, check that it worked. Execute the module selection command, then:

  • IsLocked call - get the Locked status of modules

Edit:

I just pushed some new commands for your use case: getlocked, setlocked, clearlocked, getfootprintname and filterfpregex.

The locked commands mirror get/set/clear visible, but don’t exactly match the Python commands underneath (SetLocked/IsLocked).

Example:

  • modules R.* filterrefregex 1K filtervalregex .*0603.* filterfpregex copy setlocked getlocked print - get modules matching each of the three criteria, set the locked status, then retrieve the locked status and print out the result. Should result in a list of “True” values.
3 Likes

Thank you for this extensive post. I sadly will have no time to proceed with this until the end of next week, but I’ll come back and report a bit about my experience once I’m done.

A bit of background on my use case:
i assemble PCBs in small batches like 1-5 pieces, by hand. So i use the PCB file as reference for assembly but keep selecting anything in PCBnew but the whole footprint, that’s quite annoying and the reason why i want to lock them. It’s also very useful to be able to show all equal components so i don’t have to search for the bag with the 1k resistor 25 times :wink:

@Detzi, whether or not this can be done with KiCommand, I would recommend trying the InteractiveHtmlBom plugin for hand assembly. It’s meant exactly for your use case.

4 Likes

KiCommand has been tested on pre release 5.1.6 (April 20) on Windows and no changes were necessary. There is one test (the now command) that occasionally fails, but the test will be fixed in the next release.

In the last couple of releases of KiCommand, there has been much work on making command consistent, along with updates to call and callargs that will be useful to users. Please feel free to reach out with comments, questions, or suggestions.

DRAWSEGMENT considerations?

In an attempt to unify the creation of DRAWSEGMENTs of all types,
KiCommand could use a few different approaches.

In general, the approaches would include a command with arguments. There would be two goals:

  1. Fairly easy command-line creation of new segments.
  2. (possibly) allow the extraction of segment definition, modify some of the parameters, then create a new segment with the modified parameters.

Let’s talk about the possible methods of creating a new DRAWSEGMENT. To do that, we’ll first talk about the different DRAWSEGMENTs that exist. There are 6 within the source code, and 4 that are accessible from the GUI.

  1. Line (S_SEGMENT)
  2. Polygon (S_POLYGON)
  3. Bezier Curve (S_CURVE)
  4. Circle (S_CIRCLE)
  5. Arc (S_ARC)
  6. Rectangle (S_RECT)

Only the bolded DRAWSEGMENT types are available from the GUI, so we’ll focus on those. Specifying Line and Polygon is fairly straightforward and are easily described by the end points and vertex points, respectively.

Arc and circle are a little different, and they have multiple ways that might be desired to specify the points. One of these methods, for each type, is also the native method for creating the DRAWSEGMENT within Python.

Methods for specifying circle. I’ll also supply a shorthand name for each method. All points and dimensions would be specified in native units.

  1. CircleP CenterPoint, StartPoint (a point on the circle) - this is the native method to create a circle.
  2. CircleR CenterPoint, Radius
  3. CircleC CirclePoint1, CirclePoint2, Radius (+/- indicates direction, CW/CCW or RW/LW, make sure this matches Angle direction)

Methods for specifying an arc.

  1. ArcA StartPoint, CenterPoint, AngleDegrees (+/- indicates direction) - this is the native method to create an arc.
  2. ArcP StartPoint, EndPoint, CenterPoint
  3. ArcR StartPoint, EndPoint, RadiusNative (+/- indicates direction, CW/CCW or RW/LW, make sure this matches Angle direction)

In addition to the numbers that specify points and dimensions, there are additional paramters that might be useful to specify: thickness and layer. These are normally specified in KiCommand for all new elements through the draw parameters. Draw parameters allows you to specify the thickness and layer for all subsequent draw commands. The layer used for drawing allows the possibility that the same element commands can create either DRAWSEGMENTs or TRACKS, depending on whether or not the layer is a copper layer.

One basic question on command structure is: should the command itself specify the DRAWSEGMENT type, or should the DRAWSEGMENT type be a parameter? To allow for the possibility of extracting an existing DRAWSEGMENT’s specification, it probably makes more sense to extract the type as well. This way, when extracting several DRAWSEGMENTs at one time, the exact type of DRAWSEGMENT is included in the results.

This could result in two possible commands:

  • getsegment - returns SegmentType,ArgX,…
  • newsegment - takes a single (list) argument SegmentType,Argx,…

Where segment type is one of the strings: Line, Polygon, ArcA, ArcP, ArcR, CircleP, CircleR, CircleC. Perhaps obviously, getsegment would by definition return only ArcA, or CircleP (the native methods of specifying). However, this would preclude being able to get, for example, the Circle radius, manipulating that, and drawing a new DRAWSEGMENT.

I should definitely allow specifying the thickness and layer with the draw parameters, as this would become tedious in use not to. It might be interesting to allow layer and thickness to be specified by parameter as well.

Open questions:

  1. Should SegmentType be specified by argument within the segment list, a parameter outside the segment list, or a different command for each type?
  2. Should Layer and Thickness be optional parameters, or parameters using a different command?
  3. Should points within the parameters be specified linearly or though nested lists (X, Y points)?

The answers depend on exactly the use cases I’m trying to develop for. Perhaps I’ll generate the use cases in a subsequent post.

Does anyone have any opinions or additional considerations?

Developing this idea further.

I have basic code put together that can take an argument string and put together a list of segments. The flexibility will allow a wide variety of ways of specifying the drawsegments.

I think it’s also prudent to change the order of some arguments for Arc and Circle drawsegments.

  1. Center, if specified, is first.
  2. Radius or Angle, if specified, is last.
  3. That means any points on the segment are specified “in the middle.”
  4. All arguments can be in arbitrarily-nested lists. This might often be paired x/y points in their own list. It won’t matter how their paired or nested.
  5. Any number of numeric arguments can be specified after the segmenttype string to indicate more than one segment definition (except for polygon or (new) polyline).
  6. All numeric arguments can be specified as float, int, or string. If strings are used, they can be comma separated. Strings are converted to floats. (I might consider converting number strings without a decimal point to integers.)
  7. If not done already, i’ll Modify arithmetic operators to pass through strings (such as segment type) so you can operate on the numbers in a segment specification without affecting the segment type. It will just “pass through” unmodified.

Also, I’m trying to figure out the Arc and Circle suffix letter to be consistent between them.

More updates to come.

Here are the (proposed) general rules for circles and arcs. It’s a way to unify the specification of circles and arcs and is more consistent for both, with a defined order of arguments. Hopefully this will be easier to remember.

The two/three letters are the arguments expected. “O” is a point on the drawing.

  • “C”: specified by C(O)N (N=A or R)
  • “P”: specified by points CO(O)
  • “R”: specified by OOR
  1. CircleC CR CenterPoint, Radius

  2. CircleP CO CenterPoint, StartPoint

  3. CircleR OOR CirclePoint1, CirclePoint2, +/-Radius

  4. ArcC COA CenterPoint, StartPoint, Angle

  5. ArcP COO CenterPoint, StartPoint, EndPoint

  6. ArcR OOR StartPoint, EndPoint, +/-Radius

First, the options spell out the (hopefully easy to remember) acronym “CPR”. The P and R suffixes are very consistent in the arguments specified, but the C is a little odd. You might be able to remember that C indicates to specify a number (angle or radius) also.

I’m playing around with zones and polygons and formulating how KiCommand should handle the variety of functions. I’ve discovered that through the KiCAD GUI, it is possible to create a DRAWSEGMENT of any type on any layer, including copper. Doing so on copper does not allow adding a NET since an object mut be derived from BOARD_CONNECTED_TYPE, such as TRACK, VIA, ARC (which themselves are derived from TRACK), and ZONE_CONTAINER, among others. It is not clear to me what the utility of a DRAWSEGMENT on a copper layer is, but it seems prudent to support it.

Because DRAWSEGMENTs can be on copper, we cannot distinguish automatically the intent of the user when creating segments on copper. Older KiCommand commands assume that if a line segment is drawn on copper, it is intended to be a track. New commands will not carry this assumption forward. The command will specifically indicate the destination object, whether DRAWSEGMENT, TRACK, or ZONE_CONTAINER.

Here’s what I’m thinking:

  • newdrawing - will create a DRAWSEGMENT of specified shape on the active layer (from drawparams)
  • newzone - will create a ZONE_CONTAINER of specified shape on the active layer (from drawparams)
  • newtrack - will create TRACK, ARC, or ZONE based on the specified shape (Line/Polyline->TRACK, Arc/Circle->ARC, Polygon->ZONE) on the active layer, which must be copper. When created, TRACKs have the default net (0/’’).

I had to create a place to indicate units. With the way it was working (angle being an argument for some shapes), it was not convenient to specify the shape and use the existing mm command to convert units because the angle would be “converted” (and then be horribly wrong). So I added the ability to specify units inline. The following commands are examples of how it’s working. These command just use straight lists of numbers. The ArcC shape uses the arc angle as its last argument. The angle does not get converted to the units specified (mm), but all other points do get converted to native units from mm.

Line,mm,20,10,22,12 split newdrawing refresh
ArcC,mm,20,10,22,12,90 split newdrawing refresh
ArcM,mm,22,12,20,12.8,18,12 split newdrawing refresh
CircleP,mm,-10,-10,5 split newdrawing refresh
Polygon,mm,30,0,30,1,25,1 split newdrawing refresh
Bezier,mm,30,0,30,1,25,1 split newdrawing refresh

I’m calling the above string description a “geom”. A “geom” can also be a list with wxPoints or pairs of x/y coordinates within the specification (wxPoints must already be in native units). There will be a way to get the “geom” of objects using getgeom command on a list of objects. geoms are more fully described in post 73.

Bezier Curves are interesting because I don’t think you can create them through the GUI, but you can create them in Python, and coming soon, KiCommand. After they are created, they can be manipulated in the GUI. It also looks like there is only one type of Bezier Curve: a 4-point Bezier Curve with the Start Point, Control Point 1, Control Point 2, and End Point.

Here’s a variety of shapes, some of which were created with KiCommand. Note the Bezier Curve in yellow in the upper right.

1 Like

Geom summary to date

A geom consists of a list of values used to specify one or more geometrical shapes. The list is easily generated manually, or can be extracted from existing objects such as DRAWSEGMENTs, TRACKs, and ZONEs. There are five commands that use a geom and a wide variety of shape types to cover each of the shape types within a DRAWSEGMENT. The same geom specification can be used to generate TRACKs and ZONEs.

Commands that use geom

  • getgeom - extract the geometries into an easy-to-read list called a “geom”. This will (currently) lose some information of the object, such as thickness, corner smoothing, and layer. The output of getgeom is not a string but instead a list of strings, wxPoints, and numbers.
  • getgeomstring - extract the geometries into an easy-to-read string called a “geom”. This is suitable for cut and paste operations to duplicate the shape of an object (excluding some object parameters such as thickness and layer). This can take a list of objects or a list of geoms.
  • newdrawing - will create a DRAWSEGMENT of specified shape on the active layer (from drawparams)
  • newzone - will create a ZONE_CONTAINER of specified shape on the active layer (from drawparams). If the zone is on copper, it will have the default net (0/’’).
  • newtrack - will create TRACK, ARC, or ZONE based on the specified shape (Line/Polyline->TRACK, Arc/Circle->ARC, Polygon->ZONE) on the active layer, which must be copper. When created, TRACKs have the default net (0/’’).

General Rules for geom specification

  • A geom consists of a list of values. The first value is a shapetype, the second and optional value is a unit, followed by points and numbers (collectively, “arguments”) that specify the shape. geoms can be specified successively in the same list.
  • All arguments can be listed as a comma-separated string to make specifications easy to enter by hand. Currently you would use the split command after your comma-separated string, but this requirement might be removed.
  • All arguments can be in arbitrarily-nested lists. This might often be paired x/y points in their own list. It won’t matter how they’re paired or nested.
  • In the specification of a geom, you can put a unit string after the shape type. Units are one of mm, mil, mils, native, or nm. This affects all parameters except for angles and numbers already specified as wxPoints. It is presumed that actual wxPoints would have come from getgeom.
  • Any number of numeric argument “sets” can be specified after the segmenttype string to indicate more than one segment/object (except for polygon or (new) polyline).
  • All numeric arguments can be specified as float, int, or string. If strings are used, they can be comma separated. Strings are converted to floats. (I might consider converting number strings without a decimal point to integers.)
  • Center, if specified, is first.
  • If Start and End are both specified, Start is before End.
  • Radius or Angle, if specified, is last.
  • Arithmetic operators are modified to pass through strings (such as segment type) so you can operate on the numbers in a segment specification without affecting the segment type. It will just “pass through” unmodified.

Argument Key:

  • C - is the center point of an arc or circle.
  • B - is a control point on a Bezier curve.
  • O - is a point on the drawing.
  • R - is a radius of an arc or circle.
  • A - is an angle of an arc.
  • S - is a start point on drawing.
  • E - is a end point on drawing.
  • P - is a point

Circle and Arc Suffix Key:

  • “C”: specified by C(O)N (N=A or R)
  • “R”: specified by OOR
  • “O”: specified by all points on the drawing.
  • “P”: specified by points CO(O)

All geoms:

The one-to-four letters after the shape name are the arguments expected based on the “Argument Key.”

Line SE StartPoint, EndPoint
Bezier SBBE StartPoint, ControlPoint1, ControlPoint2, EndPoint
Polygon P a sequence of vertex points
Polyline P a sequence of vertix points.
CircleC CR CenterPoint, Radius
CircleR OOR CirclePoint1, CirclePoint2, +/-Radius
CircleO OOO StartPoint, CirclePoint1, CirclePoint2
CircleP CO CenterPoint, StartPoint
ArcC COA CenterPoint, StartPoint, Angle
ArcR OOR StartPoint, EndPoint, +/-Radius
ArcO OOO StartPoint, MidPoint, EndPoint. Although this indicates "Mid" point, any point on the arc will suffice.
ArcP COO CenterPoint, StartPoint, EndPoint

Note that for all geoms, you can repeat sets of arguments for another shape of the same type. To specify this, just continue listing arguments.

  • Line,Units,Start1,End1,Start2,End2,Start3,End3,Start4,End4

This is different than Polyline, which creates segemnts identical to Line, but chains them together and only requires a list of vertex/points.

  • Polyline,mm,P1,P2,P3,P4

That will create segments:

  • P1,P2
  • P2,P3
  • P3,P4

Note that Polyline is not necessarily a closed area, you need to repeat P1 at the end of the point list if you want it closed. Whereas,

  • Polygon,mm,P1,P2,P3,P4

will create a closed polygon with specified vertices, with P4 connected to P1.

Example Commands:

Line,mm,20,10,22,12 split newdrawing refresh
ArcC,mm,20,10,22,12,90 split newdrawing refresh
ArcM,mm,22,12,20,12.8,18,12 split newdrawing refresh
CircleP,mm,-10,-10,5 split newdrawing refresh
Polygon,mm,30,0,30,1,25,1 split newdrawing refresh
Bezier,mm,30,0,30,1,25,1 split newdrawing refresh

Additional Thoughts

Polygons for DRAWSEGMENTs and ZONEs are treated differently by KiCAD. A ZONE treats vertices as the outside boundary, with corners rounded within those bounds based on a parameter that geoms don’t currently preserve. DRAWSEGMENTs and TRACKs (and Polylines) treat vertices as the midpoint of the drawn line, with material/layer extending beyond the points by the thickness. It’s not clear yet how/if KiCommand should handle conversion of these shapes so that ZONEs and DRAWSEGMENT Polygons turn out identical.

I’m thinking about how to add VIAs inline, so that you could specify an entire connected track. Something like “Via,[Type],Drill,ToLayerName” that you could place in the midst of a Polyline and it would make a Via connecting the current layer to the ToLayerName and set that layer is the “current layer” to continue the Polyline. I’m also considering how to add *drawparameters" so thickness or layer can be modified inline as well, perhaps those can be modifications to the current geom or current and future geoms until changed, based on the name of the parameter.

I also want to support DRAWSEGMENTS, TRACKS, ZONE_CONTAINER and ZONE_CONTAINERS in the midst of geom strings, that way you can copy any existing shape from or to a drawing, track, or zone.

That’s all I have for now. This represents my current thoughts and is subject to change. I’ll modify the Tutorial/Wiki with updated information when applicable. This is not currently released as of the time of this writing, but being developed for the next release of KiCommand.

@HiGreg
First thanks for this awesome tool!!
I’m using KC 5.1.6 Modern Toolset on a mac. In case anyone else on a mac has trouble getting KiCommand installed (like I did), putting it under ~/Library/Preferences/kicad/scripting/plugins/ worked for me.

Here’s a couple things I’ve noted so far:

  1. There is no default location during KiCad install (macOS) for the Demos folder, so kicommand.test fails finding the demo projects. Maybe for the mac use ~/Library/Application Support/kicad/demos ?
  2. If the popup KiCommand window is closed, then unable to restart KiCommand window without first closing the pcbnew window.
  3. When using the GRID command on a selected trace, only the Start point X Y points are snapped to the grid. The End point X Y points retain their previous values.

Thank you for the feedback!

  1. I don’t have experience running KiCAD on a Mac, so I really appreciate your finding out the demo projects’ location.

  2. I’ll look into the window not coming back.

  3. You’re right. At the time that command was written, I only took into account DRAWSEGMENTs, and not TRACKs. I’ll fix this in the next release. If you want to fix it now, you can edit line 792 of kicommand.py from

    if isinstance(seg, pcbnew.DRAWSEGMENT):

To

if isinstance(seg, (pcbnew.DRAWSEGMENT, pcbnew.TRACK) ):

@HiGreg
Wow! Thanks for the quick response.

  1. The Demos folder doesn’t get installed anywhere during KiCad installation on the mac, I was just suggesting a location. Open for any other convenient location.

  2. Thanks for looking into the window return problem.

  3. YES!!! It appears (from a quick test) that tracks (and vias) are now snapped correctly. What a great time saver!!

1 Like

One of the things that you can do is query a DRAWSEGMENT to determine its attributes. With the call command, you can get all the attributes at once. For example, select one or more DRAWSEGMENTs, then execute the following:

  • drawings selected GetCenter,GetStart,GetEnd,GetRadius split call

You will get the results of each of those Python method calls on the selected objects.

With that in mind you can use the newdrawing command in an upcoming release of KiCommand to create basic objects. I’ve put together a few for testing. One thing I realized while testing is that the specification for ArcR–where you specify the Start point, End point, and radius–does not fully specify an ARC. For any two points and a given radius, there are four ARCs that start and end at those points. Namely Clockwise/Rightward with angle less than 180, Clockwise/Rightward with angle greater than 180, Counter-clockwise/Leftward with angle less than 180, Counter-clockwise/Leftward with angle greater than 180. Unfortunately this cannot be disambiguated with a sign on the radius. On the “bright” side, one of the main reasons I can think of why to use this specification of an Arc is to make sure the start and end point are at given locations, and the curvature is defined. More likely, however, you will find the round command more useful, as it will create an ARC between two lines, and make sure the connections are smooth–at the same angle–forming a smooth transition between line and ARC.

Another issue is with ArcP, where center, start, and end are specified. There are two ARCs that pass through the points. If a direction, either CW/RW or CCW/LW is assumed, then ArcP only specifies one ARC.

At this point, assume that the Arc* definitions might be changing.

Here are some of the commands I’ve used for testing. I haven’t verified all the conditions, particularly when internal calculations result in infinity (which happens with the slope calculation of a vertical line).

CircleR,mm,2,0,0,2,2 split newdrawing refresh
Line,mm,0,0,0,5 split newdrawing
CircleC,mm,20,5,2 split newdrawing
CircleR,mm,10,7,12,5,2 split newdrawing
CircleR,mm,8,5,10,3,2 split newdrawing refresh
CircleO,mm,7,5,5,7,5,3 split newdrawing 
CircleP,mm,0,5,2,5 split newdrawing
ArcC,mm,0,0,2,0,361 split newdrawing
ArcC,mm,5,0,7,0,360 split newdrawing
ArcC,mm,10,0,12,0,359 split newdrawing
ArcC,mm,15,0,17,0,271 split newdrawing
ArcC,mm,20,0,22,0,270 split newdrawing
ArcC,mm,25,0,27,0,269 split newdrawing
ArcC,mm,30,0,32,0,181 split newdrawing
ArcC,mm,35,0,37,0,180 split newdrawing
ArcC,mm,40,0,42,0,179 split newdrawing
ArcC,mm,45,0,47,0,91 split newdrawing
ArcC,mm,50,0,52,0,90 split newdrawing
ArcC,mm,55,0,57,0,89 split newdrawing
ArcC,mm,60,0,62,0,1 split newdrawing
ArcC,mm,65,0,67,0,0 split newdrawing
ArcC,mm,70,0,72,0,-1 split newdrawing
ArcC,mm,75,0,77,0,-89 split newdrawing
ArcC,mm,80,0,82,0,-90 split newdrawing
ArcC,mm,85,0,87,0,-91 split newdrawing
ArcC,mm,90,0,92,0,-179 split newdrawing
ArcC,mm,95,0,97,0,-180 split newdrawing
ArcC,mm,100,0,102,0,-181 split newdrawing
ArcC,mm,105,0,107,0,-269 split newdrawing
ArcC,mm,110,0,112,0,-270 split newdrawing
ArcC,mm,115,0,117,0,-271 split newdrawing
ArcC,mm,120,0,122,0,-359 split newdrawing
ArcC,mm,125,0,127,0,-360 split newdrawing
ArcC,mm,130,0,132,0,-361 split newdrawing
ArcR,mm,25,7,25,3,2 split newdrawing
ArcO,mm,0,2,2,0,-2,0 split newdrawing "this has problem. should be start,mid,end"
ArcP,mm,0,0,2,0,-2,0 split newdrawing "CSE"
Polygon,mm,0,0,5,5,10,-10,15,15
Polyline,mm,0,0,5,5,10,-10,15,15
Bezier,mm,0,0,5,5,10,-5,15,0

Arc Testing

I’m testing out the ArcO geom shape. The full test is about 1300 arcs, with an exhaustive list of points varying angles from -360 to 360 degrees on each combination of start, middle, and end points. Finally debugged all the calculations! Here’s a snippet of the test result. The lines go from origin to start and origin to end. The pink line (on Margin layer) goes from origin to the middle point (which doesn’t have to be the exact middle of the angle).

An excerpt of the KiCommand string looks like:

  • Layer,Margin,Line,mm,6,9,5.5,9.86602540378,Layer,Dwgs.User,Line,mm,6,9,7.0,9.0,Line,mm,6,9,6.5,9.86602540378,ArcO,mm,7.0,9.0,5.5,9.86602540378,6.5,9.86602540378,Layer,Margin,Line,mm,6,12,5.0,12.0,Layer,Dwgs.User,Line,mm,6,12,7.0,12.0,Line,mm,6,12,6.5,12.8660254038,ArcO,mm,7.0,12.0,5.0,12.0,6.5,12.8660254038,Layer,Margin,Line,mm,6,15,5.5,14.1339745962,Layer,Dwgs.User,Line,mm,6,15,7.0,15.0,Line,mm,6,15,6.5,15.8660254038,ArcO,mm,7.0,15.0,5.5,14.1339745962,6.5,15.8660254038,Layer,Margin,Line,mm,6,18,6.5,17.1339745962,Layer,Dwgs.User,Line,mm,6,18,7.0,18.0,Line,mm,6,18,6.5,18.8660254038,ArcO,mm,7.0,18.0,6.5,17.1339745962,6.5,18.8660254038,Layer,Margin,Line,mm,6,27,5.5,27.8660254038,Layer,Dwgs.User,Line,mm,6,27,7.0,27.0,Line,mm,6,27,6.5,27.8660254038,ArcO,mm,7.0,27.0,5.5,27.8660254038,6.5,27.8660254038,Layer,Margin,Line,mm,6,30,5.0,30.0,Layer,Dwgs.User,Line,mm,6,30,7.0,30.0,Line,mm,6,30,6.5,30.8660254038,ArcO,mm,7.0,30.0,5.0,30.0,6.5,30.8660254038, followed by “split newdrawing refresh

Interesting statistics:

  • number of elements (ArdcO and Line): 4800
  • KiCommand string length: 215556
  • Processing time: 5.6 seconds (on my Windows test computer)

@HiGreg
I’m trying (still learning!) to use KiCommand to locate and change sizes of specific track segments and have a few questions:

First, is there anyway to clear the KiCommand history window? After a long session it tends to fill up.

In the following example I am trying to locate all nets that have a segment of specific width. How do I remove duplicate netnames from the list? I’ve tried using “dict” with limited success:

clear tracks copy GetNetname call swap GetWidth call 0.3048 mm = filter copy dict print

In the second example I would like to select and highlight the matching track segments so I can find them visually in pcbnew window:

clear tracks copy GetWidth call 0.3048 mm = filter SetSelected call

I have also tried using SetHighlighted and SetBrightened without any visual change.

I’m glad you’re using KiCommand!

  • Clearing history window: Click in the window, use Ctrl-a (on Windows…perhaps on MacOS, it’s Command-A), then hit the Backspace or Delete key.
  • you can use the command select instead of SetSelected call, it does the same thing (to view the definition of the command, precede it with a single quote mark and follow it with see. like this: 'select see).
  • Use the refresh command to refresh the view, the tracks should highlight then.
  • Your second command looks correct. There may be some rounding error when comparing floating point. You can use 4 roundn or multiply by a constant (10000) and convert to int with 10000 * int

You’re on the right track! Try some of what I mentioned and ask another question if you’re having trouble.

Edit: oops: you’re already converting the 0.3048 to mm, so multiplying by 10000 and rounding won’t do what I thought. Use the roundn and that should work.