Add cpp dsn2pcb from upstream
parent
fe87698d35
commit
52774eab40
|
@ -0,0 +1,340 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) 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
|
||||
this service 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 make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. 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.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
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
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the 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 a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE 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.
|
||||
|
||||
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
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{description}
|
||||
Copyright (C) {year} {fullname}
|
||||
|
||||
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.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision 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, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
{signature of Ty Coon}, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This 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.
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
all: c_pcb c_pcb_dsn c_pcb_view
|
||||
|
||||
c_pcb: c_pcb.cpp mymath.cpp mymath.h router.cpp router.h layer.cpp layer.h io.h
|
||||
c++ -O2 --std=c++14 c_pcb.cpp router.cpp layer.cpp mymath.cpp -oc_pcb
|
||||
|
||||
c_pcb_dsn: c_pcb_dsn.cpp router.h mymath.h
|
||||
c++ -O2 --std=c++14 c_pcb_dsn.cpp -oc_pcb_dsn
|
||||
|
||||
c_pcb_view: c_pcb_view.cpp mymath.cpp mymath.h io.h
|
||||
c++ -O2 --std=c++14 `pkg-config --cflags glfw3` c_pcb_view.cpp mymath.cpp -oc_pcb_view `pkg-config --static --libs glfw3` -D GL_SILENCE_DEPRECATION
|
||||
|
||||
clean:
|
||||
rm c_pcb c_pcb_dsn c_pcb_view
|
|
@ -0,0 +1,815 @@
|
|||
/*
|
||||
C-PCB
|
||||
Copyright (C) 2015 Chris Hinsley
|
||||
chris (dot) hinsley (at) gmail (dot) com
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "router.h"
|
||||
#include "math.h"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
struct tree
|
||||
{
|
||||
std::string m_value;
|
||||
std::vector <tree> m_branches;
|
||||
};
|
||||
|
||||
struct pin
|
||||
{
|
||||
std::string m_name;
|
||||
std::string m_form;
|
||||
double m_x;
|
||||
double m_y;
|
||||
double m_angle;
|
||||
};
|
||||
|
||||
struct component
|
||||
{
|
||||
std::string m_name;
|
||||
std::map<std::string, pin> m_pin_map;
|
||||
};
|
||||
|
||||
struct instance
|
||||
{
|
||||
std::string m_name;
|
||||
std::string m_comp;
|
||||
std::string m_side;
|
||||
double m_x;
|
||||
double m_y;
|
||||
double m_angle;
|
||||
};
|
||||
|
||||
struct rule
|
||||
{
|
||||
double m_radius;
|
||||
double m_gap;
|
||||
};
|
||||
|
||||
struct circuit
|
||||
{
|
||||
std::string m_via;
|
||||
rule m_rule;
|
||||
};
|
||||
|
||||
struct padstack
|
||||
{
|
||||
points_2d m_shape;
|
||||
rule m_rule;
|
||||
};
|
||||
|
||||
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems)
|
||||
{
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, delim))
|
||||
{
|
||||
elems.push_back(item);
|
||||
}
|
||||
return elems;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(const std::string &s, char delim)
|
||||
{
|
||||
std::vector<std::string> elems;
|
||||
split(s, delim, elems);
|
||||
return elems;
|
||||
}
|
||||
|
||||
auto shape_to_cords(const points_2d &shape, double a1, double a2)
|
||||
{
|
||||
auto cords = points_2d{};
|
||||
auto rads = fmod(a1+a2, 2*M_PI);
|
||||
auto s = sin(rads);
|
||||
auto c = cos(rads);
|
||||
for (auto &p : shape)
|
||||
{
|
||||
auto px = double(c*p.m_x - s*p.m_y);
|
||||
auto py = double(s*p.m_x + c*p.m_y);
|
||||
cords.push_back(point_2d{px, py});
|
||||
}
|
||||
return cords;
|
||||
}
|
||||
|
||||
//read input till given byte appears
|
||||
auto read_until(std::istream &in, char c)
|
||||
{
|
||||
char input;
|
||||
while (in.get(input))
|
||||
{
|
||||
if (input == c) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//read whitespace
|
||||
auto read_whitespace(std::istream &in)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
auto b = in.peek();
|
||||
if (b != '\t' && b != '\n' && b != '\r' && b != ' ') break;
|
||||
char c;
|
||||
in.get(c);
|
||||
}
|
||||
}
|
||||
|
||||
auto read_node_name(std::istream &in)
|
||||
{
|
||||
std::string s;
|
||||
for (;;)
|
||||
{
|
||||
auto b = in.peek();
|
||||
if (b == '\t' || b == '\n' || b == '\r' || b == ' ' || b == ')') break;
|
||||
char c;
|
||||
in.get(c);
|
||||
s.push_back(c);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
auto read_string(std::istream &in)
|
||||
{
|
||||
std::string s;
|
||||
for (;;)
|
||||
{
|
||||
auto b = in.peek();
|
||||
if (b == '\t' || b == '\n' || b == '\r' || b == ' ' || b == ')') break;
|
||||
char c;
|
||||
in.get(c);
|
||||
s.push_back(c);
|
||||
}
|
||||
return tree{s, {}};
|
||||
}
|
||||
|
||||
auto read_quoted_string(std::istream &in)
|
||||
{
|
||||
std::string s;
|
||||
for (;;)
|
||||
{
|
||||
auto b = in.peek();
|
||||
if (b == '"') break;
|
||||
char c;
|
||||
in.get(c);
|
||||
s.push_back(c);
|
||||
}
|
||||
return tree{s, {}};
|
||||
}
|
||||
|
||||
tree read_tree(std::istream &in)
|
||||
{
|
||||
read_until(in, '(');
|
||||
read_whitespace(in);
|
||||
auto t = tree{read_node_name(in), {}};
|
||||
for (;;)
|
||||
{
|
||||
read_whitespace(in);
|
||||
auto b = in.peek();
|
||||
char c;
|
||||
if (b == EOF) break;
|
||||
if (b == ')')
|
||||
{
|
||||
in.get(c);
|
||||
break;
|
||||
}
|
||||
if (b == '(')
|
||||
{
|
||||
t.m_branches.push_back(read_tree(in));
|
||||
continue;
|
||||
}
|
||||
if (b == '"')
|
||||
{
|
||||
in.get(c);
|
||||
t.m_branches.push_back(read_quoted_string(in));
|
||||
in.get(c);
|
||||
continue;
|
||||
}
|
||||
t.m_branches.push_back(read_string(in));
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
tree *search_tree(tree &t, const char *s)
|
||||
{
|
||||
if (t.m_value == s) return &t;
|
||||
for (auto &ct : t.m_branches)
|
||||
{
|
||||
auto st = search_tree(ct, s);
|
||||
if (st != nullptr) return st;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void print_tree(const tree &t, int indent)
|
||||
{
|
||||
if (!t.m_value.empty())
|
||||
{
|
||||
for (auto i = 0; i < indent; ++i) std::cout << " ";
|
||||
std::cout << t.m_value << '\n';
|
||||
}
|
||||
for (auto &ct : t.m_branches) print_tree(ct, indent+1);
|
||||
}
|
||||
|
||||
void ss_reset(std::stringstream &ss, const std::string &s)
|
||||
{
|
||||
ss.str(s);
|
||||
ss.clear();
|
||||
}
|
||||
|
||||
void get_value(std::stringstream &ss, std::vector<tree>::iterator t, int &x)
|
||||
{
|
||||
ss_reset(ss, t->m_value);
|
||||
ss >> x;
|
||||
}
|
||||
|
||||
void get_value(std::stringstream &ss, std::vector<tree>::iterator t, double &x)
|
||||
{
|
||||
ss_reset(ss, t->m_value);
|
||||
ss >> x;
|
||||
}
|
||||
|
||||
void get_2d(std::stringstream &ss, std::vector<tree>::iterator t, double &x, double &y)
|
||||
{
|
||||
get_value(ss, t, x);
|
||||
get_value(ss, t + 1, y);
|
||||
}
|
||||
|
||||
void get_rect(std::stringstream &ss, std::vector<tree>::iterator t, double &x1, double &y1, double &x2, double &y2)
|
||||
{
|
||||
get_2d(ss, t, x1, y1);
|
||||
get_2d(ss, t + 2, x2, y2);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
//process comand args
|
||||
auto use_file = false;
|
||||
std::ifstream arg_infile;
|
||||
auto arg_b = 1;
|
||||
|
||||
std::stringstream ss;
|
||||
for (auto i = 1; i < argc; ++i)
|
||||
{
|
||||
if (argv[i][0] == '-')
|
||||
{
|
||||
//option
|
||||
std::string opt = argv[i];
|
||||
while (!opt.empty() && opt[0] == '-') opt.erase(0, 1);
|
||||
if (++i >= argc) goto help;
|
||||
ss_reset(ss, argv[i]);
|
||||
if (opt == "b") ss >> arg_b;
|
||||
else
|
||||
{
|
||||
help:
|
||||
std::cout << "c_pcb_dsn [switches] [filename]\neg. c_pcb_dsn -b 6 test1.dsn\n";
|
||||
std::cout << "reads from stdin if no filename.\n";
|
||||
std::cout << "-b: border gap, default 1\n";
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//filename
|
||||
arg_infile.open(argv[i], std::ifstream::in);
|
||||
use_file = true;
|
||||
}
|
||||
}
|
||||
|
||||
//reading from stdin or file
|
||||
std::istream &in = use_file ? arg_infile : std::cin;
|
||||
|
||||
//create tree from input
|
||||
auto tree = read_tree(in);
|
||||
|
||||
auto structure_root = search_tree(tree, "structure");
|
||||
auto layer_to_index_map = std::map<std::string, int>{};
|
||||
auto layer_to_keepout_map = std::map<std::string, paths>{};
|
||||
const auto units = 1000.0;
|
||||
auto num_layers = 0;
|
||||
auto minx = double(1000000.0);
|
||||
auto miny = double(1000000.0);
|
||||
auto maxx = double(-1000000.0);
|
||||
auto maxy = double(-1000000.0);
|
||||
auto default_rule = rule{0.25, 0.25};
|
||||
auto default_via = std::string{"Via[0-1]_600:400_um"};
|
||||
auto track_id = 0;
|
||||
for (auto &&structure_node : structure_root->m_branches)
|
||||
{
|
||||
if (structure_node.m_value == "layer")
|
||||
{
|
||||
num_layers++;
|
||||
auto layer_index = 0;
|
||||
auto layer_name = structure_node.m_branches[0].m_value;
|
||||
for (auto &&layer_node : structure_node.m_branches)
|
||||
{
|
||||
if (layer_node.m_value == "property")
|
||||
{
|
||||
for (auto &&property_node : layer_node.m_branches)
|
||||
{
|
||||
if (property_node.m_value == "index")
|
||||
{
|
||||
get_value(ss, begin(property_node.m_branches), layer_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
layer_to_index_map[layer_name] = layer_index;
|
||||
}
|
||||
else if (structure_node.m_value == "via")
|
||||
{
|
||||
for (auto &&via_node : structure_node.m_branches)
|
||||
{
|
||||
default_via = via_node.m_value;
|
||||
}
|
||||
}
|
||||
else if (structure_node.m_value == "rule")
|
||||
{
|
||||
for (auto &&rule_node : structure_node.m_branches)
|
||||
{
|
||||
if (rule_node.m_value == "width")
|
||||
{
|
||||
get_value(ss, begin(rule_node.m_branches), default_rule.m_radius);
|
||||
default_rule.m_radius /= (2 * units);
|
||||
}
|
||||
else if ((rule_node.m_value == "clear"
|
||||
|| rule_node.m_value == "clearance")
|
||||
&& rule_node.m_branches.size() == 1)
|
||||
{
|
||||
get_value(ss, begin(rule_node.m_branches), default_rule.m_gap);
|
||||
default_rule.m_gap /= (2 * units);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (structure_node.m_value == "boundary")
|
||||
{
|
||||
for (auto &&boundary_node : structure_node.m_branches)
|
||||
{
|
||||
if (boundary_node.m_value == "path")
|
||||
{
|
||||
for (auto cords = begin(boundary_node.m_branches) + 2;
|
||||
cords != end(boundary_node.m_branches); cords += 2)
|
||||
{
|
||||
double px, py;
|
||||
get_2d(ss, cords, px, py);
|
||||
px /= units;
|
||||
py /= -units;
|
||||
minx = std::min(px, minx);
|
||||
maxx = std::max(px, maxx);
|
||||
miny = std::min(py, miny);
|
||||
maxy = std::max(py, maxy);
|
||||
}
|
||||
}
|
||||
else if (boundary_node.m_value == "rect")
|
||||
{
|
||||
double x1, y1, x2, y2;
|
||||
get_rect(ss, begin(boundary_node.m_branches) + 1, x1, y1, x2, y2);
|
||||
x1 /= units;
|
||||
y1 /= -units;
|
||||
x2 /= units;
|
||||
y2 /= -units;
|
||||
minx = std::min(x1, minx);
|
||||
maxx = std::max(x1, maxx);
|
||||
miny = std::min(y1, miny);
|
||||
maxy = std::max(y1, maxy);
|
||||
minx = std::min(x2, minx);
|
||||
maxx = std::max(x2, maxx);
|
||||
miny = std::min(y2, miny);
|
||||
maxy = std::max(y2, maxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (structure_node.m_value == "keepout")
|
||||
{
|
||||
for (auto &&keepout_node : structure_node.m_branches)
|
||||
{
|
||||
if (keepout_node.m_value == "polygon")
|
||||
{
|
||||
auto layer = keepout_node.m_branches[0].m_value;
|
||||
auto p = path{};
|
||||
for (auto cords = begin(keepout_node.m_branches) + 2;
|
||||
cords != end(keepout_node.m_branches); cords += 2)
|
||||
{
|
||||
double px, py;
|
||||
get_2d(ss, cords, px, py);
|
||||
px /= units;
|
||||
py /= -units;
|
||||
p.emplace_back(point_3d(px, py, 0.0));
|
||||
minx = std::min(px, minx);
|
||||
maxx = std::max(px, maxx);
|
||||
miny = std::min(py, miny);
|
||||
maxy = std::max(py, maxy);
|
||||
}
|
||||
p.push_back(p.front());
|
||||
layer_to_keepout_map[layer].push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto library_root = search_tree(tree, "library");
|
||||
auto name_to_component_map = std::map<std::string, component>{};
|
||||
auto name_to_padstack_map = std::map<std::string, std::map<int, padstack>>{};
|
||||
for (auto &&library_node : library_root->m_branches)
|
||||
{
|
||||
if (library_node.m_value == "image")
|
||||
{
|
||||
auto component_name = library_node.m_branches[0].m_value;
|
||||
auto the_comp = component{component_name, std::map<std::string, pin>{}};
|
||||
for (auto image_node = begin(library_node.m_branches) + 1;
|
||||
image_node != end(library_node.m_branches); ++image_node)
|
||||
{
|
||||
if (image_node->m_value == "pin")
|
||||
{
|
||||
auto the_pin = pin{};
|
||||
the_pin.m_form = image_node->m_branches[0].m_value;
|
||||
if (image_node->m_branches[1].m_value == "rotate")
|
||||
{
|
||||
get_value(ss, begin(image_node->m_branches[1].m_branches), the_pin.m_angle);
|
||||
the_pin.m_name = image_node->m_branches[2].m_value;
|
||||
get_2d(ss, begin(image_node->m_branches) + 3, the_pin.m_x, the_pin.m_y);
|
||||
the_pin.m_angle *= (M_PI / 180.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
the_pin.m_angle = 0.0;
|
||||
the_pin.m_name = image_node->m_branches[1].m_value;
|
||||
get_2d(ss, begin(image_node->m_branches) + 2, the_pin.m_x, the_pin.m_y);
|
||||
}
|
||||
the_pin.m_x /= units;
|
||||
the_pin.m_y /= -units;
|
||||
the_comp.m_pin_map[the_pin.m_name] = the_pin;
|
||||
}
|
||||
}
|
||||
name_to_component_map[component_name] = the_comp;
|
||||
}
|
||||
else if (library_node.m_value == "padstack")
|
||||
{
|
||||
for (auto padstack_node = begin(library_node.m_branches) + 1;
|
||||
padstack_node != end(library_node.m_branches); ++padstack_node)
|
||||
{
|
||||
if (padstack_node->m_value == "shape")
|
||||
{
|
||||
auto points = points_2d{};
|
||||
auto the_rule = default_rule;
|
||||
if (padstack_node->m_branches[0].m_value == "circle")
|
||||
{
|
||||
get_value(ss, begin(padstack_node->m_branches[0].m_branches) + 1, the_rule.m_radius);
|
||||
the_rule.m_radius /= (2 * units);
|
||||
}
|
||||
else if (padstack_node->m_branches[0].m_value == "path")
|
||||
{
|
||||
get_value(ss, begin(padstack_node->m_branches[0].m_branches) + 1, the_rule.m_radius);
|
||||
the_rule.m_radius /= (2 * units);
|
||||
double x1, y1, x2, y2;
|
||||
get_rect(ss, begin(padstack_node->m_branches[0].m_branches) + 2, x1, y1, x2, y2);
|
||||
if (x1 != 0.0
|
||||
|| x2 != 0.0
|
||||
|| y1 != 0.0
|
||||
|| y2 != 0.0)
|
||||
{
|
||||
x1 /= units;
|
||||
y1 /= -units;
|
||||
x2 /= units;
|
||||
y2 /= -units;
|
||||
points.push_back(point_2d{x1, y1});
|
||||
points.push_back(point_2d{x2, y2});
|
||||
}
|
||||
}
|
||||
else if (padstack_node->m_branches[0].m_value == "rect")
|
||||
{
|
||||
the_rule.m_radius = 0.0;
|
||||
double x1, y1, x2, y2;
|
||||
get_rect(ss, begin(padstack_node->m_branches[0].m_branches) + 1, x1, y1, x2, y2);
|
||||
x1 /= units;
|
||||
y1 /= -units;
|
||||
x2 /= units;
|
||||
y2 /= -units;
|
||||
points.push_back(point_2d{x1, y1});
|
||||
points.push_back(point_2d{x2, y1});
|
||||
points.push_back(point_2d{x2, y2});
|
||||
points.push_back(point_2d{x1, y2});
|
||||
points.push_back(point_2d{x1, y1});
|
||||
}
|
||||
else if (padstack_node->m_branches[0].m_value == "polygon")
|
||||
{
|
||||
the_rule.m_radius = 0.0;
|
||||
for (auto poly_node = begin(padstack_node->m_branches[0].m_branches) + 2;
|
||||
poly_node != end(padstack_node->m_branches[0].m_branches); poly_node += 2)
|
||||
{
|
||||
double x1, y1;
|
||||
get_2d(ss, poly_node, x1, y1);
|
||||
x1 /= units;
|
||||
y1 /= -units;
|
||||
points.push_back(point_2d{x1, y1});
|
||||
}
|
||||
points.push_back(points.front());
|
||||
}
|
||||
auto layer_index = layer_to_index_map[padstack_node->m_branches[0].m_branches[0].m_value];
|
||||
name_to_padstack_map[library_node.m_branches[0].m_value][layer_index] = padstack{points, the_rule};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto placement_root = search_tree(tree, "placement");
|
||||
auto name_to_instance_map = std::map<std::string, instance>{};
|
||||
for (auto &&placement_node : placement_root->m_branches)
|
||||
{
|
||||
if (placement_node.m_value == "component")
|
||||
{
|
||||
auto component_name = placement_node.m_branches[0].m_value;
|
||||
for (auto component_node = begin(placement_node.m_branches) + 1;
|
||||
component_node != end(placement_node.m_branches); ++component_node)
|
||||
{
|
||||
if (component_node->m_value == "place")
|
||||
{
|
||||
auto the_instance = instance{};
|
||||
auto instance_name = component_node->m_branches[0].m_value;
|
||||
the_instance.m_name = instance_name;
|
||||
the_instance.m_comp = component_name;
|
||||
get_2d(ss, begin(component_node->m_branches) + 1, the_instance.m_x, the_instance.m_y);
|
||||
the_instance.m_side = component_node->m_branches[3].m_value;
|
||||
get_value(ss, begin(component_node->m_branches) + 4, the_instance.m_angle);
|
||||
the_instance.m_angle *= -(M_PI / 180.0);
|
||||
the_instance.m_x /= units;
|
||||
the_instance.m_y /= -units;
|
||||
name_to_instance_map[instance_name] = the_instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto all_pads = pads{};
|
||||
for (auto &&inst : name_to_instance_map)
|
||||
{
|
||||
auto instance = inst.second;
|
||||
auto component = name_to_component_map[instance.m_comp];
|
||||
for (auto &&p : component.m_pin_map)
|
||||
{
|
||||
auto pin = p.second;
|
||||
auto m_x = pin.m_x;
|
||||
auto m_y = pin.m_y;
|
||||
if (instance.m_side != "front") m_x = -m_x;
|
||||
auto s = sin(instance.m_angle);
|
||||
auto c = cos(instance.m_angle);
|
||||
auto px = double((c*m_x - s*m_y) + instance.m_x);
|
||||
auto py = double((s*m_x + c*m_y) + instance.m_y);
|
||||
for (auto &&p : name_to_padstack_map[pin.m_form])
|
||||
{
|
||||
auto tp = point_3d{px, py, (double)p.first};
|
||||
auto cords = shape_to_cords(p.second.m_shape, pin.m_angle, instance.m_angle);
|
||||
all_pads.push_back(pad{p.second.m_rule.m_radius, p.second.m_rule.m_gap, tp, cords});
|
||||
for (auto &&p1 : cords)
|
||||
{
|
||||
auto x = p1.m_x + px;
|
||||
auto y = p1.m_y + py;
|
||||
minx = std::min(x - p.second.m_rule.m_radius - p.second.m_rule.m_gap, minx);
|
||||
maxx = std::max(x + p.second.m_rule.m_radius + p.second.m_rule.m_gap, maxx);
|
||||
miny = std::min(y - p.second.m_rule.m_radius - p.second.m_rule.m_gap, miny);
|
||||
maxy = std::max(y + p.second.m_rule.m_radius + p.second.m_rule.m_gap, maxy);
|
||||
}
|
||||
minx = std::min(px - p.second.m_rule.m_radius - p.second.m_rule.m_gap, minx);
|
||||
maxx = std::max(px + p.second.m_rule.m_radius + p.second.m_rule.m_gap, maxx);
|
||||
miny = std::min(py - p.second.m_rule.m_radius - p.second.m_rule.m_gap, miny);
|
||||
maxy = std::max(py + p.second.m_rule.m_radius + p.second.m_rule.m_gap, maxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto network_root = search_tree(tree, "network");
|
||||
auto name_to_circuit_map = std::map<std::string, circuit>{};
|
||||
for (auto &&network_node : network_root->m_branches)
|
||||
{
|
||||
if (network_node.m_value == "class")
|
||||
{
|
||||
auto the_circuit = circuit{default_via, default_rule};
|
||||
for (auto &&class_node : network_node.m_branches)
|
||||
{
|
||||
if (class_node.m_value == "rule")
|
||||
{
|
||||
for (auto &&dims : class_node.m_branches)
|
||||
{
|
||||
if (dims.m_value == "width")
|
||||
{
|
||||
get_value(ss, begin(dims.m_branches), the_circuit.m_rule.m_radius);
|
||||
the_circuit.m_rule.m_radius /= (2 * units);
|
||||
}
|
||||
else if ((dims.m_value == "clearance"
|
||||
|| dims.m_value == "clear")
|
||||
&& dims.m_branches.size() == 1)
|
||||
{
|
||||
get_value(ss, begin(dims.m_branches), the_circuit.m_rule.m_gap);
|
||||
the_circuit.m_rule.m_gap /= (2 * units);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (class_node.m_value == "circuit")
|
||||
{
|
||||
for (auto &&circuit_node : class_node.m_branches)
|
||||
{
|
||||
if (circuit_node.m_value == "use_via")
|
||||
{
|
||||
the_circuit.m_via = circuit_node.m_branches[0].m_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto &&netname : network_node.m_branches)
|
||||
{
|
||||
if (netname.m_branches.empty()) name_to_circuit_map[netname.m_value] = the_circuit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto wiring_root = search_tree(tree, "wiring");
|
||||
auto net_to_wires_map = std::map<std::string, paths>{};
|
||||
for (auto &&wiring_node : wiring_root->m_branches)
|
||||
{
|
||||
if (wiring_node.m_value == "wire")
|
||||
{
|
||||
auto z = 0.0;
|
||||
auto radius = 0.0;
|
||||
auto wire = path{};
|
||||
for (auto &&wire_node : wiring_node.m_branches)
|
||||
{
|
||||
if (wire_node.m_value == "path"
|
||||
|| wire_node.m_value == "polyline_path")
|
||||
{
|
||||
z = layer_to_index_map[wire_node.m_branches[0].m_value];
|
||||
get_value(ss, begin(wire_node.m_branches) + 1, radius);
|
||||
radius /= (2 * units);
|
||||
|
||||
for (auto poly_node = begin(wire_node.m_branches) + 2;
|
||||
poly_node != end(wire_node.m_branches); poly_node += 2)
|
||||
{
|
||||
double x, y;
|
||||
get_2d(ss, poly_node, x, y);
|
||||
x /= units;
|
||||
y /= -units;
|
||||
wire.push_back(point_3d(x, y, z));
|
||||
minx = std::min(x, minx);
|
||||
maxx = std::max(x, maxx);
|
||||
miny = std::min(y, miny);
|
||||
maxy = std::max(y, maxy);
|
||||
}
|
||||
}
|
||||
else if (wire_node.m_value == "net")
|
||||
{
|
||||
net_to_wires_map[wire_node.m_branches[0].m_value].emplace_back(std::move(wire));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (wiring_node.m_value == "via")
|
||||
{
|
||||
double x, y;
|
||||
get_2d(ss, begin(wiring_node.m_branches) + 1, x, y);
|
||||
x /= units;
|
||||
y /= -units;
|
||||
minx = std::min(x, minx);
|
||||
maxx = std::max(x, maxx);
|
||||
miny = std::min(y, miny);
|
||||
maxy = std::max(y, maxy);
|
||||
|
||||
for (auto wire_node = begin(wiring_node.m_branches) + 3;
|
||||
wire_node != end(wiring_node.m_branches); ++wire_node)
|
||||
{
|
||||
if (wire_node->m_value == "net")
|
||||
{
|
||||
net_to_wires_map[wire_node->m_branches[0].m_value].emplace_back(
|
||||
path{point_3d{x, y, 0}, point_3d{x, y, double(num_layers - 1)}});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto the_tracks = tracks{};
|
||||
for (auto &&network_node : network_root->m_branches)
|
||||
{
|
||||
if (network_node.m_value == "net")
|
||||
{
|
||||
for (auto &net_node : network_node.m_branches)
|
||||
{
|
||||
if (net_node.m_value == "pins")
|
||||
{
|
||||
auto the_pads = pads{};
|
||||
for (auto &&p : net_node.m_branches)
|
||||
{
|
||||
auto pin_info = split(p.m_value, '-');
|
||||
auto instance_name = pin_info[0];
|
||||
auto pin_name = pin_info[1];
|
||||
auto instance = name_to_instance_map[instance_name];
|
||||
auto component = name_to_component_map[instance.m_comp];
|
||||
auto pin = component.m_pin_map[pin_name];
|
||||
auto m_x = pin.m_x;
|
||||
auto m_y = pin.m_y;
|
||||
if (instance.m_side != "front") m_x = -m_x;
|
||||
auto s = sin(instance.m_angle);
|
||||
auto c = cos(instance.m_angle);
|
||||
auto px = double((c*m_x - s*m_y) + instance.m_x);
|
||||
auto py = double((s*m_x + c*m_y) + instance.m_y);
|
||||
for (auto &&p : name_to_padstack_map[pin.m_form])
|
||||
{
|
||||
auto tp = point_3d{px, py, (double)p.first};
|
||||
auto cords = shape_to_cords(p.second.m_shape, pin.m_angle, instance.m_angle);
|
||||
auto term = pad{p.second.m_rule.m_radius, p.second.m_rule.m_gap, tp, cords};
|
||||
the_pads.push_back(term);
|
||||
all_pads.erase(std::find(begin(all_pads), end(all_pads), term));
|
||||
}
|
||||
}
|
||||
auto &&net_name = network_node.m_branches[0].m_value;
|
||||
auto &&net = name_to_circuit_map[net_name];
|
||||
auto track_rule = net.m_rule;
|
||||
auto via_rule = name_to_padstack_map[net.m_via][0].m_rule;
|
||||
the_tracks.push_back(track{std::to_string(track_id++), track_rule.m_radius, via_rule.m_radius, track_rule.m_gap,
|
||||
the_pads, net_to_wires_map[net_name]});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//unused pads and the keepouts
|
||||
auto all_keepouts = paths{};
|
||||
for (auto &&k : layer_to_keepout_map)
|
||||
{
|
||||
if (k.first == "signal")
|
||||
{
|
||||
for (auto &&l : layer_to_index_map)
|
||||
{
|
||||
auto z = (double)l.second;
|
||||
for (auto &&p : k.second)
|
||||
{
|
||||
for (auto &&c : p) c.m_z = z;
|
||||
all_keepouts.push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto z = (double)layer_to_index_map[k.first];
|
||||
for (auto &&p : k.second)
|
||||
{
|
||||
for (auto &&c : p) c.m_z = z;
|
||||
all_keepouts.push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
the_tracks.push_back(track{std::to_string(track_id++), 0.0, 0.0, 0.0, all_pads, all_keepouts});
|
||||
|
||||
//output pcb format
|
||||
auto border = double(arg_b);
|
||||
std::cout << "(" << maxx - minx + border * 2
|
||||
<< " " << maxy - miny + border * 2
|
||||
<< " " << num_layers << ")\n";
|
||||
minx -= border;
|
||||
miny -= border;
|
||||
for (auto &&track : the_tracks)
|
||||
{
|
||||
std::cout << "(" << track.m_id << " " << track.m_track_radius << " "
|
||||
<< track.m_via_radius << " " << track.m_gap << " (";
|
||||
for (auto i = 0; i < static_cast<int>(track.m_pads.size()); ++i)
|
||||
{
|
||||
auto &&term = track.m_pads[i];
|
||||
std::cout << "(" << term.m_radius << " " << term.m_gap
|
||||
<< " (" << term.m_pos.m_x - minx
|
||||
<< " " << term.m_pos.m_y - miny
|
||||
<< " " << term.m_pos.m_z << ") (";
|
||||
for (auto j = 0; j < static_cast<int>(term.m_shape.size()); ++j)
|
||||
{
|
||||
auto cord = term.m_shape[j];
|
||||
std::cout << "(" << cord.m_x << " " << cord.m_y << ")";
|
||||
}
|
||||
std::cout << "))";
|
||||
}
|
||||
std::cout << ") (";
|
||||
for (auto i = 0; i < static_cast<int>(track.m_paths.size()); ++i)
|
||||
{
|
||||
std::cout << "(";
|
||||
auto &&p = track.m_paths[i];
|
||||
for (auto j = 0; j < static_cast<int>(p.size()); ++j)
|
||||
{
|
||||
std::cout << "(" << p[j].m_x - minx
|
||||
<< " " << p[j].m_y - miny
|
||||
<< " " << p[j].m_z << ")";
|
||||
}
|
||||
std::cout << ")";
|
||||
}
|
||||
std::cout << "))\n";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
C-PCB
|
||||
Copyright (C) 2015 Chris Hinsley
|
||||
chris (dot) hinsley (at) gmail (dot) com
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef LAYER_H
|
||||
#define LAYER_H
|
||||
|
||||
#include "mymath.h"
|
||||
#include <memory>
|
||||
|
||||
extern double length_2d(const point_2d &p);
|
||||
extern double det_2d(const point_2d &p1, const point_2d &p2);
|
||||
extern double dot_2d(const point_2d &p1, const point_2d &p2);
|
||||
extern point_2d sub_2d(const point_2d &p1, const point_2d &p2);
|
||||
extern point_2d perp_2d(const point_2d &p);
|
||||
extern point_2d scale_2d(const point_2d &p, double s);
|
||||
extern bool collide_thick_lines_2d(const point_2d &tl1_p1, const point_2d &tl1_p2,
|
||||
const point_2d &tl2_p1, const point_2d &tl2_p2, double r);
|
||||
|
||||
//layer class
|
||||
class layer
|
||||
{
|
||||
public:
|
||||
struct dims
|
||||
{
|
||||
int m_width;
|
||||
int m_height;
|
||||
};
|
||||
|
||||
struct line
|
||||
{
|
||||
bool operator==(const line &l) const
|
||||
{
|
||||
return std::tie(m_p1, m_p2, m_radius, m_gap) == std::tie(l.m_p1, l.m_p2, l.m_radius, l.m_gap);
|
||||
}
|
||||
point_2d m_p1;
|
||||
point_2d m_p2;
|
||||
double m_radius;
|
||||
double m_gap;
|
||||
};
|
||||
|
||||
struct record
|
||||
{
|
||||
record(int id, const line &l)
|
||||
: m_id(id)
|
||||
, m_line(l)
|
||||
{
|
||||
auto pv = perp_2d(sub_2d(l.m_p2, l.m_p1));
|
||||
auto len = length_2d(pv);
|
||||
m_lv_norm = scale_2d(pv, 1.0 / len);
|
||||
m_lv_dist = dot_2d(m_lv_norm, l.m_p1);
|
||||
|
||||
m_pv_norm = perp_2d(m_lv_norm);
|
||||
m_pv_dist1 = dot_2d(m_pv_norm, l.m_p1);
|
||||
m_pv_dist2 = m_pv_dist1 - len;
|
||||
}
|
||||
auto hit(const line &l, double d)
|
||||
{
|
||||
auto dp1 = dot_2d(m_lv_norm, l.m_p1) - m_lv_dist;
|
||||
auto dp2 = dot_2d(m_lv_norm, l.m_p2) - m_lv_dist;
|
||||
if (dp1 > d && dp2 > d) return false;
|
||||
if (dp1 < -d && dp2 < -d) return false;
|
||||
|
||||
dp1 = dot_2d(m_pv_norm, l.m_p1);
|
||||
dp2 = dot_2d(m_pv_norm, l.m_p2);
|
||||
if (dp1 - m_pv_dist1 > d && dp2 - m_pv_dist1 > d) return false;
|
||||
if (dp1 - m_pv_dist2 < -d && dp2 - m_pv_dist2 < -d) return false;
|
||||
|
||||
return collide_thick_lines_2d(l.m_p1, l.m_p2, m_line.m_p1, m_line.m_p2, d);
|
||||
}
|
||||
int m_id;
|
||||
line m_line;
|
||||
point_2d m_lv_norm;
|
||||
double m_lv_dist;
|
||||
|
||||
point_2d m_pv_norm;
|
||||
double m_pv_dist1;
|
||||
double m_pv_dist2;
|
||||
};
|
||||
|
||||
struct aabb
|
||||
{
|
||||
int m_minx;
|
||||
int m_miny;
|
||||
int m_maxx;
|
||||
int m_maxy;
|
||||
};
|
||||
|
||||
typedef std::vector<std::shared_ptr<record>> bucket;
|
||||
typedef std::vector<bucket> buckets;
|
||||
|
||||
layer(const dims &dims, double s);
|
||||
~layer();
|
||||
aabb get_aabb(const line &l);
|
||||
void add_line(const line &l);
|
||||
void sub_line(const line &l);
|
||||
bool hit_line(const line &l);
|
||||
|
||||
private:
|
||||
int m_width;
|
||||
int m_height;
|
||||
double m_scale;
|
||||
buckets m_buckets;
|
||||
int m_test;
|
||||
};
|
||||
|
||||
//layers class
|
||||
class layers
|
||||
{
|
||||
public:
|
||||
struct dims
|
||||
{
|
||||
int m_width;
|
||||
int m_height;
|
||||
int m_depth;
|
||||
};
|
||||
|
||||
struct line
|
||||
{
|
||||
point_3d m_p1;
|
||||
point_3d m_p2;
|
||||
double m_radius;
|
||||
double m_gap;
|
||||
};
|
||||
|
||||
layers(const dims &dims, double s);
|
||||
~layers();
|
||||
void add_line(const point_3d &p1, const point_3d &p2, double r, double g);
|
||||
void sub_line(const point_3d &p1, const point_3d &p2, double r, double g);
|
||||
bool hit_line(const point_3d &p1, const point_3d &p2, double r, double g);
|
||||
void add_line(const line &l);
|
||||
void sub_line(const line &l);
|
||||
bool hit_line(const line &l);
|
||||
|
||||
private:
|
||||
int m_depth;
|
||||
std::vector<std::shared_ptr<layer>> m_layers;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
C-PCB
|
||||
Copyright (C) 2015 Chris Hinsley
|
||||
chris (dot) hinsley (at) gmail (dot) com
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef MYMATH_H
|
||||
#define MYMATH_H
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
//public math structures
|
||||
|
||||
struct point_2d
|
||||
{
|
||||
point_2d() : m_x(0.0), m_y(0.0) {}
|
||||
point_2d(double x, double y) : m_x(x), m_y(y) {}
|
||||
bool operator==(const point_2d &p) const {
|
||||
return std::tie(m_x, m_y) == std::tie(p.m_x, p.m_y); }
|
||||
bool operator!=(const point_2d &p) const {
|
||||
return std::tie(m_x, m_y) != std::tie(p.m_x, p.m_y); }
|
||||
bool operator<(const point_2d &p) const {
|
||||
return std::tie(m_x, m_y) < std::tie(p.m_x, p.m_y); }
|
||||
double m_x;
|
||||
double m_y;
|
||||
};
|
||||
|
||||
typedef std::vector<point_2d> points_2d;
|
||||
|
||||
struct point_3d
|
||||
{
|
||||
point_3d() : m_x(0.0), m_y(0.0), m_z(0.0) {}
|
||||
point_3d(double x, double y, double z) : m_x(x), m_y(y), m_z(z) {}
|
||||
bool operator==(const point_3d &p) const {
|
||||
return std::tie(m_x, m_y, m_z) == std::tie(p.m_x, p.m_y, p.m_z); }
|
||||
bool operator!=(const point_3d &p) const {
|
||||
return std::tie(m_x, m_y, m_z) != std::tie(p.m_x, p.m_y, p.m_z); }
|
||||
bool operator<(const point_3d &p) const {
|
||||
return std::tie(m_x, m_y, m_z) < std::tie(p.m_x, p.m_y, p.m_z); }
|
||||
double m_x;
|
||||
double m_y;
|
||||
double m_z;
|
||||
};
|
||||
|
||||
typedef std::vector<point_3d> points_3d;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
C-PCB
|
||||
Copyright (C) 2015 Chris Hinsley
|
||||
chris (dot) hinsley (at) gmail (dot) com
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef ROUTER_H
|
||||
#define ROUTER_H
|
||||
|
||||
#include "mymath.h"
|
||||
#include "layer.h"
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
class pcb;
|
||||
class net;
|
||||
|
||||
struct pad
|
||||
{
|
||||
bool operator==(const pad &t) const {
|
||||
return std::tie(m_radius, m_gap, m_pos, m_shape)
|
||||
== std::tie(t.m_radius, t.m_gap, t.m_pos, t.m_shape); }
|
||||
bool operator<(const pad &t) const { return m_pos < t.m_pos; }
|
||||
double m_radius;
|
||||
double m_gap;
|
||||
point_3d m_pos;
|
||||
points_2d m_shape;
|
||||
};
|
||||
typedef std::vector<pad> pads;
|
||||
|
||||
//grid node and collections
|
||||
struct node
|
||||
{
|
||||
bool operator<(const node &n) const {
|
||||
return std::tie(m_x, m_y, m_z) < std::tie(n.m_x, n.m_y, n.m_z); }
|
||||
bool operator==(const node &n) const {
|
||||
return std::tie(m_x, m_y, m_z) == std::tie(n.m_x, n.m_y, n.m_z); }
|
||||
int manhattan_distance(const node &n) const
|
||||
{
|
||||
auto dx = m_x - n.m_x;
|
||||
auto dy = m_y - n.m_y;
|
||||
auto dz = m_z - n.m_z;
|
||||
return std::abs(dx) + std::abs(dy) + std::abs(dz);
|
||||
}
|
||||
int euclidian_distance(const node &n) const
|
||||
{
|
||||
auto dx = m_x - n.m_x;
|
||||
auto dy = m_y - n.m_y;
|
||||
auto dz = m_z - n.m_z;
|
||||
return int(sqrt(dx * dx + dy * dy + dz * dz));
|
||||
}
|
||||
int squared_euclidian_distance(const node &n) const
|
||||
{
|
||||
auto dx = m_x - n.m_x;
|
||||
auto dy = m_y - n.m_y;
|
||||
auto dz = m_z - n.m_z;
|
||||
return int(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
node mid(const node &n) const
|
||||
{
|
||||
return node{(m_x + n.m_x)/2, (m_y + n.m_y)/2, (m_z + n.m_z)/2};
|
||||
}
|
||||
int m_x;
|
||||
int m_y;
|
||||
int m_z;
|
||||
};
|
||||
typedef std::vector<node> nodes;
|
||||
typedef std::vector<nodes> nodess;
|
||||
typedef std::set<node> node_set;
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<node>
|
||||
{
|
||||
auto operator()(const node& n) const
|
||||
{
|
||||
return (std::hash<int>()(n.m_x)
|
||||
^ std::hash<int>()(n.m_y)
|
||||
^ std::hash<int>()(n.m_z));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//netlist structures
|
||||
typedef std::vector<point_3d> path;
|
||||
typedef std::vector<path> paths;
|
||||
|
||||
struct track
|
||||
{
|
||||
std::string m_id;
|
||||
double m_track_radius;
|
||||
double m_via_radius;
|
||||
double m_gap;
|
||||
pads m_pads;
|
||||
paths m_paths;
|
||||
};
|
||||
typedef std::vector<track> tracks;
|
||||
|
||||
typedef std::vector<net> nets;
|
||||
typedef double (*dfunc_t)(const point_3d &, const point_3d &);
|
||||
|
||||
//net object
|
||||
class net
|
||||
{
|
||||
public:
|
||||
net(const track &t, pcb *pcb);
|
||||
bool route();
|
||||
void print_net();
|
||||
void remove();
|
||||
void shuffle_topology();
|
||||
|
||||
int m_area;
|
||||
double m_radius;
|
||||
paths m_wires;
|
||||
nodess m_paths;
|
||||
std::vector<layers::line> m_paths_collision_lines;
|
||||
pads m_pads;
|
||||
std::vector<layers::line> m_pad_collision_lines;
|
||||
std::vector<nodes> m_pad_end_nodes;
|
||||
std::vector<layers::line> m_wire_collision_lines;
|
||||
node_set m_wire_nodes;
|
||||
layer::aabb m_bbox;
|
||||
|
||||
private:
|
||||
void add_pad_collision_lines();
|
||||
void sub_pad_collision_lines();
|
||||
void add_wire_collision_lines();
|
||||
void sub_wire_collision_lines();
|
||||
std::vector<layers::line> paths_collision_lines() const;
|
||||
void add_paths_collision_lines();
|
||||
void sub_paths_collision_lines();
|
||||
nodess optimise_paths(const nodess &paths);
|
||||
std::pair<nodes, bool> backtrack_path(const node_set &vis, const node &end,
|
||||
double radius, double via, double gap);
|
||||
|
||||
pcb *m_pcb;
|
||||
std::string m_id;
|
||||
double m_via;
|
||||
double m_gap;
|
||||
};
|
||||
|
||||
//pcb class
|
||||
class pcb
|
||||
{
|
||||
public:
|
||||
//dimensions of pcb board in grid points/layers
|
||||
struct dims
|
||||
{
|
||||
double m_width;
|
||||
double m_height;
|
||||
double m_depth;
|
||||
};
|
||||
|
||||
pcb(const dims &dims, const nodess &rfvs, const nodess &rpvs,
|
||||
int res, int verb, int quant, int viascost);
|
||||
~pcb();
|
||||
auto get_node(const node &n);
|
||||
void add_track(track &t);
|
||||
bool route(double timeout);
|
||||
int cost();
|
||||
void increase_quantization();
|
||||
void print_pcb();
|
||||
void print_netlist();
|
||||
void print_stats();
|
||||
point_3d node_to_point(const node &n);
|
||||
node point_to_node(const point_3d &p);
|
||||
point_3d node_to_pad_point(const node &n);
|
||||
node pad_point_to_node(const point_3d &p);
|
||||
nodes &all_marked(const nodess &vec, const node &n);
|
||||
nodes &all_not_shorting(const nodes &gather, const node &n, double radius, double gap);
|
||||
nodes &all_not_shorting_via(const nodes &gather, const node &n, double radius, double gap);
|
||||
void mark_distances(double radius, double via, double gap,
|
||||
const node_set &starts, const nodes &ends, const node &mid, double mid_scale);
|
||||
void unmark_distances();
|
||||
|
||||
int m_resolution;
|
||||
int m_quantization;
|
||||
int m_depth;
|
||||
int m_viascost;
|
||||
std::map<node, point_3d> m_deform;
|
||||
layers m_layers;
|
||||
layers m_via_layers;
|
||||
nodess m_routing_flood_vectors;
|
||||
nodess m_routing_path_vectors;
|
||||
|
||||
private:
|
||||
void set_node(const node &n, unsigned int value);
|
||||
nodes &all_not_marked(const nodess &vec, const node &n);
|
||||
void reset_areas();
|
||||
void shuffle_netlist();
|
||||
int hoist_net(int n);
|
||||
void remove_netlist();
|
||||
|
||||
int m_width;
|
||||
int m_height;
|
||||
int m_stride;
|
||||
int m_verbosity;
|
||||
nets m_netlist;
|
||||
std::vector<int> m_nodes;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue