816 lines
22 KiB
C++
816 lines
22 KiB
C++
/*
|
|
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";
|
|
}
|
|
}
|