add bt_player
41
MySymbols.pretty/bt_player.kicad_mod
Normal file
@@ -0,0 +1,41 @@
|
||||
(module bt_player (layer F.Cu) (tedit 619E2E58)
|
||||
(fp_text reference REF** (at 8.6 5.5) (layer F.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_text value bt_player (at 13.7 -8) (layer F.Fab)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_line (start -4.05 5.25) (end -4.05 -7.18312) (layer Dwgs.User) (width 0.12))
|
||||
(fp_line (start -5.25 6.35762) (end -5.25 5.25) (layer Dwgs.User) (width 0.12))
|
||||
(fp_line (start -5.25 5.25) (end -4.05 5.25) (layer Dwgs.User) (width 0.12))
|
||||
(fp_line (start 5.95 -1.75) (end 4.05 -1.75) (layer Dwgs.User) (width 0.12))
|
||||
(fp_line (start 4.05 -1.75) (end 4.05 -7.182366) (layer Dwgs.User) (width 0.12))
|
||||
(fp_line (start 5.95 -1.75) (end 5.95 -0.81) (layer Dwgs.User) (width 0.12))
|
||||
(fp_line (start 5.95 -0.81) (end 8.20674 -0.81) (layer Dwgs.User) (width 0.12))
|
||||
(fp_arc (start 0 0) (end -4.049999 -7.183119) (angle -301.1588483) (layer Dwgs.User) (width 0.12))
|
||||
(fp_text user BATT (at 8 -3.3) (layer F.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_text user SPK (at -6.1 -2.45) (layer F.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_text user ANT (at -6.05 2.7) (layer F.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_line (start -3.92 7.25) (end 3.91 7.25) (layer Dwgs.User) (width 0.12))
|
||||
(fp_poly (pts (xy 4.07 -1.75) (xy 5.95 -1.75) (xy 5.97 -0.81) (xy 8.19 -0.81)
|
||||
(xy 8.22 0.53) (xy 8.09 1.56) (xy 7.83 2.63) (xy 7.58 3.26)
|
||||
(xy 7.39 3.64) (xy 7.09 4.22) (xy 6.74 4.77) (xy 6.23 5.39)
|
||||
(xy 5.74 5.9) (xy 5.46 6.18) (xy 4.91 6.62) (xy 4.13 7.13)
|
||||
(xy 3.88 7.26) (xy -3.85 7.27) (xy -4.2 7.09) (xy -4.54 6.87)
|
||||
(xy -4.82 6.68) (xy -5.25 6.33) (xy -5.25 5.26) (xy -4.05 5.26)
|
||||
(xy -4.04 -7.19) (xy 4.05 -7.19)) (layer Eco2.User) (width 0.1))
|
||||
(fp_text user Cutt-out (at 0.59 0.89) (layer Dwgs.User)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(pad 4 thru_hole circle (at 5.25 -3.75) (size 1 1) (drill 0.3) (layers *.Cu *.Mask))
|
||||
(pad 5 thru_hole circle (at 6.8 -1.75) (size 1 1) (drill 0.3) (layers *.Cu *.Mask))
|
||||
(pad 3 thru_hole circle (at -5.1 -5.1) (size 1 1) (drill 0.3) (layers *.Cu *.Mask))
|
||||
(pad 2 thru_hole circle (at -6.1 -3.9) (size 1 1) (drill 0.3) (layers *.Cu *.Mask))
|
||||
(pad 1 thru_hole circle (at -6.25 4.25) (size 1 1) (drill 0.3) (layers *.Cu *.Mask))
|
||||
)
|
||||
3387
kicad-symbols/Device.bck
Normal file
@@ -16811,4 +16811,21 @@ X + 2 0 200 100 D 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# bt_player
|
||||
#
|
||||
DEF bt_player U 0 40 Y Y 1 F N
|
||||
F0 "U" -50 250 50 H V C CNN
|
||||
F1 "bt_player" -50 -450 50 H V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
DRAW
|
||||
S -550 200 150 -400 0 1 0 N
|
||||
X ANT 1 250 100 100 L 50 50 1 1 I
|
||||
X SPK+ 2 250 -150 100 L 50 50 1 1 I
|
||||
X SPK- 3 250 -250 100 L 50 50 1 1 I
|
||||
X BATT- 4 -650 0 100 R 50 50 1 1 I
|
||||
X BATT+ 5 -650 100 100 R 50 50 1 1 I
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
#End Library
|
||||
|
||||
2
kicad_plugins/.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
674
kicad_plugins/LICENSE
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
81
kicad_plugins/README.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# RF-Tools for KiCAD
|
||||
**compatibility: KiCAD 5.1.x**
|
||||
|
||||
**<h2>Rounder tools for tracks</h2>**
|
||||
|
||||
(to be copied on [KiCAD plugins dir](https://kicad-source-mirror.readthedocs.io/en/latest/Documentation/development/pcbnew-plugins/#typical-plugin-structure-ppi_pi_struct))
|
||||
|
||||
* Rounder for tracks (*Action Plugin*)
|
||||
* Solder Mask Expander (*Action Plugin*)
|
||||
* Track Length (*Action Plugin*)
|
||||
* Via Fence Generator (*Action Plugin*) [pyclipper required]
|
||||
* Trace Clearance Generator
|
||||
|
||||
<br/>
|
||||
|
||||
[](resources/tracks-rounder.gif?raw=true "Tracks Rounder")
|
||||
|
||||
<br/>
|
||||
|
||||
[](resources/solder-mask-expander.gif?raw=true "Solder Mask Expander")
|
||||
|
||||
<br/>
|
||||
|
||||
[](resources/track-length.png?raw=true "Track Lenght")
|
||||
|
||||
<br/>
|
||||
|
||||
[](resources/via-fencing.png?raw=true "Via Fence Generator")
|
||||
|
||||
<br/>
|
||||
|
||||
Trace Clearance Generator:
|
||||
|
||||
Generate a copper pour keepout for a selected trace.
|
||||
|
||||

|
||||
|
||||
|
||||
<br/>
|
||||
<hr>
|
||||
<h2>Footprint Wizards:</h2>
|
||||
|
||||
(to be copied on [KiCAD plugins dir](https://kicad-source-mirror.readthedocs.io/en/latest/Documentation/development/pcbnew-plugins/#typical-plugin-structure-ppi_pi_struct))
|
||||
|
||||
* microwave RF Arc footprint wizard
|
||||
* microwave RF Mitered footprint wizard
|
||||
* microwave RF Taper footprint wizard
|
||||
|
||||
|
||||
[](resources/uwave-Arc-footprint.gif?raw=true "microwave RF Arc")
|
||||
|
||||
[](resources/uwave-Mitered-footprint.gif?raw=true "microwave RF Mitered")
|
||||
|
||||
[](resources/uwave-Tamper-footprint.gif?raw=true "microwave RF Taper")
|
||||
|
||||
Simply launch the fotprint wizard and select the uwave tool:
|
||||
|
||||

|
||||
|
||||
<br>
|
||||
<hr>
|
||||
<h2>Siblings/suggested plugins:</h2>
|
||||
<br>
|
||||
|
||||
[Via Stitching Generator](https://github.com/jsreynaud/kicad-action-scripts)
|
||||
|
||||
<br>
|
||||
|
||||

|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
[Via Teardrops Generator](https://github.com/NilujePerchut/kicad_scripts)
|
||||
|
||||
<br>
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
14
kicad_plugins/__init__.py
Normal file
@@ -0,0 +1,14 @@
|
||||
# pcbnew loads this folder as a package using import
|
||||
# thus __init__.py (this file) is executed
|
||||
# We import the plugin class here and register it to pcbnew
|
||||
|
||||
from . import rf_tools_wizards
|
||||
|
||||
from . import round_tracks
|
||||
|
||||
from . import trace_solder_expander
|
||||
from . import tracks_length
|
||||
|
||||
from . import via_fence_generator
|
||||
|
||||
from . import trace_clearance
|
||||
BIN
kicad_plugins/resources/extras/stitching-vias-help.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
252
kicad_plugins/resources/extras/stitching-vias-help.svg
Normal file
@@ -0,0 +1,252 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
height="40.400002"
|
||||
width="73.133354"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="stitching-vias-help.svg"
|
||||
viewBox="0 0 68.56252 37.875002"
|
||||
inkscape:export-filename="/home/mau/.kicad_plugins/ViaStitching/stitching-vias-help.png"
|
||||
inkscape:export-xdpi="270.51999"
|
||||
inkscape:export-ydpi="270.51999">
|
||||
<metadata
|
||||
id="metadata40">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="824"
|
||||
id="namedview38"
|
||||
showgrid="true"
|
||||
inkscape:snap-to-guides="false"
|
||||
inkscape:snap-grids="true"
|
||||
inkscape:zoom="13.427526"
|
||||
inkscape:cx="36.566677"
|
||||
inkscape:cy="22.199999"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
fit-margin-top="1"
|
||||
fit-margin-left="2"
|
||||
fit-margin-right="5"
|
||||
fit-margin-bottom="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3017"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true"
|
||||
spacingx="0.5"
|
||||
spacingy="0.5"
|
||||
originx="27.34375"
|
||||
originy="11.937501" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs4">
|
||||
<filter
|
||||
id="c"
|
||||
height="1.3651"
|
||||
width="1.2097"
|
||||
y="-0.18257"
|
||||
x="-0.10484"
|
||||
style="color-interpolation-filters:sRGB">
|
||||
<feGaussianBlur
|
||||
stdDeviation="1.5978799"
|
||||
id="feGaussianBlur7" />
|
||||
</filter>
|
||||
<filter
|
||||
id="d"
|
||||
height="1.4696"
|
||||
width="1.4809999"
|
||||
y="-0.23481999"
|
||||
x="-0.24049"
|
||||
style="color-interpolation-filters:sRGB">
|
||||
<feGaussianBlur
|
||||
stdDeviation="1.5978799"
|
||||
id="feGaussianBlur10" />
|
||||
</filter>
|
||||
</defs>
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3872"
|
||||
d="m 1.875,0.9375 v 36 h 62.000018 l -1.8e-5,-36 z"
|
||||
style="opacity:0.69599998;fill:#dfbd8a;fill-opacity:1;stroke:none;stroke-width:4.54269791;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263" />
|
||||
<g
|
||||
id="g1472"
|
||||
transform="translate(3.087584,3.5878498)">
|
||||
<g
|
||||
transform="rotate(90,28.381175,29.318675)"
|
||||
id="g928">
|
||||
<rect
|
||||
style="fill:#008000;fill-opacity:1;stroke:none;stroke-width:1.1333822;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.99997282;stroke-opacity:1"
|
||||
id="rect4495"
|
||||
width="26"
|
||||
height="38"
|
||||
x="1.3550172"
|
||||
y="1.3550172"
|
||||
inkscape:export-filename="C:\kicad-wb-1602\msys64\home\userC\RF-round-diff\new-solder-mask\bitmaps_png\sources\stitching-vias.png"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263" />
|
||||
<g
|
||||
transform="matrix(1.6382539,0,0,1.5572263,2.6122379,1.7181587)"
|
||||
id="g16"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-filename="C:\kicad-wb-1602\msys64\home\userC\RF-round-diff\new-solder-mask\bitmaps_png\sources\stitching-vias.png">
|
||||
<rect
|
||||
height="16"
|
||||
width="16"
|
||||
y="0"
|
||||
x="0"
|
||||
id="rect18"
|
||||
style="fill-opacity:0" />
|
||||
</g>
|
||||
<rect
|
||||
style="opacity:0.25;fill:#008000;fill-opacity:1;stroke:#b3b3b3;stroke-width:2.71003437;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.99997282;stroke-opacity:1"
|
||||
id="rect4737"
|
||||
width="26"
|
||||
height="38"
|
||||
x="1.3550172"
|
||||
y="1.3550172"
|
||||
inkscape:export-filename="C:\kicad-wb-1602\msys64\home\userC\RF-round-diff\new-solder-mask\bitmaps_png\sources\stitching-vias.png"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263" />
|
||||
<g
|
||||
id="g856"
|
||||
transform="translate(1.3550172,11.417517)">
|
||||
<path
|
||||
sodipodi:nodetypes="sssss"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3867-9-4-6"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffcc00;stroke-width:2.4375;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 15.25,8.875 c 0,-1.932996 1.567003,-3.499999 3.500001,-3.499999 1.932996,0 3.499999,1.567003 3.499999,3.499999 0,1.932998 -1.567003,3.500001 -3.499999,3.500001 C 16.817003,12.375001 15.25,10.807998 15.25,8.875 Z" />
|
||||
<path
|
||||
sodipodi:nodetypes="sssss"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3867-9-4-3"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffcc00;stroke-width:2.4375;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 3.75,9 c 0,-1.932997 1.567003,-3.5 3.5,-3.5 1.932997,0 3.5,1.567003 3.5,3.5 0,1.932997 -1.567003,3.5 -3.5,3.5 -1.932997,0 -3.5,-1.567003 -3.5,-3.5 z" />
|
||||
</g>
|
||||
<g
|
||||
id="g860"
|
||||
transform="translate(0.8550172,0.91751696)">
|
||||
<path
|
||||
sodipodi:nodetypes="sssss"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3867-9-4-6-5"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffcc00;stroke-width:2.4375;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 15.75,30.625 c 0,-1.932996 1.567003,-3.499999 3.500001,-3.499999 1.932996,0 3.499999,1.567003 3.499999,3.499999 0,1.932998 -1.567003,3.500001 -3.499999,3.500001 C 17.317003,34.125001 15.75,32.557998 15.75,30.625 Z" />
|
||||
<path
|
||||
sodipodi:nodetypes="sssss"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3867-9-4-3-2"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffcc00;stroke-width:2.4375;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 4.25,30.75 c 0,-1.932997 1.567003,-3.5 3.5,-3.5 1.932997,0 3.5,1.567003 3.5,3.5 0,1.932997 -1.567003,3.5 -3.5,3.5 -1.932997,0 -3.5,-1.567003 -3.5,-3.5 z" />
|
||||
</g>
|
||||
<g
|
||||
id="g856-8"
|
||||
transform="translate(1.3550172,0.16751712)">
|
||||
<path
|
||||
sodipodi:nodetypes="sssss"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3867-9-4-6-53"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffcc00;stroke-width:2.4375;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 15.25,8.875 c 0,-1.932996 1.567003,-3.499999 3.500001,-3.499999 1.932996,0 3.499999,1.567003 3.499999,3.499999 0,1.932998 -1.567003,3.500001 -3.499999,3.500001 C 16.817003,12.375001 15.25,10.807998 15.25,8.875 Z" />
|
||||
<path
|
||||
sodipodi:nodetypes="sssss"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3867-9-4-3-8"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffcc00;stroke-width:2.4375;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 3.75,9 c 0,-1.932997 1.567003,-3.5 3.5,-3.5 1.932997,0 3.5,1.567003 3.5,3.5 0,1.932997 -1.567003,3.5 -3.5,3.5 -1.932997,0 -3.5,-1.567003 -3.5,-3.5 z" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0,0.6470588,-0.93749999,0,26.742247,5.8693535)"
|
||||
id="g835">
|
||||
<path
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.89442718px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 22.607525,15.607526 H 6.6075245"
|
||||
id="path5185"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="m 16.607525,17.607526 6,-2 -6,-2"
|
||||
id="path5191"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="m 12.607525,13.607526 -6.0000005,2 6.0000005,2"
|
||||
id="path5195"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#333333;stroke:#333333;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 5.6075245,12.107526 v 7"
|
||||
id="path3088"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:#333333;stroke:#333333;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 23.607525,12.107526 v 7"
|
||||
id="path3088-3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
<text
|
||||
id="text872"
|
||||
y="18.931452"
|
||||
x="1.7110295"
|
||||
style="font-style:normal;font-weight:normal;font-size:27.82968521px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:#333333;stroke-width:0.69574213"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:9.27656174px;fill:#333333;stroke:#333333;stroke-width:0.69574213"
|
||||
y="18.931452"
|
||||
x="1.7110295"
|
||||
id="tspan870"
|
||||
sodipodi:role="line">d</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
BIN
kicad_plugins/resources/extras/stitching-vias.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
155
kicad_plugins/resources/extras/stitching-vias.svg
Normal file
@@ -0,0 +1,155 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
height="27.733334"
|
||||
width="27.733334"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="stitching-vias-green-2.svg"
|
||||
viewBox="0 0 26 26"
|
||||
inkscape:export-filename="C:\kicad-wb-1602\msys64\home\userC\RF-round-diff\new-solder-mask\bitmaps_png\sources\soldermask_clearance-26.png"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263">
|
||||
<metadata
|
||||
id="metadata40">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="824"
|
||||
id="namedview38"
|
||||
showgrid="true"
|
||||
inkscape:snap-to-guides="false"
|
||||
inkscape:snap-grids="true"
|
||||
inkscape:zoom="7.2765875"
|
||||
inkscape:cx="-6.0737825"
|
||||
inkscape:cy="19.890843"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3017"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true"
|
||||
spacingx="0.5"
|
||||
spacingy="0.5"
|
||||
originx="0"
|
||||
originy="0" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs4">
|
||||
<filter
|
||||
id="c"
|
||||
height="1.3651"
|
||||
width="1.2097"
|
||||
y="-0.18257"
|
||||
x="-0.10484"
|
||||
style="color-interpolation-filters:sRGB">
|
||||
<feGaussianBlur
|
||||
stdDeviation="1.5978799"
|
||||
id="feGaussianBlur7" />
|
||||
</filter>
|
||||
<filter
|
||||
id="d"
|
||||
height="1.4696"
|
||||
width="1.4809999"
|
||||
y="-0.23481999"
|
||||
x="-0.24049"
|
||||
style="color-interpolation-filters:sRGB">
|
||||
<feGaussianBlur
|
||||
stdDeviation="1.5978799"
|
||||
id="feGaussianBlur10" />
|
||||
</filter>
|
||||
</defs>
|
||||
<rect
|
||||
style="fill:#008000;fill-opacity:1;stroke:none;stroke-width:0.9375;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.99997282;stroke-opacity:1"
|
||||
id="rect4495"
|
||||
width="26"
|
||||
height="26"
|
||||
x="-1.0458432e-15"
|
||||
y="1.7763568e-15"
|
||||
inkscape:export-filename="C:\kicad-wb-1602\msys64\home\userC\RF-round-diff\new-solder-mask\bitmaps_png\sources\stitching-vias.png"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263" />
|
||||
<g
|
||||
transform="matrix(1.6382539,0,0,1.5572263,1.2572207,0.36314149)"
|
||||
id="g16"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-filename="C:\kicad-wb-1602\msys64\home\userC\RF-round-diff\new-solder-mask\bitmaps_png\sources\stitching-vias.png">
|
||||
<rect
|
||||
height="16"
|
||||
width="16"
|
||||
y="0"
|
||||
x="0"
|
||||
id="rect18"
|
||||
style="fill-opacity:0" />
|
||||
</g>
|
||||
<rect
|
||||
style="opacity:0.25;fill:#008000;fill-opacity:1;stroke:#b3b3b3;stroke-width:2.24165964;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.99997282;stroke-opacity:1"
|
||||
id="rect4737"
|
||||
width="26"
|
||||
height="26"
|
||||
x="0"
|
||||
y="1.7193647e-08"
|
||||
inkscape:export-filename="C:\kicad-wb-1602\msys64\home\userC\RF-round-diff\new-solder-mask\bitmaps_png\sources\stitching-vias.png"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263" />
|
||||
<g
|
||||
id="g845"
|
||||
transform="translate(28,-6.000001)">
|
||||
<path
|
||||
sodipodi:nodetypes="sssss"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3867-9-4-36"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffcc00;stroke-width:2.4375;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m -18.5,13.625001 c 0,-1.932997 1.567003,-3.5 3.5,-3.5 1.932998,0 3.5,1.567003 3.5,3.5 0,1.932997 -1.567002,3.5 -3.5,3.5 -1.932997,0 -3.5,-1.567003 -3.5,-3.5 z" />
|
||||
<path
|
||||
sodipodi:nodetypes="sssss"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3867-9-4-6"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffcc00;stroke-width:2.4375;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m -12.75,24.250001 c 0,-1.932996 1.567003,-3.499999 3.500001,-3.499999 1.932996,0 3.499999,1.567003 3.499999,3.499999 0,1.932998 -1.567003,3.500001 -3.499999,3.500001 -1.932998,0 -3.500001,-1.567003 -3.500001,-3.500001 z" />
|
||||
<path
|
||||
sodipodi:nodetypes="sssss"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3867-9-4-3"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffcc00;stroke-width:2.4375;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m -24.25,24.375001 c 0,-1.932997 1.567003,-3.5 3.5,-3.5 1.932997,0 3.5,1.567003 3.5,3.5 0,1.932997 -1.567003,3.5 -3.5,3.5 -1.932997,0 -3.5,-1.567003 -3.5,-3.5 z" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.7 KiB |
BIN
kicad_plugins/resources/extras/teardrops-help.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
219
kicad_plugins/resources/extras/teardrops-help.svg
Normal file
@@ -0,0 +1,219 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
height="46.027241"
|
||||
width="72.56057"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="teardrops-help.svg"
|
||||
viewBox="0 0 68.025533 43.150538"
|
||||
inkscape:export-filename="/home/mau/.kicad_plugins/teardrops/rcs/teardrops-help.png"
|
||||
inkscape:export-xdpi="222.26949"
|
||||
inkscape:export-ydpi="222.26949">
|
||||
<metadata
|
||||
id="metadata40">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="824"
|
||||
id="namedview38"
|
||||
showgrid="true"
|
||||
inkscape:snap-to-guides="false"
|
||||
inkscape:snap-grids="true"
|
||||
inkscape:zoom="7.7907941"
|
||||
inkscape:cx="24.431197"
|
||||
inkscape:cy="26.246953"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
fit-margin-top="1"
|
||||
fit-margin-left="1"
|
||||
fit-margin-right="10"
|
||||
fit-margin-bottom="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3017"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true"
|
||||
spacingx="0.5"
|
||||
spacingy="0.5"
|
||||
originx="19.137753"
|
||||
originy="8.0752684" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs4">
|
||||
<filter
|
||||
id="c"
|
||||
height="1.3651"
|
||||
width="1.2097"
|
||||
y="-0.18257"
|
||||
x="-0.10484"
|
||||
style="color-interpolation-filters:sRGB">
|
||||
<feGaussianBlur
|
||||
stdDeviation="1.5978799"
|
||||
id="feGaussianBlur7" />
|
||||
</filter>
|
||||
<filter
|
||||
id="d"
|
||||
height="1.4696"
|
||||
width="1.4809999"
|
||||
y="-0.23481999"
|
||||
x="-0.24049"
|
||||
style="color-interpolation-filters:sRGB">
|
||||
<feGaussianBlur
|
||||
stdDeviation="1.5978799"
|
||||
id="feGaussianBlur10" />
|
||||
</filter>
|
||||
</defs>
|
||||
<path
|
||||
d="m 30.637753,17.075268 h 19.5 m -19.5,0 c 0,1.932997 -1.567003,3.5 -3.5,3.5 -1.932997,0 -3.5,-1.567003 -3.5,-3.5 0,-1.932997 1.567003,-3.5 3.5,-3.5 1.932997,0 3.5,1.567003 3.5,3.5 z"
|
||||
style="opacity:1;fill:none;stroke:#ffcc00;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path3867"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
sodipodi:nodetypes="ccsssss" />
|
||||
<path
|
||||
id="path3002"
|
||||
style="opacity:0.25;fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 30.637753,17.075268 h 20.5 m -20.5,0 c 0,1.932997 -1.567003,3.5 -3.5,3.5 -1.932997,0 -3.5,-1.567003 -3.5,-3.5 0,-1.932997 1.567003,-3.5 3.5,-3.5 1.932997,0 3.5,1.567003 3.5,3.5 z"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
sodipodi:nodetypes="ccsssss" />
|
||||
<g
|
||||
transform="matrix(1.6382539,0,0,1.5572263,20.394974,9.4384095)"
|
||||
id="g16"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263">
|
||||
<rect
|
||||
height="16"
|
||||
width="16"
|
||||
y="0"
|
||||
x="0"
|
||||
id="rect18"
|
||||
style="fill-opacity:0" />
|
||||
</g>
|
||||
<circle
|
||||
style="opacity:0.76300001;fill:#1a1a1a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:14.23387146;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path825"
|
||||
cx="27.148506"
|
||||
cy="17.077711"
|
||||
r="1.8978496" />
|
||||
<path
|
||||
style="fill:#008080;fill-opacity:0.79049294;stroke:none;stroke-width:0.9375px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 30.137753,13.075268 2.5,1 2,0.5 2,0.5 2.5,0.5 v 2.999999 l -2.5,0.500001 -2,0.5 -2,0.5 -2.5,1 z"
|
||||
id="path21"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3872-9"
|
||||
d="M 3.075268,3.075268 V 40.07527 h 53.4375 l -1.5e-5,-37.000002 z"
|
||||
style="opacity:0.25;fill:#cccccc;fill-opacity:1;stroke:#b3b3b3;stroke-width:4.27553606;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263" />
|
||||
<g
|
||||
id="g909"
|
||||
transform="translate(4.137753,9.075268)">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3088-0"
|
||||
d="M 11.437501,13 H 18"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.9375px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3088-3-2"
|
||||
d="M 11.437501,3 H 18"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.9375px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5191-2"
|
||||
d="m 17.187501,19.625 -1.875,-5.625 -1.875,5.625"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.9375px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5195-9"
|
||||
d="m 13.451452,-3.7327 1.875,5.625001 1.875,-5.625001"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.9375px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.9375px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 30.405053,24.311317 v 6.562499"
|
||||
id="path3088-0-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.9375px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 39.030054,24.186317 v 6.562499"
|
||||
id="path3088-3-2-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.9375px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="m 23.780053,30.061317 5.625,-1.875 -5.625,-1.875"
|
||||
id="path5191-2-4"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.9375px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="m 45.762754,26.200268 -5.625001,1.875 5.625001,1.875"
|
||||
id="path5195-9-6"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.5px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#333333;fill-opacity:1;stroke:none;stroke-width:0.9375"
|
||||
x="30.72328"
|
||||
y="37.698124"
|
||||
id="text944"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan964"
|
||||
x="30.72328"
|
||||
y="37.698124">h%</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.5px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#333333;fill-opacity:1;stroke:none;stroke-width:0.9375"
|
||||
x="5.5483317"
|
||||
y="19.921503"
|
||||
id="text944-5"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan942-4"
|
||||
x="5.5483317"
|
||||
y="19.921503"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.5px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#333333;stroke-width:0.9375">v%</tspan></text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.9 KiB |
BIN
kicad_plugins/resources/extras/teardrops.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
kicad_plugins/resources/solder-mask-expander-preview.png
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
kicad_plugins/resources/solder-mask-expander.gif
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
kicad_plugins/resources/trace-clearance.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
kicad_plugins/resources/track-length-preview.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
kicad_plugins/resources/track-length.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
kicad_plugins/resources/tracks-rounder-preview.png
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
kicad_plugins/resources/tracks-rounder.gif
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
kicad_plugins/resources/uw-footprint-wizards.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
kicad_plugins/resources/uwave-Arc-footprint-preview.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
kicad_plugins/resources/uwave-Arc-footprint.gif
Normal file
|
After Width: | Height: | Size: 145 KiB |
BIN
kicad_plugins/resources/uwave-Arc-footprint.mp4
Normal file
BIN
kicad_plugins/resources/uwave-Arc-footprint.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
kicad_plugins/resources/uwave-Mitered-footprint-preview.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
kicad_plugins/resources/uwave-Mitered-footprint.gif
Normal file
|
After Width: | Height: | Size: 141 KiB |
BIN
kicad_plugins/resources/uwave-Mitered-footprint.mp4
Normal file
BIN
kicad_plugins/resources/uwave-Mitered-footprint.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
kicad_plugins/resources/uwave-Tamper-footprint-preview.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
kicad_plugins/resources/uwave-Tamper-footprint.gif
Normal file
|
After Width: | Height: | Size: 192 KiB |
BIN
kicad_plugins/resources/uwave-Tamper-footprint.mp4
Normal file
BIN
kicad_plugins/resources/uwave-Tamper-footprint.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
kicad_plugins/resources/via-fencing-preview.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
kicad_plugins/resources/via-fencing.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
11
kicad_plugins/rf_tools_wizards/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# pcbnew loads this folder as a package using import
|
||||
# thus __init__.py (this file) is executed
|
||||
# We import the plugin class here and register it to pcbnew
|
||||
|
||||
from . import uwArcPrimitive_wizard
|
||||
from . import uwMitered_wizard
|
||||
from . import uwTaper_wizard
|
||||
|
||||
|
||||
|
||||
|
||||
193
kicad_plugins/rf_tools_wizards/uwArcPrimitive_wizard.py
Normal file
@@ -0,0 +1,193 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
# This python script wizard creates an arc track for microwave applications
|
||||
# Author easyw
|
||||
# taskkill -im pcbnew.exe /f & C:\KiCad-v5-nightly\bin\pcbnew
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import math, cmath
|
||||
|
||||
from pcbnew import *
|
||||
import pcbnew
|
||||
import FootprintWizardBase
|
||||
|
||||
|
||||
class uwArcPrimitive_wizard(FootprintWizardBase.FootprintWizard):
|
||||
|
||||
def GetName(self):
|
||||
return "uW Arc Pad"
|
||||
|
||||
def GetDescription(self):
|
||||
return "uW Arc Pad Footprint Wizard"
|
||||
|
||||
def GenerateParameterList(self):
|
||||
|
||||
self.AddParam("Corner", "width", self.uMM, 1.319)
|
||||
self.AddParam("Corner", "radius", self.uMM, 5.0, min_value=0, designator='r', hint="Arc radius")
|
||||
self.AddParam("Corner", "angle", self.uDegrees, 90, designator='a')
|
||||
self.AddParam("Corner", "square_end", self.uBool, False)
|
||||
self.AddParam("Corner", "solder_clearance", self.uMM, 0.0)
|
||||
self.AddParam("Corner", "linear", self.uBool, False)
|
||||
|
||||
def CheckParameters(self):
|
||||
|
||||
pads = self.parameters['Corner']
|
||||
|
||||
|
||||
def GetValue(self):
|
||||
name = "{0:.2f}_{1:0.2f}_{2:.0f}".format(pcbnew.ToMM(self.parameters["Corner"]["width"]),pcbnew.ToMM(self.parameters["Corner"]["radius"]),(self.parameters["Corner"]["angle"]))
|
||||
if not self.parameters["Corner"]["linear"]:
|
||||
pref = "uwArc"
|
||||
else:
|
||||
pref = "uwLine"
|
||||
if self.parameters["Corner"]["square_end"]:
|
||||
pref += "R"
|
||||
return pref + "%s" % name
|
||||
|
||||
def GetReferencePrefix(self):
|
||||
if not self.parameters["Corner"]["linear"]:
|
||||
pref = "uwA"
|
||||
else:
|
||||
pref = "uwL"
|
||||
#if self.parameters["Corner"]["rectangle"]:
|
||||
# pref += "R"
|
||||
return pref + "***"
|
||||
|
||||
# build a custom pad
|
||||
def smdCustomArcPad(self, module, size, pos, rad, name, angle_D, layer, ln, solder_clearance):
|
||||
if hasattr(pcbnew, 'D_PAD'):
|
||||
pad = D_PAD(module)
|
||||
else:
|
||||
pad = PAD(module)
|
||||
## NB pads must be the same size and have the same center
|
||||
pad.SetSize(size)
|
||||
#pad.SetSize(pcbnew.wxSize(size[0]/5,size[1]/5))
|
||||
pad.SetShape(PAD_SHAPE_CUSTOM) #PAD_RECT)
|
||||
pad.SetAttribute(PAD_ATTRIB_SMD) #PAD_SMD)
|
||||
#pad.SetDrillSize (0.)
|
||||
#Set only the copper layer without mask
|
||||
#since nothing is mounted on these pads
|
||||
pad.SetPos0(pos)
|
||||
pad.SetPosition(pos)
|
||||
pad.SetPadName(name)
|
||||
#pad.Rotate(pos, angle)
|
||||
pad.SetAnchorPadShape(PAD_SHAPE_CIRCLE) #PAD_SHAPE_RECT)
|
||||
if solder_clearance > 0:
|
||||
pad.SetLocalSolderMaskMargin(solder_clearance)
|
||||
pad.SetLayerSet(pad.ConnSMDMask())
|
||||
else:
|
||||
pad.SetLayerSet( LSET(layer) )
|
||||
|
||||
if not ln:
|
||||
pad.AddPrimitive(pcbnew.wxPoint(0,rad), pcbnew.wxPoint(0,0), int(angle_D*10), (size[0]))
|
||||
else:
|
||||
pad.AddPrimitive(pcbnew.wxPoint(0,0), pcbnew.wxPoint(rad,0), (size[0]))
|
||||
return pad
|
||||
|
||||
def smdPad(self,module,size,pos,name,ptype,angle_D,layer,solder_clearance,offs=None):
|
||||
if hasattr(pcbnew, 'D_PAD'):
|
||||
pad = D_PAD(module)
|
||||
else:
|
||||
pad = PAD(module)
|
||||
pad.SetSize(size)
|
||||
pad.SetShape(ptype) #PAD_SHAPE_RECT PAD_SHAPE_OVAL PAD_SHAPE_TRAPEZOID PAD_SHAPE_CIRCLE
|
||||
# PAD_ATTRIB_CONN PAD_ATTRIB_SMD
|
||||
pad.SetAttribute(PAD_ATTRIB_SMD)
|
||||
if solder_clearance > 0:
|
||||
pad.SetLocalSolderMaskMargin(solder_clearance)
|
||||
pad.SetLayerSet(pad.ConnSMDMask())
|
||||
else:
|
||||
pad.SetLayerSet( LSET(layer) )
|
||||
#pad.SetDrillSize (0.)
|
||||
#pad.SetLayerSet(pad.ConnSMDMask())
|
||||
pad.SetPos0(pos)
|
||||
pad.SetPosition(pos)
|
||||
#pad.SetOrientationDegrees(90-angle_D/10)
|
||||
pad.SetOrientationDegrees(angle_D)
|
||||
if offs is not None:
|
||||
pad.SetOffset(offs)
|
||||
pad.SetName(name)
|
||||
return pad
|
||||
|
||||
def BuildThisFootprint(self):
|
||||
|
||||
pads = self.parameters['Corner']
|
||||
|
||||
radius = pads['radius'] #outline['diameter'] / 2
|
||||
width = pads['width']
|
||||
sold_clear = pads['solder_clearance']
|
||||
line = pads['linear']
|
||||
|
||||
angle_deg = float(pads["angle"]) #*10)
|
||||
angle = math.radians(angle_deg) #/10) #To radians
|
||||
sign = 1.
|
||||
if angle < 0:
|
||||
sign = -1.
|
||||
|
||||
pos = pcbnew.wxPoint(0,0)
|
||||
offset1 = pcbnew.wxPoint(-sign*width/2,0)
|
||||
offset2 = pcbnew.wxPoint(0,0)
|
||||
module = self.module
|
||||
size_pad = pcbnew.wxSize(width, width)
|
||||
#size_pad = pcbnew.wxSize(width/5, width/5)
|
||||
module.Add(self.smdCustomArcPad(module, size_pad, pcbnew.wxPoint(0,0), radius, "1", (angle_deg), F_Cu, line, sold_clear))
|
||||
size_pad = pcbnew.wxSize(width, width)
|
||||
end_coord = (radius) * cmath.exp(math.radians(angle_deg-90)*1j)
|
||||
if pads['square_end'] or angle_deg == 0 or radius == 0:
|
||||
if not line:
|
||||
## NB pads must be the same size and have the same center
|
||||
module.Add(self.smdPad(module, size_pad, pcbnew.wxPoint(0,0), "1", PAD_SHAPE_RECT,0,F_Cu,sold_clear,offset1))
|
||||
else:
|
||||
module.Add(self.smdPad(module, size_pad, pcbnew.wxPoint(0,0), "1", PAD_SHAPE_RECT,0,F_Cu,sold_clear))
|
||||
if not line:
|
||||
#pos = pcbnew.wxPoint(end_coord.real+(sign*width/2)*math.cos(angle),end_coord.imag+(sign*width/2)*math.sin(angle)+radius)
|
||||
pos = pcbnew.wxPoint(end_coord.real,end_coord.imag+radius)
|
||||
module.Add(self.smdPad(module, size_pad, pos, "1", PAD_SHAPE_RECT,90-angle_deg,F_Cu,sold_clear,wxPoint(0,(sign*width/2))))
|
||||
#*math.sin(math.pi/2-angle),(sign*width/2)*math.cos(math.pi/2-angle))))
|
||||
else:
|
||||
pos = pcbnew.wxPoint(radius,0) #+width/2,0)
|
||||
module.Add(self.smdPad(module, size_pad, pos, "1", PAD_SHAPE_RECT,0,F_Cu,sold_clear))
|
||||
else:
|
||||
## NB pads must be the same size and have the same center
|
||||
#size_pad = pcbnew.wxSize(width/5, width/5)
|
||||
size_pad = pcbnew.wxSize(width, width)
|
||||
if not line:
|
||||
pos = pcbnew.wxPoint(end_coord.real,end_coord.imag+radius)
|
||||
else:
|
||||
pos = pcbnew.wxPoint(radius,0)
|
||||
module.Add(self.smdPad(module, size_pad, pos, "1", PAD_SHAPE_CIRCLE,0,F_Cu,sold_clear))
|
||||
|
||||
# Text size
|
||||
text_size = self.GetTextSize() # IPC nominal
|
||||
thickness = self.GetTextThickness()
|
||||
textposy = self.draw.GetLineThickness()/2 + self.GetTextSize()/2 + thickness #+ outline['margin']
|
||||
self.draw.Reference( 0, -textposy-width, text_size )
|
||||
if not line:
|
||||
self.draw.Value( 0, radius+textposy+width, text_size )
|
||||
else:
|
||||
self.draw.Value( 0, textposy+width, text_size )
|
||||
# set SMD attribute
|
||||
# set SMD attribute
|
||||
if hasattr(pcbnew, 'MOD_VIRTUAL'):
|
||||
module.SetAttributes(pcbnew.MOD_VIRTUAL)
|
||||
else:
|
||||
module.SetAttributes(pcbnew.FP_EXCLUDE_FROM_BOM | pcbnew.FP_EXCLUDE_FROM_POS_FILES)
|
||||
__version__ = 1.7
|
||||
self.buildmessages += ("version: {:.1f}".format(__version__))
|
||||
|
||||
uwArcPrimitive_wizard().register()
|
||||
352
kicad_plugins/rf_tools_wizards/uwMitered_wizard.py
Normal file
@@ -0,0 +1,352 @@
|
||||
# This python script wizard creates a mitered bend for microwave applications
|
||||
# https://lists.launchpad.net/kicad-developers/msg17996.html
|
||||
# Author Henrik Forsten & easyw
|
||||
# improved pads using Primitive pads, single net node
|
||||
|
||||
from __future__ import division
|
||||
import FootprintWizardBase
|
||||
|
||||
import pcbnew
|
||||
from pcbnew import *
|
||||
import math
|
||||
|
||||
class UWMiterFootprintWizard(FootprintWizardBase.FootprintWizard):
|
||||
def GetName(self):
|
||||
return "uW Mitered Bend"
|
||||
|
||||
def GetDescription(self):
|
||||
return "Mitered Bend Footprint Wizard"
|
||||
|
||||
def GenerateParameterList(self):
|
||||
self.AddParam("Corner", "width", self.uMM, 1.31968)
|
||||
self.AddParam("Corner", "height", self.uMM, 1.57)
|
||||
self.AddParam("Corner", "*angle", self.uDegrees, 90)
|
||||
self.AddParam("Corner", "solder_clearance", self.uMM, 0.0)
|
||||
|
||||
# class UWMiterFootprintWizard(FootprintWizardBase.FootprintWizard):
|
||||
# def __init__(self):
|
||||
# FootprintWizardBase.FootprintWizard.__init__(self)
|
||||
# self.name = "uW Mitered Bend"
|
||||
# self.description = "Mitered Bend Footprint Wizard"
|
||||
# self.parameters = {
|
||||
# "Corner":{
|
||||
# "width": FromMM(0.34),
|
||||
# "height": FromMM(0.17),
|
||||
# "*angle": 90,
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# self.ClearErrors()
|
||||
|
||||
# build a rectangular pad
|
||||
def smdRectPad(self, module, size, pos, name, angle, layer, solder_clearance):
|
||||
if hasattr(pcbnew, 'D_PAD'):
|
||||
pad = D_PAD(module)
|
||||
else:
|
||||
pad = PAD(module)
|
||||
pad.SetSize(size)
|
||||
pad.SetShape(PAD_SHAPE_RECT) #PAD_RECT)
|
||||
pad.SetAttribute(PAD_ATTRIB_SMD) #PAD_SMD)
|
||||
#Set only the copper layer without mask
|
||||
#since nothing is mounted on these pads
|
||||
pad.SetLayerSet( LSET(F_Cu) )
|
||||
pad.SetPos0(pos)
|
||||
pad.SetPosition(pos)
|
||||
pad.SetPadName(name)
|
||||
pad.Rotate(pos, angle)
|
||||
if solder_clearance > 0:
|
||||
pad.SetLocalSolderMaskMargin(solder_clearance)
|
||||
pad.SetLayerSet(pad.ConnSMDMask())
|
||||
else:
|
||||
pad.SetLayerSet( LSET(layer) )
|
||||
#Set clearance to small value, because
|
||||
#pads can be very close together.
|
||||
#If distance is smaller than clearance
|
||||
#DRC doesn't allow routing the pads
|
||||
pad.SetLocalClearance(1)
|
||||
return pad
|
||||
|
||||
# build a custom pad
|
||||
def smdCustomPolyPad(self, module, size, pos, name, vpoints, layer, solder_clearance):
|
||||
if hasattr(pcbnew, 'D_PAD'):
|
||||
pad = D_PAD(module)
|
||||
else:
|
||||
pad = PAD(module)
|
||||
## NB pads must be the same size and have the same center
|
||||
pad.SetSize(size)
|
||||
#pad.SetSize(pcbnew.wxSize(size[0]/5,size[1]/5))
|
||||
pad.SetShape(PAD_SHAPE_CUSTOM) #PAD_RECT)
|
||||
pad.SetAttribute(PAD_ATTRIB_SMD) #PAD_SMD)
|
||||
#pad.SetDrillSize (0.)
|
||||
#Set only the copper layer without mask
|
||||
#since nothing is mounted on these pads
|
||||
#pad.SetPos0(wxPoint(0,0)) #pos)
|
||||
#pad.SetPosition(wxPoint(0,0)) #pos)
|
||||
pad.SetPos0(pos)
|
||||
pad.SetPosition(pos)
|
||||
#pad.SetOffset(pos)
|
||||
pad.SetPadName(name)
|
||||
#pad.Rotate(pos, angle)
|
||||
pad.SetAnchorPadShape(PAD_SHAPE_RECT) #PAD_SHAPE_CIRCLE) #PAD_SHAPE_RECT)
|
||||
if solder_clearance > 0:
|
||||
pad.SetLocalSolderMaskMargin(solder_clearance)
|
||||
pad.SetLayerSet(pad.ConnSMDMask())
|
||||
else:
|
||||
pad.SetLayerSet( LSET(layer) )
|
||||
|
||||
if hasattr(pcbnew, 'D_PAD'):
|
||||
pad.AddPrimitive(vpoints,0) # (size[0]))
|
||||
else:
|
||||
pad.AddPrimitivePoly(vpoints, 0, True) # (size[0]))
|
||||
|
||||
return pad
|
||||
|
||||
def Polygon(self, points, layer):
|
||||
"""
|
||||
Draw a polygon through specified points
|
||||
"""
|
||||
import pcbnew
|
||||
|
||||
polygon = pcbnew.EDGE_MODULE(self.module)
|
||||
polygon.SetWidth(0) #Disables outline
|
||||
|
||||
polygon.SetLayer(layer)
|
||||
polygon.SetShape(pcbnew.S_POLYGON)
|
||||
|
||||
polygon.SetPolyPoints(points)
|
||||
|
||||
self.module.Add(polygon)
|
||||
|
||||
|
||||
# This method checks the parameters provided to wizard and set errors
|
||||
def CheckParameters(self):
|
||||
p = self.parameters
|
||||
width = p["Corner"]["width"]
|
||||
height = p["Corner"]["height"]
|
||||
angle = p["Corner"]["*angle"]
|
||||
|
||||
errors = []
|
||||
if (width<0):
|
||||
errors.append("Width has invalid value")
|
||||
if width/height < 0.25:
|
||||
errors.append("Too small width to height ratio")
|
||||
if angle > 90:
|
||||
errors.append("Too large angle")
|
||||
if angle < 0:
|
||||
errors.append("Angle must be positive")
|
||||
errors = ', '.join(errors)
|
||||
print (errors)
|
||||
return errors == ""
|
||||
|
||||
def bilinear_interpolation(self, x, y, points):
|
||||
'''http://stackoverflow.com/questions/8661537/how-to-perform-bilinear-interpolation-in-python
|
||||
Interpolate (x,y) from values associated with four points.
|
||||
|
||||
The four points are a list of four triplets: (x, y, value).
|
||||
The four points can be in any order. They should form a rectangle.
|
||||
|
||||
>>> bilinear_interpolation(12, 5.5,
|
||||
... [(10, 4, 100),
|
||||
... (20, 4, 200),
|
||||
... (10, 6, 150),
|
||||
... (20, 6, 300)])
|
||||
165.0
|
||||
|
||||
'''
|
||||
# See formula at: http://en.wikipedia.org/wiki/Bilinear_interpolation
|
||||
|
||||
points = sorted(points) # order points by x, then by y
|
||||
(x1, y1, q11), (_x1, y2, q12), (x2, _y1, q21), (_x2, _y2, q22) = points
|
||||
|
||||
return (q11 * (x2 - x) * (y2 - y) +
|
||||
q21 * (x - x1) * (y2 - y) +
|
||||
q12 * (x2 - x) * (y - y1) +
|
||||
q22 * (x - x1) * (y - y1)
|
||||
) / ((x2 - x1) * (y2 - y1) + 0.0)
|
||||
|
||||
def OptimalMiter(self, w, h, angle):
|
||||
"""Calculate optimal miter by interpolating from table.
|
||||
https://awrcorp.com/download/faq/english/docs/Elements/MBENDA.htm
|
||||
"""
|
||||
wh = w/h
|
||||
whs = [0.5, 1.0, 2.0]
|
||||
angles = [0, 30, 60, 90, 120]
|
||||
table = [
|
||||
[0, 12, 45, 75, 98],
|
||||
[0, 19, 41, 63, 92],
|
||||
[0, 7, 31, 56, 79]
|
||||
]
|
||||
for i, x in enumerate(whs):
|
||||
if x > wh:
|
||||
break
|
||||
for j, y in enumerate(angles):
|
||||
if y > angle:
|
||||
break
|
||||
i = min(i-1,1)
|
||||
j = min(j-1,3)
|
||||
px = lambda ii,jj: (whs[ii],angles[jj],table[ii][jj])
|
||||
x1 = px(i,j)
|
||||
x2 = px(i+1,j)
|
||||
y1 = px(i,j+1)
|
||||
y2 = px(i+1,j+1)
|
||||
return self.bilinear_interpolation(wh, angle, [x1,x2,y1,y2])/100.0
|
||||
|
||||
# build the footprint from parameters
|
||||
#def BuildThisFootprint(self):
|
||||
def BuildFootprint(self):
|
||||
|
||||
if hasattr(pcbnew, 'MODULE'):
|
||||
module = MODULE(None) # create a new module
|
||||
else:
|
||||
module = FOOTPRINT(None) # create a new module
|
||||
#module = self.module
|
||||
self.module = module
|
||||
self.buildmessages = ""
|
||||
|
||||
if not self.CheckParameters():
|
||||
return
|
||||
|
||||
p = self.parameters
|
||||
width = p["Corner"]["width"]
|
||||
height = p["Corner"]["height"]
|
||||
angle_deg = float(p["Corner"]["*angle"])
|
||||
angle = angle_deg*0.0174532925 #To radians
|
||||
sold_clear = p["Corner"]['solder_clearance']
|
||||
#reference and value
|
||||
#text_size = self.GetTextSize() # IPC nominal
|
||||
|
||||
textposy = width + FromMM(1)
|
||||
size_text = wxSize( FromMM( 0.6), FromMM( 0.5) )
|
||||
|
||||
module.name = "'uwm_{0:.2f}_{1:0.2f}_{2:.0f}'".format(ToMM(width),ToMM(height),angle_deg)
|
||||
|
||||
#module.SetReference("uwm_{0:.2f}_{1:0.2f}_{2:.0f}".format(ToMM(width),ToMM(height),angle_deg))
|
||||
module.SetReference("uwM***") # give it a default value
|
||||
module.Reference().SetPos0(wxPoint(0, textposy))
|
||||
module.Reference().SetPosition(module.Reference().GetPos0())
|
||||
module.Reference().SetTextSize( size_text )
|
||||
if hasattr(module.Reference(), 'SetThickness'):
|
||||
module.Reference().SetThickness(FromMM(0.125))
|
||||
else:
|
||||
module.Reference().SetTextThickness(FromMM(0.125))
|
||||
module.Reference().SetVisible(True)
|
||||
|
||||
textposy = textposy + FromMM(1)
|
||||
#module.SetValue("Val***") # give it a default value
|
||||
module.SetValue("uwM_{0:.2f}_{1:0.2f}_{2:.0f}".format(ToMM(width),ToMM(height),angle_deg))
|
||||
module.Value().SetPos0( wxPoint(0, textposy) )
|
||||
module.Value().SetPosition(module.Value().GetPos0())
|
||||
module.Value().SetTextSize( size_text )
|
||||
module.Value().SetVisible(False) #0)
|
||||
|
||||
# fpid = FPID(self.module.GetReference()) #the name in library
|
||||
# module.SetFPID( fpid )
|
||||
|
||||
#Calculate the miter
|
||||
w = width
|
||||
|
||||
#Width of the corner from edge of the corner to inside corner
|
||||
corner_width = ToMM(w)/math.cos(angle/2)
|
||||
|
||||
#Get proportion of width to cut
|
||||
cut = self.OptimalMiter(width, height, angle_deg)
|
||||
cut_pc = cut
|
||||
print ("Cut: {0:.2f}%".format(cut*100))
|
||||
|
||||
#Distance from uncut outside corner point to point 7
|
||||
cut = FromMM(cut*corner_width/math.cos((math.pi-angle)/2))
|
||||
|
||||
#Distance between points 2 and 3 and points 3 and 4
|
||||
#Minimum of w/2 to satisfy DRC, otherwise pads are too close
|
||||
#and track connected to other pad overlaps the other one.
|
||||
#Rounded trace end can also stick out of the cut area
|
||||
#if a is too small.
|
||||
a = max(cut-width*math.tan(angle/2),w/2)
|
||||
|
||||
#Distance between points 3 and 4
|
||||
x34 = a*math.sin(angle)
|
||||
y34 = a*math.cos(angle)
|
||||
#Distance between points 4 and 5
|
||||
x45 = width*math.cos(angle)
|
||||
y45 = width*math.sin(angle)
|
||||
|
||||
# 1 2
|
||||
#8 +--+
|
||||
# | |3
|
||||
#7 \ --+ 4
|
||||
# \ |
|
||||
# \--+ 5
|
||||
# 6
|
||||
|
||||
# maui extension of polygon
|
||||
#points = [
|
||||
# (0,0-w/2),
|
||||
# (w,0-w/2),
|
||||
# (w,a),
|
||||
# (w+x34+w/2*math.sin(angle),a+y34+w/2*math.cos(angle)),
|
||||
# (w+x34-x45+w/2*math.sin(angle),a+y34+y45+w/2*math.cos(angle)),
|
||||
# (cut*math.sin(angle),a+width*math.tan(angle/2)+cut*math.cos(angle)),
|
||||
# (0,a+width*math.tan(angle/2)-cut),
|
||||
# (0,0-w/2)]
|
||||
points = [
|
||||
(0-w/2,0-w/2+w/2),
|
||||
(w-w/2,0-w/2+w/2),
|
||||
(w-w/2,a+w/2),
|
||||
(w+x34+w/2*math.sin(angle)-w/2,a+y34+w/2*math.cos(angle)+w/2),
|
||||
(w+x34-x45+w/2*math.sin(angle)-w/2,a+y34+y45+w/2*math.cos(angle)+w/2),
|
||||
(cut*math.sin(angle)-w/2,a+width*math.tan(angle/2)+cut*math.cos(angle)+w/2),
|
||||
(0-w/2,a+width*math.tan(angle/2)-cut+w/2),
|
||||
(0-w/2,0-w/2+w/2)]
|
||||
|
||||
#Last two points can be equal
|
||||
if points[-2] == points[-1]:
|
||||
points = points[:-1]
|
||||
|
||||
points = [wxPoint(*point) for point in points]
|
||||
vpoints = wxPoint_Vector(points)
|
||||
#self.Polygon(points, F_Cu)
|
||||
|
||||
#Create pads
|
||||
pad_l = width/2 #10 allowing big track to join the fp
|
||||
size_pad = wxSize(width,pad_l)
|
||||
|
||||
#module.Add(self.smdRectPad(module, size_pad, wxPoint(width/2,-pad_l/2), "1", 0))
|
||||
layer = F_Cu; # sold_clear = 0
|
||||
module.Add(self.smdCustomPolyPad(module, size_pad, wxPoint(width/2,-pad_l/2), "1", vpoints, layer,sold_clear))
|
||||
# smdCustomPolyPad(self, module, size, pos, name, points, layer, solder_clearance):
|
||||
size_pad = wxSize(pad_l,width)
|
||||
|
||||
#Halfway between points 4 and 5
|
||||
posx = ((w+x34) + (w+x34-x45))/2
|
||||
posy = ((a+y34) + (a+y34+y45))/2
|
||||
|
||||
#Position pad so that pad edge touches polygon edge
|
||||
posx += (pad_l/2)*math.sin(angle)
|
||||
posy += (pad_l/2)*math.cos(angle)+w/4
|
||||
size_pad = wxSize(pad_l, width)
|
||||
#solder clearance added only to polygon
|
||||
module.Add(self.smdRectPad(module, size_pad, wxPoint(posx,posy), "1", (angle_deg-90)*10,layer,0.0))
|
||||
# moving anchor to center of first pad
|
||||
module.MoveAnchorPosition(wxPoint(-width/2,pad_l/2))
|
||||
# set SMD attribute
|
||||
# set SMD attribute
|
||||
if hasattr(pcbnew, 'MOD_VIRTUAL'):
|
||||
module.SetAttributes(pcbnew.MOD_VIRTUAL)
|
||||
else:
|
||||
module.SetAttributes(pcbnew.FP_EXCLUDE_FROM_BOM | pcbnew.FP_EXCLUDE_FROM_POS_FILES)
|
||||
self.buildmessages = (
|
||||
"Building new {name} footprint with the following parameters:\n\n"
|
||||
.format(name=module.name))
|
||||
self.buildmessages += ("Track Width: {0:.4f}mm\n".format(ToMM(width)))
|
||||
self.buildmessages += ("PCB Height: {0:.4f}mm\n".format(ToMM(height)))
|
||||
self.buildmessages += ("Angle: {:.1f}deg\n\n".format(angle_deg))
|
||||
self.buildmessages += ("Cut: {0:.2f}%\n".format(cut_pc*100))
|
||||
__version__ = 1.6
|
||||
self.buildmessages += ("version: {:.1f}".format(__version__))
|
||||
|
||||
|
||||
# create our footprint wizard
|
||||
uwmiter_wizard = UWMiterFootprintWizard()
|
||||
|
||||
# register it into pcbnew
|
||||
uwmiter_wizard.register()
|
||||
210
kicad_plugins/rf_tools_wizards/uwTaper_wizard.py
Normal file
@@ -0,0 +1,210 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
# This python script wizard creates an arc track for microwave applications
|
||||
# Author easyw
|
||||
# taskkill -im pcbnew.exe /f & C:\KiCad-v5-nightly\bin\pcbnew
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import math, cmath
|
||||
|
||||
from pcbnew import *
|
||||
import pcbnew
|
||||
import FootprintWizardBase
|
||||
|
||||
|
||||
class uwTaper_wizard(FootprintWizardBase.FootprintWizard):
|
||||
|
||||
def GetName(self):
|
||||
return "uW Taper Pad"
|
||||
|
||||
def GetDescription(self):
|
||||
return "uW Taper Pad Footprint Wizard"
|
||||
|
||||
def GenerateParameterList(self):
|
||||
|
||||
self.AddParam("Taper", "P1 width", self.uMM, 0.5, min_value=0, hint="Pad 1 width")
|
||||
self.AddParam("Taper", "P1 height", self.uMM, 0.5, min_value=0, hint="Pad 1 height")
|
||||
self.AddParam("Taper", "P2 width", self.uMM, 1.0, min_value=0, hint="Pad 2 width")
|
||||
self.AddParam("Taper", "P2 height", self.uMM, 1.0, min_value=0, hint="Pad 2 height")
|
||||
self.AddParam("Taper", "P2 vert offset", self.uMM, 0.0, hint="Pad 2 vertical offset")
|
||||
self.AddParam("Taper", "length", self.uMM, 3.0, min_value=0, hint="length")
|
||||
self.AddParam("Taper", "solder_clearance", self.uMM, 0.0, min_value=0, hint="Solder Clearance")
|
||||
|
||||
def CheckParameters(self):
|
||||
|
||||
pads = self.parameters['Taper']
|
||||
|
||||
|
||||
def GetValue(self):
|
||||
name = "{0:.2f}_{1:0.2f}_{2:.2f}_{3:.2f}_{4:.2f}".format(pcbnew.ToMM(self.parameters["Taper"]["P1 width"]),\
|
||||
pcbnew.ToMM(self.parameters["Taper"]["P1 height"]),pcbnew.ToMM(self.parameters["Taper"]["P2 width"]),\
|
||||
pcbnew.ToMM(self.parameters["Taper"]["P2 height"]),pcbnew.ToMM(self.parameters["Taper"]["length"]))
|
||||
return "uwT" + "%s" % name
|
||||
|
||||
def GetReferencePrefix(self):
|
||||
return "uwT" + "***"
|
||||
|
||||
# build a custom pad
|
||||
def smdCustomPolyPad(self, module, size, pos, name, vpoints, layer, solder_clearance):
|
||||
if hasattr(pcbnew, 'D_PAD'):
|
||||
pad = D_PAD(module)
|
||||
else:
|
||||
pad = PAD(module)
|
||||
#pad = PAD(module)
|
||||
## NB pads must be the same size and have the same center
|
||||
pad.SetSize(size)
|
||||
#pad.SetSize(pcbnew.wxSize(size[0]/5,size[1]/5))
|
||||
pad.SetShape(PAD_SHAPE_CUSTOM) #PAD_RECT)
|
||||
pad.SetAttribute(PAD_ATTRIB_SMD) #PAD_SMD)
|
||||
#pad.SetDrillSize (0.)
|
||||
#Set only the copper layer without mask
|
||||
#since nothing is mounted on these pads
|
||||
#pad.SetPos0(wxPoint(0,0)) #pos)
|
||||
#pad.SetPosition(wxPoint(0,0)) #pos)
|
||||
pad.SetPos0(pos)
|
||||
pad.SetPosition(pos)
|
||||
#pad.SetOffset(pos)
|
||||
pad.SetPadName(name)
|
||||
#pad.Rotate(pos, angle)
|
||||
pad.SetAnchorPadShape(PAD_SHAPE_RECT) #PAD_SHAPE_CIRCLE) #PAD_SHAPE_RECT)
|
||||
if solder_clearance > 0:
|
||||
pad.SetLocalSolderMaskMargin(solder_clearance)
|
||||
pad.SetLayerSet(pad.ConnSMDMask())
|
||||
else:
|
||||
pad.SetLayerSet( LSET(layer) )
|
||||
|
||||
if hasattr(pcbnew, 'D_PAD'):
|
||||
pad.AddPrimitive(vpoints,0) # (size[0]))
|
||||
else:
|
||||
pad.AddPrimitivePoly(vpoints, 0, True) # (size[0]))
|
||||
return pad
|
||||
|
||||
def smdPad(self,module,size,pos,name,ptype,angle_D,layer,solder_clearance,offs=None):
|
||||
if hasattr(pcbnew, 'D_PAD'):
|
||||
pad = D_PAD(module)
|
||||
else:
|
||||
pad = PAD(module)
|
||||
pad.SetSize(size)
|
||||
pad.SetShape(ptype) #PAD_SHAPE_RECT PAD_SHAPE_OVAL PAD_SHAPE_TRAPEZOID PAD_SHAPE_CIRCLE
|
||||
# PAD_ATTRIB_CONN PAD_ATTRIB_SMD
|
||||
pad.SetAttribute(PAD_ATTRIB_SMD)
|
||||
if solder_clearance > 0:
|
||||
pad.SetLocalSolderMaskMargin(solder_clearance)
|
||||
pad.SetLayerSet(pad.ConnSMDMask())
|
||||
else:
|
||||
pad.SetLayerSet( LSET(layer) )
|
||||
#pad.SetDrillSize (0.)
|
||||
#pad.SetLayerSet(pad.ConnSMDMask())
|
||||
pad.SetPos0(pos)
|
||||
pad.SetPosition(pos)
|
||||
#pad.SetOrientationDegrees(90-angle_D/10)
|
||||
pad.SetOrientationDegrees(angle_D)
|
||||
if offs is not None:
|
||||
pad.SetOffset(offs)
|
||||
pad.SetName(name)
|
||||
return pad
|
||||
|
||||
def Polygon(self, points, layer):
|
||||
"""
|
||||
Draw a polygon through specified points
|
||||
"""
|
||||
import pcbnew
|
||||
|
||||
polygon = pcbnew.EDGE_MODULE(self.module)
|
||||
polygon.SetWidth(0) #Disables outline
|
||||
|
||||
polygon.SetLayer(layer)
|
||||
polygon.SetShape(pcbnew.S_POLYGON)
|
||||
|
||||
polygon.SetPolyPoints(points)
|
||||
|
||||
self.module.Add(polygon)
|
||||
|
||||
def BuildThisFootprint(self):
|
||||
|
||||
pads = self.parameters['Taper']
|
||||
|
||||
width1 = pads['P1 width']
|
||||
width2 = pads['P2 width']
|
||||
height1 = pads['P1 height']
|
||||
height2 = pads['P2 height']
|
||||
length = pads['length']
|
||||
p2vof = pads['P2 vert offset']
|
||||
sold_clear = pads['solder_clearance']
|
||||
w1=width1;w2=width2;
|
||||
h1=height1;h2=height2;
|
||||
|
||||
pos = pcbnew.wxPoint(0,0)
|
||||
offset1 = pcbnew.wxPoint(0,0)
|
||||
#offset2 = pcbnew.wxPoint(length+w1/2,0)
|
||||
offset2 = pcbnew.wxPoint(0,0)
|
||||
module = self.module
|
||||
# 1 2 3 4
|
||||
# +--+
|
||||
# / |
|
||||
# / |
|
||||
#9 +---+ |
|
||||
# | + + |
|
||||
#8 +---+ |
|
||||
# \ |
|
||||
# \ |
|
||||
# +--+
|
||||
# 7 6 5
|
||||
points = [
|
||||
(-w1/2,-h1/2),
|
||||
(w1/2,-h1/2),
|
||||
(w1/2+length-w2/2,-h2/2-p2vof),
|
||||
(w1/2+length+w2/2,-h2/2-p2vof),
|
||||
(w1/2+length+w2/2,h2/2-p2vof),
|
||||
(w1/2+length-w2/2,h2/2-p2vof),
|
||||
(w1/2,h1/2),
|
||||
(-w1/2,h1/2),
|
||||
]
|
||||
#Last two points can be equal
|
||||
if points[-2] == points[-1]:
|
||||
points = points[:-1]
|
||||
points = [wxPoint(*point) for point in points]
|
||||
vpoints = wxPoint_Vector(points)
|
||||
# self.Polygon(points, F_Cu)
|
||||
|
||||
size_pad = pcbnew.wxSize(width1, height1)
|
||||
#module.Add(self.smdPad(module, size_pad, pcbnew.wxPoint(0,0), "1", PAD_SHAPE_RECT,0,F_Cu,sold_clear,offset1))
|
||||
module.Add(self.smdCustomPolyPad(module, size_pad, wxPoint(0,0), "1", vpoints,F_Cu,sold_clear))
|
||||
|
||||
size_pad = pcbnew.wxSize(width2, height2)
|
||||
#solder clearance added only to polygon
|
||||
module.Add(self.smdPad(module, size_pad, pcbnew.wxPoint(length+w1/2,0-p2vof), "1", PAD_SHAPE_RECT,0,F_Cu,0.0,offset2))
|
||||
|
||||
# Text size
|
||||
text_size = self.GetTextSize() # IPC nominal
|
||||
thickness = self.GetTextThickness()
|
||||
textposy = self.draw.GetLineThickness()/2 + self.GetTextSize()/2 + thickness #+ outline['margin']
|
||||
height = max(height1,height2)
|
||||
self.draw.Reference( 0+length/2, -textposy-height/2, text_size )
|
||||
self.draw.Value( 0+length/2, textposy+height/2+text_size/2, text_size )
|
||||
# set SMD attribute
|
||||
if hasattr(pcbnew, 'MOD_VIRTUAL'):
|
||||
module.SetAttributes(pcbnew.MOD_VIRTUAL)
|
||||
else:
|
||||
module.SetAttributes(pcbnew.FP_EXCLUDE_FROM_BOM | pcbnew.FP_EXCLUDE_FROM_POS_FILES)
|
||||
# module.SetAttributes(pcbnew.MOD_VIRTUAL)
|
||||
# module.SetAttributes(pcbnew.FP_EXCLUDE_FROM_BOM | pcbnew.FP_EXCLUDE_FROM_POS_FILES)
|
||||
__version__ = 1.5
|
||||
self.buildmessages += ("version: {:.1f}".format(__version__))
|
||||
|
||||
uwTaper_wizard().register()
|
||||
141
kicad_plugins/round_tracks/RoundTrackDlg.py
Normal file
@@ -0,0 +1,141 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
###########################################################################
|
||||
## Python code generated with wxFormBuilder (version Oct 26 2018)
|
||||
## http://www.wxformbuilder.org/
|
||||
##
|
||||
## PLEASE DO *NOT* EDIT THIS FILE!
|
||||
###########################################################################
|
||||
|
||||
import wx
|
||||
import wx.xrc
|
||||
|
||||
###########################################################################
|
||||
## Class RoundTrackDlg
|
||||
###########################################################################
|
||||
|
||||
class RoundTrackDlg ( wx.Dialog ):
|
||||
|
||||
def __init__( self, parent ):
|
||||
wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Round Track parameters", pos = wx.DefaultPosition, size = wx.Size( 432,532 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER )
|
||||
|
||||
self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
|
||||
|
||||
bSizer3 = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Select Two angled Tracks\n", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_comment.Wrap( -1 )
|
||||
|
||||
bSizer3.Add( self.m_comment, 0, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
bSizer31 = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
self.m_staticText3 = wx.StaticText( self, wx.ID_ANY, u"Distance from Intersection (mm)", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText3.Wrap( -1 )
|
||||
|
||||
bSizer31.Add( self.m_staticText3, 1, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
self.m_distanceMM = wx.TextCtrl( self, wx.ID_ANY, u"5", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_distanceMM.SetMinSize( wx.Size( 1000,-1 ) )
|
||||
|
||||
bSizer31.Add( self.m_distanceMM, 1, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
|
||||
bSizer3.Add( bSizer31, 0, 0, 5 )
|
||||
|
||||
bSizer311 = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
self.m_staticText31 = wx.StaticText( self, wx.ID_ANY, u"Number of segments .. (1-32)", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText31.Wrap( -1 )
|
||||
|
||||
bSizer311.Add( self.m_staticText31, 1, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
self.m_segments = wx.TextCtrl( self, wx.ID_ANY, u"16", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_segments.SetMinSize( wx.Size( 1000,-1 ) )
|
||||
|
||||
bSizer311.Add( self.m_segments, 1, wx.ALL, 5 )
|
||||
|
||||
|
||||
bSizer3.Add( bSizer311, 1, wx.EXPAND, 5 )
|
||||
|
||||
self.m_staticline1 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
|
||||
bSizer3.Add( self.m_staticline1, 0, wx.EXPAND |wx.ALL, 5 )
|
||||
|
||||
bSizer12 = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
self.m_staticText1013 = wx.StaticText( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText1013.Wrap( -1 )
|
||||
|
||||
bSizer12.Add( self.m_staticText1013, 1, wx.ALL, 5 )
|
||||
|
||||
self.m_bitmap1 = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.Size( 180,100 ), 0 )
|
||||
bSizer12.Add( self.m_bitmap1, 1, wx.EXPAND, 5 )
|
||||
|
||||
|
||||
bSizer3.Add( bSizer12, 1, wx.EXPAND, 5 )
|
||||
|
||||
bSizer1 = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
self.m_buttonRound = wx.Button( self, wx.ID_OK, u"Round", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
|
||||
self.m_buttonRound.SetDefault()
|
||||
bSizer1.Add( self.m_buttonRound, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
self.m_buttonCancel = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
bSizer1.Add( self.m_buttonCancel, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
|
||||
bSizer3.Add( bSizer1, 0, wx.ALIGN_RIGHT|wx.EXPAND, 5 )
|
||||
|
||||
sbSizer1 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"Reconnecting" ), wx.VERTICAL )
|
||||
|
||||
bSizer611 = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
self.m_staticText81 = wx.StaticText( sbSizer1.GetStaticBox(), wx.ID_ANY, u"Select a Track to delete round segments", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText81.Wrap( -1 )
|
||||
|
||||
bSizer611.Add( self.m_staticText81, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
self.m_buttonDelete = wx.Button( sbSizer1.GetStaticBox(), wx.ID_OK, u"Delete", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
bSizer611.Add( self.m_buttonDelete, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
self.m_staticline2 = wx.StaticLine( sbSizer1.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
|
||||
bSizer611.Add( self.m_staticline2, 0, wx.EXPAND |wx.ALL, 5 )
|
||||
|
||||
|
||||
sbSizer1.Add( bSizer611, 1, wx.EXPAND, 5 )
|
||||
|
||||
bSizer111 = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
bSizer8 = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
self.m_buttonReconnect = wx.Button( sbSizer1.GetStaticBox(), wx.ID_OK, u"Connect", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
bSizer8.Add( self.m_buttonReconnect, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
self.m_checkBoxDelete = wx.CheckBox( sbSizer1.GetStaticBox(), wx.ID_ANY, u"clean path", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
bSizer8.Add( self.m_checkBoxDelete, 0, wx.ALL, 5 )
|
||||
|
||||
|
||||
bSizer111.Add( bSizer8, 1, wx.EXPAND, 5 )
|
||||
|
||||
self.m_staticText10111 = wx.StaticText( sbSizer1.GetStaticBox(), wx.ID_ANY, u"Select tracks including one round corner to be straighten", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText10111.Wrap( -1 )
|
||||
|
||||
bSizer111.Add( self.m_staticText10111, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
|
||||
sbSizer1.Add( bSizer111, 1, wx.EXPAND, 5 )
|
||||
|
||||
|
||||
bSizer3.Add( sbSizer1, 1, wx.EXPAND, 5 )
|
||||
|
||||
|
||||
self.SetSizer( bSizer3 )
|
||||
self.Layout()
|
||||
|
||||
self.Centre( wx.BOTH )
|
||||
|
||||
def __del__( self ):
|
||||
pass
|
||||
|
||||
|
||||
1175
kicad_plugins/round_tracks/Track_Rounder.fbp
Normal file
2
kicad_plugins/round_tracks/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from .round_trk import Tracks_Rounder
|
||||
Tracks_Rounder().register()
|
||||
BIN
kicad_plugins/round_tracks/round_track.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
108
kicad_plugins/round_tracks/round_track.svg
Normal file
@@ -0,0 +1,108 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
height="26"
|
||||
width="26"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="round_track.svg">
|
||||
<metadata
|
||||
id="metadata50">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="824"
|
||||
id="namedview48"
|
||||
showgrid="true"
|
||||
inkscape:zoom="16.23626"
|
||||
inkscape:cx="15.481167"
|
||||
inkscape:cy="17.524039"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2"
|
||||
inkscape:snap-to-guides="false"
|
||||
inkscape:snap-grids="true"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3006"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs4" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3783"
|
||||
d="M 22.079265,22.989018 22,4 3.669302,3.8797396"
|
||||
style="fill:none;fill-opacity:1;stroke:#4d4d4d;stroke-width:1.72992396;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:none;stroke:#008000;stroke-width:2.16862085;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path2986"
|
||||
sodipodi:cx="4"
|
||||
sodipodi:cy="22"
|
||||
sodipodi:rx="19.517588"
|
||||
sodipodi:ry="19.517588"
|
||||
d="M 4.0006035,2.4824123 A 19.517588,19.517588 0 0 1 23.517584,21.988092"
|
||||
sodipodi:start="4.7124199"
|
||||
sodipodi:end="6.2825752"
|
||||
sodipodi:open="true"
|
||||
transform="matrix(0.92224512,0,0,0.92224512,0.3110195,1.7106073)" />
|
||||
<rect
|
||||
style="fill:#2ac23c;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="rect3776"
|
||||
width="5"
|
||||
height="5.0000005"
|
||||
x="1.5"
|
||||
y="1.4999995"
|
||||
ry="2.5"
|
||||
rx="2.5" />
|
||||
<rect
|
||||
rx="2.5"
|
||||
ry="2.5"
|
||||
y="1.4999995"
|
||||
x="19.5"
|
||||
height="5.0000005"
|
||||
width="5"
|
||||
id="rect3761"
|
||||
style="fill:#2ac23c;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="fill:#2ac23c;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="rect3763"
|
||||
width="5"
|
||||
height="5.0000005"
|
||||
x="19.5"
|
||||
y="19.5"
|
||||
ry="2.5"
|
||||
rx="2.5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
BIN
kicad_plugins/round_tracks/round_track_help.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
196
kicad_plugins/round_tracks/round_track_help.svg
Normal file
@@ -0,0 +1,196 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
height="40.120056"
|
||||
width="65.120071"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="round_track_help.svg"
|
||||
inkscape:export-filename="/home/mau/.kicad_plugins/round_tracks/round_track_help.png"
|
||||
inkscape:export-xdpi="220.90854"
|
||||
inkscape:export-ydpi="220.90854">
|
||||
<metadata
|
||||
id="metadata50">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="824"
|
||||
id="namedview48"
|
||||
showgrid="true"
|
||||
inkscape:zoom="10.165207"
|
||||
inkscape:cx="28.451364"
|
||||
inkscape:cy="21.719276"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2"
|
||||
inkscape:snap-to-guides="false"
|
||||
inkscape:snap-grids="true"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
fit-margin-top="1"
|
||||
fit-margin-left="5"
|
||||
fit-margin-right="2"
|
||||
fit-margin-bottom="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3006"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true"
|
||||
originx="16.060028"
|
||||
originy="9.0600291" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs4" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3872"
|
||||
d="M 7.0600278,3.0600278 V 37.060029 H 61.060044 l -1.6e-5,-34.0000012 z"
|
||||
style="opacity:0.69599998;fill:#dfbd8a;fill-opacity:1;stroke:#b3b3b3;stroke-width:4.12005568;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3783"
|
||||
d="M 38.139293,33.060029 38.031313,9.0915631 13.060028,8.9397666"
|
||||
style="fill:none;fill-opacity:1;stroke:#4d934d;stroke-width:2.26843739;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:none;stroke:#008000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path2986"
|
||||
sodipodi:cx="20.060026"
|
||||
sodipodi:cy="27.060026"
|
||||
sodipodi:rx="18"
|
||||
sodipodi:ry="18"
|
||||
d="M 20.060583,9.0600262 A 18,18 0 0 1 38.060023,27.049044"
|
||||
sodipodi:start="4.7124199"
|
||||
sodipodi:end="6.2825752"
|
||||
sodipodi:open="true" />
|
||||
<rect
|
||||
style="fill:#2ac23c;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect3776"
|
||||
width="5"
|
||||
height="5.0000005"
|
||||
x="17.560028"
|
||||
y="6.5600266"
|
||||
ry="2.5"
|
||||
rx="2.5" />
|
||||
<rect
|
||||
rx="2.5"
|
||||
ry="2.5"
|
||||
y="6.5600266"
|
||||
x="35.560028"
|
||||
height="5.0000005"
|
||||
width="5"
|
||||
id="rect3761"
|
||||
style="fill:#2ac23c;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="fill:#2ac23c;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect3763"
|
||||
width="5"
|
||||
height="5.0000005"
|
||||
x="35.560028"
|
||||
y="24.560026"
|
||||
ry="2.5"
|
||||
rx="2.5" />
|
||||
<g
|
||||
id="g835"
|
||||
transform="rotate(-90,32.060026,0.60752525)">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5185"
|
||||
d="M 22.607525,15.607526 H 6.6075245"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.89442718px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5191"
|
||||
d="m 16.607525,17.607526 6,-2 -6,-2"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5195"
|
||||
d="m 12.607525,13.607526 -6.0000005,2 6.0000005,2"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3088"
|
||||
d="m 5.6075245,12.107526 v 7"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3088-3"
|
||||
d="m 23.607525,12.107526 v 7"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:29.68499756px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:#333333;stroke-width:0.74212497"
|
||||
x="50.686302"
|
||||
y="20.711531"
|
||||
id="text872"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan870"
|
||||
x="50.686302"
|
||||
y="20.711531"
|
||||
style="font-size:9.8949995px;fill:#333333;stroke:#333333;stroke-width:0.74212497">d</tspan></text>
|
||||
<g
|
||||
id="g918"
|
||||
transform="rotate(-45,5.0662856,2.9738479)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5191-1"
|
||||
d="m 9.6075245,32.607525 5.9999995,-2 -5.9999995,-2"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.89442718px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 30.060028,17.060027 -11.31371,11.31371"
|
||||
id="path5185-4"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:10.5511179px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:#333333;stroke-width:0.65944487"
|
||||
x="18.22471"
|
||||
y="23.864855"
|
||||
id="text942"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan940"
|
||||
x="18.22471"
|
||||
y="23.864855"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.65944487">r</tspan></text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.2 KiB |
813
kicad_plugins/round_tracks/round_trk.py
Executable file
@@ -0,0 +1,813 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2019 Maurice https://github.com/easyw/
|
||||
|
||||
# some source tips @
|
||||
# https://github.com/bpkempke/kicad-scripts
|
||||
# https://github.com/MitjaNemec/Kicad_action_plugins
|
||||
# https://github.com/jsreynaud/kicad-action-scripts
|
||||
|
||||
# GNU GENERAL PUBLIC LICENSE
|
||||
# Version 3, 29 June 2007
|
||||
#
|
||||
# Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
# Everyone is permitted to copy and distribute verbatim copies
|
||||
# of this license document, but changing it is not allowed.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
|
||||
# import round_trk; reload(round_trk)
|
||||
|
||||
## todo:
|
||||
# 1) insert check drc for rounding & fencing
|
||||
# 2) add radius as text to rounded curve
|
||||
# 3) add selected track lenght
|
||||
|
||||
import sys
|
||||
import os
|
||||
from pcbnew import *
|
||||
import wx
|
||||
import pcbnew
|
||||
import math
|
||||
import cmath
|
||||
|
||||
#from .RoundTrackDlg import RoundTrackDlg
|
||||
from . import RoundTrackDlg
|
||||
|
||||
|
||||
ToUnits=pcbnew.ToMM #ToMils
|
||||
FromUnits=pcbnew.FromMM #Mils
|
||||
|
||||
debug = False #True
|
||||
debug2 = False
|
||||
show_points = False
|
||||
show_points2 = False
|
||||
|
||||
global delete_before_connect
|
||||
delete_before_connect = False
|
||||
|
||||
# N_SEGMENTS = 32 #4#32
|
||||
# distI = FromMM(10)
|
||||
|
||||
# import pcbnew; print (pcbnew.PLUGIN_DIRECTORIES_SEARCH)
|
||||
|
||||
# Python plugin stuff
|
||||
|
||||
class RoundTrack_Dlg(RoundTrackDlg.RoundTrackDlg):
|
||||
# from https://github.com/MitjaNemec/Kicad_action_plugins
|
||||
# hack for new wxFormBuilder generating code incompatible with old wxPython
|
||||
# noinspection PyMethodOverriding
|
||||
def SetSizeHints(self, sz1, sz2):
|
||||
if wx.__version__ < '4.0':
|
||||
self.SetSizeHintsSz(sz1, sz2)
|
||||
else:
|
||||
super(RoundTrack_Dlg, self).SetSizeHints(sz1, sz2)
|
||||
|
||||
def onDeleteClick(self, event):
|
||||
return self.EndModal(wx.ID_DELETE)
|
||||
|
||||
def onConnectClick(self, event):
|
||||
return self.EndModal(wx.ID_REVERT)
|
||||
|
||||
def __init__(self, parent):
|
||||
global delete_before_connect
|
||||
import wx
|
||||
RoundTrackDlg.RoundTrackDlg.__init__(self, parent)
|
||||
#self.GetSizer().Fit(self)
|
||||
self.SetMinSize(self.GetSize())
|
||||
self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick)
|
||||
self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick)
|
||||
if wx.__version__ < '4.0':
|
||||
self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
|
||||
self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
|
||||
else:
|
||||
self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
|
||||
self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
|
||||
if self.m_checkBoxDelete.IsChecked():
|
||||
delete_before_connect = True
|
||||
|
||||
#
|
||||
class Tracks_Rounder(pcbnew.ActionPlugin):
|
||||
|
||||
def defaults(self):
|
||||
self.name = "Rounder for Tracks\n version 2.5"
|
||||
self.category = "Modify PCB"
|
||||
self.description = "Rounder for selected Traces on the PCB"
|
||||
self.icon_file_name = os.path.join(os.path.dirname(__file__), "./round_track.png")
|
||||
self.show_toolbar_button = True
|
||||
|
||||
def Warn(self, message, caption='Warning!'):
|
||||
dlg = wx.MessageDialog(
|
||||
None, message, caption, wx.OK | wx.ICON_WARNING)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
|
||||
def CheckDistanceInput(self, value, data):
|
||||
val = None
|
||||
try:
|
||||
val = float(value.replace(',','.'))
|
||||
if val <= 0:
|
||||
raise Exception("Invalid")
|
||||
except:
|
||||
self.Warn(
|
||||
"Invalid parameter for %s: Must be a positive number" % data)
|
||||
val = None
|
||||
return val
|
||||
|
||||
def CheckSegmentsInput(self, value, data):
|
||||
val = None
|
||||
try:
|
||||
val = int(value)
|
||||
if (val < 2) or (val >32):
|
||||
raise Exception("Invalid")
|
||||
except:
|
||||
self.Warn(
|
||||
"Invalid parameter for %s: Must be bigger than 2" % data)
|
||||
val = None
|
||||
return val
|
||||
|
||||
def Run(self):
|
||||
global delete_before_connect
|
||||
#self.pcb = GetBoard()
|
||||
# net_name = "GND"
|
||||
pcb = pcbnew.GetBoard()
|
||||
|
||||
#from https://github.com/MitjaNemec/Kicad_action_plugins
|
||||
#hack wxFormBuilder py2/py3
|
||||
# _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0]
|
||||
_pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetName() == 'PcbFrame'][0]
|
||||
#aParameters = RoundTrackDlg(None)
|
||||
aParameters = RoundTrack_Dlg(_pcbnew_frame)
|
||||
if hasattr (pcb, 'm_Uuid'):
|
||||
aParameters.m_buttonDelete.Disable()
|
||||
aParameters.m_checkBoxDelete.Disable()
|
||||
#aParameters = RoundTrack_DlgEx(_pcbnew_frame)
|
||||
aParameters.Show()
|
||||
#end hack
|
||||
aParameters.m_distanceMM.SetValue("5")
|
||||
aParameters.m_segments.SetValue("16")
|
||||
aParameters.m_bitmap1.SetBitmap(wx.Bitmap( os.path.join(os.path.dirname(os.path.realpath(__file__)), "round_track_help.png") ) )
|
||||
modal_result = aParameters.ShowModal()
|
||||
segments = self.CheckSegmentsInput(
|
||||
aParameters.m_segments.GetValue(), "number of segments")
|
||||
distI = FromMM(self.CheckDistanceInput(aParameters.m_distanceMM.GetValue(), "distance from intersection"))
|
||||
if aParameters.m_checkBoxDelete.IsChecked():
|
||||
delete_before_connect = True
|
||||
else:
|
||||
delete_before_connect = False
|
||||
if segments is not None and distI is not None:
|
||||
if modal_result == wx.ID_OK:
|
||||
Round_Selection(pcb, distI, segments)
|
||||
pcbnew.Refresh()
|
||||
elif modal_result == wx.ID_DELETE:
|
||||
Delete_Segments(pcb)
|
||||
#wx.LogMessage('Round Segments on Track Net Deleted')
|
||||
elif modal_result == wx.ID_REVERT:
|
||||
wxLogDebug('Connecting Tracks',debug)
|
||||
Connect_Segments(pcb)
|
||||
else:
|
||||
None # Cancel
|
||||
#pcbnew.Refresh()
|
||||
else:
|
||||
None # Invalid input
|
||||
aParameters.Destroy()
|
||||
|
||||
#Round_Selection(pcb)
|
||||
#
|
||||
|
||||
|
||||
def wxLogDebug(msg,show):
|
||||
"""printing messages only if show is omitted or True"""
|
||||
if show:
|
||||
wx.LogMessage(msg)
|
||||
#
|
||||
def distance (p1,p2):
|
||||
return math.hypot(p1.y-p2.y,p1.x-p2.x)
|
||||
#
|
||||
#gets the angle of a track
|
||||
def getTrackAngle(t1,center):
|
||||
#use atan2 so the correct quadrant is returned
|
||||
if t1.GetStart().x == center.x and t1.GetStart().y == center.y:
|
||||
wxLogDebug("Start = Center",debug)
|
||||
return math.atan2((t1.GetEnd().y - t1.GetStart().y), (t1.GetEnd().x - t1.GetStart().x))
|
||||
else:
|
||||
wxLogDebug("End = Center",debug)
|
||||
return math.atan2((t1.GetStart().y - t1.GetEnd().y), (t1.GetStart().x - t1.GetEnd().x));
|
||||
#
|
||||
#track length
|
||||
def GetTrackLength(t1):
|
||||
return t1.GetLength()
|
||||
#
|
||||
def create_Track(pcb,p1,p2,lyr=None,w=None,Nn=None,Ts=None):
|
||||
#draw segment to test
|
||||
#new_line = pcbnew.DRAWSEGMENT(pcb)
|
||||
if hasattr(pcbnew,'TRACK'):
|
||||
new_line = pcbnew.TRACK(pcb)
|
||||
else:
|
||||
new_shape = PCB_SHAPE()
|
||||
new_line = PCB_TRACK(new_shape)
|
||||
new_line.SetStart(p1)
|
||||
new_line.SetEnd(p2)
|
||||
if w is None:
|
||||
new_line.SetWidth(FromUnits(1.5)) #FromUnits(int(mask_width)))
|
||||
else:
|
||||
new_line.SetWidth(FromUnits(w))
|
||||
if lyr is None:
|
||||
lyr = F_SilkS
|
||||
if Nn is not None:
|
||||
new_line.SetNet(Nn)
|
||||
#new_line.SetNetname(Nn)
|
||||
new_line.SetLayer(lyr) #pcbnew.F_SilkS) #pcb.GetLayerID(mask_layer))
|
||||
if Ts is not None:
|
||||
tsc = 0
|
||||
Nname = new_line.GetNetname()
|
||||
for c in Nname:
|
||||
tsc = tsc + ord(c)
|
||||
if hasattr(new_line, 'SetTimeStamp'):
|
||||
new_line.SetTimeStamp(tsc) # adding a unique number (this netname) as timestamp to mark this segment as generated by this script on this netname
|
||||
pcb.Add(new_line)
|
||||
return new_line
|
||||
#
|
||||
def create_Arc(pcb,p1,p2,mp,lyr=None,w=None,Nn=None,Ts=None):
|
||||
#import pcbnew
|
||||
#from pcbnew import *
|
||||
#b = pcbnew.GetBoard()
|
||||
#new_shape = PCB_SHAPE()
|
||||
#new_arc = PCB_ARC(new_shape)
|
||||
#p1= wxPoint(203200000, 127000000)
|
||||
#md= wxPoint(221160512, 134439488)
|
||||
#p2= wxPoint(228600000, 152400000)
|
||||
#new_arc.SetStart(p1)
|
||||
#new_arc.SetMid(md)
|
||||
#new_arc.SetEnd(p2)
|
||||
#new_arc.SetWidth(250000)
|
||||
#new_arc.SetLayer(pcbnew.B_Cu)
|
||||
#b.Add(new_arc)
|
||||
#pcbnew.Refresh()
|
||||
|
||||
#draw segment to test
|
||||
#new_line = pcbnew.DRAWSEGMENT(pcb)
|
||||
if hasattr(pcbnew,'TRACK'):
|
||||
new_arc = pcbnew.TRACK(pcb)
|
||||
else:
|
||||
#new_shape = PCB_SHAPE()
|
||||
#new_arc = PCB_ARC(new_shape)
|
||||
new_trk = PCB_TRACK(pcb)
|
||||
new_arc = PCB_ARC(new_trk)
|
||||
new_arc.SetStart(p1)
|
||||
new_arc.SetEnd(p2)
|
||||
new_arc.SetMid(mp)
|
||||
if w is None:
|
||||
new_arc.SetWidth(FromUnits(1.5)) #FromUnits(int(mask_width)))
|
||||
else:
|
||||
new_arc.SetWidth(FromUnits(w))
|
||||
if lyr is None:
|
||||
lyr = F_SilkS
|
||||
if Nn is not None:
|
||||
new_arc.SetNet(Nn)
|
||||
#new_arc.SetNetname(Nn)
|
||||
new_arc.SetLayer(lyr) #pcbnew.F_SilkS) #pcb.GetLayerID(mask_layer))
|
||||
if Ts is not None:
|
||||
tsc = 0
|
||||
Nname = new_arc.GetNetname()
|
||||
for c in Nname:
|
||||
tsc = tsc + ord(c)
|
||||
if hasattr(new_arc, 'SetTimeStamp'):
|
||||
new_arc.SetTimeStamp(tsc) # adding a unique number (this netname) as timestamp to mark this segment as generated by this script on this netname
|
||||
pcb.Add(new_arc)
|
||||
return new_arc
|
||||
#
|
||||
|
||||
def create_Draw(pcb,p1,p2,lyr=None,w=None):
|
||||
#draw segment to test
|
||||
if hasattr(pcbnew,'DRAWSEGMENT'):
|
||||
new_line = pcbnew.DRAWSEGMENT(pcb)
|
||||
else:
|
||||
new_line = PCB_SHAPE()
|
||||
#new_line = pcbnew.TRACK(pcb)
|
||||
new_line.SetStart(p1)
|
||||
new_line.SetEnd(p2)
|
||||
if w is None:
|
||||
new_line.SetWidth(FromUnits(1.5)) #FromUnits(int(mask_width)))
|
||||
else:
|
||||
new_line.SetWidth(FromUnits(w))
|
||||
if lyr is None:
|
||||
lyr = F_SilkS
|
||||
new_line.SetLayer(lyr) #pcbnew.F_SilkS) #pcb.GetLayerID(mask_layer))
|
||||
pcb.Add(new_line)
|
||||
return new_line
|
||||
#
|
||||
def create_Text(pcb, txt, p, w, lyr):
|
||||
if hasattr(pcbnew,'TEXTE_PCB'):
|
||||
mytxt = pcbnew.TEXTE_PCB(pcb)
|
||||
else:
|
||||
mytxt = pcbnew.PCB_TEXT(EDA_TEXT) #Cast_to_PCB_TEXT(EDA_TEXT)
|
||||
mytxt.SetText(txt)
|
||||
mytxt.SetLayer(lyr)
|
||||
mytxt.SetPosition(p)
|
||||
mytxt.SetHorizJustify(pcbnew.GR_TEXT_HJUSTIFY_CENTER)
|
||||
mytxt.SetTextSize(pcbnew.wxSize(w,w))
|
||||
if hasattr(mytext, 'SetThickness'):
|
||||
mytxt.SetThickness(int(w/4))
|
||||
else:
|
||||
mytxt.SetTextThickness(int(w/4))
|
||||
pcb.Add(mytxt)
|
||||
#
|
||||
|
||||
def getAngleRadians(p1,p2):
|
||||
#return math.degrees(math.atan2((p1.y-p2.y),(p1.x-p2.x)))
|
||||
return (math.atan2((p1.y-p2.y),(p1.x-p2.x)))
|
||||
#
|
||||
|
||||
def rotatePoint(r,sa,da,c):
|
||||
# sa, da in radians
|
||||
x = c.x - math.cos(sa+da) * r
|
||||
y = c.y - math.sin(sa+da) * r
|
||||
return wxPoint(x,y)
|
||||
|
||||
def create_round_segments(pcb,sp,a1,ep,a2,cntr,rad,layer,width,Nn,N_SEGMENTS):
|
||||
start_point = sp
|
||||
end_point = ep
|
||||
pos = sp
|
||||
next_pos = ep
|
||||
a1 = getAngleRadians(cntr,sp)
|
||||
a2 = getAngleRadians(cntr,ep)
|
||||
wxLogDebug('a1:'+str(math.degrees(a1))+' a2:'+str(math.degrees(a2))+' a2-a1:'+str(math.degrees(a2-a1)),debug)
|
||||
if (a2-a1) > 0 and abs(a2-a1) > math.radians(180):
|
||||
deltaA = -(math.radians(360)-(a2-a1))/N_SEGMENTS
|
||||
wxLogDebug('deltaA reviewed:'+str(math.degrees(deltaA)),debug)
|
||||
elif (a2-a1) < 0 and abs(a2-a1) > math.radians(180):
|
||||
deltaA = (math.radians(360)-abs(a2-a1))/N_SEGMENTS
|
||||
wxLogDebug('deltaA reviewed2:'+str(math.degrees(deltaA)),debug)
|
||||
else:
|
||||
deltaA = (a2-a1)/N_SEGMENTS
|
||||
delta=deltaA
|
||||
wxLogDebug('delta:'+str(math.degrees(deltaA))+' radius:'+str(ToMM(rad)),debug)
|
||||
points = []
|
||||
#import round_trk; import importlib; importlib.reload(round_trk)
|
||||
for ii in range (N_SEGMENTS+1): #+1):
|
||||
points.append(pos)
|
||||
#t = create_Track(pos,pos)
|
||||
prv_pos = pos
|
||||
#pos = pos + fraction_delta
|
||||
#posPolar = cmath.polar(pos)
|
||||
#(rad) * cmath.exp(math.radians(deltaA)*1j) #cmath.rect(r, phi) : Return the complex number x with polar coordinates r and phi.
|
||||
#pos = wxPoint(posPolar.real+sp.x,posPolar.imag+sp.y)
|
||||
pos = rotatePoint(rad,a1,delta,cntr)
|
||||
delta=delta+deltaA
|
||||
wxLogDebug("pos:"+str(ToUnits(prv_pos.x))+":"+str(ToUnits(prv_pos.y))+";"+str(ToUnits(pos.x))+":"+str(ToUnits(pos.y)),debug)
|
||||
if hasattr(pcbnew,'TRACK'):
|
||||
for i, p in enumerate(points):
|
||||
#if i < len (points)-1:
|
||||
if i < len (points)-2:
|
||||
t = create_Track(pcb,p,points[i+1],layer,width,Nn,True) #adding ts code to segments
|
||||
t = create_Track(pcb,points[-2],ep,layer,width,Nn,True) #avoiding rounding on last segment
|
||||
else:
|
||||
# for i, p in enumerate(points):
|
||||
# #if i < len (points)-1:
|
||||
# if i < len (points)-2:
|
||||
# t = create_Arc(pcb,p,points[i+1],layer,width,Nn,True) #adding ts code to segments
|
||||
#t = create_Track(pcb,points[-2],ep,layer,width,Nn,True) #avoiding rounding on last segment
|
||||
p1 = points[0]
|
||||
p2 = points[-1]
|
||||
mp = mid_point(points[0],points[-1],(a2-a1))
|
||||
|
||||
# #t = create_Arc(pcb,points[0],points[-1],mp,layer,width,Nn,True)
|
||||
#p1= wxPoint(203200000, 127000000)
|
||||
#mp= wxPoint(221160512, 134439488)
|
||||
#p2= wxPoint(228600000, 152400000)
|
||||
#mp = mid_point(p1,p2,math.pi/2)
|
||||
#wx.LogMessage(str(mp))
|
||||
t = create_Arc(pcb,p1,p2,mp,layer,width,Nn,True)
|
||||
#t = create_Arc(pcb,points[-2],ep,layer,width,Nn,True)
|
||||
return points[-1]
|
||||
#
|
||||
def mid_point(p1,p2,angle): #wxpoints,angle in radians
|
||||
"""mid_point(prev_vertex,vertex,angle)-> mid_vertex
|
||||
returns mid point on arc of angle between prev_vertex and vertex"""
|
||||
#angle=math.radians(angle/2)
|
||||
angle=(angle/2)
|
||||
basic_angle=math.atan2(p2.y-p1.y,p2.x-p1.x)-math.pi/2
|
||||
shift=(1-math.cos(angle))*math.hypot(p2.y-p1.y,p2.x-p1.x)/2/math.sin(angle)
|
||||
midpoint=wxPoint((p2.x+p1.x)/2+shift*math.cos(basic_angle),(p2.y+p1.y)/2+shift*math.sin(basic_angle))
|
||||
return midpoint
|
||||
###
|
||||
def create_round_points(pcb,sp,a1,ep,a2,cntr,rad,N_SEGMENTS):
|
||||
#TODO: Put some error checking in here...
|
||||
#Re-order the two converging tracks if we're selecting the startpoint
|
||||
start_point = sp
|
||||
end_point = ep
|
||||
pos = sp
|
||||
next_pos = ep
|
||||
wxLogDebug('sp:'+str(ToMM(sp))+';ep:'+str(ToMM(ep))+';cntr:'+str(ToMM(cntr)),debug)
|
||||
a1 = getAngleRadians(cntr,sp)
|
||||
a2 = getAngleRadians(cntr,ep)
|
||||
wxLogDebug('sp:'+str(ToMM(sp))+';ep:'+str(ToMM(ep))+';cntr:'+str(ToMM(cntr)),debug)
|
||||
wxLogDebug('a1:'+str(math.degrees(a1))+' a2:'+str(math.degrees(a2))+' a2-a1:'+str(math.degrees(a2-a1)),debug)
|
||||
#if a1 < 0:
|
||||
# a1 = math.radians(180) -a1
|
||||
#if a2 < 0:
|
||||
# a2 = math.radians(180) -a2
|
||||
if (a2-a1) > 0 and abs(a2-a1) > math.radians(180):
|
||||
deltaA = -(math.radians(360)-(a2-a1))/N_SEGMENTS
|
||||
wxLogDebug('deltaA reviewed:'+str(math.degrees(deltaA)),debug)
|
||||
elif (a2-a1) < 0 and abs(a2-a1) > math.radians(180):
|
||||
deltaA = (math.radians(360)-abs(a2-a1))/N_SEGMENTS
|
||||
wxLogDebug('deltaA reviewed2:'+str(math.degrees(deltaA)),debug)
|
||||
else:
|
||||
deltaA = (a2-a1)/N_SEGMENTS
|
||||
delta=deltaA
|
||||
wxLogDebug('delta:'+str(math.degrees(deltaA))+' radius:'+str(ToMM(rad)),debug)
|
||||
points = []
|
||||
#import round_trk; import importlib; importlib.reload(round_trk)
|
||||
for ii in range (N_SEGMENTS+1):
|
||||
points.append(pos)
|
||||
#t = create_Track(pos,pos)
|
||||
prv_pos = pos
|
||||
#pos = pos + fraction_delta
|
||||
#posPolar = cmath.polar(pos)
|
||||
#(rad) * cmath.exp(math.radians(deltaA)*1j) #cmath.rect(r, phi) : Return the complex number x with polar coordinates r and phi.
|
||||
#pos = wxPoint(posPolar.real+sp.x,posPolar.imag+sp.y)
|
||||
pos = rotatePoint(rad,a1,delta,cntr)
|
||||
delta=delta+deltaA
|
||||
wxLogDebug("pos:"+str(ToUnits(prv_pos.x))+":"+str(ToUnits(prv_pos.y))+";"+str(ToUnits(pos.x))+":"+str(ToUnits(pos.y)),debug)
|
||||
for i, p in enumerate(points):
|
||||
if i < len (points):
|
||||
t = create_Draw(pcb,p,p,B_CrtYd,0.5+i*0.05)
|
||||
#
|
||||
def not_eq(a,b):
|
||||
if abs(a-b) >= 1: #1nm
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
#
|
||||
|
||||
def getCircleCenterRadius(sp,ep,ip):
|
||||
#center
|
||||
# NB add always set float even if values are pcb internal Units!!!
|
||||
x1 = float(sp.x); y1 = float(sp.y)
|
||||
x2 = float(ep.x); y2 = float(ep.y)
|
||||
xi = float(ip.x); yi = float(ip.y)
|
||||
# mg formula
|
||||
cxN = (y2-y1)*(yi-y1)*(yi-y2)-(xi-x1)*x1*(yi-y2)+(xi-x2)*x2*(yi-y1)
|
||||
cxD = -x2*yi-xi*y1+x2*y1+xi*y2+x1*yi-x1*y2
|
||||
if cxD != 0:
|
||||
Cx = cxN/cxD
|
||||
else:
|
||||
#stop
|
||||
Cx= FromMM(100)
|
||||
wxLogDebug(str(ToMM(y1))+':'+str(ToMM(yi))+':'+str(ToMM(y2)),debug)
|
||||
wxLogDebug(str(ToMM(x1))+':'+str(ToMM(xi))+':'+str(ToMM(x2)),debug)
|
||||
if not_eq(yi,y1):
|
||||
Cy = y1 - (xi-x1)/(yi-y1)*(Cx-x1)
|
||||
elif yi==y1 and (yi!=y2):
|
||||
Cx = x1
|
||||
Cy = y2 - (xi-x2)/(yi-y2)*(Cx-x2)
|
||||
elif yi==y2 and (yi!=y1):
|
||||
Cx = x2
|
||||
Cy = y1 - (xi-x1)/(yi-y1)*(Cx-x1)
|
||||
else:
|
||||
Cy = FromMM(100)
|
||||
# import round_trk; reload(round_trk)
|
||||
# import round_trk; import importlib; importlib.reload(round_trk)
|
||||
|
||||
radius = math.hypot(Cx-sp.x,Cy-sp.y)
|
||||
return wxPoint(Cx,Cy), radius
|
||||
#
|
||||
def deleteSelectedTracks(pcb):
|
||||
tracks = pcb.GetTracks()
|
||||
tracks_cp = list(tracks)
|
||||
l = len (tracks_cp)
|
||||
if hasattr(pcbnew,'TRACK'):
|
||||
track_item = pcbnew.TRACK
|
||||
else:
|
||||
track_item = pcbnew.PCB_TRACK
|
||||
for i in range(l):
|
||||
if type(tracks_cp[i]) is track_item and tracks_cp[i].IsSelected(): #item.GetNetname() == net_name:
|
||||
pcb.RemoveNative(tracks_cp[i])
|
||||
#for item in pcb.GetTracks():
|
||||
# if type(item) is TRACK and item.IsSelected(): #item.GetNetname() == net_name:
|
||||
# pcb.RemoveNative(item)
|
||||
# #pcb.Delete(item)
|
||||
#
|
||||
def deleteListTracks(pcb,tracks):
|
||||
tracksToDel_cp = list(tracks)
|
||||
l = len (tracksToDel_cp)
|
||||
if hasattr(pcbnew,'TRACK'):
|
||||
track_item = pcbnew.TRACK
|
||||
else:
|
||||
track_item = pcbnew.PCB_TRACK
|
||||
for i in range(l):
|
||||
if type(tracksToDel_cp[i]) is track_item: #item.GetNetname() == net_name:
|
||||
pcb.RemoveNative(tracksToDel_cp[i])
|
||||
#for item in tracks:
|
||||
# if type(item) is TRACK: #item.GetNetname() == net_name:
|
||||
# pcb.RemoveNative(item)
|
||||
# #pcb.Delete(item)
|
||||
#
|
||||
def selectListTracks(pcb,tracks):
|
||||
if hasattr(pcbnew,'TRACK'):
|
||||
track_item = pcbnew.TRACK
|
||||
else:
|
||||
track_item = pcbnew.PCB_TRACK
|
||||
for item in tracks:
|
||||
if type(item) is track_item:
|
||||
item.SetSelected()
|
||||
#
|
||||
|
||||
def getSelTracksLength(pcb):
|
||||
ln = 0.
|
||||
if hasattr(pcbnew,'TRACK'):
|
||||
track_item = pcbnew.TRACK
|
||||
else:
|
||||
track_item = pcbnew.PCB_TRACK
|
||||
for item in pcb.GetTracks():
|
||||
if type(item) is track_item and item.IsSelected():
|
||||
ln+=(item.GetLength())
|
||||
return(ln)
|
||||
#print(pcbnew.ToMM(ln))
|
||||
#
|
||||
## def HitTest(self, *args): for Tracks and Vias
|
||||
|
||||
##-----------------------------------------------------------------------------------------------------
|
||||
def Round_Selection(pcb,distI,segments):
|
||||
global delete_before_connect
|
||||
tracks = []
|
||||
#print ("TRACKS WHICH MATCH CRITERIA:")
|
||||
if hasattr(pcbnew,'TRACK'):
|
||||
track_item = pcbnew.TRACK
|
||||
else:
|
||||
track_item = pcbnew.PCB_TRACK
|
||||
for item in pcb.GetTracks():
|
||||
if type(item) is track_item and item.IsSelected(): #item.GetNetname() == net_name:
|
||||
tracks.append(item)
|
||||
wxLogDebug(str(len(tracks)),debug)
|
||||
|
||||
if len (tracks) == 2:
|
||||
#add all the possible intersections to a unique set, for iterating over later
|
||||
intersections = set();
|
||||
for t1 in range(len(tracks)):
|
||||
for t2 in range(t1+1, len(tracks)):
|
||||
#check if these two tracks share an endpoint
|
||||
# reduce it to a 2-part tuple so there are not multiple objects of the same point in the set
|
||||
if(tracks[t1].IsPointOnEnds(tracks[t2].GetStart())):
|
||||
intersections.add((tracks[t2].GetStart().x, tracks[t2].GetStart().y))
|
||||
if(tracks[t1].IsPointOnEnds(tracks[t2].GetEnd())):
|
||||
intersections.add((tracks[t2].GetEnd().x, tracks[t2].GetEnd().y))
|
||||
if len(intersections)==1:
|
||||
for ip in intersections:
|
||||
(x,y) = ip
|
||||
wxLogDebug("intersections: "+str(ToUnits(x))+":"+str(ToUnits(y)),debug)
|
||||
#wx.LogMessage(str(tracks[0].GetStart()))
|
||||
intersection = wxPoint(x,y)
|
||||
if tracks[0].GetStart() == pcbnew.wxPoint(x,y):
|
||||
first_trk_extNode = tracks[0].GetEnd()
|
||||
#wx.LogMessage("tracks[0] external node="+str(ToUnits(tracks[0].GetEnd().x))+";"+str(ToUnits(tracks[0].GetEnd().y)))
|
||||
else:
|
||||
first_trk_extNode = tracks[0].GetStart()
|
||||
#wx.LogMessage("tracks[0] external node="+str(ToUnits(tracks[0].GetStart().x))+";"+str(ToUnits(tracks[0].GetStart().y)))
|
||||
if tracks[1].GetStart() == pcbnew.wxPoint(x,y):
|
||||
last_trk_extNode = tracks[1].GetEnd()
|
||||
#wx.LogMessage("tracks[1] external node="+str(ToUnits(tracks[1].GetEnd().x))+";"+str(ToUnits(tracks[1].GetEnd().y)))
|
||||
else:
|
||||
last_trk_extNode = tracks[1].GetStart()
|
||||
#wx.LogMessage("tracks[1] external node="+str(ToUnits(tracks[1].GetStart().x))+";"+str(ToUnits(tracks[1].GetStart().y)))
|
||||
angle1 = math.degrees((getTrackAngle(tracks[0],intersection)))
|
||||
angle2 = math.degrees((getTrackAngle(tracks[1],intersection)))
|
||||
end_coord1 = (distI) * cmath.exp(math.radians(angle1)*1j) #cmath.rect(r, phi) : Return the complex number x with polar coordinates r and phi.
|
||||
end_coord2 = (distI) * cmath.exp(math.radians(angle2)*1j)
|
||||
startP = wxPoint(end_coord1.real+x,end_coord1.imag+y)
|
||||
endP = wxPoint(end_coord2.real+x,end_coord2.imag+y)
|
||||
layer = tracks[0].GetLayer()
|
||||
width = ToMM(tracks[0].GetWidth())
|
||||
Nname = tracks[0].GetNet() #.GetNetname()
|
||||
wxLogDebug("offset1 = "+str(ToUnits(startP)),debug) #+":"+str(ToUnits(endP)),debug)
|
||||
wxLogDebug("offset2 = "+str(ToUnits(endP)),debug) #end_coord2.real+x))+":"+str(ToUnits(end_coord2.imag+y)))
|
||||
center,radius = getCircleCenterRadius( startP,endP,intersection )
|
||||
#rad = math.hypot(center.x-startP.x,center.y-startP.y)
|
||||
wxLogDebug('radius'+str(ToMM(radius)),debug)
|
||||
wxLogDebug('center'+str(ToMM(center)),debug)
|
||||
# import round_trk; import importlib; importlib.reload(round_trk)
|
||||
lenT1 = GetTrackLength(tracks[0])
|
||||
dist1 = math.hypot(startP.y-intersection.y,startP.x-intersection.x)
|
||||
lenT2 = GetTrackLength(tracks[1])
|
||||
dist2 = math.hypot(endP.y-intersection.y,endP.x-intersection.x)
|
||||
wxLogDebug('Len T1 {0:.3f} mm, dist1 {1:.3f} mm, LenT2 {2:.3f} mm, dist2 {3:.3f} mm'.format(ToMM(lenT1),ToMM(dist1),ToMM(lenT2),ToMM(dist2)),debug)
|
||||
if show_points:
|
||||
create_Draw(pcb,startP,startP,F_Mask,0.2)
|
||||
create_Draw(pcb,intersection,intersection,Eco1_User,1.5)
|
||||
create_Draw(pcb,endP,endP,B_Mask,0.2)
|
||||
create_Draw(pcb,center,center,F_SilkS,2.)
|
||||
create_round_points(pcb,startP,angle1,endP,angle2,center,radius,segments)
|
||||
pcbnew.Refresh()
|
||||
selectListTracks(pcb,tracks)
|
||||
if (lenT1 < dist1) or (lenT2 < dist2):
|
||||
wxLogDebug('Segments too short compared to selected distance {0:.3f} mm'.format(ToMM(distI)),True)
|
||||
else:
|
||||
#create_Track(pcb,first_trk_extNode,startP,layer,width,Nname) #B_Cu,0.2)
|
||||
#if delete_before_connect:
|
||||
deleteListTracks(pcb,tracks)
|
||||
create_Track(pcb,startP,first_trk_extNode,layer,width,Nname) #B_Cu,0.2)
|
||||
#create_Draw(pcb,startP,startP,F_Mask,1.5)
|
||||
newEP = create_round_segments(pcb,startP,angle1,endP,angle2,center,radius,layer,width,Nname,segments) #B_Cu,0.2)
|
||||
#wxLogDebug(str(newEP)+':'+str(endP),True)
|
||||
#create_Draw(pcb,endP,endP,B_Mask,1.9)
|
||||
create_Track(pcb,endP,last_trk_extNode,layer,width,Nname) # B_Cu,0.2)
|
||||
#create_Track(pcb,last_trk_extNode,endP,layer,width,Nname) # B_Cu,0.2)
|
||||
#deleteSelectedTracks(pcb)
|
||||
#selectListTracks(pcb,tracks)
|
||||
w3 = 3*float(width)
|
||||
rad = float(ToMM(radius))
|
||||
wxLogDebug(str(w3),debug)
|
||||
msg = u'Corner Radius: {0:.3f} mm'.format(rad)
|
||||
msg+= u'\nAngle between tracks: {0:.1f} deg'.format(angle1-angle2)
|
||||
if rad < w3:
|
||||
msg += u'\n\u2718 ALERT: Radius < 3 *(track width) !!!\n[{0:.3f}mm < 3*{1:.3f}mm]'.format(rad,width)
|
||||
#else:
|
||||
# #msg = u'\n\u2714 Radius > 3 * (track width)'
|
||||
# msg = u'\u2714 Corner Radius: {0:.3f} mm'.format(rad)
|
||||
wxLogDebug(msg,True)
|
||||
pcbnew.Refresh()
|
||||
# import round_trk; reload(round_trk)
|
||||
# import round_trk; import importlib; importlib.reload(round_trk)
|
||||
else:
|
||||
wxLogDebug("you must select two tracks (only)",not debug)
|
||||
#
|
||||
def Delete_Segments(pcb, track=None):
|
||||
global delete_before_connect
|
||||
tracks = []
|
||||
tracksToKeep = []
|
||||
if track is None:
|
||||
if hasattr(pcbnew,'TRACK'):
|
||||
track_item = pcbnew.TRACK
|
||||
else:
|
||||
track_item = pcbnew.PCB_TRACK
|
||||
for item in pcb.GetTracks():
|
||||
if type(item) is track_item and item.IsSelected():
|
||||
tracks.append(item)
|
||||
wxLogDebug('tracks selected: '+str(len(tracks)),debug2)
|
||||
else:
|
||||
tracks.append(track)
|
||||
if len (tracks) == 1 and delete_before_connect:
|
||||
Netname = tracks[0].GetNetname()
|
||||
tsc = 0
|
||||
for c in Netname:
|
||||
tsc = tsc + ord(c)
|
||||
nseg = 0
|
||||
tracksToDel = []
|
||||
for track in pcb.GetTracks():
|
||||
if hasattr(track,'GetTimeStamp'):
|
||||
tsd = track.GetTimeStamp()
|
||||
else:
|
||||
tsd = track.m_Uuid.AsLegacyTimestamp()
|
||||
wxLogDebug('tracks ts: '+str(tsc)+';'+str(tsd),debug2)
|
||||
if tsd == tsc and tsd != 0:
|
||||
tracksToDel.append(track)
|
||||
#pcb.RemoveNative(track)
|
||||
nseg+=1
|
||||
if nseg > 0:
|
||||
tracksToDel_cp = list(tracksToDel)
|
||||
l = len (tracksToDel_cp)
|
||||
#for track in tracksToDel:
|
||||
for i in range(l):
|
||||
pcb.RemoveNative(tracksToDel_cp[i])
|
||||
wxLogDebug(u'\u2714 Round Segments on Track Net Deleted',True)
|
||||
else:
|
||||
Netname = tracks[0].GetNetname()
|
||||
tsc = 0
|
||||
for c in Netname:
|
||||
tsc = tsc + ord(c)
|
||||
nseg = 0
|
||||
tracksToDel = []
|
||||
if hasattr(pcbnew,'TRACK'):
|
||||
track_item = pcbnew.TRACK
|
||||
else:
|
||||
track_item = pcbnew.PCB_TRACK
|
||||
for track in pcb.GetTracks():
|
||||
if type(track) is track_item and track.IsSelected():
|
||||
if hasattr(track,'GetTimeStamp'):
|
||||
tsd = track.GetTimeStamp()
|
||||
else:
|
||||
tsd = track.m_Uuid.AsLegacyTimestamp()
|
||||
wxLogDebug('tracks ts: '+str(tsc)+';'+str(tsd),debug2)
|
||||
if tsd == tsc and tsd != 0:
|
||||
tracksToDel.append(track)
|
||||
#pcb.RemoveNative(track)
|
||||
nseg+=1
|
||||
else:
|
||||
tracksToKeep.append(track)
|
||||
if nseg > 0:
|
||||
tracksToDel_cp = list(tracksToDel)
|
||||
l = len (tracksToDel_cp)
|
||||
for i in range(l):
|
||||
pcb.RemoveNative(tracksToDel_cp[i])
|
||||
#for track in tracksToDel:
|
||||
# pcb.RemoveNative(track)
|
||||
wxLogDebug(u'\u2714 Round Segments on Selected Track deleted',True)
|
||||
elif delete_before_connect:
|
||||
wxLogDebug(u'\u2718 you must select One track only',not debug)
|
||||
return tracksToKeep
|
||||
#
|
||||
def Connect_Segments(pcb):
|
||||
tracks = []
|
||||
tracksToKeep = []
|
||||
if hasattr(pcbnew,'TRACK'):
|
||||
track_item = pcbnew.TRACK
|
||||
else:
|
||||
track_item = pcbnew.PCB_TRACK
|
||||
for item in pcb.GetTracks():
|
||||
if type(item) is track_item and item.IsSelected():
|
||||
tracks.append(item)
|
||||
wxLogDebug(str(len(tracks)),debug)
|
||||
|
||||
if len (tracks) >= 2:
|
||||
pi_exists = True
|
||||
if len (tracks) > 2:
|
||||
tracksToKeep = Delete_Segments(pcb)
|
||||
if len (tracksToKeep) == 2:
|
||||
tracks[0] = tracksToKeep[0]
|
||||
tracks[1] = tracksToKeep[1]
|
||||
else:
|
||||
wxLogDebug(u'\u2718 wrong selection (error)\nselect Only one corner to be straighten',not debug)
|
||||
else:
|
||||
Delete_Segments(pcb,tracks[0])
|
||||
#getting points
|
||||
if tracks[0].GetStart().x < tracks[0].GetEnd().x:
|
||||
first_trk_startP = tracks[0].GetStart()
|
||||
first_trk_endP = tracks[0].GetEnd()
|
||||
else:
|
||||
first_trk_startP = tracks[0].GetEnd()
|
||||
first_trk_endP = tracks[0].GetStart()
|
||||
if tracks[1].GetStart().x < tracks[1].GetEnd().x:
|
||||
last_trk_startP = tracks[1].GetStart()
|
||||
last_trk_endP = tracks[1].GetEnd()
|
||||
else:
|
||||
last_trk_startP = tracks[1].GetEnd()
|
||||
last_trk_endP = tracks[1].GetStart()
|
||||
wxLogDebug('sp1:'+str(first_trk_startP)+';'+str(first_trk_endP),debug2)
|
||||
wxLogDebug('sp2:'+str(last_trk_startP)+';'+str(last_trk_endP),debug2)
|
||||
x1 = float(first_trk_startP.x); y1 = float(first_trk_startP.y)
|
||||
x3 = float(first_trk_endP.x); y3 = float(first_trk_endP.y)
|
||||
x2 = float(last_trk_startP.x); y2 = float(last_trk_startP.y)
|
||||
x4 = float(last_trk_endP.x); y4 = float(last_trk_endP.y)
|
||||
if (x3!=x1) and (x4!=x2):
|
||||
N = y2-y1-x2*(y4-y2)/(x4-x2)+x1*(y3-y1)/(x3-x1)
|
||||
D = (y3-y1)/(x3-x1)-(y4-y2)/(x4-x2)
|
||||
xi = N/D
|
||||
yi = y1+(y3-y1)/(x3-x1)*(xi-x1)
|
||||
elif (x3==x1):
|
||||
xi = x1
|
||||
yi = y2+(y4-y2)/(x4-x2)*(x1-x2)
|
||||
elif (x4 == x2):
|
||||
xi = x2
|
||||
yi = y1 + (y3-y1)/(x3-x1)*(x2-x1)
|
||||
else:
|
||||
pi_exists = False
|
||||
wxLogDebug(u'\u2718 intersection point doesn\'t exist',not debug)
|
||||
if pi_exists:
|
||||
wxLogDebug('pi:'+str(wxPoint(xi,yi)),debug2) #xi)+';'+str(yi),debug1)
|
||||
wxLogDebug('sp1:('+str(ToMM(x1))+','+str(ToMM(y1))+')'+\
|
||||
';('+str(ToMM(x2))+','+str(ToMM(y2))+')',debug2)
|
||||
wxLogDebug('sp2:('+str(ToMM(x3))+','+str(ToMM(y3))+')'+\
|
||||
';('+str(ToMM(x4))+','+str(ToMM(y4))+')',debug2)
|
||||
wxLogDebug('pi:('+str(ToMM(xi))+','+str(ToMM(yi))+')',debug2)
|
||||
pi = wxPoint(xi,yi)
|
||||
if show_points2:
|
||||
#create_Text(pcb, txt, p, w)
|
||||
create_Text(pcb,'1',wxPoint(x1,y1),FromMM(1.0),pcbnew.F_SilkS)
|
||||
create_Text(pcb,'2',wxPoint(x2,y2),FromMM(1.0),pcbnew.F_SilkS)
|
||||
create_Text(pcb,'3',wxPoint(x3,y3),FromMM(1.0),pcbnew.F_SilkS)
|
||||
create_Text(pcb,'4',wxPoint(x4,y4),FromMM(1.0),pcbnew.F_SilkS)
|
||||
create_Text(pcb,'C',wxPoint(xi,yi),FromMM(2.0),pcbnew.B_SilkS)
|
||||
wxLogDebug('dp1,pi)'+str(distance(wxPoint(x1,y1),pi)),debug2)
|
||||
wxLogDebug('dp3,pi)'+str(distance(wxPoint(x3,y3),pi)),debug2)
|
||||
if distance(wxPoint(x1,y1),pi) > distance(wxPoint(x3,y3),pi):
|
||||
tracks[0].SetStart(wxPoint(x1,y1))
|
||||
tracks[0].SetEnd(pi)
|
||||
else:
|
||||
tracks[0].SetStart(wxPoint(x3,y3))
|
||||
tracks[0].SetEnd(pi)
|
||||
wxLogDebug('dp2,pi)'+str(distance(wxPoint(x2,y2),pi)),debug2)
|
||||
wxLogDebug('dp4,pi)'+str(distance(wxPoint(x4,y4),pi)),debug2)
|
||||
if distance(wxPoint(x2,y2),pi) > distance(wxPoint(x4,y4),pi):
|
||||
tracks[1].SetStart(wxPoint(x2,y2))
|
||||
tracks[1].SetEnd(pi)
|
||||
else:
|
||||
tracks[1].SetStart(wxPoint(x4,y4))
|
||||
tracks[1].SetEnd(pi)
|
||||
pcbnew.Refresh()
|
||||
else:
|
||||
wxLogDebug(u'\u2718 you must select two tracks only',not debug)
|
||||
#
|
||||
72
kicad_plugins/trace_clearance/TraceClearanceDlg.py
Normal file
@@ -0,0 +1,72 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
###########################################################################
|
||||
## Python code generated with wxFormBuilder (version Oct 26 2018)
|
||||
## http://www.wxformbuilder.org/
|
||||
##
|
||||
## PLEASE DO *NOT* EDIT THIS FILE!
|
||||
###########################################################################
|
||||
|
||||
import wx
|
||||
import wx.xrc
|
||||
|
||||
###########################################################################
|
||||
## Class TraceClearanceDlg
|
||||
###########################################################################
|
||||
|
||||
class TraceClearanceDlg ( wx.Dialog ):
|
||||
|
||||
def __init__( self, parent ):
|
||||
wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 373,480 ), style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER )
|
||||
|
||||
self.SetSizeHints( wx.Size( 373,580 ), wx.DefaultSize )
|
||||
|
||||
bSizer2 = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
self.m_staticText4 = wx.StaticText( self, wx.ID_ANY, u"Add copper pour keepout\nto selected traces.", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText4.Wrap( -1 )
|
||||
|
||||
bSizer2.Add( self.m_staticText4, 0, wx.ALL, 5 )
|
||||
|
||||
bSizer5 = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
self.m_bitmap = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
bSizer5.Add( self.m_bitmap, 0, wx.ALL, 5 )
|
||||
|
||||
|
||||
bSizer2.Add( bSizer5, 1, wx.EXPAND, 5 )
|
||||
|
||||
bSizer3 = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
self.m_staticText5 = wx.StaticText( self, wx.ID_ANY, u"Zone clearance (mm)", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText5.Wrap( -1 )
|
||||
|
||||
bSizer3.Add( self.m_staticText5, 0, wx.ALL, 5 )
|
||||
|
||||
self.m_clearance = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
bSizer3.Add( self.m_clearance, 0, wx.ALL, 5 )
|
||||
|
||||
|
||||
bSizer2.Add( bSizer3, 1, wx.EXPAND, 5 )
|
||||
|
||||
bSizer4 = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
self.m_button_ok = wx.Button( self, wx.ID_OK, u"OK", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
bSizer4.Add( self.m_button_ok, 0, wx.ALL, 5 )
|
||||
|
||||
self.m_button_cancel = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
bSizer4.Add( self.m_button_cancel, 0, wx.ALL, 5 )
|
||||
|
||||
|
||||
bSizer2.Add( bSizer4, 1, wx.EXPAND, 5 )
|
||||
|
||||
|
||||
self.SetSizer( bSizer2 )
|
||||
self.Layout()
|
||||
|
||||
self.Centre( wx.BOTH )
|
||||
|
||||
def __del__( self ):
|
||||
pass
|
||||
|
||||
|
||||
2
kicad_plugins/trace_clearance/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from .trace_clearance import TraceClearance
|
||||
TraceClearance().register()
|
||||
485
kicad_plugins/trace_clearance/trace_clearance.fbp
Normal file
@@ -0,0 +1,485 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<wxFormBuilder_Project>
|
||||
<FileVersion major="1" minor="15" />
|
||||
<object class="Project" expanded="1">
|
||||
<property name="class_decoration">; </property>
|
||||
<property name="code_generation">Python</property>
|
||||
<property name="disconnect_events">1</property>
|
||||
<property name="disconnect_mode">source_name</property>
|
||||
<property name="disconnect_php_events">0</property>
|
||||
<property name="disconnect_python_events">0</property>
|
||||
<property name="embedded_files_path">res</property>
|
||||
<property name="encoding">UTF-8</property>
|
||||
<property name="event_generation">connect</property>
|
||||
<property name="file">TraceClearanceDlg</property>
|
||||
<property name="first_id">1000</property>
|
||||
<property name="help_provider">none</property>
|
||||
<property name="indent_with_spaces"></property>
|
||||
<property name="internationalize">0</property>
|
||||
<property name="name">TraceClearanceDlg</property>
|
||||
<property name="namespace"></property>
|
||||
<property name="path">.</property>
|
||||
<property name="precompiled_header"></property>
|
||||
<property name="relative_path">1</property>
|
||||
<property name="skip_lua_events">1</property>
|
||||
<property name="skip_php_events">1</property>
|
||||
<property name="skip_python_events">1</property>
|
||||
<property name="ui_table">UI</property>
|
||||
<property name="use_enum">0</property>
|
||||
<property name="use_microsoft_bom">0</property>
|
||||
<object class="Dialog" expanded="1">
|
||||
<property name="aui_managed">0</property>
|
||||
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
|
||||
<property name="bg"></property>
|
||||
<property name="center">wxBOTH</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="event_handler">impl_virtual</property>
|
||||
<property name="extra_style"></property>
|
||||
<property name="fg"></property>
|
||||
<property name="font"></property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="minimum_size">373,580</property>
|
||||
<property name="name">TraceClearanceDlg</property>
|
||||
<property name="pos"></property>
|
||||
<property name="size">373,580</property>
|
||||
<property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="title"></property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizer2</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Add copper pour keepout
to selected traces.</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_staticText4</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizer5</property>
|
||||
<property name="orient">wxHORIZONTAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticBitmap" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="bitmap"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_bitmap</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizer3</property>
|
||||
<property name="orient">wxHORIZONTAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Zone clearance (mm)</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_staticText5</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxTextCtrl" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="maxlength"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_clearance</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="value"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizer4</property>
|
||||
<property name="orient">wxHORIZONTAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxButton" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="bitmap"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="current"></property>
|
||||
<property name="default">0</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="disabled"></property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="focus"></property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_OK</property>
|
||||
<property name="label">OK</property>
|
||||
<property name="margins"></property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_button_ok</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="position"></property>
|
||||
<property name="pressed"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxButton" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="bitmap"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="current"></property>
|
||||
<property name="default">0</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="disabled"></property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="focus"></property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_CANCEL</property>
|
||||
<property name="label">Cancel</property>
|
||||
<property name="margins"></property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_button_cancel</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="position"></property>
|
||||
<property name="pressed"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</wxFormBuilder_Project>
|
||||
BIN
kicad_plugins/trace_clearance/trace_clearance.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
235
kicad_plugins/trace_clearance/trace_clearance.py
Executable file
@@ -0,0 +1,235 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2019 Maurice https://github.com/easyw/
|
||||
# Copyright 2020 Matt Huszagh https://github.com/matthuszagh
|
||||
|
||||
# GNU GENERAL PUBLIC LICENSE
|
||||
# Version 3, 29 June 2007
|
||||
#
|
||||
# Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
# Everyone is permitted to copy and distribute verbatim copies
|
||||
# of this license document, but changing it is not allowed.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
|
||||
import os
|
||||
import pcbnew
|
||||
import wx
|
||||
# import numpy as np
|
||||
from . import TraceClearanceDlg
|
||||
import math
|
||||
|
||||
class TraceClearance_Dlg(TraceClearanceDlg.TraceClearanceDlg):
|
||||
"""
|
||||
"""
|
||||
|
||||
def SetSizeHints(self, sz1, sz2):
|
||||
if wx.__version__ < '4.0':
|
||||
self.SetSizeHintsSz(sz1, sz2)
|
||||
else:
|
||||
super(TraceClearance_Dlg, self).SetSizeHints(sz1, sz2)
|
||||
|
||||
def __init__(self, parent):
|
||||
"""
|
||||
"""
|
||||
TraceClearanceDlg.TraceClearanceDlg.__init__(self, parent)
|
||||
self.SetMinSize(self.GetSize())
|
||||
|
||||
|
||||
class TraceClearance(pcbnew.ActionPlugin):
|
||||
"""
|
||||
"""
|
||||
|
||||
def defaults(self):
|
||||
"""
|
||||
"""
|
||||
self.name = "Trace Clearance Generator\n version 1.4"
|
||||
self.category = ""
|
||||
self.description = (
|
||||
"Generate a copper pour keepout for a selected trace."
|
||||
)
|
||||
self.show_toolbar_button = True
|
||||
self.icon_file_name = os.path.join(
|
||||
os.path.dirname(__file__), "./trace_clearance.png"
|
||||
)
|
||||
|
||||
def Run(self):
|
||||
"""
|
||||
"""
|
||||
_pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetName() == 'PcbFrame'][0]
|
||||
# _pcbnew_frame = [
|
||||
# x
|
||||
# for x in wx.GetTopLevelWindows()
|
||||
# if x.GetTitle().lower().startswith("pcbnew")
|
||||
# ][0]
|
||||
wx_params = TraceClearance_Dlg(_pcbnew_frame)
|
||||
wx_params.m_clearance.SetValue("0.2")
|
||||
wx_params.m_bitmap.SetBitmap(
|
||||
wx.Bitmap(
|
||||
os.path.join(
|
||||
os.path.dirname(os.path.realpath(__file__)),
|
||||
"trace_clearance_dialog.png",
|
||||
)
|
||||
)
|
||||
)
|
||||
modal_res = wx_params.ShowModal()
|
||||
clearance = pcbnew.FromMM(
|
||||
self.InputValid(wx_params.m_clearance.GetValue())
|
||||
)
|
||||
if clearance is not None:
|
||||
pcb = pcbnew.GetBoard()
|
||||
if modal_res == wx.ID_OK:
|
||||
tracks = selected_tracks(pcb)
|
||||
if len(tracks) > 0:
|
||||
set_keepouts(pcb, tracks, clearance)
|
||||
else:
|
||||
self.Warn("At least one track must be selected.")
|
||||
elif modal_res == wx.ID_CANCEL:
|
||||
wx_params.Destroy()
|
||||
|
||||
def Warn(self, message, caption="Warning!"):
|
||||
"""
|
||||
"""
|
||||
dlg = wx.MessageDialog(None, message, caption, wx.OK | wx.ICON_WARNING)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
|
||||
def InputValid(self, value):
|
||||
"""
|
||||
"""
|
||||
try:
|
||||
float_val = float(value)
|
||||
except:
|
||||
self.Warn("Clearance must be a floating point number.")
|
||||
|
||||
if float_val <= 0:
|
||||
self.Warn("Clearance must be positive.")
|
||||
|
||||
return float_val
|
||||
|
||||
|
||||
def selected_tracks(pcb):
|
||||
"""
|
||||
TODO should we use a common import with solder expander to avoid
|
||||
redundant functionality?
|
||||
"""
|
||||
tracks = []
|
||||
if hasattr(pcbnew,'TRACK'):
|
||||
track_item = pcbnew.TRACK
|
||||
else:
|
||||
track_item = pcbnew.PCB_TRACK
|
||||
for item in pcb.GetTracks():
|
||||
if type(item) is track_item and item.IsSelected():
|
||||
tracks.append(item)
|
||||
return tracks
|
||||
|
||||
|
||||
def set_keepouts(pcb, tracks, clearance):
|
||||
"""
|
||||
"""
|
||||
for track in tracks:
|
||||
track_start = track.GetStart()
|
||||
track_end = track.GetEnd()
|
||||
if track_start.x == track_end.x and track_start.y == track_end.y:
|
||||
continue
|
||||
track_width = track.GetWidth()
|
||||
layer = track.GetLayerSet()
|
||||
|
||||
if hasattr(pcbnew,'ZONE_CONTAINER'):
|
||||
keepout = pcbnew.ZONE_CONTAINER(pcb)
|
||||
pts = poly_points(track_start, track_end, track_width, clearance)
|
||||
keepout.AddPolygon(pts)
|
||||
keepout.SetIsKeepout(True)
|
||||
keepout.SetDoNotAllowCopperPour(True)
|
||||
keepout.SetDoNotAllowVias(False)
|
||||
keepout.SetDoNotAllowTracks(False)
|
||||
keepout.SetLayerSet(layer)
|
||||
else:
|
||||
keepout = pcbnew.ZONE(pcb)
|
||||
pts = poly_points(track_start, track_end, track_width, clearance)
|
||||
# wx.LogMessage(str(pts))
|
||||
keepout.AddPolygon(pts)
|
||||
#keepout.SetIsKeepout(True)
|
||||
keepout.SetIsRuleArea(True) # was SetIsKeepout
|
||||
keepout.SetDoNotAllowCopperPour(True)
|
||||
keepout.SetDoNotAllowVias(False)
|
||||
keepout.SetDoNotAllowTracks(False)
|
||||
keepout.SetLayerSet(layer)
|
||||
pcb.Add(keepout)
|
||||
|
||||
pcbnew.Refresh()
|
||||
|
||||
|
||||
def poly_points(track_start, track_end, track_width, clearance):
|
||||
"""
|
||||
"""
|
||||
delta = track_width / 2 + clearance
|
||||
dx = track_end.x - track_start.x
|
||||
dy = track_end.y - track_start.y
|
||||
# theta = np.arctan2(dy, dx)
|
||||
theta = math.atan2(dy, dx)
|
||||
# len = np.sqrt(np.power(dx, 2) + np.power(dy, 2))
|
||||
len = math.sqrt(math.pow(dx, 2) + math.pow(dy, 2))
|
||||
dx_norm = dx / len
|
||||
dy_norm = dy / len
|
||||
|
||||
delta_x = delta * -dy_norm
|
||||
delta_y = delta * dx_norm
|
||||
pt_delta = pcbnew.wxPoint(delta_x, delta_y)
|
||||
|
||||
pts = []
|
||||
pts.append(track_start + pt_delta)
|
||||
for pt in semicircle_points(track_start, delta, theta, True):
|
||||
pts.append(pt)
|
||||
pts.append(track_start - pt_delta)
|
||||
pts.append(track_end - pt_delta)
|
||||
for pt in semicircle_points(track_end, delta, theta, False):
|
||||
pts.append(pt)
|
||||
pts.append(track_end + pt_delta)
|
||||
return pcbnew.wxPoint_Vector(pts)
|
||||
|
||||
|
||||
def semicircle_points(circle_center, radius, angle_norm, is_start=True):
|
||||
"""
|
||||
"""
|
||||
num_points = 20
|
||||
|
||||
# angles = np.linspace(
|
||||
# angle_norm + np.pi / 2, angle_norm + 3 * np.pi / 2, num_points + 2
|
||||
# )
|
||||
start = angle_norm + math.pi / 2
|
||||
stop = angle_norm + 3 * math.pi / 2
|
||||
num_vals = num_points
|
||||
delta = (stop-start)/(num_vals-1)
|
||||
evenly_spaced = [start + i * delta for i in range(num_vals)]
|
||||
# print(evenly_spaced)
|
||||
angles = evenly_spaced
|
||||
# wx.LogMessage(str(angles))
|
||||
angles = angles[1:-1]
|
||||
# wx.LogMessage(str(angles)+'1')
|
||||
if not is_start:
|
||||
# angles = np.add(angles, np.pi)
|
||||
angles.append(math.pi)
|
||||
pts = []
|
||||
for ang in angles:
|
||||
# pts.append(
|
||||
# circle_center
|
||||
# + pcbnew.wxPoint(radius * np.cos(ang), radius * np.sin(ang))
|
||||
# )
|
||||
pts.append(
|
||||
circle_center
|
||||
+ pcbnew.wxPoint(radius * math.cos(ang), radius * math.sin(ang))
|
||||
)
|
||||
return pcbnew.wxPoint_Vector(pts)
|
||||
105
kicad_plugins/trace_clearance/trace_clearance.svg
Normal file
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="15.88482mm"
|
||||
height="15.721636mm"
|
||||
viewBox="0 0 15.88482 15.721636"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||
sodipodi:docname="trace_clearance.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="15.839192"
|
||||
inkscape:cx="14.743001"
|
||||
inkscape:cy="37.63336"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2098"
|
||||
inkscape:window-x="3840"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-20.417313,-280.90036)">
|
||||
<rect
|
||||
id="rect3713"
|
||||
width="15.791624"
|
||||
height="15.721636"
|
||||
x="20.417313"
|
||||
y="280.90036"
|
||||
style="fill:#408b40;fill-opacity:1;stroke-width:0.11733633" />
|
||||
<circle
|
||||
style="fill:#404500;fill-opacity:1;stroke-width:0.26458332"
|
||||
id="path4520"
|
||||
cx="26.331844"
|
||||
cy="288.75327"
|
||||
r="4.1104908" />
|
||||
<rect
|
||||
style="fill:#404500;fill-opacity:1;stroke-width:0.17122415"
|
||||
id="rect4522"
|
||||
width="9.9543514"
|
||||
height="8.2116957"
|
||||
x="26.235428"
|
||||
y="284.6459" />
|
||||
<circle
|
||||
r="0.930112"
|
||||
cy="288.75327"
|
||||
cx="25.799042"
|
||||
id="circle4535"
|
||||
style="fill:#ffd940;fill-opacity:1;stroke-width:0.05986928" />
|
||||
<rect
|
||||
y="287.82385"
|
||||
x="25.777225"
|
||||
height="1.8581228"
|
||||
width="10.415862"
|
||||
id="rect4537"
|
||||
style="fill:#ffd940;fill-opacity:1;stroke-width:0.08331572" />
|
||||
<path
|
||||
style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 26.758661,284.67076 -4.415098,4.97522"
|
||||
id="path5158"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 33.096885,284.68121 -7.235291,8.1532"
|
||||
id="path5162"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 36.115144,288.42192 -3.960871,4.46336"
|
||||
id="path5166"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
BIN
kicad_plugins/trace_clearance/trace_clearance_dialog.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
184
kicad_plugins/trace_clearance/trace_clearance_dialog.svg
Normal file
@@ -0,0 +1,184 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="94.798798mm"
|
||||
height="62.886559mm"
|
||||
viewBox="0 0 94.798796 62.886559"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||
sodipodi:docname="trace_clearance_dialog.svg">
|
||||
<defs
|
||||
id="defs2">
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Lend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Lend"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path5887"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
transform="matrix(-0.8,0,0,-0.8,-10,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Lstart"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Lstart"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path5884"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
transform="matrix(0.8,0,0,0.8,10,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.9899495"
|
||||
inkscape:cx="-17.310534"
|
||||
inkscape:cy="13.316301"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="2098"
|
||||
inkscape:window-x="3840"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(15.132237,-257.3179)">
|
||||
<path
|
||||
style="fill:#408b40;fill-opacity:1;stroke-width:0.46934533"
|
||||
d="m -15.132237,257.3179 h 63.166496 v 62.88656 h -63.166496 z"
|
||||
id="rect3713"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#404500;fill-opacity:1;stroke-width:1.05833328"
|
||||
d="m 24.967851,288.72954 a 16.441963,16.441963 0 0 1 -16.441964,16.44196 16.441963,16.441963 0 0 1 -16.44196,-16.44196 16.441963,16.441963 0 0 1 16.44196,-16.442 16.441963,16.441963 0 0 1 16.441964,16.442 z"
|
||||
id="path4520"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#404500;fill-opacity:1;stroke-width:0.68489659"
|
||||
d="m 8.140223,272.30006 h 39.817404 v 32.8468 H 8.140223 Z"
|
||||
id="rect4522"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#ffd940;fill-opacity:1;stroke-width:0.23947711"
|
||||
d="m 10.115127,288.72954 a 3.720448,3.720448 0 0 1 -3.720448,3.72044 3.720448,3.720448 0 0 1 -3.720448,-3.72044 3.720448,3.720448 0 0 1 3.720448,-3.72048 3.720448,3.720448 0 0 1 3.720448,3.72048 z"
|
||||
id="circle4535"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#ffd940;fill-opacity:1;stroke-width:0.33326289"
|
||||
d="m 6.307411,285.01186 h 41.663452 v 7.43252 H 6.307411 Z"
|
||||
id="rect4537"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 10.233155,272.3995 -7.427237,292.30038"
|
||||
id="path5158"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 35.586051,272.4413 6.644887,305.0541"
|
||||
id="path5162"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 47.659087,287.40414 31.815603,305.25758"
|
||||
id="path5166"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.19122508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-end:url(#Arrow1Lend)"
|
||||
d="M 50.053403,292.92078 V 304.7657"
|
||||
id="path5335"
|
||||
inkscape:connector-curvature="0" />
|
||||
<g
|
||||
aria-label="clearance"
|
||||
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||
id="text6820"
|
||||
transform="matrix(4,0,0,4,-96.801489,-866.28354)">
|
||||
<path
|
||||
d="m 37.996455,291.0657 v 0.11851 q -0.05374,-0.0296 -0.108176,-0.0441 -0.05374,-0.0152 -0.108865,-0.0152 -0.123335,0 -0.191548,0.0786 -0.06821,0.0779 -0.06821,0.21911 0,0.14125 0.06821,0.2198 0.06821,0.0779 0.191548,0.0779 0.05512,0 0.108865,-0.0145 0.05443,-0.0152 0.108176,-0.0448 v 0.11713 q -0.05306,0.0248 -0.110243,0.0372 -0.0565,0.0124 -0.120579,0.0124 -0.174322,0 -0.276985,-0.10955 -0.102664,-0.10956 -0.102664,-0.29559 0,-0.18879 0.103353,-0.29697 0.104041,-0.10818 0.284564,-0.10818 0.05857,0 0.114378,0.0124 0.05581,0.0117 0.108176,0.0358 z"
|
||||
style="font-size:1.41111112px;stroke-width:0.26458332"
|
||||
id="path6846"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 38.216941,290.73566 h 0.126779 v 1.07211 h -0.126779 z"
|
||||
style="font-size:1.41111112px;stroke-width:0.26458332"
|
||||
id="path6848"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 39.269073,291.39022 v 0.062 h -0.58291 q 0.0083,0.13091 0.07855,0.19981 0.07097,0.0682 0.197059,0.0682 0.07304,0 0.141249,-0.0179 0.0689,-0.0179 0.136426,-0.0537 v 0.11989 q -0.06821,0.0289 -0.139871,0.0441 -0.07166,0.0152 -0.145383,0.0152 -0.184657,0 -0.292833,-0.10749 -0.107487,-0.10748 -0.107487,-0.29076 0,-0.18948 0.101975,-0.30041 0.102664,-0.11163 0.276297,-0.11163 0.155718,0 0.245979,0.1006 0.09095,0.0999 0.09095,0.27216 z m -0.12678,-0.0372 q -0.0014,-0.10404 -0.05857,-0.16606 -0.0565,-0.062 -0.150206,-0.062 -0.106109,0 -0.170188,0.06 -0.06339,0.0599 -0.07304,0.16881 z"
|
||||
style="font-size:1.41111112px;stroke-width:0.26458332"
|
||||
id="path6850"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 39.827867,291.41985 q -0.153651,0 -0.212906,0.0351 -0.05926,0.0351 -0.05926,0.11989 0,0.0675 0.0441,0.10749 0.04479,0.0393 0.121268,0.0393 0.105419,0 0.168809,-0.0744 0.06408,-0.0751 0.06408,-0.19913 v -0.0283 z m 0.25287,-0.0524 v 0.44028 h -0.126779 v -0.11713 q -0.04341,0.0703 -0.108176,0.10404 -0.06477,0.0331 -0.158474,0.0331 -0.118512,0 -0.188792,-0.0661 -0.06959,-0.0668 -0.06959,-0.17846 0,-0.13023 0.08682,-0.19637 0.08751,-0.0661 0.260449,-0.0661 h 0.177767 v -0.0124 q 0,-0.0875 -0.05788,-0.13505 -0.05719,-0.0482 -0.16123,-0.0482 -0.06615,0 -0.128847,0.0159 -0.0627,0.0159 -0.120578,0.0475 v -0.11713 q 0.06959,-0.0269 0.135048,-0.04 0.06546,-0.0138 0.127468,-0.0138 0.167432,0 0.250114,0.0868 0.08268,0.0868 0.08268,0.26321 z"
|
||||
style="font-size:1.41111112px;stroke-width:0.26458332"
|
||||
id="path6852"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 40.789049,291.15458 q -0.02136,-0.0124 -0.04685,-0.0179 -0.02481,-0.006 -0.05512,-0.006 -0.107487,0 -0.165364,0.0703 -0.05719,0.0696 -0.05719,0.20051 v 0.40652 h -0.127468 v -0.7717 h 0.127468 v 0.11989 q 0.03996,-0.0703 0.104042,-0.10404 0.06408,-0.0345 0.155718,-0.0345 0.01309,0 0.02894,0.002 0.01585,0.001 0.03514,0.005 z"
|
||||
style="font-size:1.41111112px;stroke-width:0.26458332"
|
||||
id="path6854"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 41.272741,291.41985 q -0.153652,0 -0.212907,0.0351 -0.05926,0.0351 -0.05926,0.11989 0,0.0675 0.0441,0.10749 0.04479,0.0393 0.121268,0.0393 0.10542,0 0.168809,-0.0744 0.06408,-0.0751 0.06408,-0.19913 v -0.0283 z m 0.25287,-0.0524 v 0.44028 h -0.12678 v -0.11713 q -0.04341,0.0703 -0.108176,0.10404 -0.06477,0.0331 -0.158474,0.0331 -0.118512,0 -0.188792,-0.0661 -0.06959,-0.0668 -0.06959,-0.17846 0,-0.13023 0.08682,-0.19637 0.08751,-0.0661 0.260449,-0.0661 h 0.177767 v -0.0124 q 0,-0.0875 -0.05788,-0.13505 -0.05719,-0.0482 -0.16123,-0.0482 -0.06615,0 -0.128847,0.0159 -0.0627,0.0159 -0.120578,0.0475 v -0.11713 q 0.06959,-0.0269 0.135048,-0.04 0.06546,-0.0138 0.127468,-0.0138 0.167432,0 0.250114,0.0868 0.08268,0.0868 0.08268,0.26321 z"
|
||||
style="font-size:1.41111112px;stroke-width:0.26458332"
|
||||
id="path6856"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 42.428226,291.34199 v 0.46578 h -0.12678 v -0.46164 q 0,-0.10956 -0.04272,-0.16399 -0.04272,-0.0544 -0.128158,-0.0544 -0.102664,0 -0.161919,0.0654 -0.05926,0.0655 -0.05926,0.17846 v 0.43615 h -0.127468 v -0.7717 h 0.127468 v 0.11989 q 0.04548,-0.0696 0.106798,-0.10404 0.06201,-0.0345 0.142627,-0.0345 0.132981,0 0.201194,0.0827 0.06821,0.082 0.06821,0.24184 z"
|
||||
style="font-size:1.41111112px;stroke-width:0.26458332"
|
||||
id="path6858"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 43.236445,291.0657 v 0.11851 q -0.05374,-0.0296 -0.108176,-0.0441 -0.05374,-0.0152 -0.108865,-0.0152 -0.123335,0 -0.191547,0.0786 -0.06821,0.0779 -0.06821,0.21911 0,0.14125 0.06821,0.2198 0.06821,0.0779 0.191547,0.0779 0.05512,0 0.108865,-0.0145 0.05443,-0.0152 0.108176,-0.0448 v 0.11713 q -0.05306,0.0248 -0.110243,0.0372 -0.0565,0.0124 -0.120579,0.0124 -0.174321,0 -0.276985,-0.10955 -0.102664,-0.10956 -0.102664,-0.29559 0,-0.18879 0.103353,-0.29697 0.104042,-0.10818 0.284565,-0.10818 0.05857,0 0.114377,0.0124 0.05581,0.0117 0.108176,0.0358 z"
|
||||
style="font-size:1.41111112px;stroke-width:0.26458332"
|
||||
id="path6860"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 44.117011,291.39022 v 0.062 h -0.58291 q 0.0083,0.13091 0.07855,0.19981 0.07097,0.0682 0.19706,0.0682 0.07304,0 0.141249,-0.0179 0.0689,-0.0179 0.136425,-0.0537 v 0.11989 q -0.06821,0.0289 -0.13987,0.0441 -0.07166,0.0152 -0.145383,0.0152 -0.184658,0 -0.292834,-0.10749 -0.107487,-0.10748 -0.107487,-0.29076 0,-0.18948 0.101975,-0.30041 0.102664,-0.11163 0.276297,-0.11163 0.155718,0 0.24598,0.1006 0.09095,0.0999 0.09095,0.27216 z m -0.126779,-0.0372 q -0.0014,-0.10404 -0.05857,-0.16606 -0.0565,-0.062 -0.150206,-0.062 -0.106109,0 -0.170188,0.06 -0.06339,0.0599 -0.07304,0.16881 z"
|
||||
style="font-size:1.41111112px;stroke-width:0.26458332"
|
||||
id="path6862"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
120
kicad_plugins/trace_solder_expander/SolderExpanderDlg.py
Normal file
@@ -0,0 +1,120 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
###########################################################################
|
||||
## Python code generated with wxFormBuilder (version Oct 26 2018)
|
||||
## http://www.wxformbuilder.org/
|
||||
##
|
||||
## PLEASE DO *NOT* EDIT THIS FILE!
|
||||
###########################################################################
|
||||
|
||||
import wx
|
||||
import wx.xrc
|
||||
|
||||
###########################################################################
|
||||
## Class SolderExpanderDlg
|
||||
###########################################################################
|
||||
|
||||
class SolderExpanderDlg ( wx.Dialog ):
|
||||
|
||||
def __init__( self, parent ):
|
||||
wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Solder Mask Expansion", pos = wx.DefaultPosition, size = wx.Size( 579,761 ), style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER )
|
||||
|
||||
self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
|
||||
|
||||
bSizer3 = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Select Tracks to add\na Solder Mask clearance expansion\nor One Pad to apply Solder Mask clearance\nexpansion to connected tracks\n", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_comment.Wrap( -1 )
|
||||
|
||||
bSizer3.Add( self.m_comment, 0, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
bSizer4 = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
|
||||
bSizer4.Add( ( 0, 1), 1, wx.EXPAND, 5 )
|
||||
|
||||
self.m_bitmap1 = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.Size( 177,102 ), 0 )
|
||||
bSizer4.Add( self.m_bitmap1, 0, wx.EXPAND, 5 )
|
||||
|
||||
self.m_staticText4 = wx.StaticText( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText4.Wrap( -1 )
|
||||
|
||||
bSizer4.Add( self.m_staticText4, 0, wx.EXPAND, 5 )
|
||||
|
||||
|
||||
bSizer3.Add( bSizer4, 1, wx.EXPAND, 5 )
|
||||
|
||||
bSizer31 = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
self.m_staticText3 = wx.StaticText( self, wx.ID_ANY, u"Solder Mask width (mm)\nto Add to Track's width", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText3.Wrap( -1 )
|
||||
|
||||
bSizer31.Add( self.m_staticText3, 1, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
self.m_clearanceMM = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_clearanceMM.SetMinSize( wx.Size( 1000,-1 ) )
|
||||
|
||||
bSizer31.Add( self.m_clearanceMM, 1, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
|
||||
bSizer3.Add( bSizer31, 0, 0, 5 )
|
||||
|
||||
bSizer1 = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
self.m_staticText101 = wx.StaticText( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText101.Wrap( -1 )
|
||||
|
||||
bSizer1.Add( self.m_staticText101, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
self.m_button1 = wx.Button( self, wx.ID_OK, u"OK", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
|
||||
self.m_button1.SetDefault()
|
||||
bSizer1.Add( self.m_button1, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
self.m_button2 = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
bSizer1.Add( self.m_button2, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
|
||||
bSizer3.Add( bSizer1, 0, wx.ALIGN_RIGHT|wx.EXPAND, 5 )
|
||||
|
||||
self.m_staticline1 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
|
||||
bSizer3.Add( self.m_staticline1, 0, wx.EXPAND |wx.ALL, 5 )
|
||||
|
||||
bSizer11 = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
self.m_staticText1011 = wx.StaticText( self, wx.ID_ANY, u"Select a Mask segment to delete the Mask path", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText1011.Wrap( -1 )
|
||||
|
||||
bSizer11.Add( self.m_staticText1011, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
self.m_buttonDelete = wx.Button( self, wx.ID_OK, u"Delete", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
bSizer11.Add( self.m_buttonDelete, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
|
||||
bSizer3.Add( bSizer11, 1, wx.EXPAND, 5 )
|
||||
|
||||
bSizerSet = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
self.m_staticText10111 = wx.StaticText( self, wx.ID_ANY, u"check this to discretize arcs", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText10111.Wrap( -1 )
|
||||
|
||||
bSizerSet.Add( self.m_staticText10111, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
self.m_checkBoxD = wx.CheckBox( self, wx.ID_ANY, u"segments", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
# self.m_checkBoxD.SetToolTip( u"check this to discretize arcs with segments" )
|
||||
|
||||
bSizerSet.Add( self.m_checkBoxD, 0, wx.ALL, 5 )
|
||||
|
||||
|
||||
bSizer3.Add( bSizerSet, 1, wx.EXPAND, 5 )
|
||||
|
||||
|
||||
self.SetSizer( bSizer3 )
|
||||
self.Layout()
|
||||
|
||||
self.Centre( wx.BOTH )
|
||||
|
||||
def __del__( self ):
|
||||
pass
|
||||
|
||||
|
||||
2
kicad_plugins/trace_solder_expander/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from .trace_solder_expander import Solder_Expander
|
||||
Solder_Expander().register()
|
||||
954
kicad_plugins/trace_solder_expander/solderExpander.fbp
Normal file
@@ -0,0 +1,954 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<wxFormBuilder_Project>
|
||||
<FileVersion major="1" minor="15" />
|
||||
<object class="Project" expanded="1">
|
||||
<property name="class_decoration"></property>
|
||||
<property name="code_generation">Python</property>
|
||||
<property name="disconnect_events">1</property>
|
||||
<property name="disconnect_mode">source_name</property>
|
||||
<property name="disconnect_php_events">0</property>
|
||||
<property name="disconnect_python_events">0</property>
|
||||
<property name="embedded_files_path">res</property>
|
||||
<property name="encoding">UTF-8</property>
|
||||
<property name="event_generation">connect</property>
|
||||
<property name="file">SolderExpanderDlg</property>
|
||||
<property name="first_id">1000</property>
|
||||
<property name="help_provider">none</property>
|
||||
<property name="indent_with_spaces"></property>
|
||||
<property name="internationalize">0</property>
|
||||
<property name="name">SolderExpanderDlg</property>
|
||||
<property name="namespace"></property>
|
||||
<property name="path">.</property>
|
||||
<property name="precompiled_header"></property>
|
||||
<property name="relative_path">1</property>
|
||||
<property name="skip_lua_events">1</property>
|
||||
<property name="skip_php_events">1</property>
|
||||
<property name="skip_python_events">1</property>
|
||||
<property name="ui_table">UI</property>
|
||||
<property name="use_enum">0</property>
|
||||
<property name="use_microsoft_bom">0</property>
|
||||
<object class="Dialog" expanded="1">
|
||||
<property name="aui_managed">0</property>
|
||||
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
|
||||
<property name="bg"></property>
|
||||
<property name="center">wxBOTH</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="event_handler">impl_virtual</property>
|
||||
<property name="extra_style"></property>
|
||||
<property name="fg"></property>
|
||||
<property name="font"></property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">SolderExpanderDlg</property>
|
||||
<property name="pos"></property>
|
||||
<property name="size">579,761</property>
|
||||
<property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
|
||||
<property name="subclass"></property>
|
||||
<property name="title">Solder Mask Expansion</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizer3</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Select Tracks to add
a Solder Mask clearance expansion
or One Pad to apply Solder Mask clearance
expansion to connected tracks
</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_comment</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizer4</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="spacer" expanded="1">
|
||||
<property name="height">1</property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="width">0</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticBitmap" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="bitmap"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_bitmap1</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size">177,102</property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label"></property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_staticText4</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag"></property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizer31</property>
|
||||
<property name="orient">wxHORIZONTAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxStaticText" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Solder Mask width (mm)
to Add to Track's width</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_staticText3</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxTextCtrl" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="maxlength"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size">1000,-1</property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_clearanceMM</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxTextValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="value"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALIGN_RIGHT|wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizer1</property>
|
||||
<property name="orient">wxHORIZONTAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label"></property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_staticText101</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxButton" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="bitmap"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">0</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="current"></property>
|
||||
<property name="default">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="disabled"></property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="focus"></property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_OK</property>
|
||||
<property name="label">OK</property>
|
||||
<property name="margins"></property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_button1</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="position"></property>
|
||||
<property name="pressed"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxButton" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="bitmap"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="current"></property>
|
||||
<property name="default">0</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="disabled"></property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="focus"></property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_CANCEL</property>
|
||||
<property name="label">Cancel</property>
|
||||
<property name="margins"></property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_button2</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="position"></property>
|
||||
<property name="pressed"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND | wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticLine" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_staticline1</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style">wxLI_HORIZONTAL</property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizer11</property>
|
||||
<property name="orient">wxHORIZONTAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Select a Mask segment to delete the Mask path</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_staticText1011</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxButton" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="bitmap"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">0</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="current"></property>
|
||||
<property name="default">0</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="disabled"></property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="focus"></property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_OK</property>
|
||||
<property name="label">Delete</property>
|
||||
<property name="margins"></property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_buttonDelete</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="position"></property>
|
||||
<property name="pressed"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizerSet</property>
|
||||
<property name="orient">wxHORIZONTAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">check this to discretize arcs</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_staticText10111</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxCheckBox" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="checked">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">segments</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_checkBoxD</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</wxFormBuilder_Project>
|
||||
BIN
kicad_plugins/trace_solder_expander/soldermask_clearance.png
Normal file
|
After Width: | Height: | Size: 988 B |
149
kicad_plugins/trace_solder_expander/soldermask_clearance.svg
Normal file
@@ -0,0 +1,149 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
height="27.733334"
|
||||
width="27.733334"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="soldermask_clearance.svg"
|
||||
viewBox="0 0 26 26"
|
||||
inkscape:export-filename="C:\Users\userC\AppData\Roaming\kicad\scripting\plugins\trace_solder_expander\soldermask_clearance.png"
|
||||
inkscape:export-xdpi="101.05263"
|
||||
inkscape:export-ydpi="101.05263">
|
||||
<metadata
|
||||
id="metadata40">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1361"
|
||||
id="namedview38"
|
||||
showgrid="true"
|
||||
inkscape:snap-to-guides="false"
|
||||
inkscape:snap-grids="true"
|
||||
inkscape:zoom="18.443509"
|
||||
inkscape:cx="7.0991957"
|
||||
inkscape:cy="12.507182"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3017"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true"
|
||||
spacingx="0.5"
|
||||
spacingy="0.5"
|
||||
originx="0"
|
||||
originy="0" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs4">
|
||||
<filter
|
||||
id="c"
|
||||
height="1.3651"
|
||||
width="1.2097"
|
||||
y="-0.18257"
|
||||
x="-0.10484"
|
||||
style="color-interpolation-filters:sRGB">
|
||||
<feGaussianBlur
|
||||
stdDeviation="1.5978799"
|
||||
id="feGaussianBlur7" />
|
||||
</filter>
|
||||
<filter
|
||||
id="d"
|
||||
height="1.4696"
|
||||
width="1.4809999"
|
||||
y="-0.23481999"
|
||||
x="-0.24049"
|
||||
style="color-interpolation-filters:sRGB">
|
||||
<feGaussianBlur
|
||||
stdDeviation="1.5978799"
|
||||
id="feGaussianBlur10" />
|
||||
</filter>
|
||||
</defs>
|
||||
<path
|
||||
style="fill:#b3b3b3;fill-opacity:1;stroke:#b3b3b3;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M -1.7193647e-8,-1.7193646e-8 V 26 H 26 V 11.5 H 14 14.03125 14.0625 C 12.8522,13.592433 10.591084,15 8,15 4.1340066,15 0.99999996,11.865993 0.99999996,8 0.99999996,4.1340066 4.1340066,0.99999996 8,0.99999996 c 2.591084,0 4.8522,1.40756694 6.0625,3.50000004 3.645833,0 8.291667,0 11.9375,0 V -1.7193646e-8 Z"
|
||||
id="rect3811"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccssscccc"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263" />
|
||||
<path
|
||||
d="m 11.5,8 h 13 m -13,0 C 11.5,9.932997 9.932997,11.5 8,11.5 6.0670034,11.5 4.5,9.932997 4.5,8 4.5,6.0670034 6.0670034,4.5 8,4.5 c 1.932997,0 3.5,1.5670034 3.5,3.5 z"
|
||||
style="opacity:1;fill:none;stroke:#ffcc00;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path3867"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263" />
|
||||
<g
|
||||
transform="matrix(1.6382539,0,0,1.5572263,1.2572207,0.36314149)"
|
||||
id="g16"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263">
|
||||
<rect
|
||||
height="16"
|
||||
width="16"
|
||||
y="0"
|
||||
x="0"
|
||||
id="rect18"
|
||||
style="fill-opacity:0" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:#006400;fill-opacity:1;stroke:none;stroke-width:1"
|
||||
d="M 0,-1.7193646e-8 V 25.999145 H 25.999145 V 10.394897 H 13.500366 c -0.924775,2.12164 -3.038255,3.605347 -5.5004882,3.605347 -3.3137084,0 -6.0003661,-2.686658 -6.0003661,-6.0003661 0,-3.313709 2.6866577,-6.0003662 6.0003661,-6.0003662 2.4692872,0 4.5872392,1.494109 5.5078122,3.6254883 H 25.999145 V -1.7193647e-8 Z"
|
||||
id="rect3869"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263" />
|
||||
<path
|
||||
id="path3002"
|
||||
style="opacity:0.25;fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 11.5,8 h 13 m -13,0 C 11.5,9.932997 9.932997,11.5 8,11.5 6.0670034,11.5 4.5,9.932997 4.5,8 4.5,6.0670034 6.0670034,4.5 8,4.5 c 1.932997,0 3.5,1.5670034 3.5,3.5 z"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccccssscccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3872"
|
||||
d="M -1.7193647e-8,-1.7193646e-8 V 26 H 26 V 11.5 H 14 14.03125 14.0625 C 12.8522,13.592433 10.591084,15 8,15 4.1340066,15 0.99999996,11.865993 0.99999996,8 0.99999996,4.1340066 4.1340066,0.99999996 8,0.99999996 c 2.591084,0 4.8522,1.40756694 6.0625,3.50000004 3.645833,0 8.291667,0 11.9375,0 V -1.7193646e-8 Z"
|
||||
style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263" />
|
||||
<circle
|
||||
style="opacity:0.76300001;fill:#1a1a1a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:14.23387146;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path825"
|
||||
cx="8.0107536"
|
||||
cy="8.0024424"
|
||||
r="1.8978496" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
@@ -0,0 +1,199 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
height="39.170238"
|
||||
width="68.170242"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="soldermask_clearance_help.svg"
|
||||
viewBox="0 0 63.909602 36.722098"
|
||||
inkscape:export-filename="/home/mau/.kicad_plugins/trace_solder_expander/soldermask_clearance_help.png"
|
||||
inkscape:export-xdpi="249.23077"
|
||||
inkscape:export-ydpi="249.23077">
|
||||
<metadata
|
||||
id="metadata40">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="824"
|
||||
id="namedview38"
|
||||
showgrid="true"
|
||||
inkscape:snap-to-guides="false"
|
||||
inkscape:snap-grids="true"
|
||||
inkscape:zoom="10.94351"
|
||||
inkscape:cx="24.081918"
|
||||
inkscape:cy="19.825662"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
fit-margin-top="1"
|
||||
fit-margin-right="2"
|
||||
fit-margin-left="5"
|
||||
fit-margin-bottom="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3017"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true"
|
||||
spacingx="0.5"
|
||||
spacingy="0.5"
|
||||
originx="10.204784"
|
||||
originy="5.5865558" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs4">
|
||||
<filter
|
||||
id="c"
|
||||
height="1.3651"
|
||||
width="1.2097"
|
||||
y="-0.18257"
|
||||
x="-0.10484"
|
||||
style="color-interpolation-filters:sRGB">
|
||||
<feGaussianBlur
|
||||
stdDeviation="1.5978799"
|
||||
id="feGaussianBlur7" />
|
||||
</filter>
|
||||
<filter
|
||||
id="d"
|
||||
height="1.4696"
|
||||
width="1.4809999"
|
||||
y="-0.23481999"
|
||||
x="-0.24049"
|
||||
style="color-interpolation-filters:sRGB">
|
||||
<feGaussianBlur
|
||||
stdDeviation="1.5978799"
|
||||
id="feGaussianBlur10" />
|
||||
</filter>
|
||||
</defs>
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3872-9"
|
||||
d="M 6.6422998,2.8922999 V 33.8298 H 60.079799 l -1.5e-5,-30.9375001 z"
|
||||
style="opacity:0.25;fill:#cccccc;fill-opacity:1;stroke:#b3b3b3;stroke-width:3.90959978;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263" />
|
||||
<g
|
||||
id="g904"
|
||||
transform="translate(10.204784,5.1355441)">
|
||||
<path
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M -1.7193647e-8,-1.7193646e-8 V 26 H 26 V 11.5 H 14 14.03125 14.0625 C 12.8522,13.592433 10.591084,15 8,15 4.1340066,15 0.99999996,11.865993 0.99999996,8 0.99999996,4.1340066 4.1340066,0.99999996 8,0.99999996 c 2.591084,0 4.8522,1.40756694 6.0625,3.50000004 3.645833,0 8.291667,0 11.9375,0 V -1.7193646e-8 Z"
|
||||
id="path3872"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccssscccc" />
|
||||
<path
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
sodipodi:nodetypes="cccccccssscccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="rect3811"
|
||||
d="M -1.7193647e-8,-1.7193646e-8 V 26 H 26 V 11.5 H 14 14.03125 14.0625 C 12.8522,13.592433 10.591084,15 8,15 4.1340066,15 0.99999996,11.865993 0.99999996,8 0.99999996,4.1340066 4.1340066,0.99999996 8,0.99999996 c 2.591084,0 4.8522,1.40756694 6.0625,3.50000004 3.645833,0 8.291667,0 11.9375,0 V -1.7193646e-8 Z"
|
||||
style="fill:#b3b3b3;fill-opacity:1;stroke:#b3b3b3;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
id="rect3869"
|
||||
d="M 0,-1.7193646e-8 V 25.999145 H 25.999145 V 10.394897 H 13.500366 c -0.924775,2.12164 -3.038255,3.605347 -5.5004882,3.605347 -3.3137084,0 -6.0003661,-2.686658 -6.0003661,-6.0003661 0,-3.313709 2.6866577,-6.0003662 6.0003661,-6.0003662 2.4692872,0 4.5872392,1.494109 5.5078122,3.6254883 H 25.999145 V -1.7193647e-8 Z"
|
||||
style="fill:#006400;fill-opacity:1;stroke:none;stroke-width:1" />
|
||||
<path
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3867"
|
||||
style="opacity:1;fill:none;stroke:#ffcc00;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 11.5,8 h 13 m -13,0 C 11.5,9.932997 9.932997,11.5 8,11.5 6.0670034,11.5 4.5,9.932997 4.5,8 4.5,6.0670034 6.0670034,4.5 8,4.5 c 1.932997,0 3.5,1.5670034 3.5,3.5 z" />
|
||||
<g
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
id="g16"
|
||||
transform="matrix(1.6382539,0,0,1.5572263,1.2572207,0.36314149)">
|
||||
<rect
|
||||
style="fill-opacity:0"
|
||||
id="rect18"
|
||||
x="0"
|
||||
y="0"
|
||||
width="16"
|
||||
height="16" />
|
||||
</g>
|
||||
<path
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 11.5,8 h 13 m -13,0 C 11.5,9.932997 9.932997,11.5 8,11.5 6.0670034,11.5 4.5,9.932997 4.5,8 4.5,6.0670034 6.0670034,4.5 8,4.5 c 1.932997,0 3.5,1.5670034 3.5,3.5 z"
|
||||
style="opacity:0.25;fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path3002" />
|
||||
<circle
|
||||
r="1.8978496"
|
||||
cy="8.0024424"
|
||||
cx="8.0107536"
|
||||
id="path825"
|
||||
style="opacity:0.76300001;fill:#1a1a1a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:14.23387146;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3088"
|
||||
d="m 28,11 h 6.562499"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.9375px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3088-3"
|
||||
d="m 27.986049,8.7326995 h 6.562499"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.9375px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<text
|
||||
id="text851"
|
||||
y="25.152184"
|
||||
x="28.789062"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#333333;fill-opacity:1;stroke:#333333;stroke-width:0.9375"
|
||||
xml:space="preserve"><tspan
|
||||
id="tspan888"
|
||||
sodipodi:role="line"
|
||||
x="28.789062"
|
||||
y="25.152184">exp</tspan></text>
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5191"
|
||||
d="M 33.75,17.624999 31.875,12 30,17.624999"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.9375px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5195"
|
||||
d="M 30,2 31.875,7.625001 33.75,2"
|
||||
style="fill:#333333;stroke:#333333;stroke-width:0.9375px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.4 KiB |
666
kicad_plugins/trace_solder_expander/trace_solder_expander.py
Executable file
@@ -0,0 +1,666 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2019 Maurice https://github.com/easyw/
|
||||
|
||||
# some source tips @
|
||||
# https://github.com/bpkempke/kicad-scripts
|
||||
# https://github.com/MitjaNemec/Kicad_action_plugins
|
||||
# https://github.com/jsreynaud/kicad-action-scripts
|
||||
|
||||
# GNU GENERAL PUBLIC LICENSE
|
||||
# Version 3, 29 June 2007
|
||||
#
|
||||
# Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
# Everyone is permitted to copy and distribute verbatim copies
|
||||
# of this license document, but changing it is not allowed.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
|
||||
|
||||
# some source tips @
|
||||
# https://github.com/bpkempke/kicad-scripts
|
||||
# https://github.com/MitjaNemec/Kicad_action_plugins
|
||||
# https://github.com/jsreynaud/kicad-action-scripts
|
||||
|
||||
# import trace_solder_expansion; reload(trace_solder_expansion)
|
||||
|
||||
import sys
|
||||
import os
|
||||
from pcbnew import *
|
||||
import wx
|
||||
import pcbnew
|
||||
import math
|
||||
import uuid
|
||||
|
||||
debug = False #True
|
||||
def wxLogDebug(msg,show):
|
||||
"""printing messages only if show is omitted or True"""
|
||||
if show:
|
||||
wx.LogMessage(msg)
|
||||
#
|
||||
def find_pcbnew_w():
|
||||
windows = wx.GetTopLevelWindows()
|
||||
pcbneww = [w for w in windows if "pcbnew" in w.GetTitle().lower()]
|
||||
if len(pcbneww) != 1:
|
||||
return None
|
||||
return pcbneww[0]
|
||||
#
|
||||
|
||||
#if (sys.version[0]) == '2':
|
||||
# from .SolderExpanderDlg import SolderExpanderDlg
|
||||
#else:
|
||||
# from .SolderExpanderDlg_py3 import SolderExpanderDlg_y3
|
||||
#from .SolderExpanderDlg import SolderExpanderDlg
|
||||
from . import SolderExpanderDlg
|
||||
|
||||
ToUnits=pcbnew.ToMM #ToMils
|
||||
FromUnits=pcbnew.FromMM #Mils
|
||||
|
||||
global discretize
|
||||
discretize = False
|
||||
# import trace_solder_expansion; reload(trace_solder_expansion)
|
||||
|
||||
# Python plugin stuff
|
||||
|
||||
class SolderExpander_Dlg(SolderExpanderDlg.SolderExpanderDlg):
|
||||
# from https://github.com/MitjaNemec/Kicad_action_plugins
|
||||
# hack for new wxFormBuilder generating code incompatible with old wxPython
|
||||
# noinspection PyMethodOverriding
|
||||
def SetSizeHints(self, sz1, sz2):
|
||||
if sys.version_info[0] == 2:
|
||||
# wxPython 2
|
||||
self.SetSizeHintsSz(sz1, sz2)
|
||||
else:
|
||||
# wxPython 3
|
||||
super(SolderExpander_Dlg, self).SetSizeHints(sz1, sz2)
|
||||
|
||||
def onDeleteClick(self, event):
|
||||
return self.EndModal(wx.ID_DELETE)
|
||||
|
||||
def __init__(self, parent):
|
||||
global discretize
|
||||
SolderExpanderDlg.SolderExpanderDlg.__init__(self, parent)
|
||||
self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick)
|
||||
self.SetMinSize(self.GetSize())
|
||||
#if self.m_checkBoxD.IsChecked():
|
||||
# discretize = True
|
||||
# #wx.LogMessage(str(discretize) + ' 0')
|
||||
#else:
|
||||
# discretize = False
|
||||
|
||||
#
|
||||
|
||||
class Solder_Expander(pcbnew.ActionPlugin):
|
||||
def defaults(self):
|
||||
self.name = "Solder Mask Expander for Tracks\n version 2.3"
|
||||
self.category = "Modify PCB"
|
||||
self.description = "Solder Mask Expander for selected Tracks on the PCB"
|
||||
self.icon_file_name = os.path.join(os.path.dirname(__file__), "./soldermask_clearance.png")
|
||||
self.show_toolbar_button = True
|
||||
|
||||
def Warn(self, message, caption='Warning!'):
|
||||
dlg = wx.MessageDialog(
|
||||
None, message, caption, wx.OK | wx.ICON_WARNING)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
|
||||
def CheckInput(self, value, data):
|
||||
val = None
|
||||
try:
|
||||
val = float(value.replace(',','.'))
|
||||
if val <= 0:
|
||||
raise Exception("Invalid")
|
||||
except:
|
||||
self.Warn(
|
||||
"Invalid parameter for %s: Must be a positive number" % data)
|
||||
val = None
|
||||
return val
|
||||
|
||||
def Run(self):
|
||||
#import pcbnew
|
||||
#pcb = pcbnew.GetBoard()
|
||||
# net_name = "GND"
|
||||
#aParameters = SolderExpanderDlg(None)
|
||||
# _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0]
|
||||
global discretize
|
||||
|
||||
# _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetName() == 'PcbFrame'][0]
|
||||
pcbnew_window = find_pcbnew_w()
|
||||
aParameters = SolderExpander_Dlg(pcbnew_window)
|
||||
aParameters.m_clearanceMM.SetValue("0.2")
|
||||
aParameters.m_bitmap1.SetBitmap(wx.Bitmap( os.path.join(os.path.dirname(os.path.realpath(__file__)), "soldermask_clearance_help.png") ) )
|
||||
pcb = pcbnew.GetBoard()
|
||||
if not(hasattr(pcbnew,'DRAWSEGMENT')):
|
||||
#if hasattr(pcb, 'm_Uuid'):
|
||||
aParameters.m_buttonDelete.Disable()
|
||||
aParameters.m_buttonDelete.Hide()
|
||||
aParameters.m_staticText1011.Hide()
|
||||
aParameters.m_checkBoxD.SetToolTip( u"check this to discretize arcs with segments" )
|
||||
#if aParameters.m_checkBoxD.IsChecked():
|
||||
# discretize = True
|
||||
# wx.LogMessage(str(discretize) + ' 1')
|
||||
#else:
|
||||
# discretize = False
|
||||
else:
|
||||
aParameters.m_checkBoxD.Hide()
|
||||
aParameters.m_staticText10111.Hide()
|
||||
modal_result = aParameters.ShowModal()
|
||||
clearance = FromMM(self.CheckInput(aParameters.m_clearanceMM.GetValue(), "extra clearance from track width"))
|
||||
|
||||
if not(hasattr(pcbnew,'DRAWSEGMENT')):
|
||||
#if hasattr(pcb, 'm_Uuid'):
|
||||
aParameters.m_buttonDelete.Disable()
|
||||
aParameters.m_buttonDelete.Hide()
|
||||
aParameters.m_staticText1011.Hide()
|
||||
discretize = aParameters.m_checkBoxD.GetValue()
|
||||
#if aParameters.m_checkBoxD.IsChecked():
|
||||
# discretize = True
|
||||
# wx.LogMessage(str(discretize) + ' 1')
|
||||
#else:
|
||||
# discretize = False
|
||||
|
||||
if clearance is not None:
|
||||
if modal_result == wx.ID_OK:
|
||||
#pcb = pcbnew.GetBoard()
|
||||
tracks=getSelTracks(pcb)
|
||||
arcs=getSelArcs(pcb)
|
||||
if len(tracks) >0 or len(arcs) >0 : #selected tracks >0
|
||||
solderExpander(pcb,tracks,clearance)
|
||||
solderExpander(pcb,arcs,clearance)
|
||||
else:
|
||||
pads=[]
|
||||
for item in pcb.GetPads():
|
||||
if item.IsSelected():
|
||||
pads.append(item)
|
||||
if len(pads) == 1:
|
||||
tracks=[]
|
||||
tracks = find_Tracks_inNet_Pad(pcb,pads[0])
|
||||
c_tracks = get_contiguous_tracks(pcb,tracks,pads[0])
|
||||
solderExpander(pcb,c_tracks,clearance)
|
||||
solderExpander(pcb,arcs,clearance)
|
||||
else:
|
||||
wx.LogMessage("Solder Mask Expander:\nSelect Tracks\nor One Pad to select connected Tracks")
|
||||
|
||||
#solderExpander(clearance)
|
||||
elif modal_result == wx.ID_DELETE:
|
||||
Delete_Segments(pcb)
|
||||
#wx.LogMessage('Solder Mask Segments on Track Net Deleted')
|
||||
else:
|
||||
None # Cancel
|
||||
else:
|
||||
None # Invalid input
|
||||
aParameters.Destroy()
|
||||
#
|
||||
def selectListTracks(pcb,tracks):
|
||||
for item in tracks:
|
||||
if type(item) is TRACK:
|
||||
item.SetSelected()
|
||||
#
|
||||
#
|
||||
#def getSelTracksLength(pcb):
|
||||
# ln = 0.
|
||||
# for item in pcb.GetTracks():
|
||||
# if type(item) is pcbnew.TRACK and item.IsSelected():
|
||||
# ln+=(item.GetLength())
|
||||
# return(ln)
|
||||
# #print(pcbnew.ToMM(ln))
|
||||
#
|
||||
def get_contiguous_tracks(pcb,trks,pad):
|
||||
LinePoints = []
|
||||
LineSegments=[]
|
||||
|
||||
#start_point = ToMM(pad.GetPosition())
|
||||
startp = (pad.GetPosition())
|
||||
start_point = ((startp.x),(startp.y))
|
||||
for t in (trks):
|
||||
LinePoints.append((t.GetStart().x,t.GetStart().y))
|
||||
LinePoints.append((t.GetEnd().x, t.GetEnd().y))
|
||||
wxLogDebug('Points '+str(LinePoints),debug)
|
||||
l= len(LinePoints)
|
||||
for i in range(0,l,2):
|
||||
LineSegments.append((LinePoints[i],LinePoints[i+1]))
|
||||
wxLogDebug(str(LineSegments),debug)
|
||||
|
||||
#segments = [(1, 2), (2, 3), (4, 5), (6, 5), (7, 6)]
|
||||
#start_point=(4,5)
|
||||
#segments_start=segments
|
||||
|
||||
segments = LineSegments
|
||||
groups=[]
|
||||
found=False
|
||||
for s in segments:
|
||||
found=False
|
||||
for g in groups:
|
||||
for sCmp in g:
|
||||
wxLogDebug('sCmp: '+(str(sCmp)),debug)
|
||||
wxLogDebug('s: '+(str(s)),debug)
|
||||
if isConn(sCmp,s): #confronto start e end
|
||||
g.append(s)
|
||||
found=True
|
||||
break;
|
||||
if (found):
|
||||
break;
|
||||
if(not found):
|
||||
groups.append([s])
|
||||
wxLogDebug('groups: '+(str(groups)),debug)
|
||||
wxLogDebug('len groups: '+(str(len(groups))),debug)
|
||||
l = 0
|
||||
lens = []
|
||||
for g in groups:
|
||||
lens.append(len(g))
|
||||
if l<len(g):
|
||||
l = len(g)
|
||||
wxLogDebug('len max groups: '+str(l),debug)
|
||||
wxLogDebug('lens in groups: '+str(lens),debug)
|
||||
found=False
|
||||
|
||||
res_g=[]
|
||||
wxLogDebug('start '+str((start_point,start_point)),debug)
|
||||
wxLogDebug('start '+str(s),debug)
|
||||
|
||||
#for g,i in enumerate(groups):
|
||||
i=0
|
||||
while (i+1) < len (groups):
|
||||
found = False
|
||||
for s in groups[i]:
|
||||
for r in groups[i+1]:
|
||||
wxLogDebug('s: '+str(s)+';r: '+str(r),debug)
|
||||
if isConn(r,s):
|
||||
for r1 in groups[i+1]:
|
||||
groups[i].append(r1)
|
||||
groups.pop(i+1)
|
||||
found=True
|
||||
break
|
||||
if found:
|
||||
break
|
||||
if not found:
|
||||
i+=1
|
||||
else:
|
||||
i=0
|
||||
l = 0
|
||||
lens = []
|
||||
for g in groups:
|
||||
lens.append(len(g))
|
||||
if l<len(g):
|
||||
l = len(g)
|
||||
wxLogDebug('groups merged: '+(str(groups)),debug)
|
||||
wxLogDebug('len max groups merged: '+str(l),debug)
|
||||
wxLogDebug('lens in groups merged: '+str(lens),debug)
|
||||
|
||||
for g in groups:
|
||||
for s in g:
|
||||
if isConn((start_point,start_point),s):
|
||||
res_g = g
|
||||
found = True
|
||||
break
|
||||
wxLogDebug('start '+str(start_point),debug)
|
||||
group = res_g
|
||||
wxLogDebug('group '+str(res_g),debug)
|
||||
wxLogDebug('len group: '+(str(len(group))),debug)
|
||||
trks_connected=[]
|
||||
for seg in res_g:
|
||||
for t in trks:
|
||||
tseg = ((t.GetStart().x,t.GetStart().y),(t.GetEnd().x,t.GetEnd().y))
|
||||
wxLogDebug('seg '+str(seg),debug)
|
||||
wxLogDebug('tseg '+str(tseg),debug)
|
||||
if isConn(seg,tseg):
|
||||
if t not in trks_connected:
|
||||
trks_connected.append(t)
|
||||
wxLogDebug('t added: '+(str(tseg)),debug)
|
||||
wxLogDebug('trks_connected '+str(len(trks_connected)),debug)
|
||||
return trks_connected
|
||||
#
|
||||
def isEq (p1,p2):
|
||||
epsilon = FromMM(0.003) # tolerance 5 nm
|
||||
delta = math.hypot(p1[0]-p2[0],p1[1]-p2[1])
|
||||
wxLogDebug('delta: '+str(delta)+'eps: '+str(epsilon),debug)
|
||||
#wxLogDebug('epsilon: '+str(epsilon),debug)
|
||||
if delta <= epsilon:
|
||||
wxLogDebug('connected',debug)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
#
|
||||
|
||||
def isConn(s1,s2):
|
||||
#if s1[0] == s2[0] or s1[1] == s2[1]:
|
||||
if isEq(s1[0],s2[0]) or isEq(s1[1],s2[1]):
|
||||
return True
|
||||
#elif s1[0] == s2[1] or s1[1] == s2[0]:
|
||||
elif isEq(s1[0],s2[1]) or isEq(s1[1],s2[0]):
|
||||
return True
|
||||
return False
|
||||
#
|
||||
|
||||
def getSelTracks(pcb):
|
||||
tracks=[]
|
||||
if hasattr(pcbnew,'TRACK'):
|
||||
track_item = pcbnew.TRACK
|
||||
else:
|
||||
track_item = pcbnew.PCB_TRACK
|
||||
for item in pcb.GetTracks():
|
||||
if type(item) is track_item and item.IsSelected():
|
||||
tracks.append(item)
|
||||
return tracks
|
||||
#
|
||||
def getSelArcs(pcb):
|
||||
tracks=[]
|
||||
if hasattr(pcbnew,'TRACK'):
|
||||
track_item = pcbnew.TRACK
|
||||
else:
|
||||
track_item = pcbnew.PCB_ARC
|
||||
for item in pcb.GetTracks():
|
||||
if type(item) is track_item and item.IsSelected():
|
||||
tracks.append(item)
|
||||
return tracks
|
||||
#
|
||||
def find_Tracks_inNet_Pad(pcb,pad):
|
||||
track_list = []
|
||||
# get list of all selected pads
|
||||
#selected_pads = [pad1, pad2]
|
||||
# get the net the pins are on
|
||||
net = pad.GetNetname()
|
||||
# find all tracks
|
||||
tracks = pcb.GetTracks()
|
||||
# find all tracks on net
|
||||
tracks_on_net = []
|
||||
for track in tracks:
|
||||
track_net_name = track.GetNetname()
|
||||
if track_net_name == net:
|
||||
tracks_on_net.append(track)
|
||||
return tracks_on_net
|
||||
#
|
||||
def not_eq(a,b):
|
||||
if abs(a-b) >= 1: #1nm
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
#
|
||||
# Function to find the circle on
|
||||
# which the given three points lie
|
||||
def getCircleCenterRadius(sp,ep,ip):
|
||||
# findCircle(x1, y1, x2, y2, x3, y3) :
|
||||
# NB add always set float even if values are pcb internal Units!!!
|
||||
x1 = float(sp.x); y1 = float(sp.y)
|
||||
x2 = float(ep.x); y2 = float(ep.y)
|
||||
x3 = float(ip.x); y3 = float(ip.y)
|
||||
|
||||
x12 = x1 - x2;
|
||||
x13 = x1 - x3;
|
||||
y12 = y1 - y2;
|
||||
y13 = y1 - y3;
|
||||
y31 = y3 - y1;
|
||||
y21 = y2 - y1;
|
||||
x31 = x3 - x1;
|
||||
x21 = x2 - x1;
|
||||
|
||||
# x1^2 - x3^2
|
||||
sx13 = math.pow(x1, 2) - math.pow(x3, 2);
|
||||
# y1^2 - y3^2
|
||||
sy13 = math.pow(y1, 2) - math.pow(y3, 2);
|
||||
sx21 = math.pow(x2, 2) - math.pow(x1, 2);
|
||||
sy21 = math.pow(y2, 2) - math.pow(y1, 2);
|
||||
|
||||
f = (((sx13) * (x12) + (sy13) *
|
||||
(x12) + (sx21) * (x13) +
|
||||
(sy21) * (x13)) // (2 *
|
||||
((y31) * (x12) - (y21) * (x13))));
|
||||
|
||||
g = (((sx13) * (y12) + (sy13) * (y12) +
|
||||
(sx21) * (y13) + (sy21) * (y13)) //
|
||||
(2 * ((x31) * (y12) - (x21) * (y13))));
|
||||
|
||||
c = (-math.pow(x1, 2) - math.pow(y1, 2) - 2 * g * x1 - 2 * f * y1);
|
||||
|
||||
# eqn of circle be x^2 + y^2 + 2*g*x + 2*f*y + c = 0
|
||||
# where centre is (h = -g, k = -f) and
|
||||
# radius r as r^2 = h^2 + k^2 - c
|
||||
h = -g;
|
||||
k = -f;
|
||||
sqr_of_r = h * h + k * k - c;
|
||||
# r is the radius
|
||||
r = round(math.sqrt(sqr_of_r), 5);
|
||||
Cx = h
|
||||
Cy = k
|
||||
radius = r
|
||||
return wxPoint(Cx,Cy), radius
|
||||
#
|
||||
def create_Solder(pcb,p1,p2,lyr=None,w=None,Nn=None,Ts=None,pcbG=None):
|
||||
#draw segment to test or from Arc
|
||||
#new_line = pcbnew.DRAWSEGMENT(pcb)
|
||||
if hasattr(pcbnew,'TRACK'):
|
||||
new_line = pcbnew.TRACK(pcb)
|
||||
else:
|
||||
#new_shape = pcbnew.S_SEGMENT()
|
||||
new_line = PCB_SHAPE()
|
||||
# new_shape = pcbnew.PCB_SHAPE()
|
||||
# new_line = pcbnew.Cast_to_PCB_SHAPE(new_shape)
|
||||
#new_soldermask_shape = PCB_SHAPE()
|
||||
#new_soldermask_line = pcbnew.Cast_to_PCB_SHAPE(new_soldermask_shape)
|
||||
#new_line = PCB_TRACK(new_shape)
|
||||
|
||||
new_line.SetStart(p1)
|
||||
new_line.SetEnd(p2)
|
||||
if w is None:
|
||||
new_line.SetWidth(FromUnits(1.5)) #FromUnits(int(mask_width)))
|
||||
else:
|
||||
#wx.LogMessage(str(w))
|
||||
new_line.SetWidth(w) #FromUnits(w))
|
||||
if lyr is None:
|
||||
lyr = F_SilkS
|
||||
elif lyr is pcbnew.F_Cu:
|
||||
lyr is pcbnew.F_Mask
|
||||
elif lyr is pcbnew.B_Cu:
|
||||
lyr is pcbnew.B_Mask
|
||||
# if Nn is not None:
|
||||
# new_line.SetNet(Nn)
|
||||
# #new_line.SetNetname(Nn)
|
||||
new_line.SetLayer(lyr) #pcbnew.F_SilkS) #pcb.GetLayerID(mask_layer))
|
||||
if Ts is not None and hasattr(pcbnew,'TRACK'):
|
||||
tsc = 0
|
||||
Nname = new_line.GetNetname()
|
||||
for c in Nname:
|
||||
tsc = tsc + ord(c)
|
||||
if hasattr(new_line, 'SetTimeStamp'):
|
||||
new_line.SetTimeStamp(tsc) # adding a unique number (this netname) as timestamp to mark this segment as generated by this script on this netname
|
||||
pcb.Add(new_line)
|
||||
if pcbG is not None:
|
||||
pcbG.AddItem(new_line)
|
||||
|
||||
return new_line
|
||||
#
|
||||
def solderExpander(pcb,tracks,clearance):
|
||||
global discretize
|
||||
# wx.LogMessage(str(discretize) + ' 2')
|
||||
mask_width = clearance #FromMM(.5) # msk espansion value each side
|
||||
#mask_layer = pcbnew.F_Mask
|
||||
|
||||
# pcb = LoadBoard(in_filename)
|
||||
#pcb = pcbnew.GetBoard()
|
||||
|
||||
#ToUnits=pcbnew.ToMM #ToMils
|
||||
#FromUnits=pcbnew.FromMM #Mils
|
||||
|
||||
for item in tracks:
|
||||
start = item.GetStart()
|
||||
end = item.GetEnd()
|
||||
width = item.GetWidth()
|
||||
layerId = item.GetLayer()
|
||||
layer = item.GetLayerSet()
|
||||
layerN = item.GetLayerName()
|
||||
layer = pcb.GetLayerID(layerN)
|
||||
track_net_name = item.GetNetname()
|
||||
ts = 0
|
||||
for c in track_net_name:
|
||||
ts = ts + ord(c)
|
||||
#wx.LogMessage("LayerName"+str(layer))
|
||||
|
||||
if layerId == pcbnew.F_Cu:
|
||||
mask_layer = pcbnew.F_Mask
|
||||
elif layerId == pcbnew.B_Cu: #'B_Cu':
|
||||
mask_layer = pcbnew.B_Mask
|
||||
else: #we shouldn't arrive here
|
||||
mask_layer = pcbnew.F_Mask
|
||||
wxLogDebug(" * Track: %s to %s, width %f mask_width %f" % (ToUnits(start),ToUnits(end),ToUnits(width), ToUnits(mask_width)),debug)
|
||||
#print (" * Track: %s to %s, width %f mask_width %f" % (ToUnits(start),ToUnits(end),ToUnits(width), ToUnits(mask_width)))
|
||||
if hasattr(pcbnew,'DRAWSEGMENT'):
|
||||
new_soldermask_line = pcbnew.DRAWSEGMENT(pcb)
|
||||
new_soldermask_line.SetStart(start)
|
||||
new_soldermask_line.SetEnd(end)
|
||||
new_soldermask_line.SetWidth(width+2*mask_width) #FromUnits(int(mask_width)))
|
||||
new_soldermask_line.SetLayer(mask_layer) #pcbnew.F_Mask) #pcb.GetLayerID(mask_layer))
|
||||
# again possible to mark via as own since no timestamp_t binding kicad v5.1.4
|
||||
if hasattr(new_soldermask_line, 'SetTimeStamp'):
|
||||
new_soldermask_line.SetTimeStamp(ts) # adding a unique number (this netname) as timestamp to mark this via as generated by this script on this netname
|
||||
pcb.Add(new_soldermask_line)
|
||||
elif type(item) is pcbnew.PCB_TRACK: #kicad 5.99
|
||||
#new_soldermask_shape = PCB_SHAPE()
|
||||
#new_soldermask_line = pcbnew.Cast_to_PCB_SHAPE(new_soldermask_shape)
|
||||
new_soldermask_line = PCB_SHAPE()
|
||||
new_soldermask_line.SetStart(start)
|
||||
new_soldermask_line.SetEnd(end)
|
||||
new_soldermask_line.SetWidth(width+2*mask_width)
|
||||
new_soldermask_line.SetLayer(mask_layer) #pcbnew.F_Mask) #pcb.GetLayerID(mask_layer))
|
||||
# again possible to mark via as own since no timestamp_t binding kicad v5.1.4
|
||||
if hasattr(new_soldermask_line, 'SetTimeStamp'):
|
||||
new_soldermask_line.SetTimeStamp(ts) # adding a unique number (this netname) as timestamp to mark this via as generated by this script on this netname
|
||||
pcb.Add(new_soldermask_line)
|
||||
else: #PCB_ARC kicad 5.99
|
||||
#new_soldermask_line = PCB_ARC(PCB_SHAPE())
|
||||
#new_soldermask_line.SetMid(item.GetMid())
|
||||
#wxLogDebug(str(item.GetMid())+' mid',True)
|
||||
md = item.GetMid()
|
||||
#wxLogDebug(str(cnt)+' center, radius '+str(rad),True)
|
||||
netName = None
|
||||
width_new = width +2*mask_width
|
||||
cnt, rad = getCircleCenterRadius(start,end,md)
|
||||
if discretize:
|
||||
segNBR = 16
|
||||
groupName = uuid.uuid4() #randomword(5)
|
||||
pcb_group = pcbnew.PCB_GROUP(None)
|
||||
pcb_group.SetName(groupName)
|
||||
pcb.Add(pcb_group)
|
||||
create_round_segs(pcb,start,end,cnt,rad,mask_layer,width_new,netName,segNBR,pcb_group)
|
||||
else:
|
||||
createDwgArc(pcb,start,end,md,cnt,mask_layer,width_new,netName)
|
||||
#break;
|
||||
pcbnew.Refresh()
|
||||
#
|
||||
def createDwgArc(pcb,p1,p2,mp,cn,lyr=None,w=None,Nn=None,Ts=None):
|
||||
# new_arc = pcbnew.PCB_SHAPE()
|
||||
# new_arc = pcbnew.Cast_to_PCB_SHAPE(new_arc)
|
||||
# new_arc.SetShape(pcbnew.SHAPE_T_ARC)
|
||||
# new_arc.SetStart(p1)
|
||||
# new_arc.SetMid(md)
|
||||
# new_arc.SetEnd(p2)
|
||||
# new_arc.SetWidth(w) #250000)
|
||||
|
||||
new_arc=pcbnew.PCB_SHAPE()
|
||||
new_arc.SetShape(pcbnew.SHAPE_T_ARC)
|
||||
use_geo=True
|
||||
if use_geo:
|
||||
# new_arc.SetArcGeometry(aStart: 'wxPoint', aMid: 'wxPoint', aEnd: 'wxPoint')
|
||||
new_arc.SetArcGeometry(p1,mp,p2)
|
||||
else:
|
||||
new_arc.SetArcStart(p1)
|
||||
new_arc.SetArcEnd(p2)
|
||||
new_arc.SetCenter(cn)
|
||||
new_arc.SetWidth(w)
|
||||
if lyr is None:
|
||||
lyr = F_SilkS
|
||||
new_arc.SetLayer(lyr) #pcbnew.F_SilkS) #pcb.GetLayerID(mask_layer))
|
||||
pcb.Add(new_arc)
|
||||
return new_arc
|
||||
#
|
||||
def getAngleRadians(p1,p2):
|
||||
#return math.degrees(math.atan2((p1.y-p2.y),(p1.x-p2.x)))
|
||||
return (math.atan2((p1.y-p2.y),(p1.x-p2.x)))
|
||||
#
|
||||
|
||||
def rotatePoint(r,sa,da,c):
|
||||
# sa, da in radians
|
||||
x = c.x - math.cos(sa+da) * r
|
||||
y = c.y - math.sin(sa+da) * r
|
||||
return wxPoint(x,y)
|
||||
#
|
||||
def create_round_segs(pcb,sp,ep,cntr,rad,layer,width,Nn,N_SEGMENTS,pcbGroup=None):
|
||||
start_point = sp
|
||||
end_point = ep
|
||||
pos = sp
|
||||
next_pos = ep
|
||||
a1 = getAngleRadians(cntr,sp)
|
||||
a2 = getAngleRadians(cntr,ep)
|
||||
wxLogDebug('a1:'+str(math.degrees(a1))+' a2:'+str(math.degrees(a2))+' a2-a1:'+str(math.degrees(a2-a1)),debug)
|
||||
if (a2-a1) > 0 and abs(a2-a1) > math.radians(180):
|
||||
deltaA = -(math.radians(360)-(a2-a1))/N_SEGMENTS
|
||||
wxLogDebug('deltaA reviewed:'+str(math.degrees(deltaA)),debug)
|
||||
elif (a2-a1) < 0 and abs(a2-a1) > math.radians(180):
|
||||
deltaA = (math.radians(360)-abs(a2-a1))/N_SEGMENTS
|
||||
wxLogDebug('deltaA reviewed2:'+str(math.degrees(deltaA)),debug)
|
||||
else:
|
||||
deltaA = (a2-a1)/N_SEGMENTS
|
||||
delta=deltaA
|
||||
wxLogDebug('delta:'+str(math.degrees(deltaA))+' radius:'+str(ToMM(rad)),debug)
|
||||
points = []
|
||||
#import round_trk; import importlib; importlib.reload(round_trk)
|
||||
for ii in range (N_SEGMENTS+1): #+1):
|
||||
points.append(pos)
|
||||
#t = create_Track(pos,pos)
|
||||
prv_pos = pos
|
||||
#pos = pos + fraction_delta
|
||||
#posPolar = cmath.polar(pos)
|
||||
#(rad) * cmath.exp(math.radians(deltaA)*1j) #cmath.rect(r, phi) : Return the complex number x with polar coordinates r and phi.
|
||||
#pos = wxPoint(posPolar.real+sp.x,posPolar.imag+sp.y)
|
||||
pos = rotatePoint(rad,a1,delta,cntr)
|
||||
delta=delta+deltaA
|
||||
#wxLogDebug("pos:"+str(ToUnits(prv_pos.x))+":"+str(ToUnits(prv_pos.y))+";"+str(ToUnits(pos.x))+":"+str(ToUnits(pos.y)),debug)
|
||||
for i, p in enumerate(points):
|
||||
#if i < len (points)-1:
|
||||
if i < len (points)-2:
|
||||
t = create_Solder(pcb,p,points[i+1],layer,width,Nn,True,pcbGroup) #adding ts code to segments
|
||||
t = create_Solder(pcb,points[-2],ep,layer,width,Nn,True,pcbGroup) #avoiding rounding on last segment
|
||||
#
|
||||
def Delete_Segments(pcb):
|
||||
draws = []
|
||||
#print ("TRACKS WHICH MATCH CRITERIA:")
|
||||
for item in pcb.GetDrawings():
|
||||
#for item in pcb.GetTracks():
|
||||
if type(item) is DRAWSEGMENT and item.IsSelected(): #item.GetNetname() == net_name:
|
||||
draws.append(item)
|
||||
wxLogDebug(str(len(draws)),debug)
|
||||
|
||||
if len (draws) == 1:
|
||||
tsd = draws[0].GetTimeStamp()
|
||||
wxLogDebug(str(tsd),debug)
|
||||
if tsd != 0:
|
||||
target_draws = filter(lambda x: (x.GetTimeStamp() == tsd), pcb.GetDrawings())
|
||||
#wx.LogMessage(str(len(target_tracks)))
|
||||
target_draws_cp = list(target_draws)
|
||||
for i in range(l):
|
||||
pcb.RemoveNative(target_draws_cp[i])
|
||||
#for draw in target_draws:
|
||||
# #if via.GetTimeStamp() == 55:
|
||||
# pcb.RemoveNative(draw)
|
||||
#wx.LogMessage('removing via')
|
||||
#pcbnew.Refresh()
|
||||
wxLogDebug(u'\u2714 Mask Segments Deleted',True)
|
||||
else:
|
||||
wxLogDebug(u'\u2718 you must select only Mask segment\n generated by this tool',not debug)
|
||||
else:
|
||||
#msg = u'\n\u2714 Radius > 3 * (track width)'
|
||||
wxLogDebug(u'\u2718 you must select One Mask segment only',not debug)
|
||||
#
|
||||
#Solder_Expander().register()
|
||||
|
||||
2
kicad_plugins/tracks_length/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from .trace_length import SelectedTracesLenght
|
||||
SelectedTracesLenght().register()
|
||||
BIN
kicad_plugins/tracks_length/trace_length.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
337
kicad_plugins/tracks_length/trace_length.py
Normal file
@@ -0,0 +1,337 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# some source tips @
|
||||
# https://github.com/bpkempke/kicad-scripts
|
||||
# https://github.com/MitjaNemec/Kicad_action_plugins
|
||||
# https://github.com/jsreynaud/kicad-action-scripts
|
||||
|
||||
|
||||
# import trace_length; reload(trace_length)
|
||||
|
||||
import sys
|
||||
import os
|
||||
from pcbnew import *
|
||||
import wx
|
||||
import pcbnew
|
||||
import math
|
||||
#import threading
|
||||
|
||||
debug = False
|
||||
def wxLogDebug(msg,dbg):
|
||||
"""printing messages only if show is omitted or True"""
|
||||
if dbg == True:
|
||||
wx.LogMessage(msg)
|
||||
#
|
||||
|
||||
def getSelTracksLength(pcb):
|
||||
ln = 0.
|
||||
for item in pcb.GetTracks():
|
||||
if not hasattr(pcbnew,'TRACK'):
|
||||
item = pcbnew.Cast_to_PCB_TRACK(item)
|
||||
trktp = pcbnew.PCB_TRACK
|
||||
else:
|
||||
trktp = pcbnew.TRACK
|
||||
if type(item) is trktp and item.IsSelected():
|
||||
ln+=(item.GetLength())
|
||||
return(ln)
|
||||
#print(pcbnew.ToMM(ln))
|
||||
#
|
||||
def getSelTracks(pcb):
|
||||
tracks=[]
|
||||
for item in pcb.GetTracks():
|
||||
if not hasattr(pcbnew,'TRACK'):
|
||||
item = pcbnew.Cast_to_PCB_TRACK(item)
|
||||
trktp = pcbnew.PCB_TRACK
|
||||
else:
|
||||
trktp = pcbnew.TRACK
|
||||
if type(item) is trktp and item.IsSelected():
|
||||
tracks.append(item)
|
||||
return tracks
|
||||
#
|
||||
def find_Tracks_between_Pads(pcb,pad1,pad2):
|
||||
track_list = []
|
||||
# get list of all selected pads
|
||||
#selected_pads = [pad1, pad2]
|
||||
# get the net the pins are on
|
||||
net = pad1.GetNetname()
|
||||
# find all tracks
|
||||
tracks = pcb.GetTracks()
|
||||
# find all tracks on net
|
||||
tracks_on_net = []
|
||||
for track in tracks:
|
||||
track_net_name = track.GetNetname()
|
||||
if track_net_name == net:
|
||||
tracks_on_net.append(track)
|
||||
return tracks_on_net
|
||||
#
|
||||
|
||||
def getTracksListLength(pcb,tracks):
|
||||
ln = 0.
|
||||
for item in tracks:
|
||||
ln+=(item.GetLength())
|
||||
return(ln)
|
||||
#
|
||||
def selectListTracks(pcb,tracks):
|
||||
for item in tracks:
|
||||
if not hasattr(pcbnew,'TRACK'):
|
||||
item = pcbnew.Cast_to_PCB_TRACK(item)
|
||||
trktp = pcbnew.PCB_TRACK
|
||||
else:
|
||||
trktp = pcbnew.TRACK
|
||||
if type(item) is trktp:
|
||||
item.SetSelected()
|
||||
#
|
||||
def getTrackAngleRadians(track):
|
||||
#return math.degrees(math.atan2((p1.y-p2.y),(p1.x-p2.x)))
|
||||
return (math.atan2((track.GetEnd().y - track.GetStart().y), (track.GetEnd().x - track.GetStart().x)))
|
||||
#
|
||||
|
||||
# Python plugin stuff
|
||||
class SelectedTracesLenght(pcbnew.ActionPlugin):
|
||||
def defaults(self):
|
||||
self.name = "Measure Length for Selected Tracks\n version 1.3"
|
||||
self.category = "Modify PCB"
|
||||
self.description = "Measure Length for Selected Tracks"
|
||||
self.icon_file_name = os.path.join(os.path.dirname(__file__), "./trace_length.png")
|
||||
self.show_toolbar_button = True
|
||||
|
||||
def Run(self):
|
||||
#self.pcb = GetBoard()
|
||||
pcb = pcbnew.GetBoard()
|
||||
ln=0.
|
||||
pads=[]
|
||||
tracks=getSelTracks(pcb)
|
||||
if len(tracks) >0: #selected tracks >0
|
||||
for item in tracks:
|
||||
ln+=(item.GetLength())
|
||||
else:
|
||||
for item in pcb.GetPads():
|
||||
if item.IsSelected():
|
||||
pads.append(item)
|
||||
if len(pads) == 1:
|
||||
tracks=[]
|
||||
tracks = find_Tracks_inNet_Pad(pcb,pads[0])
|
||||
c_tracks = get_contiguous_tracks(pcb,tracks,pads[0])
|
||||
tracks=c_tracks
|
||||
# selectListTracks(pcb,tracks) # this seems not to allow deselecting
|
||||
ln = getTracksListLength(pcb,tracks)
|
||||
selectListTracks(pcb,tracks)
|
||||
pcbnew.Refresh()
|
||||
|
||||
#else:
|
||||
# wx.LogMessage("Solder Mask Expander:\nSelect Tracks\nor One Pad to select connected Tracks")
|
||||
if ln > 0:
|
||||
#wx.LogMessage('Selected Traces Length: {0:.3f} mm'.format(ToMM(ln)))
|
||||
wxLogDebug('showing Selected Tracks',debug)
|
||||
#wx.LogMessage('debug'+str(debug))
|
||||
msg = u"Selected Tracks Length:\n{0:.3f} mm \u2714".format(ToMM(ln))
|
||||
if len(tracks) == 1:
|
||||
angle = (math.degrees(getTrackAngleRadians(tracks[0])))
|
||||
msg+=u"\nTrack Angle: {0:.1f} deg \u2714".format(angle)
|
||||
#selectListTracks(pcb,tracks)
|
||||
#pcbnew.Refresh()
|
||||
wdlg = wx.MessageDialog(None, msg,'Info message',wx.OK | wx.ICON_INFORMATION)
|
||||
result = wdlg.ShowModal()
|
||||
if result == wx.ID_OK:
|
||||
pass
|
||||
clearListTracks(pcb,tracks,True)
|
||||
#timer = threading.Timer(1000, clearListTracks(pcb,tracks,True))
|
||||
#timer.start()
|
||||
#blocking dialogw
|
||||
#wx.MessageBox("showing selection", 'Info', wx.OK | wx.ICON_INFORMATION)
|
||||
#clearListTracks(pcb,tracks)
|
||||
elif len(pads) != 1:
|
||||
wx.LogMessage('Select Tracks to calculate the Length\nor One Pad to select connected Tracks')
|
||||
#
|
||||
|
||||
|
||||
def selectListTracks(pcb,tracks):
|
||||
for item in tracks:
|
||||
if not hasattr(pcbnew,'TRACK'):
|
||||
item = pcbnew.Cast_to_PCB_TRACK(item)
|
||||
trktp = pcbnew.PCB_TRACK
|
||||
else:
|
||||
trktp = pcbnew.TRACK
|
||||
if type(item) is trktp:
|
||||
item.SetSelected()
|
||||
|
||||
def clearListTracks(pcb,tracks,refresh=None):
|
||||
wxLogDebug('deSelecting Tracks',debug)
|
||||
for trk in tracks:
|
||||
if trk.IsSelected():
|
||||
trk.ClearSelected()
|
||||
if refresh:
|
||||
pcbnew.Refresh()
|
||||
#
|
||||
#
|
||||
#def getSelTracksLength(pcb):
|
||||
# ln = 0.
|
||||
# for item in pcb.GetTracks():
|
||||
# if type(item) is pcbnew.TRACK and item.IsSelected():
|
||||
# ln+=(item.GetLength())
|
||||
# return(ln)
|
||||
# #print(pcbnew.ToMM(ln))
|
||||
#
|
||||
def get_contiguous_tracks(pcb,trks,pad):
|
||||
LinePoints = []
|
||||
LineSegments=[]
|
||||
|
||||
#start_point = ToMM(pad.GetPosition())
|
||||
startp = (pad.GetPosition())
|
||||
start_point = ((startp.x),(startp.y))
|
||||
for t in (trks):
|
||||
LinePoints.append((t.GetStart().x,t.GetStart().y))
|
||||
LinePoints.append((t.GetEnd().x, t.GetEnd().y))
|
||||
wxLogDebug('Points '+str(LinePoints),debug)
|
||||
l= len(LinePoints)
|
||||
for i in range(0,l,2):
|
||||
LineSegments.append((LinePoints[i],LinePoints[i+1]))
|
||||
wxLogDebug(str(LineSegments),debug)
|
||||
|
||||
#segments = [(1, 2), (2, 3), (4, 5), (6, 5), (7, 6)]
|
||||
#start_point=(4,5)
|
||||
#segments_start=segments
|
||||
|
||||
segments = LineSegments
|
||||
groups=[]
|
||||
found=False
|
||||
for s in segments:
|
||||
found=False
|
||||
for g in groups:
|
||||
for sCmp in g:
|
||||
wxLogDebug('sCmp: '+(str(sCmp)),debug)
|
||||
wxLogDebug('s: '+(str(s)),debug)
|
||||
if isConn(sCmp,s): #confronto start e end
|
||||
g.append(s)
|
||||
found=True
|
||||
break;
|
||||
if (found):
|
||||
break;
|
||||
if(not found):
|
||||
groups.append([s])
|
||||
wxLogDebug('groups: '+(str(groups)),debug)
|
||||
wxLogDebug('len groups: '+(str(len(groups))),debug)
|
||||
l = 0
|
||||
lens = []
|
||||
for g in groups:
|
||||
lens.append(len(g))
|
||||
if l<len(g):
|
||||
l = len(g)
|
||||
wxLogDebug('len max groups: '+str(l),debug)
|
||||
wxLogDebug('lens in groups: '+str(lens),debug)
|
||||
found=False
|
||||
|
||||
res_g=[]
|
||||
wxLogDebug('start '+str((start_point,start_point)),debug)
|
||||
wxLogDebug('start '+str(s),debug)
|
||||
|
||||
#for g,i in enumerate(groups):
|
||||
i=0
|
||||
while (i+1) < len (groups):
|
||||
found = False
|
||||
for s in groups[i]:
|
||||
for r in groups[i+1]:
|
||||
wxLogDebug('s: '+str(s)+';r: '+str(r),debug)
|
||||
if isConn(r,s):
|
||||
for r1 in groups[i+1]:
|
||||
groups[i].append(r1)
|
||||
groups.pop(i+1)
|
||||
found=True
|
||||
break
|
||||
if found:
|
||||
break
|
||||
if not found:
|
||||
i+=1
|
||||
else:
|
||||
i=0
|
||||
l = 0
|
||||
lens = []
|
||||
for g in groups:
|
||||
lens.append(len(g))
|
||||
if l<len(g):
|
||||
l = len(g)
|
||||
wxLogDebug('groups merged: '+(str(groups)),debug)
|
||||
wxLogDebug('len max groups merged: '+str(l),debug)
|
||||
wxLogDebug('lens in groups merged: '+str(lens),debug)
|
||||
|
||||
for g in groups:
|
||||
for s in g:
|
||||
if isConn((start_point,start_point),s):
|
||||
res_g = g
|
||||
found = True
|
||||
break
|
||||
wxLogDebug('start '+str(start_point),debug)
|
||||
group = res_g
|
||||
wxLogDebug('group '+str(res_g),debug)
|
||||
wxLogDebug('len group: '+(str(len(group))),debug)
|
||||
trks_connected=[]
|
||||
for seg in res_g:
|
||||
for t in trks:
|
||||
tseg = ((t.GetStart().x,t.GetStart().y),(t.GetEnd().x,t.GetEnd().y))
|
||||
wxLogDebug('seg '+str(seg),debug)
|
||||
wxLogDebug('tseg '+str(tseg),debug)
|
||||
if isConn(seg,tseg):
|
||||
if t not in trks_connected:
|
||||
trks_connected.append(t)
|
||||
wxLogDebug('t added: '+(str(tseg)),debug)
|
||||
wxLogDebug('trks_connected '+str(len(trks_connected)),debug)
|
||||
return trks_connected
|
||||
#
|
||||
def isEq (p1,p2):
|
||||
epsilon = FromMM(0.003) # tolerance 3 nm
|
||||
delta = math.hypot(p1[0]-p2[0],p1[1]-p2[1])
|
||||
wxLogDebug('delta: '+str(delta)+'eps: '+str(epsilon),debug)
|
||||
#wxLogDebug('epsilon: '+str(epsilon),debug)
|
||||
if delta <= epsilon:
|
||||
wxLogDebug('connected',debug)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
#
|
||||
def not_eq(a,b):
|
||||
if abs(a-b) >= 1: #1nm
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
#
|
||||
def isConn(s1,s2):
|
||||
#if s1[0] == s2[0] or s1[1] == s2[1]:
|
||||
if isEq(s1[0],s2[0]) or isEq(s1[1],s2[1]):
|
||||
return True
|
||||
#elif s1[0] == s2[1] or s1[1] == s2[0]:
|
||||
elif isEq(s1[0],s2[1]) or isEq(s1[1],s2[0]):
|
||||
return True
|
||||
return False
|
||||
#
|
||||
|
||||
def getSelTracks(pcb):
|
||||
tracks=[]
|
||||
for item in pcb.GetTracks():
|
||||
if not hasattr(pcbnew,'TRACK'):
|
||||
item = pcbnew.Cast_to_PCB_TRACK(item)
|
||||
trktp = pcbnew.PCB_TRACK
|
||||
else:
|
||||
trktp = pcbnew.TRACK
|
||||
if type(item) is trktp and item.IsSelected():
|
||||
tracks.append(item)
|
||||
return tracks
|
||||
#
|
||||
def find_Tracks_inNet_Pad(pcb,pad):
|
||||
track_list = []
|
||||
# get list of all selected pads
|
||||
#selected_pads = [pad1, pad2]
|
||||
# get the net the pins are on
|
||||
net = pad.GetNetname()
|
||||
# find all tracks
|
||||
tracks = pcb.GetTracks()
|
||||
# find all tracks on net
|
||||
tracks_on_net = []
|
||||
for track in tracks:
|
||||
track_net_name = track.GetNetname()
|
||||
if track_net_name == net:
|
||||
tracks_on_net.append(track)
|
||||
return tracks_on_net
|
||||
#
|
||||
|
||||
#Solder_Expander().register()
|
||||
|
||||
182
kicad_plugins/tracks_length/trace_length.svg
Normal file
@@ -0,0 +1,182 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
width="26"
|
||||
height="26"
|
||||
id="svg2"
|
||||
sodipodi:docname="trace_length.svg"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
inkscape:export-filename="/home/mau/.kicad_plugins/RF-tools-KiCAD/tracks_length/trace_length.png"
|
||||
inkscape:export-xdpi="118.15385"
|
||||
inkscape:export-ydpi="118.15385">
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="824"
|
||||
id="namedview23"
|
||||
showgrid="false"
|
||||
inkscape:zoom="23.346154"
|
||||
inkscape:cx="13"
|
||||
inkscape:cy="13"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2" />
|
||||
<metadata
|
||||
id="metadata50">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs4">
|
||||
<marker
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
id="Arrow1Send"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
|
||||
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
|
||||
id="path3806"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" />
|
||||
</marker>
|
||||
<marker
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
id="Arrow1Sstart"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
|
||||
transform="matrix(0.2,0,0,0.2,1.2,0)"
|
||||
id="path3803"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" />
|
||||
</marker>
|
||||
<marker
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
id="h"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
d="M 8.7186,4.0337 -2.2074,0.016 8.7186,-4.0017 c -1.7455,2.3721 -1.7354,5.6175 -6e-7,8.0354 z"
|
||||
transform="scale(0.6,0.6)"
|
||||
id="path10"
|
||||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" />
|
||||
</marker>
|
||||
<marker
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
id="g"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
d="M 8.7186,4.0337 -2.2074,0.016 8.7186,-4.0017 c -1.7455,2.3721 -1.7354,5.6175 -6e-7,8.0354 z"
|
||||
transform="scale(-0.6,-0.6)"
|
||||
id="path13"
|
||||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" />
|
||||
</marker>
|
||||
<filter
|
||||
x="-0.10484"
|
||||
y="-0.18257"
|
||||
width="1.2097"
|
||||
height="1.3651"
|
||||
color-interpolation-filters="sRGB"
|
||||
id="d">
|
||||
<feGaussianBlur
|
||||
id="feGaussianBlur7"
|
||||
stdDeviation="1.5978799" />
|
||||
</filter>
|
||||
</defs>
|
||||
<path
|
||||
d="M 0.25864914,10.924218 H 5.7586492 l 9.4999998,12 h 6"
|
||||
id="path3002-1"
|
||||
style="fill:none;stroke:#dfbd8a;stroke-width:5.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="M 0.25864914,10.924218 H 5.7586492 l 9.4999998,12 h 6"
|
||||
id="path3002"
|
||||
style="fill:none;stroke:#008000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0" />
|
||||
<g
|
||||
transform="translate(25,-4)"
|
||||
id="g3998" />
|
||||
<g
|
||||
id="g908"
|
||||
transform="matrix(0.73482795,0,0,0.73482795,-21.778176,0.83834692)"
|
||||
inkscape:export-xdpi="118"
|
||||
inkscape:export-ydpi="118">
|
||||
<path
|
||||
sodipodi:nodetypes="cccccccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4498"
|
||||
d="m 64.116047,27.158555 -19,-18 -6,6 -1,-1 4,-8 v 0 l 5,-5 1,1 4,-1.99999999 1,0.99999999 -3,3 14,14"
|
||||
style="fill:#f2f2f2;fill-rule:evenodd;stroke:#1a1a1a;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4502"
|
||||
d="m 53.616047,8.658555 3.5,-3.5 1,1 -1,3 5.5,5.5 -1.5,1.5 z"
|
||||
style="fill:#f2f2f2;fill-rule:evenodd;stroke:#1a1a1a;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4504"
|
||||
d="m 48.116047,11.158555 3,-3"
|
||||
style="fill:#f2f2f2;fill-rule:evenodd;stroke:#1a1a1a;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
style="fill:#f2f2f2;fill-rule:evenodd;stroke:#1a1a1a;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 51.616047,13.658555 1.5,-1.5"
|
||||
id="path4506"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4508"
|
||||
d="m 54.616047,16.658555 1.5,-1.5"
|
||||
style="fill:#f2f2f2;fill-rule:evenodd;stroke:#1a1a1a;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
style="fill:#f2f2f2;fill-rule:evenodd;stroke:#1a1a1a;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 57.116047,20.158555 2,-2"
|
||||
id="path4510"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4520"
|
||||
d="m 60.116047,23.158555 2,-2"
|
||||
style="fill:#f2f2f2;fill-rule:evenodd;stroke:#1a1a1a;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4500"
|
||||
d="m 42.116047,19.158555 7.5,-7 8,8 -2,2 -5,-5 -7.5,3 z"
|
||||
style="fill:#f2f2f2;fill-rule:evenodd;stroke:#1a1a1a;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.4 KiB |
9
kicad_plugins/via_fence_generator/__init__.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# pcbnew loads this folder as a package using import
|
||||
# thus __init__.py (this file) is executed
|
||||
# We import the plugin class here and register it to pcbnew
|
||||
|
||||
from .viafence_action import ViaFenceAction
|
||||
ViaFenceAction().register()
|
||||
|
||||
|
||||
|
||||
120
kicad_plugins/via_fence_generator/__main__.py
Normal file
@@ -0,0 +1,120 @@
|
||||
from .viafence import *
|
||||
from .viafence_dialogs import *
|
||||
|
||||
import os
|
||||
import argparse
|
||||
import json
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import wx
|
||||
import copy
|
||||
|
||||
argParser = argparse.ArgumentParser()
|
||||
argParser.add_argument("--dialog", dest="dialog", metavar="DIALOGNAME", help="Show Dialog with <DIALOGNAME>")
|
||||
argParser.add_argument("--runtests", dest="runtests", action="store_true", default=0, help="Execute testing all json test files in 'tests' subdirectory")
|
||||
argParser.add_argument("--test", dest="test", metavar="TESTNAME", help="Loads <TESTNAME> from 'tests' directory, runs it and shows/stores the result into the test file")
|
||||
argParser.add_argument("--store", dest="store", action="store_true", default=0, help="When running a test, stores the result as known-good")
|
||||
argParser.add_argument("--verbose", dest="verbose", action="store_true", default=0, help="Verbose plotting the inner workings of the algorithm")
|
||||
args = argParser.parse_args()
|
||||
|
||||
def compareTests(testDict, refDict):
|
||||
testPts = testDict['viaPoints']
|
||||
refPts = refDict['viaPoints']
|
||||
matchedPts = [point for point in testPts if point in refPts]
|
||||
return True if len(testPts) == len(refPts) == len(matchedPts) else False
|
||||
|
||||
def loadTest(testFilename):
|
||||
with open(testFilename, 'r') as file:
|
||||
return json.load(file)
|
||||
|
||||
def storeTest(testFilename, testDict):
|
||||
with open(testFilename, 'w') as file:
|
||||
json.dump(testDict, file, indent=4, sort_keys=True)
|
||||
|
||||
def runTest(testDict, verboseFunc):
|
||||
viaOffset = testDict['viaOffset']
|
||||
viaPitch = testDict['viaPitch']
|
||||
pathList = testDict['pathList']
|
||||
|
||||
newDict = copy.deepcopy(testDict)
|
||||
newDict['viaPoints'] = generateViaFence(pathList, viaOffset, viaPitch, verboseFunc)
|
||||
|
||||
return newDict
|
||||
|
||||
def printTestResult(testName, refDict, testDict):
|
||||
print("{}: {} (Ref/Test Vias: {}/{})".format(
|
||||
testName, "PASSED" if compareTests(refDict, testDict) else "FAILED",
|
||||
len(refDict['viaPoints']), len(testDict['viaPoints']) ))
|
||||
|
||||
def verbosePlot(object, isPoints = False, isPaths = False, isPolygons = False):
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
for child in object:
|
||||
data = np.array(child)
|
||||
if isPolygons:
|
||||
plt.fill(data.T[0], data.T[1], facecolor='grey', alpha=0.3, linestyle='--', linewidth=1)
|
||||
elif isPaths:
|
||||
plt.plot(data.T[0], data.T[1], linestyle='-', linewidth=3)
|
||||
elif isPoints:
|
||||
plt.plot(data.T[0], data.T[1], linestyle='', marker='x', markersize=10, mew=3)
|
||||
|
||||
def main():
|
||||
testDir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'tests')
|
||||
verboseFunc = verbosePlot if args.verbose else lambda *args,**kwargs:None
|
||||
|
||||
if (args.dialog):
|
||||
# Load and show dialog
|
||||
# os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
||||
app = wx.App()
|
||||
className = globals()[args.dialog]
|
||||
className(None).Show()
|
||||
print("Starting wxApp Now. Exit using Ctrl+C")
|
||||
app.MainLoop()
|
||||
|
||||
elif (args.test):
|
||||
# Load a test file, run the algorithm and show/store the result for later testing
|
||||
testFile = os.path.join(testDir, args.test) + ".json"
|
||||
ref = loadTest(testFile)
|
||||
test = runTest(ref, verboseFunc)
|
||||
|
||||
printTestResult(args.test, ref, test)
|
||||
|
||||
if (args.store): storeTest(testFile, test)
|
||||
|
||||
for path in test['pathList']:
|
||||
plt.plot(np.array(path).T[0], np.array(path).T[1], linewidth=5)
|
||||
|
||||
for via in test['viaPoints']:
|
||||
plt.plot(via[0], via[1], 'o', markersize=10)
|
||||
|
||||
plt.axes().set_aspect('equal','box')
|
||||
plt.ylim(plt.ylim()[::-1])
|
||||
plt.savefig(os.path.join(testDir, args.test) + '.png')
|
||||
plt.show()
|
||||
elif (args.runtests):
|
||||
# Run all tests in 'tests' subdirectory
|
||||
scriptDir = os.path.dirname(os.path.realpath(__file__))
|
||||
testDir = scriptDir + "/" + 'tests'
|
||||
testsPassed = 0
|
||||
testsTotal = 0
|
||||
|
||||
for file in os.listdir(testDir):
|
||||
if file.endswith(".json"):
|
||||
testName = os.path.basename(file)
|
||||
ref = loadTest(os.path.join(testDir, file))
|
||||
test = runTest(ref, verboseFunc)
|
||||
|
||||
printTestResult(testName, ref, test)
|
||||
|
||||
if compareTests(ref, test): testsPassed += 1
|
||||
testsTotal += 1
|
||||
|
||||
print("----\n{}/{} tests PASSED".format(testsPassed, testsTotal))
|
||||
|
||||
assert testsPassed == testsTotal
|
||||
|
||||
if testsPassed == testsTotal: exit(0)
|
||||
else: exit(1)
|
||||
|
||||
|
||||
main()
|
||||
BIN
kicad_plugins/via_fence_generator/python-pyclipper/py2-7-linux-64/pyclipper.so
Executable file
BIN
kicad_plugins/via_fence_generator/resources/fencing-vias.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
204
kicad_plugins/via_fence_generator/resources/fencing-vias.svg
Normal file
@@ -0,0 +1,204 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
height="27.733334"
|
||||
width="27.733334"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="shielding-vias.svg"
|
||||
viewBox="0 0 26 26"
|
||||
inkscape:export-filename="C:\Users\userC\AppData\Roaming\kicad\scripting\plugins\via_fence_generator\shielding-vias.png"
|
||||
inkscape:export-xdpi="99.096771"
|
||||
inkscape:export-ydpi="99.096771">
|
||||
<metadata
|
||||
id="metadata40">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1361"
|
||||
id="namedview38"
|
||||
showgrid="true"
|
||||
inkscape:snap-to-guides="false"
|
||||
inkscape:snap-grids="true"
|
||||
inkscape:zoom="14.553175"
|
||||
inkscape:cx="10.66825"
|
||||
inkscape:cy="11.459509"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3017"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true"
|
||||
spacingx="0.5"
|
||||
spacingy="0.5"
|
||||
originx="0"
|
||||
originy="0" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs4">
|
||||
<filter
|
||||
id="c"
|
||||
height="1.3651"
|
||||
width="1.2097"
|
||||
y="-0.18257"
|
||||
x="-0.10484"
|
||||
style="color-interpolation-filters:sRGB">
|
||||
<feGaussianBlur
|
||||
stdDeviation="1.5978799"
|
||||
id="feGaussianBlur7" />
|
||||
</filter>
|
||||
<filter
|
||||
id="d"
|
||||
height="1.4696"
|
||||
width="1.4809999"
|
||||
y="-0.23481999"
|
||||
x="-0.24049"
|
||||
style="color-interpolation-filters:sRGB">
|
||||
<feGaussianBlur
|
||||
stdDeviation="1.5978799"
|
||||
id="feGaussianBlur10" />
|
||||
</filter>
|
||||
</defs>
|
||||
<rect
|
||||
style="fill:#006400;fill-opacity:1;stroke:none;stroke-width:0.9375;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.99997282;stroke-opacity:1"
|
||||
id="rect4495"
|
||||
width="26"
|
||||
height="26"
|
||||
x="-1.7193647e-008"
|
||||
y="1.7193647e-008" />
|
||||
<g
|
||||
transform="matrix(1.6382539,0,0,1.5572263,1.2572207,0.36314149)"
|
||||
id="g16"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263">
|
||||
<rect
|
||||
height="16"
|
||||
width="16"
|
||||
y="0"
|
||||
x="0"
|
||||
id="rect18"
|
||||
style="fill-opacity:0" />
|
||||
</g>
|
||||
<g
|
||||
id="g4745"
|
||||
transform="translate(0,6.625)">
|
||||
<path
|
||||
sodipodi:nodetypes="sssss"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3867-9-4"
|
||||
style="opacity:1;fill:none;stroke:#ffcc00;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 10,0.37500002 C 10,2.307997 8.432997,3.8750001 6.5,3.8750001 4.567003,3.8750001 3,2.307997 3,0.37500002 3,-1.557997 4.567003,-3.125 6.5,-3.125 c 1.932997,0 3.5,1.567003 3.5,3.50000002 z" />
|
||||
<path
|
||||
sodipodi:nodetypes="sssss"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3867-9-4-7"
|
||||
style="opacity:0.25;fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 10,0.37499992 C 10,2.3079969 8.4329971,3.8750001 6.5000001,3.8750001 4.5670031,3.8750001 3,2.3079969 3,0.37499992 3,-1.5579971 4.5670031,-3.1250001 6.5000001,-3.1250001 8.4329971,-3.1250001 10,-1.5579971 10,0.37499992 Z" />
|
||||
</g>
|
||||
<g
|
||||
id="g4753">
|
||||
<g
|
||||
transform="translate(2.5,2.875)"
|
||||
id="g4544">
|
||||
<path
|
||||
d="m 11.5,8 h 12 m -12,0 c -7.6666667,12 -3.8333333,6 0,0 z"
|
||||
style="opacity:1;fill:none;stroke:#ffcc00;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path3867"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
d="m -2.5,15 h 9"
|
||||
style="opacity:1;fill:none;stroke:#ffcc00;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path3867-0"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
<g
|
||||
style="opacity:0.25;stroke:#ffffff"
|
||||
transform="translate(2.5,2.8749995)"
|
||||
id="g4544-5">
|
||||
<path
|
||||
d="m 11.5,8 h 12 m -12,0 c -7.6666667,12 -3.8333333,6 0,0 z"
|
||||
style="opacity:1;fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path3867-07"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
d="m -2.5,15 h 9"
|
||||
style="opacity:1;fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path3867-0-3"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g4741"
|
||||
transform="translate(1,1)">
|
||||
<path
|
||||
sodipodi:nodetypes="sssss"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3867-9"
|
||||
style="opacity:1;fill:none;stroke:#ffcc00;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 22,18 c 0,1.932997 -1.567003,3.5 -3.5,3.5 -1.932997,0 -3.5,-1.567003 -3.5,-3.5 0,-1.932997 1.567003,-3.5 3.5,-3.5 1.932997,0 3.5,1.567003 3.5,3.5 z" />
|
||||
<path
|
||||
sodipodi:nodetypes="sssss"
|
||||
inkscape:export-ydpi="82.105263"
|
||||
inkscape:export-xdpi="82.105263"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3867-9-1"
|
||||
style="opacity:0.25;fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 22,18 c 0,1.932997 -1.567003,3.5 -3.5,3.5 -1.932997,0 -3.5,-1.567003 -3.5,-3.5 0,-1.932997 1.567003,-3.5 3.5,-3.5 1.932997,0 3.5,1.567003 3.5,3.5 z" />
|
||||
</g>
|
||||
<rect
|
||||
style="opacity:0.25;fill:#ffffff;fill-opacity:0.85398233;stroke:#b3b3b3;stroke-width:2.30681324;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.99997282;stroke-opacity:1"
|
||||
id="rect4737"
|
||||
width="26.755686"
|
||||
height="26.755686"
|
||||
x="-0.37869588"
|
||||
y="-0.37784326" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.6 KiB |
BIN
kicad_plugins/via_fence_generator/resources/viafence.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
536
kicad_plugins/via_fence_generator/resources/viafence.svg
Normal file
@@ -0,0 +1,536 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24mm"
|
||||
height="40mm"
|
||||
viewBox="0 0 23.999999 40.000001"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="viafence.svg"
|
||||
inkscape:export-filename="viafence.png"
|
||||
inkscape:export-xdpi="160.01999"
|
||||
inkscape:export-ydpi="160.01999">
|
||||
<defs
|
||||
id="defs2">
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker7369"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Mend">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
style="fill:#666666;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
id="path7371" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Sstart"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="marker5457"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path5459"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
transform="matrix(0.2,0,0,0.2,1.2,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Send"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="marker5327"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path5329"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker4910"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Send">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
id="path4912" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker4798"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Sstart">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
transform="matrix(0.2,0,0,0.2,1.2,0)"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
id="path4800" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker4722"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Sstart"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
transform="matrix(0.2,0,0,0.2,1.2,0)"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
id="path4724" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
id="path4573"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Send"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Send"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
id="path4579"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Sstart"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Sstart"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
id="path4576"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
transform="matrix(0.2,0,0,0.2,1.2,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mstart"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mstart"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path4570"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#666666;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
transform="matrix(0.4,0,0,0.4,4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mstart"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mstart-8"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4570-7"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
transform="matrix(0.4,0,0,0.4,4,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend-6"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4573-1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mstart"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mstart-9"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path4570-1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
transform="matrix(0.4,0,0,0.4,4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend-7"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path4573-4"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mstart"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mstart-9-3"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path4570-1-0"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(0.4,0,0,0.4,4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend-7-1"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path4573-4-7"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker4798-5"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Sstart">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
transform="matrix(0.2,0,0,0.2,1.2,0)"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
id="path4800-4" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker5004-9"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Send">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
id="path5006-2" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mstart"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mstart-8-7"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4570-7-0"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
transform="matrix(0.4,0,0,0.4,4,0)" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="1"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="4.0150521"
|
||||
inkscape:cx="45.354331"
|
||||
inkscape:cy="75.590551"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
units="mm"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:bbox-paths="false"
|
||||
inkscape:bbox-nodes="false"
|
||||
inkscape:snap-bbox-edge-midpoints="false"
|
||||
inkscape:snap-bbox-midpoints="false"
|
||||
inkscape:snap-object-midpoints="true"
|
||||
inkscape:snap-center="true"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="824"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-nodes="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid4485"
|
||||
empspacing="8"
|
||||
units="mm"
|
||||
spacingx="0.49999998"
|
||||
spacingy="0.49999998" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-256.99999)">
|
||||
<rect
|
||||
style="stroke-width:0.1;stroke-miterlimit:4;stroke-dasharray:none;fill:#006400;stroke:#000000;stroke-opacity:1"
|
||||
id="rect4305"
|
||||
width="23.999998"
|
||||
height="39.999996"
|
||||
x="0"
|
||||
y="257" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#ffcc00;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 12.023009,260.99998 -0.02301,32.00001"
|
||||
id="path4487"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.29999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Sstart);marker-end:url(#Arrow1Send)"
|
||||
d="m 4.4999996,259.99999 7.0230094,-1e-5"
|
||||
id="path4562"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 3.9999996,263.99999 0,-4.5"
|
||||
id="path4910"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 12.023009,260.49998 0,-1"
|
||||
id="path4910-1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="12.7"
|
||||
y="247.78749"
|
||||
id="text5363"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5361"
|
||||
x="12.7"
|
||||
y="247.78749"
|
||||
style="font-size:3.52777791px;line-height:1.25;stroke-width:0.26458332px"> </tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="7.9664097"
|
||||
y="259.28909"
|
||||
id="text5607"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5605"
|
||||
x="7.9664097"
|
||||
y="259.28909"
|
||||
style="font-size:2.11666656px;line-height:1.25;text-align:center;text-anchor:middle;stroke-width:0.26458332px">Offset</tspan></text>
|
||||
<circle
|
||||
style="fill:#1a1a1a;fill-opacity:1;stroke:#ffcc00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path4489-9-6"
|
||||
cx="4.0230093"
|
||||
cy="267"
|
||||
r="1.5230091" />
|
||||
<circle
|
||||
style="fill:#1a1a1a;fill-opacity:1;stroke:#ffcc00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path4489-9-6-6"
|
||||
cx="3.9999993"
|
||||
cy="273"
|
||||
r="1.5230091" />
|
||||
<circle
|
||||
style="fill:#1a1a1a;fill-opacity:1;stroke:#ffcc00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path4489-9-6-2"
|
||||
cx="4"
|
||||
cy="285.02301"
|
||||
r="1.5230091" />
|
||||
<circle
|
||||
style="fill:#1a1a1a;fill-opacity:1;stroke:#ffcc00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path4489-9-6-3"
|
||||
cx="20.023008"
|
||||
cy="267"
|
||||
r="1.5230091" />
|
||||
<circle
|
||||
style="fill:#1a1a1a;fill-opacity:1;stroke:#ffcc00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path4489-9-6-6-5"
|
||||
cx="19.999998"
|
||||
cy="273"
|
||||
r="1.5230091" />
|
||||
<circle
|
||||
style="fill:#1a1a1a;fill-opacity:1;stroke:#ffcc00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path4489-9-6-2-5"
|
||||
cx="19.999998"
|
||||
cy="285.02301"
|
||||
r="1.5230091" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.29999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker4722);marker-end:url(#marker4910)"
|
||||
d="m 16.999999,267.49999 0,5"
|
||||
id="path4562-0"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 16.499999,266.99999 1,0"
|
||||
id="path4910-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 16.499999,272.99999 1,0"
|
||||
id="path4910-1-8"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="269.98706"
|
||||
y="-14.210899"
|
||||
id="text5607-1"
|
||||
transform="rotate(90)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5605-0"
|
||||
x="269.98706"
|
||||
y="-14.210899"
|
||||
style="font-size:2.11666656px;line-height:1.25;text-align:center;text-anchor:middle;stroke-width:0.26458332px">Pitch</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="5.0834432"
|
||||
y="289.84128"
|
||||
id="text5110"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5112"
|
||||
x="5.0834432"
|
||||
y="289.84128"
|
||||
style="font-size:2.11666656px;line-height:1.25;text-align:center;text-anchor:middle">Via Size</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Mend);marker-end:url(#Arrow1Mstart-8)"
|
||||
d="m 5.2022141,283.39636 -2.4224396,3.2534"
|
||||
id="path5319"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#666666;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-end:url(#marker7369)"
|
||||
d="m 20.642371,285.69684 -1.317119,-1.33825"
|
||||
id="path7343"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="18.987841"
|
||||
y="289.84128"
|
||||
id="text5110-9"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5112-9"
|
||||
x="18.987841"
|
||||
y="289.84128"
|
||||
style="font-size:2.11666656px;line-height:1.25;text-align:center;text-anchor:middle">Via Drill</tspan></text>
|
||||
<circle
|
||||
style="fill:#1a1a1a;fill-opacity:1;stroke:#ffcc00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path4489-9-6-6-4"
|
||||
cx="3.9999998"
|
||||
cy="279"
|
||||
r="1.5230091" />
|
||||
<circle
|
||||
style="fill:#1a1a1a;fill-opacity:1;stroke:#ffcc00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path4489-9-6-6-5-5"
|
||||
cx="19.999998"
|
||||
cy="279"
|
||||
r="1.5230091" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 20 KiB |
1623
kicad_plugins/via_fence_generator/resources/viafence_dialogs.fbp
Normal file
140
kicad_plugins/via_fence_generator/tests/diffms.json
Normal file
@@ -0,0 +1,140 @@
|
||||
{
|
||||
"pathList": [
|
||||
[
|
||||
[
|
||||
-2000,
|
||||
250
|
||||
],
|
||||
[
|
||||
2000,
|
||||
250
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
-2000,
|
||||
-250
|
||||
],
|
||||
[
|
||||
2000,
|
||||
-250
|
||||
]
|
||||
]
|
||||
],
|
||||
"viaOffset": 1000,
|
||||
"viaPitch": 300,
|
||||
"viaPoints": [
|
||||
[
|
||||
-2000,
|
||||
-1250
|
||||
],
|
||||
[
|
||||
2000,
|
||||
-1250
|
||||
],
|
||||
[
|
||||
-1692.3076923076924,
|
||||
-1250.0
|
||||
],
|
||||
[
|
||||
-1384.6153846153848,
|
||||
-1250.0
|
||||
],
|
||||
[
|
||||
-1076.923076923077,
|
||||
-1250.0
|
||||
],
|
||||
[
|
||||
-769.2307692307693,
|
||||
-1250.0
|
||||
],
|
||||
[
|
||||
-461.53846153846143,
|
||||
-1250.0
|
||||
],
|
||||
[
|
||||
-153.8461538461538,
|
||||
-1250.0
|
||||
],
|
||||
[
|
||||
153.8461538461538,
|
||||
-1250.0
|
||||
],
|
||||
[
|
||||
461.53846153846143,
|
||||
-1250.0
|
||||
],
|
||||
[
|
||||
769.230769230769,
|
||||
-1250.0
|
||||
],
|
||||
[
|
||||
1076.9230769230771,
|
||||
-1250.0
|
||||
],
|
||||
[
|
||||
1384.6153846153848,
|
||||
-1250.0
|
||||
],
|
||||
[
|
||||
1692.3076923076924,
|
||||
-1250.0
|
||||
],
|
||||
[
|
||||
2000,
|
||||
1250
|
||||
],
|
||||
[
|
||||
-2000,
|
||||
1250
|
||||
],
|
||||
[
|
||||
1692.3076923076924,
|
||||
1250.0
|
||||
],
|
||||
[
|
||||
1384.6153846153848,
|
||||
1250.0
|
||||
],
|
||||
[
|
||||
1076.923076923077,
|
||||
1250.0
|
||||
],
|
||||
[
|
||||
769.2307692307693,
|
||||
1250.0
|
||||
],
|
||||
[
|
||||
461.53846153846143,
|
||||
1250.0
|
||||
],
|
||||
[
|
||||
153.8461538461538,
|
||||
1250.0
|
||||
],
|
||||
[
|
||||
-153.8461538461538,
|
||||
1250.0
|
||||
],
|
||||
[
|
||||
-461.53846153846143,
|
||||
1250.0
|
||||
],
|
||||
[
|
||||
-769.230769230769,
|
||||
1250.0
|
||||
],
|
||||
[
|
||||
-1076.9230769230771,
|
||||
1250.0
|
||||
],
|
||||
[
|
||||
-1384.6153846153848,
|
||||
1250.0
|
||||
],
|
||||
[
|
||||
-1692.3076923076924,
|
||||
1250.0
|
||||
]
|
||||
]
|
||||
}
|
||||
BIN
kicad_plugins/via_fence_generator/tests/diffms.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
140
kicad_plugins/via_fence_generator/tests/diffms2.json
Normal file
@@ -0,0 +1,140 @@
|
||||
{
|
||||
"pathList": [
|
||||
[
|
||||
[
|
||||
-2000,
|
||||
500
|
||||
],
|
||||
[
|
||||
2000,
|
||||
500
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
-2000,
|
||||
-500
|
||||
],
|
||||
[
|
||||
2000,
|
||||
-500
|
||||
]
|
||||
]
|
||||
],
|
||||
"viaOffset": 500,
|
||||
"viaPitch": 300,
|
||||
"viaPoints": [
|
||||
[
|
||||
-2000,
|
||||
-1000
|
||||
],
|
||||
[
|
||||
2000,
|
||||
-1000
|
||||
],
|
||||
[
|
||||
-1692.3076923076924,
|
||||
-1000.0
|
||||
],
|
||||
[
|
||||
-1384.6153846153848,
|
||||
-1000.0
|
||||
],
|
||||
[
|
||||
-1076.923076923077,
|
||||
-1000.0
|
||||
],
|
||||
[
|
||||
-769.2307692307693,
|
||||
-1000.0
|
||||
],
|
||||
[
|
||||
-461.53846153846143,
|
||||
-1000.0
|
||||
],
|
||||
[
|
||||
-153.8461538461538,
|
||||
-1000.0
|
||||
],
|
||||
[
|
||||
153.8461538461538,
|
||||
-1000.0
|
||||
],
|
||||
[
|
||||
461.53846153846143,
|
||||
-1000.0
|
||||
],
|
||||
[
|
||||
769.230769230769,
|
||||
-1000.0
|
||||
],
|
||||
[
|
||||
1076.9230769230771,
|
||||
-1000.0
|
||||
],
|
||||
[
|
||||
1384.6153846153848,
|
||||
-1000.0
|
||||
],
|
||||
[
|
||||
1692.3076923076924,
|
||||
-1000.0
|
||||
],
|
||||
[
|
||||
2000,
|
||||
1000
|
||||
],
|
||||
[
|
||||
-2000,
|
||||
1000
|
||||
],
|
||||
[
|
||||
1692.3076923076924,
|
||||
1000.0
|
||||
],
|
||||
[
|
||||
1384.6153846153848,
|
||||
1000.0
|
||||
],
|
||||
[
|
||||
1076.923076923077,
|
||||
1000.0
|
||||
],
|
||||
[
|
||||
769.2307692307693,
|
||||
1000.0
|
||||
],
|
||||
[
|
||||
461.53846153846143,
|
||||
1000.0
|
||||
],
|
||||
[
|
||||
153.8461538461538,
|
||||
1000.0
|
||||
],
|
||||
[
|
||||
-153.8461538461538,
|
||||
1000.0
|
||||
],
|
||||
[
|
||||
-461.53846153846143,
|
||||
1000.0
|
||||
],
|
||||
[
|
||||
-769.230769230769,
|
||||
1000.0
|
||||
],
|
||||
[
|
||||
-1076.9230769230771,
|
||||
1000.0
|
||||
],
|
||||
[
|
||||
-1384.6153846153848,
|
||||
1000.0
|
||||
],
|
||||
[
|
||||
-1692.3076923076924,
|
||||
1000.0
|
||||
]
|
||||
]
|
||||
}
|
||||
BIN
kicad_plugins/via_fence_generator/tests/diffms2.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
252
kicad_plugins/via_fence_generator/tests/non-diffms.json
Normal file
@@ -0,0 +1,252 @@
|
||||
{
|
||||
"pathList": [
|
||||
[
|
||||
[
|
||||
-2000,
|
||||
501
|
||||
],
|
||||
[
|
||||
2000,
|
||||
501
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
-2000,
|
||||
-501
|
||||
],
|
||||
[
|
||||
2000,
|
||||
-501
|
||||
]
|
||||
]
|
||||
],
|
||||
"viaOffset": 500,
|
||||
"viaPitch": 300,
|
||||
"viaPoints": [
|
||||
[
|
||||
-2000,
|
||||
1
|
||||
],
|
||||
[
|
||||
2000,
|
||||
1
|
||||
],
|
||||
[
|
||||
-1692.3076923076924,
|
||||
1.0
|
||||
],
|
||||
[
|
||||
-1384.6153846153848,
|
||||
1.0
|
||||
],
|
||||
[
|
||||
-1076.923076923077,
|
||||
1.0
|
||||
],
|
||||
[
|
||||
-769.2307692307693,
|
||||
1.0
|
||||
],
|
||||
[
|
||||
-461.53846153846143,
|
||||
1.0
|
||||
],
|
||||
[
|
||||
-153.8461538461538,
|
||||
1.0
|
||||
],
|
||||
[
|
||||
153.8461538461538,
|
||||
1.0
|
||||
],
|
||||
[
|
||||
461.53846153846143,
|
||||
1.0
|
||||
],
|
||||
[
|
||||
769.230769230769,
|
||||
1.0
|
||||
],
|
||||
[
|
||||
1076.9230769230771,
|
||||
1.0
|
||||
],
|
||||
[
|
||||
1384.6153846153848,
|
||||
1.0
|
||||
],
|
||||
[
|
||||
1692.3076923076924,
|
||||
1.0
|
||||
],
|
||||
[
|
||||
2000,
|
||||
1001
|
||||
],
|
||||
[
|
||||
-2000,
|
||||
1001
|
||||
],
|
||||
[
|
||||
1692.3076923076924,
|
||||
1001.0
|
||||
],
|
||||
[
|
||||
1384.6153846153848,
|
||||
1001.0
|
||||
],
|
||||
[
|
||||
1076.923076923077,
|
||||
1001.0
|
||||
],
|
||||
[
|
||||
769.2307692307693,
|
||||
1001.0
|
||||
],
|
||||
[
|
||||
461.53846153846143,
|
||||
1001.0
|
||||
],
|
||||
[
|
||||
153.8461538461538,
|
||||
1001.0
|
||||
],
|
||||
[
|
||||
-153.8461538461538,
|
||||
1001.0
|
||||
],
|
||||
[
|
||||
-461.53846153846143,
|
||||
1001.0
|
||||
],
|
||||
[
|
||||
-769.230769230769,
|
||||
1001.0
|
||||
],
|
||||
[
|
||||
-1076.9230769230771,
|
||||
1001.0
|
||||
],
|
||||
[
|
||||
-1384.6153846153848,
|
||||
1001.0
|
||||
],
|
||||
[
|
||||
-1692.3076923076924,
|
||||
1001.0
|
||||
],
|
||||
[
|
||||
-2000,
|
||||
-1001
|
||||
],
|
||||
[
|
||||
2000,
|
||||
-1001
|
||||
],
|
||||
[
|
||||
-1692.3076923076924,
|
||||
-1001.0
|
||||
],
|
||||
[
|
||||
-1384.6153846153848,
|
||||
-1001.0
|
||||
],
|
||||
[
|
||||
-1076.923076923077,
|
||||
-1001.0
|
||||
],
|
||||
[
|
||||
-769.2307692307693,
|
||||
-1001.0
|
||||
],
|
||||
[
|
||||
-461.53846153846143,
|
||||
-1001.0
|
||||
],
|
||||
[
|
||||
-153.8461538461538,
|
||||
-1001.0
|
||||
],
|
||||
[
|
||||
153.8461538461538,
|
||||
-1001.0
|
||||
],
|
||||
[
|
||||
461.53846153846143,
|
||||
-1001.0
|
||||
],
|
||||
[
|
||||
769.230769230769,
|
||||
-1001.0
|
||||
],
|
||||
[
|
||||
1076.9230769230771,
|
||||
-1001.0
|
||||
],
|
||||
[
|
||||
1384.6153846153848,
|
||||
-1001.0
|
||||
],
|
||||
[
|
||||
1692.3076923076924,
|
||||
-1001.0
|
||||
],
|
||||
[
|
||||
2000,
|
||||
-1
|
||||
],
|
||||
[
|
||||
-2000,
|
||||
-1
|
||||
],
|
||||
[
|
||||
1692.3076923076924,
|
||||
-1.0
|
||||
],
|
||||
[
|
||||
1384.6153846153848,
|
||||
-1.0
|
||||
],
|
||||
[
|
||||
1076.923076923077,
|
||||
-1.0
|
||||
],
|
||||
[
|
||||
769.2307692307693,
|
||||
-1.0
|
||||
],
|
||||
[
|
||||
461.53846153846143,
|
||||
-1.0
|
||||
],
|
||||
[
|
||||
153.8461538461538,
|
||||
-1.0
|
||||
],
|
||||
[
|
||||
-153.8461538461538,
|
||||
-1.0
|
||||
],
|
||||
[
|
||||
-461.53846153846143,
|
||||
-1.0
|
||||
],
|
||||
[
|
||||
-769.230769230769,
|
||||
-1.0
|
||||
],
|
||||
[
|
||||
-1076.9230769230771,
|
||||
-1.0
|
||||
],
|
||||
[
|
||||
-1384.6153846153848,
|
||||
-1.0
|
||||
],
|
||||
[
|
||||
-1692.3076923076924,
|
||||
-1.0
|
||||
]
|
||||
]
|
||||
}
|
||||
BIN
kicad_plugins/via_fence_generator/tests/non-diffms.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
434
kicad_plugins/via_fence_generator/tests/simple-test.json
Normal file
@@ -0,0 +1,434 @@
|
||||
{
|
||||
"viaOffset": 500,
|
||||
"viaPitch": 300,
|
||||
"viaPoints": [
|
||||
[
|
||||
2000,
|
||||
4500
|
||||
],
|
||||
[
|
||||
1500,
|
||||
1792
|
||||
],
|
||||
[
|
||||
1500,
|
||||
500
|
||||
],
|
||||
[
|
||||
309,
|
||||
500
|
||||
],
|
||||
[
|
||||
-2000,
|
||||
2500
|
||||
],
|
||||
[
|
||||
1694.7494045294795,
|
||||
4500.0
|
||||
],
|
||||
[
|
||||
1389.498809058959,
|
||||
4500.0
|
||||
],
|
||||
[
|
||||
1084.2482135884386,
|
||||
4500.0
|
||||
],
|
||||
[
|
||||
778.9976181179181,
|
||||
4500.0
|
||||
],
|
||||
[
|
||||
473.74702264739767,
|
||||
4500.0
|
||||
],
|
||||
[
|
||||
168.4964271768772,
|
||||
4500.0
|
||||
],
|
||||
[
|
||||
-134.97345240050308,
|
||||
4481.007964279849
|
||||
],
|
||||
[
|
||||
-386.4640053423498,
|
||||
4316.612565323029
|
||||
],
|
||||
[
|
||||
-498.26181546785324,
|
||||
4037.810952514348
|
||||
],
|
||||
[
|
||||
-430.1165855145392,
|
||||
3745.243988758386
|
||||
],
|
||||
[
|
||||
-226.75812814749332,
|
||||
3518.758128147493
|
||||
],
|
||||
[
|
||||
-10.91336212905685,
|
||||
3302.9133621290566
|
||||
],
|
||||
[
|
||||
204.93140388938002,
|
||||
3087.06859611062
|
||||
],
|
||||
[
|
||||
420.7761699078168,
|
||||
2871.223830092183
|
||||
],
|
||||
[
|
||||
636.6209359262533,
|
||||
2655.3790640737466
|
||||
],
|
||||
[
|
||||
852.4657019446897,
|
||||
2439.5342980553105
|
||||
],
|
||||
[
|
||||
1068.3104679631263,
|
||||
2223.689532036874
|
||||
],
|
||||
[
|
||||
1284.1552339815635,
|
||||
2007.8447660184365
|
||||
],
|
||||
[
|
||||
1500.0,
|
||||
1469.0
|
||||
],
|
||||
[
|
||||
1500.0,
|
||||
1146.0
|
||||
],
|
||||
[
|
||||
1500.0,
|
||||
823.0
|
||||
],
|
||||
[
|
||||
1103.0,
|
||||
500.0
|
||||
],
|
||||
[
|
||||
706.0,
|
||||
500.0
|
||||
],
|
||||
[
|
||||
167.49497119958997,
|
||||
783.0100576008201
|
||||
],
|
||||
[
|
||||
25.989942399179938,
|
||||
1066.0201152016402
|
||||
],
|
||||
[
|
||||
-115.51508640123012,
|
||||
1349.0301728024601
|
||||
],
|
||||
[
|
||||
-257.0201152016401,
|
||||
1632.0402304032802
|
||||
],
|
||||
[
|
||||
-398.5251440020502,
|
||||
1915.0502880041004
|
||||
],
|
||||
[
|
||||
-540.0301728024602,
|
||||
2198.0603456049203
|
||||
],
|
||||
[
|
||||
-746.9452985193672,
|
||||
2430.745362085551
|
||||
],
|
||||
[
|
||||
-1050.755409332653,
|
||||
2500.0
|
||||
],
|
||||
[
|
||||
-1367.1702728884356,
|
||||
2500.0
|
||||
],
|
||||
[
|
||||
-1683.5851364442178,
|
||||
2500.0
|
||||
],
|
||||
[
|
||||
-2000,
|
||||
1500
|
||||
],
|
||||
[
|
||||
-1309,
|
||||
1500
|
||||
],
|
||||
[
|
||||
-609,
|
||||
99
|
||||
],
|
||||
[
|
||||
-2354,
|
||||
-1646
|
||||
],
|
||||
[
|
||||
-1654.5,
|
||||
1500.0
|
||||
],
|
||||
[
|
||||
-1169.0,
|
||||
1219.8
|
||||
],
|
||||
[
|
||||
-1029.0,
|
||||
939.6
|
||||
],
|
||||
[
|
||||
-889.0,
|
||||
659.4
|
||||
],
|
||||
[
|
||||
-749.0,
|
||||
379.20000000000005
|
||||
],
|
||||
[
|
||||
-827.125,
|
||||
-119.125
|
||||
],
|
||||
[
|
||||
-1045.25,
|
||||
-337.25
|
||||
],
|
||||
[
|
||||
-1263.375,
|
||||
-555.375
|
||||
],
|
||||
[
|
||||
-1481.5,
|
||||
-773.5
|
||||
],
|
||||
[
|
||||
-1699.625,
|
||||
-991.625
|
||||
],
|
||||
[
|
||||
-1917.75,
|
||||
-1209.75
|
||||
],
|
||||
[
|
||||
-2135.875,
|
||||
-1427.8750000000002
|
||||
],
|
||||
[
|
||||
-1646,
|
||||
-2354
|
||||
],
|
||||
[
|
||||
208,
|
||||
-500
|
||||
],
|
||||
[
|
||||
1208,
|
||||
3500
|
||||
],
|
||||
[
|
||||
2000,
|
||||
3500
|
||||
],
|
||||
[
|
||||
-1414.25,
|
||||
-2122.25
|
||||
],
|
||||
[
|
||||
-1182.5,
|
||||
-1890.5
|
||||
],
|
||||
[
|
||||
-950.75,
|
||||
-1658.75
|
||||
],
|
||||
[
|
||||
-719.0,
|
||||
-1427.0
|
||||
],
|
||||
[
|
||||
-487.25,
|
||||
-1195.25
|
||||
],
|
||||
[
|
||||
-255.5,
|
||||
-963.5
|
||||
],
|
||||
[
|
||||
-23.75,
|
||||
-731.75
|
||||
],
|
||||
[
|
||||
521.8262211985277,
|
||||
-500.0
|
||||
],
|
||||
[
|
||||
835.6524423970556,
|
||||
-500.0
|
||||
],
|
||||
[
|
||||
1149.4786635955834,
|
||||
-500.0
|
||||
],
|
||||
[
|
||||
1463.304884794111,
|
||||
-500.0
|
||||
],
|
||||
[
|
||||
1777.1311059926388,
|
||||
-500.0
|
||||
],
|
||||
[
|
||||
2090.442225924456,
|
||||
-491.57383452831357
|
||||
],
|
||||
[
|
||||
2361.7526198249857,
|
||||
-344.44044291024215
|
||||
],
|
||||
[
|
||||
2495.659716859078,
|
||||
-66.30975547371793
|
||||
],
|
||||
[
|
||||
2500.0,
|
||||
247.3274095922838
|
||||
],
|
||||
[
|
||||
2500.0,
|
||||
561.1536307908112
|
||||
],
|
||||
[
|
||||
2500.0,
|
||||
874.9798519893395
|
||||
],
|
||||
[
|
||||
2500.0,
|
||||
1188.806073187867
|
||||
],
|
||||
[
|
||||
2500.0,
|
||||
1502.632294386395
|
||||
],
|
||||
[
|
||||
2500.0,
|
||||
1816.4585155849227
|
||||
],
|
||||
[
|
||||
2482.8669417451197,
|
||||
2128.7768608496017
|
||||
],
|
||||
[
|
||||
2317.5432456181425,
|
||||
2390.4567543818575
|
||||
],
|
||||
[
|
||||
2095.6345964945144,
|
||||
2612.3654035054856
|
||||
],
|
||||
[
|
||||
1873.7259473708855,
|
||||
2834.2740526291145
|
||||
],
|
||||
[
|
||||
1651.817298247257,
|
||||
3056.182701752743
|
||||
],
|
||||
[
|
||||
1429.908649123629,
|
||||
3278.091350876371
|
||||
],
|
||||
[
|
||||
1604.0,
|
||||
3500.0
|
||||
],
|
||||
[
|
||||
1000,
|
||||
-2500
|
||||
],
|
||||
[
|
||||
2000,
|
||||
-2500
|
||||
],
|
||||
[
|
||||
1333.3333333333333,
|
||||
-2500.0
|
||||
],
|
||||
[
|
||||
1666.6666666666665,
|
||||
-2500.0
|
||||
],
|
||||
[
|
||||
2000,
|
||||
-1500
|
||||
],
|
||||
[
|
||||
1000,
|
||||
-1500
|
||||
],
|
||||
[
|
||||
1666.6666666666667,
|
||||
-1500.0
|
||||
],
|
||||
[
|
||||
1333.3333333333335,
|
||||
-1500.0
|
||||
]
|
||||
],
|
||||
"pathList": [
|
||||
[
|
||||
[
|
||||
-2000,
|
||||
-2000
|
||||
],
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
2000,
|
||||
0
|
||||
],
|
||||
[
|
||||
2000,
|
||||
2000
|
||||
],
|
||||
[
|
||||
0,
|
||||
4000
|
||||
],
|
||||
[
|
||||
2000,
|
||||
4000
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
-1000,
|
||||
2000
|
||||
],
|
||||
[
|
||||
-2000,
|
||||
2000
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
2000,
|
||||
-2000
|
||||
],
|
||||
[
|
||||
1000,
|
||||
-2000
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
BIN
kicad_plugins/via_fence_generator/tests/simple-test.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
386
kicad_plugins/via_fence_generator/viafence.py
Normal file
@@ -0,0 +1,386 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2017 Simon Kuppers https://github.com/skuep/
|
||||
# Copyright 2019 Maurice https://github.com/easyw/
|
||||
|
||||
# original plugin https://github.com/skuep/kicad-plugins
|
||||
# some source tips @
|
||||
# https://github.com/MitjaNemec/Kicad_action_plugins
|
||||
# https://github.com/jsreynaud/kicad-action-scripts
|
||||
|
||||
# GNU GENERAL PUBLIC LICENSE
|
||||
# Version 3, 29 June 2007
|
||||
#
|
||||
# Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
# Everyone is permitted to copy and distribute verbatim copies
|
||||
# of this license document, but changing it is not allowed.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
|
||||
import math
|
||||
#import pyclipper
|
||||
from bisect import bisect_left
|
||||
import wx
|
||||
import pcbnew
|
||||
|
||||
def verbose(object, *args, **kwargs):
|
||||
global verboseFunc
|
||||
verboseFunc(object, *args, **kwargs)
|
||||
|
||||
# Returns the slope of a line
|
||||
def getLineSlope(line):
|
||||
return math.atan2(line[0][1]-line[1][1], line[0][0]-line[1][0])
|
||||
|
||||
# Returns the length of a line
|
||||
def getLineLength(line):
|
||||
return math.hypot(line[0][0]-line[1][0], line[0][1]-line[1][1])
|
||||
|
||||
# Returns a sub path in a path with a path specification (startIdx, stopIdx)
|
||||
def getSubPath(path, pathSpec):
|
||||
listModulus = len(path)
|
||||
if (pathSpec[1] < pathSpec[0]): pathSpec[1] += listModulus
|
||||
return [path[i % listModulus] for i in range(pathSpec[0], pathSpec[1]+1)]
|
||||
|
||||
# Returns a list of subpaths with a list of path specifications
|
||||
def getSubPaths(path, pathSpecList):
|
||||
return [getSubPath(path, pathSpec) for pathSpec in pathSpecList if (pathSpec[0] != pathSpec[1])]
|
||||
|
||||
# Splits a path using a list of indices representing points on the path
|
||||
def splitPathByPoints(path, splitList):
|
||||
pathSpecList = [[splitList[item], splitList[item+1]] for item in range(0, len(splitList)-1)]
|
||||
return getSubPaths(path, pathSpecList)
|
||||
|
||||
# Splits a path around a list of list of indices representing a subpath within the original path
|
||||
def splitPathByPaths(path, splitList):
|
||||
pathSpecList = [[splitList[item][-1], splitList[(item+1)%len(splitList)][0]] for item in range(0, len(splitList))]
|
||||
return getSubPaths(path, pathSpecList)
|
||||
|
||||
# Return a cumulative distance vector representing the distance travelled along
|
||||
# the path at each path vertex
|
||||
def getPathCumDist(path):
|
||||
cumDist = [0.0]
|
||||
for vertexId in range(1, len(path)):
|
||||
cumDist += [cumDist[-1] + getLineLength([path[vertexId], path[vertexId-1]])]
|
||||
|
||||
return cumDist
|
||||
|
||||
# Return a list of all vertex indices where the angle between
|
||||
# the two lines connected to the vertex deviate from a straight
|
||||
# path more by the tolerance angle in degrees
|
||||
# This function is used to find bends that are larger than a certain angle
|
||||
def getPathVertices(path, angleTolerance):
|
||||
angleTolerance = angleTolerance * math.pi / 180
|
||||
vertices = []
|
||||
|
||||
# Look through all vertices except start and end vertex
|
||||
# Calculate by how much the lines before and after the vertex
|
||||
# deviate from a straight path.
|
||||
# If the deviation angle exceeds the specification, store it
|
||||
for vertexIdx in range(1, len(path)-1):
|
||||
prevSlope = getLineSlope([path[vertexIdx+1], path[vertexIdx]])
|
||||
nextSlope = getLineSlope([path[vertexIdx-1], path[vertexIdx]])
|
||||
deviationAngle = abs(prevSlope - nextSlope) - math.pi
|
||||
if (abs(deviationAngle) > angleTolerance):
|
||||
vertices += [vertexIdx]
|
||||
|
||||
return vertices
|
||||
|
||||
# Uses the cross product to check if a point is on a line defined by two other points
|
||||
def isPointOnLine(point, line):
|
||||
cross = (line[1][1] - point[1]) * (line[0][0] - point[0]) - (line[1][0] - point[0]) * (line[0][1] - point[1])
|
||||
|
||||
if ( ((line[0][0] <= point[0] <= line[1][0]) or (line[1][0] <= point[0] <= line[0][0]))
|
||||
and ((line[0][1] <= point[1] <= line[1][1]) or (line[1][1] <= point[1] <= line[0][1]))
|
||||
and (cross == 0) ):
|
||||
return True
|
||||
return False
|
||||
|
||||
# Returns a list of path indices touching any item in a list of points
|
||||
def getPathsThroughPoints(path, pointList):
|
||||
touchingPaths = []
|
||||
|
||||
for vertexIdx in range(0, len(path)):
|
||||
fromIdx = vertexIdx
|
||||
toIdx = (vertexIdx+1) % len(path)
|
||||
|
||||
# If a point in the pointList is located on this line, store the line
|
||||
for point in pointList:
|
||||
if isPointOnLine(point, [ path[fromIdx], path[toIdx] ]):
|
||||
touchingPaths += [[fromIdx, toIdx]]
|
||||
break
|
||||
|
||||
return touchingPaths
|
||||
|
||||
# A small linear interpolation class so we don't rely on scipy or numpy here
|
||||
class LinearInterpolator(object):
|
||||
def __init__(self, x_list, y_list):
|
||||
self.x_list, self.y_list = x_list, y_list
|
||||
intervals = zip(x_list, x_list[1:], y_list, y_list[1:])
|
||||
self.slopes = [(y2 - y1)/(x2 - x1) for x1, x2, y1, y2 in intervals]
|
||||
def __call__(self, x):
|
||||
i = bisect_left(self.x_list, x) - 1
|
||||
return self.y_list[i] + self.slopes[i] * (x - self.x_list[i])
|
||||
|
||||
# Interpolate a path with (x,y) vertices using a third parameter t
|
||||
class PathInterpolator:
|
||||
def __init__(self, t, path):
|
||||
# Quick and dirty transpose path so we get two list with x and y coords
|
||||
# And set up two separate interpolators for them
|
||||
x = [vertex[0] for vertex in path]
|
||||
y = [vertex[1] for vertex in path]
|
||||
self.xInterp = LinearInterpolator(t, x)
|
||||
self.yInterp = LinearInterpolator(t, y)
|
||||
def __call__(self, t):
|
||||
# Return interpolated coordinates on the original path
|
||||
return [self.xInterp(t), self.yInterp(t)]
|
||||
|
||||
# A small pyclipper wrapper class to expand a line to a polygon with a given offset
|
||||
def expandPathsToPolygons(pathList, offset):
|
||||
import pyclipper
|
||||
# Use PyclipperOffset to generate polygons that surround the original
|
||||
# paths with a constant offset all around
|
||||
co = pyclipper.PyclipperOffset()
|
||||
for path in pathList: co.AddPath(path, pyclipper.JT_ROUND, pyclipper.ET_OPENROUND)
|
||||
return co.Execute(offset)
|
||||
|
||||
# A small pyclipper wrapper to trim parts of a polygon using another polygon
|
||||
def clipPolygonWithPolygons(path, clipPathList):
|
||||
import pyclipper
|
||||
pc = pyclipper.Pyclipper()
|
||||
pc.AddPath(path, pyclipper.PT_SUBJECT, True)
|
||||
for clipPath in clipPathList: pc.AddPath(clipPath, pyclipper.PT_CLIP, True)
|
||||
return pc.Execute(pyclipper.CT_DIFFERENCE)
|
||||
|
||||
def unionPolygons(pathList):
|
||||
import pyclipper
|
||||
pc = pyclipper.Pyclipper()
|
||||
for path in pathList: pc.AddPath(path, pyclipper.PT_SUBJECT, True)
|
||||
return pc.Execute(pyclipper.CT_UNION, pyclipper.PFT_NONZERO)
|
||||
|
||||
def isPointInPolygon(point, path):
|
||||
import pyclipper
|
||||
return True if (pyclipper.PointInPolygon(point, path) == 1) else False
|
||||
|
||||
def getPathsInsidePolygon(pathList, polygon):
|
||||
filteredPathList = []
|
||||
|
||||
for path in pathList:
|
||||
allVerticesInside = True
|
||||
for vertex in path:
|
||||
if not isPointInPolygon(vertex, polygon):
|
||||
allVerticesInside = False
|
||||
break
|
||||
if (allVerticesInside): filteredPathList += [path]
|
||||
|
||||
return filteredPathList
|
||||
|
||||
# Distribute Points along a path with equal spacing to each other
|
||||
# When the path length is not evenly dividable by the minimumSpacing,
|
||||
# the actual spacing will be larger, but still smaller than 2*minimumSpacing
|
||||
# The function does not return the start and end vertex of the path
|
||||
def distributeAlongPath(path, minimumSpacing):
|
||||
# Get cumulated distance vector for the path
|
||||
# and determine the number of points that can fit to the path
|
||||
distList = getPathCumDist(path)
|
||||
nPoints = int(math.floor(distList[-1] / minimumSpacing))
|
||||
ptInterp = PathInterpolator(distList, path)
|
||||
return [ptInterp(ptIdx * distList[-1]/nPoints) for ptIdx in range(1, nPoints)]
|
||||
|
||||
# Find the leaf vertices in a list of paths,
|
||||
# additionally it calculates the slope of the line connected to the leaf vertex
|
||||
def getLeafVertices(pathList):
|
||||
allVertices = [vertex for path in pathList for vertex in path]
|
||||
leafVertices = []
|
||||
leafVertexSlopes = []
|
||||
|
||||
for path in pathList:
|
||||
for vertexIdx in [0,-1]:
|
||||
if (allVertices.count(path[vertexIdx]) == 1):
|
||||
# vertex appears only once in entire path list, store away
|
||||
# Get neighbour vertex and also calculate the slope
|
||||
leafVertex = path[vertexIdx]
|
||||
neighbourVertex = path[ [1,-2][vertexIdx] ]
|
||||
leafVertices += [leafVertex]
|
||||
leafVertexSlopes += [getLineSlope([neighbourVertex, leafVertex])]
|
||||
|
||||
return leafVertices, leafVertexSlopes
|
||||
|
||||
# Rotate and Translate a list of vertices using a given angle and offset
|
||||
def transformVertices(vertexList, offset, angle):
|
||||
return [ [ round(offset[0] + math.cos(angle) * vertex[0] - math.sin(angle) * vertex[1]),
|
||||
round(offset[1] + math.sin(angle) * vertex[0] + math.cos(angle) * vertex[1]) ]
|
||||
for vertex in vertexList]
|
||||
|
||||
# Trims a polygon flush around the given vertices
|
||||
def trimFlushPolygonAtVertices(path, vertexList, vertexSlopes, radius):
|
||||
const = 0.414
|
||||
trimPoly = [ [0, -radius], [0, 0], [0, radius], [-const*radius, radius], [-radius, const*radius],
|
||||
[-radius, -const*radius], [-const*radius, -radius] ]
|
||||
trimPolys = [transformVertices(trimPoly, vertexPos, vertexSlope)
|
||||
for vertexPos, vertexSlope in zip(vertexList, vertexSlopes)]
|
||||
|
||||
trimPolys = unionPolygons(trimPolys)
|
||||
|
||||
verbose(trimPolys, isPolygons=True)
|
||||
|
||||
return clipPolygonWithPolygons(path, trimPolys)
|
||||
|
||||
######################
|
||||
def generateViaFence(pathList, viaOffset, viaPitch, vFunc = lambda *args,**kwargs:None):
|
||||
global verboseFunc
|
||||
verboseFunc = vFunc
|
||||
viaPoints = []
|
||||
|
||||
# Remove zero length tracks
|
||||
pathList = [path for path in pathList if getLineLength(path) > 0]
|
||||
|
||||
# Expand the paths given as a parameter into one or more polygons
|
||||
# using the offset parameter
|
||||
for offsetPoly in expandPathsToPolygons(pathList, viaOffset):
|
||||
verbose([offsetPoly], isPolygons=True)
|
||||
# Filter the input path to only include paths inside this polygon
|
||||
# Find all leaf vertices and use them to trim the expanded polygon
|
||||
# around the leaf vertices so that we get a flush, flat end
|
||||
# These butt lines are then found using the leaf vertices
|
||||
# and used to split open the polygon into multiple separate open
|
||||
# paths that envelop the original path
|
||||
localPathList = getPathsInsidePolygon(pathList, offsetPoly)
|
||||
if len(localPathList) == 0: continue # This might happen with very bad input paths
|
||||
|
||||
leafVertexList, leafVertexAngles = getLeafVertices(localPathList)
|
||||
offsetPoly = trimFlushPolygonAtVertices(offsetPoly, leafVertexList, leafVertexAngles, 1.1*viaOffset)[0]
|
||||
buttLineIdxList = getPathsThroughPoints(offsetPoly, leafVertexList)
|
||||
fencePaths = splitPathByPaths(offsetPoly, buttLineIdxList)
|
||||
|
||||
verbose([offsetPoly], isPolygons=True)
|
||||
verbose([leafVertexList], isPoints=True)
|
||||
verbose(fencePaths, isPaths=True)
|
||||
|
||||
# With the now separated open paths we perform via placement on each one of them
|
||||
for fencePath in fencePaths:
|
||||
# For a nice via fence placement, we identify vertices that differ from a straight
|
||||
# line by more than 10 degrees so we find all non-arc edges
|
||||
# We combine these points with the start and end point of the path and use
|
||||
# them to place fixed vias on their positions
|
||||
tolerance_degree = 10
|
||||
fixPointIdxList = [0] + getPathVertices(fencePath, tolerance_degree) + [-1]
|
||||
fixPointList = [fencePath[idx] for idx in fixPointIdxList]
|
||||
verbose(fixPointList, isPoints=True)
|
||||
|
||||
viaPoints += fixPointList
|
||||
# Then we autoplace vias between the fixed via locations by satisfying the
|
||||
# minimum via pitch given by the user
|
||||
for subPath in splitPathByPoints(fencePath, fixPointIdxList):
|
||||
viaPoints += distributeAlongPath(subPath, viaPitch)
|
||||
|
||||
return viaPoints
|
||||
|
||||
def create_round_pts(sp,ep,cntr,rad,layer,width,Nn,N_SEGMENTS):
|
||||
start_point = sp
|
||||
end_point = ep
|
||||
pos = sp
|
||||
next_pos = ep
|
||||
a1 = getAngleRadians(cntr,sp)
|
||||
a2 = getAngleRadians(cntr,ep)
|
||||
#wxLogDebug('a1:'+str(math.degrees(a1))+' a2:'+str(math.degrees(a2))+' a2-a1:'+str(math.degrees(a2-a1)),debug)
|
||||
if (a2-a1) > 0 and abs(a2-a1) > math.radians(180):
|
||||
deltaA = -(math.radians(360)-(a2-a1))/N_SEGMENTS
|
||||
#wxLogDebug('deltaA reviewed:'+str(math.degrees(deltaA)),debug)
|
||||
elif (a2-a1) < 0 and abs(a2-a1) > math.radians(180):
|
||||
deltaA = (math.radians(360)-abs(a2-a1))/N_SEGMENTS
|
||||
#wxLogDebug('deltaA reviewed2:'+str(math.degrees(deltaA)),debug)
|
||||
else:
|
||||
deltaA = (a2-a1)/N_SEGMENTS
|
||||
delta=deltaA
|
||||
#wxLogDebug('delta:'+str(math.degrees(deltaA))+' radius:'+str(ToMM(rad)),debug)
|
||||
points = []
|
||||
#import round_trk; import importlib; importlib.reload(round_trk)
|
||||
for ii in range (N_SEGMENTS+1): #+1):
|
||||
points.append(pos)
|
||||
#t = create_Track(pos,pos)
|
||||
prv_pos = pos
|
||||
#pos = pos + fraction_delta
|
||||
#posPolar = cmath.polar(pos)
|
||||
#(rad) * cmath.exp(math.radians(deltaA)*1j) #cmath.rect(r, phi) : Return the complex number x with polar coordinates r and phi.
|
||||
#pos = wxPoint(posPolar.real+sp.x,posPolar.imag+sp.y)
|
||||
pos = rotatePoint(rad,a1,delta,cntr)
|
||||
delta=delta+deltaA
|
||||
#wxLogDebug("pos:"+str(ToUnits(prv_pos.x))+":"+str(ToUnits(prv_pos.y))+";"+str(ToUnits(pos.x))+":"+str(ToUnits(pos.y)),debug)
|
||||
return points
|
||||
#if 0:
|
||||
# for i, p in enumerate(points):
|
||||
# #if i < len (points)-1:
|
||||
# if i < len (points)-2:
|
||||
# t = create_Solder(pcb,p,points[i+1],layer,width,Nn,True,pcbGroup) #adding ts code to segments
|
||||
# t = create_Solder(pcb,points[-2],ep,layer,width,Nn,True,pcbGroup) #avoiding rounding on last segment
|
||||
#
|
||||
# Function to find the circle on
|
||||
# which the given three points lie
|
||||
def getCircleCenterRadius(sp,ep,ip):
|
||||
# findCircle(x1, y1, x2, y2, x3, y3) :
|
||||
# NB add always set float even if values are pcb internal Units!!!
|
||||
x1 = float(sp.x); y1 = float(sp.y)
|
||||
x2 = float(ep.x); y2 = float(ep.y)
|
||||
x3 = float(ip.x); y3 = float(ip.y)
|
||||
|
||||
x12 = x1 - x2;
|
||||
x13 = x1 - x3;
|
||||
y12 = y1 - y2;
|
||||
y13 = y1 - y3;
|
||||
y31 = y3 - y1;
|
||||
y21 = y2 - y1;
|
||||
x31 = x3 - x1;
|
||||
x21 = x2 - x1;
|
||||
|
||||
# x1^2 - x3^2
|
||||
sx13 = math.pow(x1, 2) - math.pow(x3, 2);
|
||||
# y1^2 - y3^2
|
||||
sy13 = math.pow(y1, 2) - math.pow(y3, 2);
|
||||
sx21 = math.pow(x2, 2) - math.pow(x1, 2);
|
||||
sy21 = math.pow(y2, 2) - math.pow(y1, 2);
|
||||
|
||||
f = (((sx13) * (x12) + (sy13) *
|
||||
(x12) + (sx21) * (x13) +
|
||||
(sy21) * (x13)) // (2 *
|
||||
((y31) * (x12) - (y21) * (x13))));
|
||||
|
||||
g = (((sx13) * (y12) + (sy13) * (y12) +
|
||||
(sx21) * (y13) + (sy21) * (y13)) //
|
||||
(2 * ((x31) * (y12) - (x21) * (y13))));
|
||||
|
||||
c = (-math.pow(x1, 2) - math.pow(y1, 2) - 2 * g * x1 - 2 * f * y1);
|
||||
|
||||
# eqn of circle be x^2 + y^2 + 2*g*x + 2*f*y + c = 0
|
||||
# where centre is (h = -g, k = -f) and
|
||||
# radius r as r^2 = h^2 + k^2 - c
|
||||
h = -g;
|
||||
k = -f;
|
||||
sqr_of_r = h * h + k * k - c;
|
||||
# r is the radius
|
||||
r = round(math.sqrt(sqr_of_r), 5);
|
||||
Cx = h
|
||||
Cy = k
|
||||
radius = r
|
||||
return wx.Point(Cx,Cy), radius
|
||||
#
|
||||
def getAngleRadians(p1,p2):
|
||||
#return math.degrees(math.atan2((p1.y-p2.y),(p1.x-p2.x)))
|
||||
return (math.atan2((p1.y-p2.y),(p1.x-p2.x)))
|
||||
#
|
||||
def rotatePoint(r,sa,da,c):
|
||||
# sa, da in radians
|
||||
x = c.x - math.cos(sa+da) * r
|
||||
y = c.y - math.sin(sa+da) * r
|
||||
return wx.Point(x,y)
|
||||
639
kicad_plugins/via_fence_generator/viafence_action.py
Executable file
@@ -0,0 +1,639 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Implementation of the action plugin derived from pcbnew.ActionPlugin
|
||||
import pcbnew
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import time
|
||||
import json
|
||||
import math
|
||||
import wx
|
||||
import uuid
|
||||
|
||||
from collections import OrderedDict
|
||||
from .viafence import *
|
||||
from .viafence_dialogs import *
|
||||
|
||||
debug = False
|
||||
temporary_fix = True
|
||||
|
||||
def wxLogDebug(msg,show):
|
||||
"""printing messages only if show is omitted or True"""
|
||||
if show:
|
||||
wx.LogMessage(msg)
|
||||
#
|
||||
def getTrackAngleRadians(track):
|
||||
#return math.degrees(math.atan2((p1.y-p2.y),(p1.x-p2.x)))
|
||||
return (math.atan2((track.GetEnd().y - track.GetStart().y), (track.GetEnd().x - track.GetStart().x)))
|
||||
#
|
||||
|
||||
def distance (p1,p2):
|
||||
return math.hypot(p1.y-p2.y,p1.x-p2.x)
|
||||
|
||||
class ViaFenceAction(pcbnew.ActionPlugin):
|
||||
# ActionPlugin descriptive information
|
||||
def defaults(self):
|
||||
self.name = "Via Fence Generator\nversion 2.8"
|
||||
self.category = "Modify PCB"
|
||||
self.description = "Add a via fence to nets or tracks on the board"
|
||||
self.icon_file_name = os.path.join(os.path.dirname(__file__), "resources/fencing-vias.png")
|
||||
self.show_toolbar_button = True
|
||||
|
||||
def dumpJSON(self, file):
|
||||
dict = {
|
||||
'pathList': self.pathList,
|
||||
'viaOffset': self.viaOffset,
|
||||
'viaPitch': self.viaPitch,
|
||||
'viaPoints': self.viaPoints if hasattr(self, 'viaPoints') else []
|
||||
}
|
||||
with open(file, 'w') as file:
|
||||
json.dump(dict, file, indent=4, sort_keys=True)
|
||||
|
||||
# Return an ordered {layerId: layerName} dict of enabled layers
|
||||
def getLayerMap(self):
|
||||
layerMap = []
|
||||
for i in list(range(pcbnew.PCB_LAYER_ID_COUNT)):
|
||||
if self.boardObj.IsLayerEnabled(i):
|
||||
layerMap += [[i, self.boardObj.GetLayerName(i)]]
|
||||
return OrderedDict(layerMap)
|
||||
|
||||
# Return an ordered {netCode: netName} dict of nets in the board
|
||||
def getNetMap(self):
|
||||
netMap = OrderedDict(self.boardObj.GetNetsByNetcode())
|
||||
netMap.pop(0) # TODO: What is Net 0?
|
||||
return netMap
|
||||
|
||||
# Generates a list of net filter phrases using the local netMap
|
||||
# Currently all nets are included as filter phrases
|
||||
# Additionally, differential Nets get a special filter phrase
|
||||
def createNetFilterSuggestions(self):
|
||||
netFilterList = ['*']
|
||||
netList = [self.netMap[item].GetNetname() for item in self.netMap]
|
||||
diffMap = {'+': '-', 'P': 'N', '-': '+', 'N': 'P'}
|
||||
regexMap = {'+': '[+-]', '-': '[+-]', 'P': '[PN]', 'N': '[PN]'}
|
||||
invertDiffNet = lambda netName : netName[0:-1] + diffMap[netName[-1]]
|
||||
isDiffNet = lambda netName : True if netName[-1] in diffMap.keys() else False
|
||||
|
||||
# Translate board nets into a filter list
|
||||
for netName in netList:
|
||||
if isDiffNet(netName) and invertDiffNet(netName) in netList:
|
||||
# If we have a +/- or P/N pair, we insert a regex entry once into the filter list
|
||||
filterText = netName[0:-1] + regexMap[netName[-1]]
|
||||
if (filterText not in netFilterList): netFilterList += [filterText]
|
||||
|
||||
# Append every net to the filter list
|
||||
netFilterList += [netName]
|
||||
|
||||
return netFilterList
|
||||
|
||||
# Generates a RegEx string from a SimpleEx (which is a proprietary invention ;-))
|
||||
# The SimpleEx only supports [...] with single chars and * used as a wildcard
|
||||
def regExFromSimpleEx(self, simpleEx):
|
||||
# Escape the entire filter string. Unescape and remap specific characters that we want to allow
|
||||
subsTable = {r'\[':'[', r'\]':']', r'\*':'.*'}
|
||||
regEx = re.escape(simpleEx)
|
||||
for subsFrom, subsTo in subsTable.items(): regEx = regEx.replace(subsFrom, subsTo)
|
||||
return regEx
|
||||
|
||||
def createVias(self, viaPoints, viaDrill, viaSize, netCode):
|
||||
newVias = []
|
||||
for viaPoint in viaPoints:
|
||||
if not(hasattr(pcbnew,'DRAWSEGMENT')):
|
||||
newVia = pcbnew.PCB_VIA(self.boardObj)
|
||||
else:
|
||||
newVia = pcbnew.VIA(self.boardObj)
|
||||
if hasattr(newVia, 'SetTimeStamp'):
|
||||
ts = 55
|
||||
newVia.SetTimeStamp(ts) # adding a unique number as timestamp to mark this via as generated by this script
|
||||
self.boardObj.Add(newVia)
|
||||
|
||||
newVia.SetPosition(pcbnew.wxPoint(viaPoint[0], viaPoint[1]))
|
||||
newVia.SetWidth(viaSize)
|
||||
newVia.SetDrill(viaDrill)
|
||||
if hasattr(pcbnew, 'VIA_THROUGH'):
|
||||
newVia.SetViaType(pcbnew.VIA_THROUGH)
|
||||
else:
|
||||
newVia.SetViaType(pcbnew.VIATYPE_THROUGH)
|
||||
newVia.SetNetCode(netCode)
|
||||
newVias += [newVia]
|
||||
|
||||
return newVias
|
||||
|
||||
def onDeleteClick(self, event):
|
||||
return self.mainDlg.EndModal(wx.ID_DELETE)
|
||||
|
||||
def checkPads(self):
|
||||
##Check vias collisions with all pads => all pads on all layers
|
||||
#wxPrint("Processing all pads...")
|
||||
|
||||
if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix:
|
||||
self.clearance = 0 #TBF
|
||||
else:
|
||||
self.clearance = self.boardObj.GetDesignSettings().GetDefault().GetClearance()
|
||||
#lboard = self.boardObj.ComputeBoundingBox(False)
|
||||
#origin = lboard.GetPosition()
|
||||
# Create an initial rectangle: all is set to "REASON_NO_SIGNAL"
|
||||
# get a margin to avoid out of range
|
||||
l_clearance = self.clearance + self.viaSize #+ self.size
|
||||
#x_limit = int((lboard.GetWidth() + l_clearance) / l_clearance) + 1
|
||||
#y_limit = int((lboard.GetHeight() + l_clearance) / l_clearance) + 1
|
||||
viasToRemove = []
|
||||
removed = False
|
||||
expansion = 1.6 # extra expansion to fix HitTest
|
||||
for pad in self.boardObj.GetPads():
|
||||
#wx.LogMessage(str(self.viaPointsSafe))
|
||||
#wx.LogMessage(str(pad.GetPosition()))
|
||||
#local_offset = max(pad.GetClearance(), self.clearance, max_target_area_clearance) + (self.size / 2)
|
||||
if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix:
|
||||
pad_clr = 0 # FIXME
|
||||
local_offset = max(pad_clr, self.clearance) + (self.viaSize / 2)
|
||||
else:
|
||||
local_offset = max(pad.GetClearance(), self.clearance) + (self.viaSize / 2)
|
||||
max_size = max(pad.GetSize().x, pad.GetSize().y)
|
||||
|
||||
#start_x = int(floor(((pad.GetPosition().x - (max_size / 2.0 + local_offset)) - origin.x) / l_clearance))
|
||||
#stop_x = int(ceil(((pad.GetPosition().x + (max_size / 2.0 + local_offset)) - origin.x) / l_clearance))
|
||||
|
||||
#start_y = int(floor(((pad.GetPosition().y - (max_size / 2.0 + local_offset)) - origin.y) / l_clearance))
|
||||
#stop_y = int(ceil(((pad.GetPosition().y + (max_size / 2.0 + local_offset)) - origin.y) / l_clearance))
|
||||
|
||||
#for x in range(start_x, stop_x + 1):
|
||||
# for y in range(start_y, stop_y + 1):
|
||||
for viaPos in self.viaPointsSafe:
|
||||
if 1: #try:
|
||||
#if isinstance(rectangle[x][y], ViaObject):
|
||||
#start_rect = wxPoint(origin.x + (l_clearance * x) - local_offset,
|
||||
# origin.y + (l_clearance * y) - local_offset)
|
||||
#start_rect = pcbnew.wxPoint(viaPos[0] + (l_clearance * viaPos[0]) - local_offset,
|
||||
# viaPos[1] + (l_clearance * viaPos[1]) - local_offset)
|
||||
start_rect = pcbnew.wxPoint(viaPos[0] - local_offset*expansion,
|
||||
viaPos[1] - local_offset*expansion)
|
||||
size_rect = pcbnew.wxSize(2 * expansion * local_offset, 2 * expansion * local_offset)
|
||||
wxLogDebug(str(pcbnew.ToMM(start_rect))+'::'+str(pcbnew.ToMM(size_rect)),debug)
|
||||
if pad.HitTest(pcbnew.EDA_RECT(start_rect, size_rect), False):
|
||||
#rectangle[x][y] = self.REASON_PAD
|
||||
wxLogDebug('Hit on Pad: viaPos:'+str(viaPos),debug)
|
||||
#self.viaPointsSafe.pop(i)
|
||||
#self.viaPointsSafe.remove(viaPos)
|
||||
viasToRemove.append(viaPos)
|
||||
removed = True
|
||||
#else:
|
||||
# viaPSafe.append(viaPos)
|
||||
else: #except:
|
||||
wx.LogMessage("exception on Processing all pads...")
|
||||
#i+=1
|
||||
#self.viaPointSafe = viaPSafe
|
||||
#wx.LogMessage(str(viasToRemove))
|
||||
newPoints = [p for p in self.viaPointsSafe if p not in viasToRemove]
|
||||
#wx.LogMessage(str(newPoints))
|
||||
#wx.LogMessage(str(len(newPoints)))
|
||||
self.viaPointsSafe = newPoints
|
||||
return removed
|
||||
|
||||
def checkTracks(self):
|
||||
##Check vias collisions with all tracks
|
||||
if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix:
|
||||
self.clearance = 0 #TBF
|
||||
else:
|
||||
self.clearance = self.boardObj.GetDesignSettings().GetDefault().GetClearance()
|
||||
#lboard = self.boardObj.ComputeBoundingBox(False)
|
||||
#origin = lboard.GetPosition()
|
||||
# Create an initial rectangle: all is set to "REASON_NO_SIGNAL"
|
||||
# get a margin to avoid out of range
|
||||
l_clearance = self.clearance + self.viaSize #+ self.size
|
||||
#wxLogDebug(str(l_clearance),True)
|
||||
#x_limit = int((lboard.GetWidth() + l_clearance) / l_clearance) + 1
|
||||
#y_limit = int((lboard.GetHeight() + l_clearance) / l_clearance) + 1
|
||||
viasToRemove = []
|
||||
removed = False
|
||||
expansion = 2 # extra expansion to fix HitTest
|
||||
for track in self.boardObj.GetTracks():
|
||||
#wx.LogMessage(str(self.viaPointsSafe))
|
||||
#wx.LogMessage(str(pad.GetPosition()))
|
||||
#local_offset = max(pad.GetClearance(), self.clearance, max_target_area_clearance) + (self.size / 2)
|
||||
if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix:
|
||||
trk_clr = 0 # FIXME
|
||||
#trk_clr = track.GetClearance()
|
||||
local_offset = max(trk_clr, self.clearance) + (self.viaSize / 2)
|
||||
else:
|
||||
local_offset = max(track.GetClearance(), self.clearance) + (self.viaSize / 2)
|
||||
#wxLogDebug(str(max_size),True)
|
||||
#max_size = max(pad.GetSize().x, pad.GetSize().y)
|
||||
|
||||
#start_x = int(floor(((pad.GetPosition().x - (max_size / 2.0 + local_offset)) - origin.x) / l_clearance))
|
||||
#stop_x = int(ceil(((pad.GetPosition().x + (max_size / 2.0 + local_offset)) - origin.x) / l_clearance))
|
||||
|
||||
#start_y = int(floor(((pad.GetPosition().y - (max_size / 2.0 + local_offset)) - origin.y) / l_clearance))
|
||||
#stop_y = int(ceil(((pad.GetPosition().y + (max_size / 2.0 + local_offset)) - origin.y) / l_clearance))
|
||||
|
||||
#for x in range(start_x, stop_x + 1):
|
||||
# for y in range(start_y, stop_y + 1):
|
||||
#wx.LogMessage(str(getTrackAngleRadians(track)))
|
||||
angle = abs(math.degrees(getTrackAngleRadians(track)))
|
||||
if (angle > 15 and angle <75) or (angle > 105 and angle <165) or (angle > 195 and angle <255) or (angle > 285 and angle <345):
|
||||
expansion = 1.4 # extra expansion to fix HitTest
|
||||
#wx.LogMessage(str(angle)+'::'+str(expansion))
|
||||
else:
|
||||
expansion = 2.0 # extra expansion to fix HitTest
|
||||
#wx.LogMessage(str(angle)+'::'+str(expansion))
|
||||
for viaPos in self.viaPointsSafe:
|
||||
if 1: #try:
|
||||
#if isinstance(rectangle[x][y], ViaObject):
|
||||
#start_rect = wxPoint(origin.x + (l_clearance * x) - local_offset,
|
||||
# origin.y + (l_clearance * y) - local_offset)
|
||||
#start_rect = pcbnew.wxPoint(viaPos[0] + (l_clearance * viaPos[0]) - local_offset,
|
||||
# viaPos[1] + (l_clearance * viaPos[1]) - local_offset)
|
||||
start_rect = pcbnew.wxPoint(viaPos[0] - local_offset*expansion,
|
||||
viaPos[1] - local_offset*expansion)
|
||||
size_rect = pcbnew.wxSize(2 * expansion * local_offset, 2 * expansion * local_offset)
|
||||
wxLogDebug(str(pcbnew.ToMM(start_rect))+'::'+str(pcbnew.ToMM(size_rect)),debug)
|
||||
#wxLogDebug(str(track.GetNetCode()),True)
|
||||
#wxLogDebug(str(self.viaNetId),True)
|
||||
#wxLogDebug(str(type(track)),True)
|
||||
if (hasattr(pcbnew,'DRAWSEGMENT')):
|
||||
trk_type = pcbnew.TRACK
|
||||
else:
|
||||
trk_type = pcbnew.PCB_TRACK
|
||||
if track.GetNetCode() != self.viaNetId or type(track) != trk_type: #PCB_VIA_T:
|
||||
#wxLogDebug('here',True)
|
||||
#if track.HitTest(pcbnew.EDA_RECT(start_rect, size_rect), False):
|
||||
aContained=False;aAccuracy=0
|
||||
if track.HitTest(pcbnew.EDA_RECT(start_rect, size_rect), aContained, aAccuracy):
|
||||
#rectangle[x][y] = self.REASON_PAD
|
||||
wxLogDebug('Hit on Track: viaPos:'+str(viaPos),debug)
|
||||
#self.viaPointsSafe.pop(i)
|
||||
#self.viaPointsSafe.remove(viaPos)
|
||||
viasToRemove.append(viaPos)
|
||||
removed = True
|
||||
#else:
|
||||
# viaPSafe.append(viaPos)
|
||||
else: #except:
|
||||
wx.LogMessage("exception on Processing all tracks...")
|
||||
#i+=1
|
||||
#self.viaPointSafe = viaPSafe
|
||||
#wx.LogMessage(str(viasToRemove))
|
||||
newPoints = [p for p in self.viaPointsSafe if p not in viasToRemove]
|
||||
#wx.LogMessage(str(newPoints))
|
||||
#wx.LogMessage(str(len(newPoints)))
|
||||
self.viaPointsSafe = newPoints
|
||||
return removed
|
||||
# ------------------------------------------------------------------------------------
|
||||
|
||||
def DoKeyPress(self, event):
|
||||
if event.GetKeyCode() == wx.WXK_RETURN:
|
||||
self.mainDlg.EndModal(wx.ID_OK)
|
||||
else:
|
||||
event.Skip()
|
||||
|
||||
def selfToMainDialog(self):
|
||||
self.mainDlg.lstLayer.SetItems(list(self.layerMap.values())) #maui
|
||||
self.mainDlg.lstLayer.SetSelection(self.layerId)
|
||||
self.mainDlg.txtNetFilter.SetItems(self.netFilterList)
|
||||
self.mainDlg.txtNetFilter.SetSelection(self.netFilterList.index(self.netFilter))
|
||||
self.mainDlg.txtViaOffset.SetValue(str(pcbnew.ToMM(self.viaOffset)))
|
||||
self.mainDlg.txtViaPitch.SetValue(str(pcbnew.ToMM(self.viaPitch)))
|
||||
self.mainDlg.txtViaDrill.SetValue(str(pcbnew.ToMM(self.viaDrill)))
|
||||
self.mainDlg.txtViaSize.SetValue(str(pcbnew.ToMM(self.viaSize)))
|
||||
self.mainDlg.txtViaOffset.Bind(wx.EVT_KEY_DOWN, self.DoKeyPress)
|
||||
#self.mainDlg.txtViaOffset.Bind(wx.EVT_TEXT_ENTER, self.mainDlg.EndModal(wx.ID_OK))
|
||||
self.mainDlg.txtViaPitch.Bind(wx.EVT_KEY_DOWN, self.DoKeyPress)
|
||||
self.mainDlg.txtViaDrill.Bind(wx.EVT_KEY_DOWN, self.DoKeyPress)
|
||||
self.mainDlg.txtViaSize.Bind(wx.EVT_KEY_DOWN, self.DoKeyPress)
|
||||
|
||||
self.mainDlg.lstViaNet.SetItems([item.GetNetname() for item in self.netMap.values()])
|
||||
for i, item in enumerate (self.netMap.values()):
|
||||
if self.mainDlg.lstViaNet.GetString(i) in ["GND", "/GND"]:
|
||||
self.mainDlg.lstViaNet.SetSelection(i)
|
||||
break
|
||||
if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix: #temporary_fix!!!
|
||||
self.mainDlg.chkNetFilter.Enable (False)
|
||||
self.mainDlg.chkNetFilter.SetValue(self.isNetFilterChecked)
|
||||
self.mainDlg.txtNetFilter.Enable(self.isNetFilterChecked)
|
||||
self.mainDlg.chkLayer.SetValue(self.isLayerChecked)
|
||||
self.mainDlg.lstLayer.Enable(self.isLayerChecked)
|
||||
self.mainDlg.chkIncludeDrawing.SetValue(self.isIncludeDrawingChecked)
|
||||
self.mainDlg.chkIncludeSelection.SetValue(self.isIncludeSelectionChecked)
|
||||
self.mainDlg.chkDebugDump.SetValue(self.isDebugDumpChecked)
|
||||
self.mainDlg.chkRemoveViasWithClearanceViolation.SetValue(self.isRemoveViasWithClearanceViolationChecked)
|
||||
self.mainDlg.chkSameNetZoneViasOnly.SetValue(self.isSameNetZoneViasOnlyChecked)
|
||||
self.mainDlg.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick)
|
||||
# hiding unimplemented controls
|
||||
#self.mainDlg.chkRemoveViasWithClearanceViolation.Hide()
|
||||
self.mainDlg.chkSameNetZoneViasOnly.Hide()
|
||||
|
||||
def mainDialogToSelf(self):
|
||||
self.netFilter = self.mainDlg.txtNetFilter.GetValue()
|
||||
if len(list(self.layerMap.keys())) > 0:
|
||||
self.layerId = list(self.layerMap.keys())[self.mainDlg.lstLayer.GetSelection()] #maui
|
||||
self.viaOffset = pcbnew.FromMM(float(self.mainDlg.txtViaOffset.GetValue().replace(',','.')))
|
||||
self.viaPitch = pcbnew.FromMM(float(self.mainDlg.txtViaPitch.GetValue().replace(',','.')))
|
||||
self.viaDrill = pcbnew.FromMM(float(self.mainDlg.txtViaDrill.GetValue().replace(',','.')))
|
||||
self.viaSize = pcbnew.FromMM(float(self.mainDlg.txtViaSize.GetValue().replace(',','.')))
|
||||
if len(list(self.netMap.keys())) > 0:
|
||||
self.viaNetId = list(self.netMap.keys())[self.mainDlg.lstViaNet.GetSelection()] #maui
|
||||
self.isNetFilterChecked = self.mainDlg.chkNetFilter.GetValue()
|
||||
self.isLayerChecked = self.mainDlg.chkLayer.GetValue()
|
||||
self.isIncludeDrawingChecked = self.mainDlg.chkIncludeDrawing.GetValue()
|
||||
self.isIncludeSelectionChecked = self.mainDlg.chkIncludeSelection.GetValue()
|
||||
self.isDebugDumpChecked = self.mainDlg.chkDebugDump.GetValue()
|
||||
self.isSameNetZoneViasOnlyChecked = self.mainDlg.chkSameNetZoneViasOnly.GetValue()
|
||||
self.isRemoveViasWithClearanceViolationChecked = self.mainDlg.chkRemoveViasWithClearanceViolation.GetValue()
|
||||
|
||||
def Run(self):
|
||||
#check for pyclipper lib
|
||||
pyclip = False
|
||||
try:
|
||||
import pyclipper
|
||||
pyclip = True
|
||||
# import pyclipper; pyclipper.__file__
|
||||
except:
|
||||
#error exception if pyclipper lib is missing
|
||||
import sys, os
|
||||
from sys import platform as _platform
|
||||
if sys.version_info.major == 2 and sys.version_info.minor == 7:
|
||||
if _platform == "linux" or _platform == "linux2":
|
||||
# linux
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)),'python-pyclipper','py2-7-linux-64'))
|
||||
elif _platform == "darwin":
|
||||
#osx
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)),'python-pyclipper','py2-7-mac-64'))
|
||||
else:
|
||||
#win
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)),'python-pyclipper','py2-7-win-64'))
|
||||
try:
|
||||
import pyclipper
|
||||
pyclip = True
|
||||
except:
|
||||
msg = u"\u2718 ERROR Missing KiCAD \'pyclipper\' python module:\nplease install it using pip\nin your KiCAD python environment.\n[You may need administrative rights]"
|
||||
wdlg = wx.MessageDialog(None, msg,'ERROR message',wx.OK | wx.ICON_WARNING)# wx.ICON_ERROR)
|
||||
result = wdlg.ShowModal()
|
||||
if pyclip:
|
||||
#import pyclipper
|
||||
import os
|
||||
#self.mainDlg = MainDialog(None)
|
||||
#self.selfToMainDialog()
|
||||
|
||||
self.boardObj = pcbnew.GetBoard()
|
||||
self.boardDesignSettingsObj = self.boardObj.GetDesignSettings()
|
||||
self.boardPath = os.path.dirname(os.path.realpath(self.boardObj.GetFileName()))
|
||||
self.layerMap = self.getLayerMap()
|
||||
if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix:
|
||||
self.highlightedNetId = -1
|
||||
# Nasty work around... GetHighLightNetCodes returns a swig object >_<
|
||||
# hl_nets = filter(lambda x: x.IsSelected(), self.boardObj.GetTracks())
|
||||
# hl_net_codes = set(net.GetNetCode() for net in hl_nets)
|
||||
# if len(hl_net_codes) == 1:
|
||||
# self.highlightedNetId = hl_net_codes.pop()
|
||||
# else:
|
||||
# wdlg = wx.MessageDialog(None, u"\u2718 ERROR Please only select one net",'ERROR message',wx.OK | wx.ICON_WARNING)# wx.ICON_ERROR)
|
||||
# result = wdlg.ShowModal()
|
||||
# return
|
||||
else:
|
||||
self.highlightedNetId = self.boardObj.GetHighLightNetCode()
|
||||
self.netMap = self.getNetMap()
|
||||
self.netFilterList = self.createNetFilterSuggestions()
|
||||
self.netFilter = self.netMap[self.highlightedNetId].GetNetname() if self.highlightedNetId != -1 else self.netFilterList[0]
|
||||
self.viaSize = self.boardDesignSettingsObj.GetCurrentViaSize()
|
||||
self.layerId = 0 #TODO: How to get currently selected layer?
|
||||
self.viaDrill = self.boardDesignSettingsObj.GetCurrentViaDrill()
|
||||
self.viaPitch = pcbnew.FromMM(1.3)
|
||||
self.viaOffset = pcbnew.FromMM(1.3)
|
||||
self.viaNetId = 0 #TODO: Maybe a better init value here. Try to find "GND" maybe?
|
||||
self.isNetFilterChecked = 1 if self.highlightedNetId != -1 else 0
|
||||
#if len(list(self.netMap.keys())) > 0:
|
||||
# self.viaNetId = list(self.netMap.keys())[self.mainDlg.lstViaNet.GetSelection()] #maui
|
||||
|
||||
self.isLayerChecked = 0
|
||||
self.isIncludeDrawingChecked = 0
|
||||
self.isIncludeSelectionChecked = 1
|
||||
self.isDebugDumpChecked = 0
|
||||
self.isRemoveViasWithClearanceViolationChecked = 1
|
||||
self.isSameNetZoneViasOnlyChecked = 0
|
||||
|
||||
self.mainDlg = MainDialog(None)
|
||||
self.selfToMainDialog()
|
||||
if hasattr(self.boardObj, 'm_Uuid'):
|
||||
self.mainDlg.m_buttonDelete.Disable()
|
||||
self.mainDlg.m_buttonDelete.SetToolTip( u"fencing vias are placed in a group,\nto delete fencing vias, just delete the group" )
|
||||
reply = self.mainDlg.ShowModal()
|
||||
if (reply == wx.ID_OK):
|
||||
# User pressed OK.
|
||||
# Assemble a list of pcbnew.BOARD_ITEMs derived objects that support GetStart/GetEnd and IsOnLayer
|
||||
self.mainDialogToSelf()
|
||||
lineObjects = []
|
||||
arcObjects = []
|
||||
|
||||
# creating a unique group for vias
|
||||
if not(hasattr(pcbnew,'DRAWSEGMENT')): #creating a group of fencing vias
|
||||
groupName = uuid.uuid4() #randomword(5)
|
||||
pcb_group = pcbnew.PCB_GROUP(None)
|
||||
pcb_group.SetName(groupName)
|
||||
self.boardObj.Add(pcb_group)
|
||||
|
||||
|
||||
# Do we want to include net tracks?
|
||||
if (self.isNetFilterChecked):
|
||||
# Find nets that match the generated regular expression and add their tracks to the list
|
||||
netRegex = self.regExFromSimpleEx(self.netFilter)
|
||||
for netId in self.netMap:
|
||||
if re.match(netRegex, self.netMap[netId].GetNetname()):
|
||||
for trackObject in self.boardObj.TracksInNet(netId):
|
||||
#wx.LogMessage('type '+str(trackObject.GetStart()))
|
||||
#wx.LogMessage('type '+str(trackObject.GetMid()))
|
||||
if (hasattr(pcbnew,'DRAWSEGMENT')):
|
||||
trk_type = pcbnew.TRACK
|
||||
else:
|
||||
trk_type = pcbnew.PCB_TRACK
|
||||
trk_arc = pcbnew.PCB_ARC
|
||||
if hasattr(trackObject,'GetMid()'):
|
||||
arcObjects += [trackObject]
|
||||
elif type(trackObject) is trk_type:
|
||||
lineObjects += [trackObject]
|
||||
|
||||
# wx.LogMessage('net selected '+str(lineObjects))
|
||||
# wx.LogMessage('net selected '+str(arcObjects))
|
||||
|
||||
# Do we want to include drawing segments?
|
||||
if (self.isIncludeDrawingChecked):
|
||||
boardItem = self.boardObj.GetDrawings().GetFirst()
|
||||
while boardItem is not None:
|
||||
if pcbnew.DRAWSEGMENT.ClassOf(boardItem):
|
||||
# A drawing segment (not a text or something else)
|
||||
drawingObject = boardItem.Cast()
|
||||
if drawingObject.GetShape() == pcbnew.S_SEGMENT:
|
||||
# A straight line
|
||||
lineObjects += [drawingObject]
|
||||
|
||||
boardItem = boardItem.Next()
|
||||
|
||||
# Do we want to include track segments?
|
||||
if (self.isIncludeSelectionChecked):
|
||||
if (hasattr(pcbnew,'DRAWSEGMENT')):
|
||||
trk_type = pcbnew.TRACK
|
||||
else:
|
||||
trk_type = pcbnew.PCB_TRACK
|
||||
trk_arc = pcbnew.PCB_ARC
|
||||
for item in self.boardObj.GetTracks():
|
||||
#wx.LogMessage('type track: %s' % str(type(item)))
|
||||
if not (hasattr(pcbnew,'DRAWSEGMENT')):
|
||||
if type(item) is trk_arc and item.IsSelected():
|
||||
wx.LogMessage('type track: %s' % str(type(item)))
|
||||
arcObjects += [item]
|
||||
if type(item) is trk_type and item.IsSelected():
|
||||
lineObjects += [item]
|
||||
|
||||
# Do we want to filter the generated lines by layer?
|
||||
if (self.isLayerChecked):
|
||||
# Filter by layer
|
||||
# TODO: Make layer selection also a regex
|
||||
lineObjects = [lineObject for lineObject in lineObjects if lineObject.IsOnLayer(self.layerId)]
|
||||
arcObjects = [arcObject for arcObject in arcObjects if arcObject.IsOnLayer(self.layerId)]
|
||||
#wx.LogMessage('arcs: %s' % str(arcObjects))
|
||||
|
||||
for arc in arcObjects:
|
||||
segNBR = 16
|
||||
start = arc.GetStart()
|
||||
end = arc.GetEnd()
|
||||
md = arc.GetMid()
|
||||
width = arc.GetWidth()
|
||||
layer = arc.GetLayerSet()
|
||||
netName = None
|
||||
cnt, rad = getCircleCenterRadius(start,end,md)
|
||||
pts = create_round_pts(start,end,cnt,rad,layer,width,netName,segNBR)
|
||||
self.pathListArcs = [[ [p.x, p.y],
|
||||
[pts[i+1].x, pts[i+1].y] ]
|
||||
for i,p in enumerate(pts[:-1])]
|
||||
# Generate via fence
|
||||
try:
|
||||
viaPointsArcs = []
|
||||
if len (arcObjects) > 0:
|
||||
viaPointsArcs = generateViaFence(self.pathListArcs, self.viaOffset, self.viaPitch)
|
||||
viaObjListArcs = self.createVias(viaPointsArcs, self.viaDrill, self.viaSize, self.viaNetId)
|
||||
for v in viaObjListArcs:
|
||||
pcb_group.AddItem(v)
|
||||
except Exception as exc:
|
||||
wx.LogMessage('exception on via fence generation: %s' % str(exc))
|
||||
import traceback
|
||||
wx.LogMessage(traceback.format_exc())
|
||||
viaPoints = []
|
||||
#wx.LogMessage('pL: %s' % str(self.pathListArcs))
|
||||
#wx.LogMessage('pts: %s' % str(pts))
|
||||
|
||||
# Generate a path list from the pcbnew.BOARD_ITEM objects
|
||||
self.pathList = [[ [lineObject.GetStart()[0], lineObject.GetStart()[1]],
|
||||
[lineObject.GetEnd()[0], lineObject.GetEnd()[1]] ]
|
||||
for lineObject in lineObjects]
|
||||
#wx.LogMessage('pL: %s' % str(self.pathList))
|
||||
|
||||
|
||||
# Generate via fence
|
||||
try:
|
||||
viaPointsArcs = []
|
||||
viaPoints = generateViaFence(self.pathList, self.viaOffset, self.viaPitch)
|
||||
#if len (arcObjects) > 0:
|
||||
# viaPointsArcs = generateViaFence(self.pathListArcs, self.viaOffset, self.viaPitch)
|
||||
except Exception as exc:
|
||||
wx.LogMessage('exception on via fence generation: %s' % str(exc))
|
||||
import traceback
|
||||
wx.LogMessage(traceback.format_exc())
|
||||
viaPoints = []
|
||||
|
||||
if (self.isDebugDumpChecked):
|
||||
self.viaPoints = viaPoints
|
||||
self.dumpJSON(os.path.join(self.boardPath, time.strftime("viafence-%Y%m%d-%H%M%S.json")))
|
||||
|
||||
removed = False
|
||||
if (self.isRemoveViasWithClearanceViolationChecked):
|
||||
#if self.mainDlg.chkRemoveViasWithClearanceViolation.GetValue():
|
||||
# Remove Vias that violate clearance to other things
|
||||
# Check against other tracks
|
||||
#wx.LogMessage('hereIam')
|
||||
# removing generated & colliding vias
|
||||
viaPointsSafe = []
|
||||
for i,v in enumerate(viaPoints):
|
||||
#clearance = v.GetClearance()
|
||||
collision_found = False
|
||||
tolerance = 1 + 0.2
|
||||
# This should be handled with Net Clearance
|
||||
for j, vn in enumerate(viaPoints[i+1:]):
|
||||
if distance (pcbnew.wxPoint(v[0], v[1]),pcbnew.wxPoint(vn[0], vn[1])) < int(self.viaSize*tolerance): # +clearance viasize+20%:
|
||||
collision_found = True
|
||||
if not collision_found:
|
||||
viaPointsSafe.append(v)
|
||||
self.viaPointsSafe = viaPointsSafe
|
||||
#wx.LogMessage(str(len(self.viaPointsSafe)))
|
||||
removed = self.checkPads()
|
||||
remvd = self.checkTracks()
|
||||
removed = removed or remvd
|
||||
else:
|
||||
self.viaPointsSafe = viaPoints
|
||||
#wx.LogMessage(str(len(self.viaPointsSafe)))
|
||||
#self.checkPads()
|
||||
#wx.LogMessage(str(len(self.viaPointsSafe)))
|
||||
viaObjList = self.createVias(self.viaPointsSafe, self.viaDrill, self.viaSize, self.viaNetId)
|
||||
# viaObjListArcs = []
|
||||
# if len (arcObjects) > 0:
|
||||
# viaObjListArcs = self.createVias(viaPointsArcs, self.viaDrill, self.viaSize, self.viaNetId)
|
||||
if not(hasattr(pcbnew,'DRAWSEGMENT')): #creating a group of fencing vias
|
||||
# groupName = uuid.uuid4() #randomword(5)
|
||||
# pcb_group = pcbnew.PCB_GROUP(None)
|
||||
# pcb_group.SetName(groupName)
|
||||
# self.boardObj.Add(pcb_group)
|
||||
for v in viaObjList:
|
||||
pcb_group.AddItem(v)
|
||||
#for v in viaObjListArcs:
|
||||
# pcb_group.AddItem(v)
|
||||
via_nbr = len(self.viaPointsSafe)
|
||||
via_nbr += len(viaPointsArcs)
|
||||
msg = u'Placed {0:} Fencing Vias.\n\u26A0 Please run a DRC check on your board.'.format(str(via_nbr))
|
||||
if removed:
|
||||
msg += u'\n\u281B Removed DRC colliding vias.'
|
||||
wx.LogMessage(msg)
|
||||
#viaObjList = self.createVias(viaPoints, self.viaDrill, self.viaSize, self.viaNetId)
|
||||
#via_nbr = len(viaPoints)
|
||||
|
||||
|
||||
elif (reply == wx.ID_DELETE):
|
||||
#user clicked ('Delete Fence Vias')
|
||||
target_tracks = filter(lambda x: ((x.Type() == pcbnew.PCB_VIA_T)and (x.GetTimeStamp() == 55)), self.boardObj.GetTracks())
|
||||
#wx.LogMessage(str(len(target_tracks)))
|
||||
target_tracks_cp = list(target_tracks)
|
||||
l = len (target_tracks_cp)
|
||||
for i in range(l):
|
||||
#if type(target_tracks_cp[i]) is PCB_TRACK and target_tracks_cp[i].IsSelected(): #item.GetNetname() == net_name:
|
||||
self.boardObj.RemoveNative(target_tracks_cp[i]) #removing via
|
||||
#for via in target_tracks:
|
||||
# #if via.GetTimeStamp() == 55:
|
||||
# self.boardObj.RemoveNative(via)
|
||||
# #wx.LogMessage('removing via')
|
||||
#pcbnew.Refresh()
|
||||
self.mainDlg.Destroy() #the Dlg needs to be destroyed to release pcbnew
|
||||
|
||||
# TODO: Implement
|
||||
# if (self.isRemoveViasWithClearanceViolationChecked):
|
||||
# # Remove Vias that violate clearance to other things
|
||||
# # Check against other tracks
|
||||
# for viaObj in viaObjList:
|
||||
# for track in self.boardObj.GetTracks():
|
||||
# clearance = track.GetClearance(viaObj)
|
||||
# if track.HitTest(False, clearance):
|
||||
# self.boardObj.RemoveNative(viaObj)
|
||||
|
||||
# TODO: Implement
|
||||
# if (self.isSameNetZoneViasOnlyChecked):
|
||||
# # Keep via only if it is in a filled zone with the same net
|
||||
|
||||
# import numpy as np
|
||||
# import matplotlib.pyplot as plt
|
||||
|
||||
# for path in self.pathList:
|
||||
# plt.plot(np.array(path).T[0], np.array(path).T[1], linewidth=2)
|
||||
# for via in viaPoints:
|
||||
# plt.plot(via[0], via[1], 'o', markersize=10)
|
||||
|
||||
|
||||
# plt.ylim(plt.ylim()[::-1])
|
||||
# plt.axes().set_aspect('equal','box')
|
||||
# plt.show()
|
||||
|
||||
226
kicad_plugins/via_fence_generator/viafence_basedialogs.py
Normal file
@@ -0,0 +1,226 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
###########################################################################
|
||||
## Python code generated with wxFormBuilder (version Oct 26 2018)
|
||||
## http://www.wxformbuilder.org/
|
||||
##
|
||||
## PLEASE DO *NOT* EDIT THIS FILE!
|
||||
###########################################################################
|
||||
|
||||
import wx
|
||||
import wx.xrc
|
||||
|
||||
###########################################################################
|
||||
## Class MainDialogBase
|
||||
###########################################################################
|
||||
|
||||
class MainDialogBase ( wx.Dialog ):
|
||||
|
||||
def __init__( self, parent ):
|
||||
wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Via Fence Generator", pos = wx.DefaultPosition, size = wx.Size( 503,567 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.RESIZE_BORDER )
|
||||
|
||||
import sys #maui
|
||||
if sys.version_info[0] == 2:
|
||||
self.SetSizeHintsSz( wx.Size( -1,-1 ), wx.Size( -1,-1 ) )
|
||||
else:
|
||||
self.SetSizeHints( wx.Size( -1,-1 ), wx.Size( -1,-1 ) )
|
||||
|
||||
mainSizer = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
gbSizer4 = wx.GridBagSizer( 0, 0 )
|
||||
gbSizer4.SetFlexibleDirection( wx.BOTH )
|
||||
gbSizer4.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED )
|
||||
|
||||
bSizer23 = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
sbSizer2 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"Via Settings" ), wx.VERTICAL )
|
||||
|
||||
fgSizer4 = wx.FlexGridSizer( 8, 2, 0, 0 )
|
||||
fgSizer4.AddGrowableCol( 1 )
|
||||
fgSizer4.SetFlexibleDirection( wx.BOTH )
|
||||
fgSizer4.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED )
|
||||
|
||||
self.m_staticText11 = wx.StaticText( sbSizer2.GetStaticBox(), wx.ID_ANY, u"Offset (mm):", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText11.Wrap( -1 )
|
||||
|
||||
fgSizer4.Add( self.m_staticText11, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
self.txtViaOffset = wx.TextCtrl( sbSizer2.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER|wx.TE_RIGHT )
|
||||
fgSizer4.Add( self.txtViaOffset, 0, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
self.m_staticText21 = wx.StaticText( sbSizer2.GetStaticBox(), wx.ID_ANY, u"Pitch (mm):", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText21.Wrap( -1 )
|
||||
|
||||
fgSizer4.Add( self.m_staticText21, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
self.txtViaPitch = wx.TextCtrl( sbSizer2.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER|wx.TE_RIGHT )
|
||||
fgSizer4.Add( self.txtViaPitch, 0, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
self.m_staticText13 = wx.StaticText( sbSizer2.GetStaticBox(), wx.ID_ANY, u"Via Drill (mm):", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText13.Wrap( -1 )
|
||||
|
||||
fgSizer4.Add( self.m_staticText13, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
self.txtViaDrill = wx.TextCtrl( sbSizer2.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER|wx.TE_RIGHT )
|
||||
fgSizer4.Add( self.txtViaDrill, 0, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
self.m_staticText14 = wx.StaticText( sbSizer2.GetStaticBox(), wx.ID_ANY, u"Via Size (mm):", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText14.Wrap( -1 )
|
||||
|
||||
fgSizer4.Add( self.m_staticText14, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
self.txtViaSize = wx.TextCtrl( sbSizer2.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER|wx.TE_RIGHT )
|
||||
fgSizer4.Add( self.txtViaSize, 0, wx.EXPAND|wx.ALL, 5 )
|
||||
|
||||
self.m_staticText23 = wx.StaticText( sbSizer2.GetStaticBox(), wx.ID_ANY, u"Via Net:", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.m_staticText23.Wrap( -1 )
|
||||
|
||||
fgSizer4.Add( self.m_staticText23, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
lstViaNetChoices = []
|
||||
self.lstViaNet = wx.Choice( sbSizer2.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, lstViaNetChoices, 0 )
|
||||
self.lstViaNet.SetSelection( 0 )
|
||||
fgSizer4.Add( self.lstViaNet, 1, wx.EXPAND|wx.ALL, 5 )
|
||||
|
||||
|
||||
sbSizer2.Add( fgSizer4, 1, wx.EXPAND, 5 )
|
||||
|
||||
|
||||
bSizer23.Add( sbSizer2, 1, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
|
||||
gbSizer4.Add( bSizer23, wx.GBPosition( 0, 0 ), wx.GBSpan( 1, 1 ), wx.EXPAND, 5 )
|
||||
|
||||
bSizer21 = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
|
||||
bSizer21.Add( ( 0, 9), 0, 0, 5 )
|
||||
|
||||
self.bmpViafence = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
bSizer21.Add( self.bmpViafence, 1, wx.EXPAND, 5 )
|
||||
|
||||
|
||||
gbSizer4.Add( bSizer21, wx.GBPosition( 0, 1 ), wx.GBSpan( 1, 1 ), wx.EXPAND|wx.ALL, 5 )
|
||||
|
||||
sbSizer411 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"Input Tracks" ), wx.VERTICAL )
|
||||
|
||||
gSizer4 = wx.GridSizer( 3, 1, 0, 0 )
|
||||
|
||||
self.chkIncludeSelection = wx.CheckBox( sbSizer411.GetStaticBox(), wx.ID_ANY, u"Include Selected", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.chkIncludeSelection.SetValue(True)
|
||||
gSizer4.Add( self.chkIncludeSelection, 0, wx.ALL, 5 )
|
||||
|
||||
self.chkIncludeDrawing = wx.CheckBox( sbSizer411.GetStaticBox(), wx.ID_ANY, u"Include Drawing Lines", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
gSizer4.Add( self.chkIncludeDrawing, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 5 )
|
||||
|
||||
fgSizer311 = wx.FlexGridSizer( 1, 2, 0, 10 )
|
||||
fgSizer311.AddGrowableCol( 1 )
|
||||
fgSizer311.SetFlexibleDirection( wx.HORIZONTAL )
|
||||
fgSizer311.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED )
|
||||
|
||||
self.chkNetFilter = wx.CheckBox( sbSizer411.GetStaticBox(), wx.ID_ANY, u"Net(s):", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
fgSizer311.Add( self.chkNetFilter, 0, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
txtNetFilterChoices = []
|
||||
self.txtNetFilter = wx.ComboBox( sbSizer411.GetStaticBox(), wx.ID_ANY, u"Combo!", wx.DefaultPosition, wx.DefaultSize, txtNetFilterChoices, 0 )
|
||||
self.txtNetFilter.Enable( False )
|
||||
|
||||
fgSizer311.Add( self.txtNetFilter, 1, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
|
||||
gSizer4.Add( fgSizer311, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
fgSizer31 = wx.FlexGridSizer( 1, 2, 0, 10 )
|
||||
fgSizer31.AddGrowableCol( 1 )
|
||||
fgSizer31.SetFlexibleDirection( wx.HORIZONTAL )
|
||||
fgSizer31.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED )
|
||||
|
||||
self.chkLayer = wx.CheckBox( sbSizer411.GetStaticBox(), wx.ID_ANY, u"Layer:", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
fgSizer31.Add( self.chkLayer, 1, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
lstLayerChoices = []
|
||||
self.lstLayer = wx.Choice( sbSizer411.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, lstLayerChoices, 0 )
|
||||
self.lstLayer.SetSelection( 0 )
|
||||
self.lstLayer.Enable( False )
|
||||
|
||||
fgSizer31.Add( self.lstLayer, 1, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
|
||||
gSizer4.Add( fgSizer31, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
|
||||
sbSizer411.Add( gSizer4, 0, wx.EXPAND, 5 )
|
||||
|
||||
|
||||
gbSizer4.Add( sbSizer411, wx.GBPosition( 1, 0 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
sbSizer4 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"Output VIAs" ), wx.VERTICAL )
|
||||
|
||||
gSizer2 = wx.GridSizer( 3, 1, 0, 0 )
|
||||
|
||||
self.chkSameNetZoneViasOnly = wx.CheckBox( sbSizer4.GetStaticBox(), wx.ID_ANY, u"Keep VIAs in \nVia Net zones only", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
gSizer2.Add( self.chkSameNetZoneViasOnly, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 )
|
||||
|
||||
self.chkRemoveViasWithClearanceViolation = wx.CheckBox( sbSizer4.GetStaticBox(), wx.ID_ANY, u"Remove VIAs violating \nclearance rules", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
gSizer2.Add( self.chkRemoveViasWithClearanceViolation, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT|wx.LEFT, 5 )
|
||||
|
||||
self.m_buttonDelete = wx.Button( sbSizer4.GetStaticBox(), wx.ID_ANY, u"Delete Vias", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
gSizer2.Add( self.m_buttonDelete, 0, wx.ALIGN_CENTER|wx.ALL, 5 )
|
||||
|
||||
|
||||
sbSizer4.Add( gSizer2, 1, wx.EXPAND, 5 )
|
||||
|
||||
|
||||
gbSizer4.Add( sbSizer4, wx.GBPosition( 1, 1 ), wx.GBSpan( 1, 1 ), wx.EXPAND|wx.ALL, 5 )
|
||||
|
||||
|
||||
gbSizer4.AddGrowableCol( 0 )
|
||||
|
||||
mainSizer.Add( gbSizer4, 1, wx.EXPAND, 5 )
|
||||
|
||||
bSizer5 = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
self.chkDebugDump = wx.CheckBox( self, wx.ID_ANY, u"Debug Dump", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
bSizer5.Add( self.chkDebugDump, 0, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
|
||||
bSizer5.Add( ( 0, 0), 1, wx.EXPAND, 5 )
|
||||
|
||||
m_sdbSizer1 = wx.StdDialogButtonSizer()
|
||||
self.m_sdbSizer1OK = wx.Button( self, wx.ID_OK )
|
||||
m_sdbSizer1.AddButton( self.m_sdbSizer1OK )
|
||||
self.m_sdbSizer1Cancel = wx.Button( self, wx.ID_CANCEL )
|
||||
m_sdbSizer1.AddButton( self.m_sdbSizer1Cancel )
|
||||
m_sdbSizer1.Realize();
|
||||
|
||||
bSizer5.Add( m_sdbSizer1, 0, wx.EXPAND|wx.ALL, 5 )
|
||||
|
||||
|
||||
mainSizer.Add( bSizer5, 0, wx.EXPAND, 5 )
|
||||
|
||||
|
||||
self.SetSizer( mainSizer )
|
||||
self.Layout()
|
||||
|
||||
self.Centre( wx.BOTH )
|
||||
|
||||
# Connect Events
|
||||
self.Bind( wx.EVT_INIT_DIALOG, self.OnInitDialog )
|
||||
self.chkNetFilter.Bind( wx.EVT_CHECKBOX, self.OnNetFilterCheckBox )
|
||||
self.chkLayer.Bind( wx.EVT_CHECKBOX, self.OnLayerCheckBox )
|
||||
|
||||
def __del__( self ):
|
||||
pass
|
||||
|
||||
|
||||
# Virtual event handlers, overide them in your derived class
|
||||
def OnInitDialog( self, event ):
|
||||
event.Skip()
|
||||
|
||||
def OnNetFilterCheckBox( self, event ):
|
||||
event.Skip()
|
||||
|
||||
def OnLayerCheckBox( self, event ):
|
||||
event.Skip()
|
||||
|
||||
|
||||
30
kicad_plugins/via_fence_generator/viafence_dialogs.py
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
from .viafence_basedialogs import *
|
||||
|
||||
class MainDialog(MainDialogBase):
|
||||
def __init__(self, parent):
|
||||
MainDialogBase.__init__(self, parent)
|
||||
# Small workaround to fix the paths generated by wxFormBuilder
|
||||
self.bmpViafence.SetBitmap(wx.Bitmap( os.path.join(os.path.dirname(os.path.realpath(__file__)), "resources", "viafence.png") ) )
|
||||
|
||||
def OnInitDialog(self, event):
|
||||
self.Layout()
|
||||
self.GetSizer().Fit(self)
|
||||
self.SetMinSize(self.GetSize())
|
||||
#self.SetMaxSize(self.GetSize())
|
||||
self.SetTitle(u"Via Fence Generator")
|
||||
if sys.version_info[0] == 2:
|
||||
self.chkDebugDump.SetToolTipString( u"Creates a json file in the same directory as the opened board file containing the tracks and settings" )
|
||||
else:
|
||||
self.chkDebugDump.SetToolTip( u"Creates a json file in the same directory as the opened board file containing the tracks and settings" )
|
||||
|
||||
|
||||
def OnNetFilterCheckBox(self, event):
|
||||
self.txtNetFilter.Enable(event.IsChecked())
|
||||
|
||||
def OnLayerCheckBox(self, event):
|
||||
self.lstLayer.Enable(event.IsChecked())
|
||||
|
||||