/*
* hyp2mat - convert hyperlynx files to matlab scripts
* Copyright 2012 Koen De Vleeschauwer.
*
* This file is part of hyp2mat.
*
* 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 .
*/
#include
#include
#include
#include "hypfile.h"
using namespace std;
using namespace HypFile;
/*
* Hyperlynx 'BOARD_FILE' section.
* Hyperlynx file header.
*/
bool HypFile::Hyp::exec_board_file(parse_param& h)
{
if (trace_hyp) cerr << "board_file" << endl;
return false;
}
/*
* Hyperlynx 'VERSION' record.
* Specifies version number.
* Required record; must be first record of the file.
*/
bool HypFile::Hyp::exec_version(parse_param& h)
{
if (trace_hyp) cerr << "version: vers = " << h.vers << endl;
if (h.vers < 2.0) error("warning: version 1.x deprecated");
return false;
}
/*
* Hyperlynx 'DATA_MODE' record.
* Specifies whether data is sufficient for power simulation.
*/
bool HypFile::Hyp::exec_data_mode(parse_param& h)
{
if (trace_hyp) cerr << "data_mode: detailed = " << h.detailed << endl;
return false;
}
/*
* Hyperlynx 'UNITS' record.
* Specifies measurement system (english/metric) for the rest of the file.
*/
bool HypFile::Hyp::exec_units(parse_param& h)
{
if (trace_hyp) cerr << "units: unit_system_english = " << h.unit_system_english << " metal_thickness_weight = " << h.metal_thickness_weight << endl;
// convert everything to meter
if (h.unit_system_english) {
unit = inches; // lengths in inches. 1 in = 2.54 cm = 0.0254 m
if (h.metal_thickness_weight)
metal_thickness_unit = copper_imperial_weight * unit; // metal thickness in ounces/ft2. 1 oz/ft2 copper = 1.341 mil
else
metal_thickness_unit = unit; // metal thickness in inches
}
else {
unit = 0.01; // lengths in centimeters. 1 cm = 0.01 m
if (h.metal_thickness_weight)
metal_thickness_unit = copper_metric_weight * unit; // metal thickness in grams/cm2. 1 gr/cm2 copper = 0.1116 cm
else
metal_thickness_unit = unit; // metal thickness in centimeters
}
return false;
}
/*
* Hyperlynx 'PLANE_SEP' record.
* Defines default trace to plane separation
*/
bool HypFile::Hyp::exec_plane_sep(parse_param& h)
{
if (trace_hyp) cerr << "plane_sep: default_plane_separation = " << h.default_plane_separation << endl;
board.plane_separation = h.default_plane_separation * unit;
return false;
}
/*
* Hyperlynx 'PERIMETER_SEGMENT' subrecord of 'BOARD' record.
* Draws linear board outline segment.
*/
bool HypFile::Hyp::exec_perimeter_segment(parse_param& h)
{
if (trace_hyp) cerr << "perimeter_segment: x1 = " << h.x1 << " y1 = " << h.y1 << " x2 = " << h.x2 << " y2 = " << h.y2 << endl;
Polygon poly;
h.x1 *= unit;
h.y1 *= unit;
h.x2 *= unit;
h.y2 *= unit;
poly.width = 0;
poly.positive = true;
poly.vertex.push_back(Point(h.x1, h.y1));
poly.vertex.push_back(Point(h.x2, h.y2));
// Add segment to board outline
add_perimeter_polygon(poly);
return false;
}
/*
* Hyperlynx 'PERIMETER_ARC' subrecord of 'BOARD' record.
* Draws arc segment of board outline.
*/
bool HypFile::Hyp::exec_perimeter_arc(parse_param& h)
{
if (trace_hyp) cerr << "perimeter_arc: x1 = " << h.x1 << " y1 = " << h.y1 << " x2 = " << h.x2 << " y2 = " << h.y2 << " xc = " << h.xc << " yc = " << h.yc << " r = " << h.r << endl;
Polygon poly;
h.x1 *= unit;
h.y1 *= unit;
h.x2 *= unit;
h.y2 *= unit;
h.xc *= unit;
h.yc *= unit;
h.r *= unit;
poly = arc2poly(h.x1, h.y1, h.x2, h.y2, h.xc, h.yc, h.r, false); // 'PERIMETER_ARC' draws arc counterclockwise
// Add arc to board outline
add_perimeter_polygon(poly);
return false;
}
/*
* Hyperlynx 'A' attribute subrecord of 'BOARD' record.
* Defines board attributes as name/value pairs.
*/
bool HypFile::Hyp::exec_board_attribute(parse_param& h)
{
if (trace_hyp) cerr << "board_attribute: name = " << h.name << " value = " << h.value << endl;
Attribute a;
a.name = h.name;
a.value = h.value;
board.attribute.push_back(a);
return false;
}
/*
* Add a polygon to the board outline
*/
void HypFile::Hyp::add_perimeter_polygon(Polygon new_segment)
{
// Note first polygon of board perimeter is the board outline, and positive.
// Subsequent polygons are board cutouts, and negative.
// safety check
if (new_segment.vertex.empty())
return;
if (new_segment.vertex.size() == 1) {
error("runt perimeter segment");
return;
}
/* add new segment to list of PERIMETER_SEGMENT and PERIMETER_ARC segments */
board.segments.push_back(new_segment);
/* re-calculate board edge
* loop over the list of segments, trying to re-construct the
* board edge piece by piece. */
board.edge.clear();
PolygonList segs = board.segments;
Polygon current_edge;
bool found = false;
do {
found = false;
/* find segment to add to existing edge */
for (PolygonList::iterator i = segs.begin(); i != segs.end(); ++i) {
if (current_edge.vertex.empty() || (i->vertex.front() == current_edge.vertex.back())) {
/* first point of segment is last point of current edge: add segment to edge */
found = true;
current_edge.vertex.insert(current_edge.vertex.end(), i->vertex.begin(), i->vertex.end());
}
else if (i->vertex.back() == current_edge.vertex.back()) {
/* last point of segment is last point of current edge: add segment to edge back to front */
found = true;
current_edge.vertex.insert(current_edge.vertex.end(), i->vertex.rbegin(), i->vertex.rend());
};
if (found) {
/* erase added segment from list of unused segments */
segs.erase(i);
/* check if current edge is closed */
if (current_edge.vertex.front() == current_edge.vertex.back()) {
/* store old edge, begin new one */
current_edge.positive = false;
board.edge.push_back(current_edge);
current_edge.vertex.clear();
}
break;
}
}
} while (found);
/* only first polygon of board perimeter is positive, rest are holes. */
if (!board.edge.empty()) board.edge.front().positive = true;
return;
}
/* not truncated */