freerouting/src/main/java/eu/mihosoft/freerouting/designformats/specctra/Wiring.java

787 lines
29 KiB
Java

/*
* Copyright (C) 2014 Alfons Wirtz
* website www.freerouting.net
*
* 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 at <http://www.gnu.org/licenses/>
* for more details.
*
* Wiring.java
*
* Created on 24. Mai 2004, 07:20
*/
package designformats.specctra;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Iterator;
import datastructures.UndoableObjects;
import geometry.planar.FloatPoint;
import geometry.planar.Point;
import geometry.planar.IntBox;
import geometry.planar.IntPoint;
import geometry.planar.Line;
import geometry.planar.Polyline;
import board.RoutingBoard;
import board.Item;
import board.Via;
import board.Trace;
import board.PolylineTrace;
import board.FixedState;
import board.ItemSelectionFilter;
import datastructures.IndentFileWriter;
import datastructures.IdentifierType;
/**
* Class for reading and writing wiring scopes from dsn-files.
*
* @author Alfons Wirtz
*/
class Wiring extends ScopeKeyword
{
/** Creates a new instance of Wiring */
public Wiring()
{
super("wiring");
}
public boolean read_scope(ReadScopeParameter p_par)
{
Object next_token = null;
for (;;)
{
Object prev_token = next_token;
try
{
next_token = p_par.scanner.next_token();
}
catch (java.io.IOException e)
{
System.out.println("Wiring.read_scope: IO error scanning file");
return false;
}
if (next_token == null)
{
System.out.println("Wiring.read_scope: unexpected end of file");
return false;
}
if (next_token == CLOSED_BRACKET)
{
// end of scope
break;
}
boolean read_ok = true;
if (prev_token == OPEN_BRACKET)
{
if (next_token == Keyword.WIRE)
{
read_wire_scope(p_par);
}
else if (next_token == Keyword.VIA)
{
read_ok = read_via_scope(p_par);
}
else
{
skip_scope(p_par.scanner);
}
}
if (!read_ok)
{
return false;
}
}
RoutingBoard board = p_par.board_handling.get_routing_board();
for (int i = 1; i <= board.rules.nets.max_net_no(); ++i)
{
board.normalize_traces(i);
}
return true;
}
public static void write_scope(WriteScopeParameter p_par) throws java.io.IOException
{
p_par.file.start_scope();
p_par.file.write("wiring");
// write the wires
Collection<Trace> board_wires = p_par.board.get_traces();
Iterator<Trace> it = board_wires.iterator();
while (it.hasNext())
{
write_wire_scope(p_par, it.next());
}
Collection<Via> board_vias = p_par.board.get_vias();
for (Via curr_via : board_vias)
{
write_via_scope(p_par, curr_via);
}
// write the conduction areas
Iterator<UndoableObjects.UndoableObjectNode> it2 = p_par.board.item_list.start_read_object();
for(;;)
{
Object curr_ob = p_par.board.item_list.read_object(it2);
if (curr_ob == null)
{
break;
}
if (!(curr_ob instanceof board.ConductionArea))
{
continue;
}
board.ConductionArea curr_area = (board.ConductionArea) curr_ob;
if (!(p_par.board.layer_structure.arr [curr_area.get_layer()].is_signal))
{
// This conduction areas arw written in the structure scope.
continue;
}
write_conduction_area_scope(p_par, (board.ConductionArea) curr_ob);
}
p_par.file.end_scope();
}
private static void write_via_scope(WriteScopeParameter p_par, Via p_via) throws java.io.IOException
{
library.Padstack via_padstack = p_via.get_padstack();
FloatPoint via_location = p_via.get_center().to_float();
double [] via_coor = p_par.coordinate_transform.board_to_dsn(via_location);
int net_no;
rules.Net via_net;
if (p_via.net_count() > 0)
{
net_no = p_via.get_net_no(0);
via_net = p_par.board.rules.nets.get(net_no);
}
else
{
net_no = 0;
via_net = null;
}
p_par.file.start_scope();
p_par.file.write("via ");
p_par.identifier_type.write(via_padstack.name, p_par.file);
for (int i = 0; i < via_coor.length; ++i)
{
p_par.file.write(" ");
p_par.file.write((new Double(via_coor[i])).toString());
}
if (via_net != null)
{
write_net(via_net, p_par.file, p_par.identifier_type);
}
Rule.write_item_clearance_class(p_par.board.rules.clearance_matrix.get_name(p_via.clearance_class_no()),
p_par.file, p_par.identifier_type);
write_fixed_state(p_par.file, p_via.get_fixed_state());
p_par.file.end_scope();
}
private static void write_wire_scope(WriteScopeParameter p_par, Trace p_wire) throws java.io.IOException
{
if (!(p_wire instanceof PolylineTrace))
{
System.out.println("Wiring.write_wire_scope: trace type not yet implemented");
return;
}
PolylineTrace curr_wire = (PolylineTrace) p_wire;
int layer_no = curr_wire.get_layer();
board.Layer board_layer = p_par.board.layer_structure.arr[layer_no];
Layer curr_layer = new Layer(board_layer.name, layer_no, board_layer.is_signal);
double wire_width = p_par.coordinate_transform.board_to_dsn(2 * curr_wire.get_half_width());
rules.Net wire_net = null;
if (curr_wire.net_count() > 0)
{
wire_net = p_par.board.rules.nets.get(curr_wire.get_net_no(0));
}
if (wire_net == null)
{
System.out.println("Wiring.write_wire_scope: net not found");
return;
}
p_par.file.start_scope();
p_par.file.write("wire");
if(p_par.compat_mode)
{
Point[] corner_arr = curr_wire.polyline().corner_arr();
FloatPoint[] float_corner_arr = new FloatPoint [corner_arr.length];
for (int i = 0; i < corner_arr.length; ++i)
{
float_corner_arr[i] = corner_arr[i].to_float();
}
double [] coors = p_par.coordinate_transform.board_to_dsn(float_corner_arr);
PolygonPath curr_path = new PolygonPath(curr_layer, wire_width, coors);
curr_path.write_scope(p_par.file, p_par.identifier_type);
}
else
{
double [] coors = p_par.coordinate_transform.board_to_dsn(curr_wire.polyline().arr);
PolylinePath curr_path = new PolylinePath(curr_layer, wire_width, coors);
curr_path.write_scope(p_par.file, p_par.identifier_type);
}
write_net(wire_net, p_par.file, p_par.identifier_type);
Rule.write_item_clearance_class(p_par.board.rules.clearance_matrix.get_name(p_wire.clearance_class_no()),
p_par.file, p_par.identifier_type);
write_fixed_state(p_par.file, curr_wire.get_fixed_state());
p_par.file.end_scope();
}
private static void write_conduction_area_scope(WriteScopeParameter p_par, board.ConductionArea p_conduction_area) throws java.io.IOException
{
int net_count = p_conduction_area.net_count();
if (net_count <= 0 || net_count > 1)
{
System.out.println("Plane.write_scope: unexpected net count");
return;
}
rules.Net curr_net = p_par.board.rules.nets.get(p_conduction_area.get_net_no(0));
geometry.planar.Area curr_area = p_conduction_area.get_area();
int layer_no = p_conduction_area.get_layer();
board.Layer board_layer = p_par.board.layer_structure.arr[ layer_no];
Layer conduction_layer = new Layer(board_layer.name, layer_no, board_layer.is_signal);
geometry.planar.Shape boundary_shape;
geometry.planar.Shape [] holes;
if (curr_area instanceof geometry.planar.Shape)
{
boundary_shape = (geometry.planar.Shape) curr_area;
holes = new geometry.planar.Shape [0];
}
else
{
boundary_shape = curr_area.get_border();
holes = curr_area.get_holes();
}
p_par.file.start_scope();
p_par.file.write("wire ");
Shape dsn_shape = p_par.coordinate_transform.board_to_dsn(boundary_shape, conduction_layer);
if (dsn_shape != null)
{
dsn_shape.write_scope(p_par.file, p_par.identifier_type);
}
for (int i = 0; i < holes.length; ++i)
{
Shape dsn_hole = p_par.coordinate_transform.board_to_dsn(holes[i], conduction_layer);
dsn_hole.write_hole_scope(p_par.file, p_par.identifier_type);
}
write_net(curr_net, p_par.file, p_par.identifier_type);
Rule.write_item_clearance_class(p_par.board.rules.clearance_matrix.get_name(p_conduction_area.clearance_class_no()),
p_par.file, p_par.identifier_type);
p_par.file.end_scope();
}
static private void write_net(rules.Net p_net, IndentFileWriter p_file, IdentifierType p_identifier_type) throws java.io.IOException
{
p_file.new_line();
p_file.write("(");
Net.write_net_id(p_net, p_file, p_identifier_type);
p_file.write(")");
}
static private void write_fixed_state(IndentFileWriter p_file, FixedState p_fixed_state) throws java.io.IOException
{
if (p_fixed_state == FixedState.UNFIXED)
{
return;
}
p_file.new_line();
p_file.write("(type ");
if (p_fixed_state == FixedState.SHOVE_FIXED)
{
p_file.write("shove_fixed)");
}
else if (p_fixed_state == FixedState.SYSTEM_FIXED)
{
p_file.write("fix)");
}
else
{
p_file.write("protect)");
}
}
private Item read_wire_scope(ReadScopeParameter p_par)
{
Net.Id net_id = null;
String clearance_class_name = null;
board.FixedState fixed = board.FixedState.UNFIXED;
Path path = null; // Used, if a trace is read.
Shape border_shape = null; // Used, if a conduction area is read.
Collection<Shape> hole_list = new LinkedList<Shape>();
Object next_token = null;
for (;;)
{
Object prev_token = next_token;
try
{
next_token = p_par.scanner.next_token();
}
catch (java.io.IOException e)
{
System.out.println("Wiring.read_wire_scope: IO error scanning file");
return null;
}
if (next_token == null)
{
System.out.println("Wiring.read_wire_scope: unexpected end of file");
return null;
}
if (next_token == CLOSED_BRACKET)
{
// end of scope
break;
}
if (prev_token == OPEN_BRACKET)
{
if (next_token == Keyword.POLYGON_PATH)
{
path = Shape.read_polygon_path_scope(p_par.scanner, p_par.layer_structure);
}
else if (next_token == Keyword.POLYLINE_PATH)
{
path = Shape.read_polyline_path_scope(p_par.scanner, p_par.layer_structure);
}
else if (next_token == Keyword.RECTANGLE)
{
border_shape = Shape.read_rectangle_scope(p_par.scanner, p_par.layer_structure);
}
else if (next_token == Keyword.POLYGON)
{
border_shape = Shape.read_polygon_scope(p_par.scanner, p_par.layer_structure);
}
else if (next_token == Keyword.CIRCLE)
{
border_shape = Shape.read_circle_scope(p_par.scanner, p_par.layer_structure);
}
else if (next_token == Keyword.WINDOW)
{
Shape hole_shape = Shape.read_scope(p_par.scanner, p_par.layer_structure);
hole_list.add(hole_shape);
// overread the closing bracket
try
{
next_token = p_par.scanner.next_token();
}
catch (java.io.IOException e)
{
System.out.println("Wiring.read_wire_scope: IO error scanning file");
return null;
}
if (next_token != Keyword.CLOSED_BRACKET)
{
System.out.println("Wiring.read_wire_scope: closing bracket expected");
return null;
}
}
else if (next_token == Keyword.NET)
{
net_id = read_net_id(p_par.scanner);
}
else if (next_token == Keyword.CLEARANCE_CLASS)
{
clearance_class_name = DsnFile.read_string_scope(p_par.scanner);
}
else if (next_token == Keyword.TYPE)
{
fixed = calc_fixed(p_par.scanner);
}
else
{
skip_scope(p_par.scanner);
}
}
}
if (path == null && border_shape == null)
{
System.out.println("Wiring.read_wire_scope: shape missing");
return null;
}
RoutingBoard board = p_par.board_handling.get_routing_board();
rules.NetClass net_class = board.rules.get_default_net_class();
Collection<rules.Net> found_nets = get_subnets(net_id, board.rules);
int[] net_no_arr = new int[found_nets.size()];
int curr_index = 0;
for (rules.Net curr_net : found_nets)
{
net_no_arr[curr_index] = curr_net.net_number;
net_class = curr_net.get_class();
++curr_index;
}
int clearance_class_no = -1;
if (clearance_class_name != null)
{
clearance_class_no = board.rules.clearance_matrix.get_no(clearance_class_name);
}
int layer_no;
int half_width;
if (path != null)
{
layer_no = path.layer.no;
half_width = (int) Math.round(p_par.coordinate_transform.dsn_to_board(path.width / 2));
}
else
{
layer_no = border_shape.layer.no;
half_width = 0;
}
if (layer_no < 0 || layer_no >= board.get_layer_count())
{
System.out.print("Wiring.read_wire_scope: unexpected layer ");
if (path != null)
{
System.out.println(path.layer.name);
}
else
{
System.out.println(border_shape.layer.name);
}
return null;
}
IntBox bounding_box = board.get_bounding_box();
Item result = null;
if (border_shape != null)
{
if (clearance_class_no < 0)
{
clearance_class_no =
net_class.default_item_clearance_classes.get(rules.DefaultItemClearanceClasses.ItemClass.AREA);
}
Collection<Shape> area = new LinkedList<Shape>();
area.add(border_shape);
area.addAll(hole_list);
geometry.planar.Area conduction_area =
Shape.transform_area_to_board(area, p_par.coordinate_transform);
result = board.insert_conduction_area(conduction_area, layer_no, net_no_arr, clearance_class_no,
false, fixed);
}
else if (path instanceof PolygonPath)
{
if (clearance_class_no < 0)
{
clearance_class_no =
net_class.default_item_clearance_classes.get(rules.DefaultItemClearanceClasses.ItemClass.TRACE);
}
IntPoint [] corner_arr = new IntPoint[path.coordinate_arr.length / 2];
double [] curr_point = new double [2];
for (int i = 0; i < corner_arr.length; ++i)
{
curr_point[0] = path.coordinate_arr[2 * i];
curr_point[1] = path.coordinate_arr[2 * i + 1];
FloatPoint curr_corner = p_par.coordinate_transform.dsn_to_board(curr_point);
if (!bounding_box.contains(curr_corner))
{
System.out.println("Wiring.read_wire_scope: wire corner outside board");
return null;
}
corner_arr[i] = curr_corner.round();
}
Polyline trace_polyline = new Polyline(corner_arr);
// Traces are not yet normalized here because cycles may be removed premature.
result = board.insert_trace_without_cleaning(trace_polyline, layer_no, half_width, net_no_arr, clearance_class_no, fixed);
}
else if (path instanceof PolylinePath)
{
if (clearance_class_no < 0)
{
clearance_class_no =
net_class.default_item_clearance_classes.get(rules.DefaultItemClearanceClasses.ItemClass.TRACE);
}
Line [] line_arr = new Line[path.coordinate_arr.length / 4];
double [] curr_point = new double [2];
for (int i = 0; i < line_arr.length; ++i)
{
curr_point[0] = path.coordinate_arr[4 * i];
curr_point[1] = path.coordinate_arr[4 * i + 1];
FloatPoint curr_a = p_par.coordinate_transform.dsn_to_board(curr_point);
curr_point[0] = path.coordinate_arr[4 * i + 2];
curr_point[1] = path.coordinate_arr[4 * i + 3];
FloatPoint curr_b = p_par.coordinate_transform.dsn_to_board(curr_point);
line_arr[i] = new Line(curr_a.round(), curr_b.round());
}
Polyline trace_polyline = new Polyline(line_arr);
result = board.insert_trace_without_cleaning(trace_polyline, layer_no, half_width, net_no_arr, clearance_class_no, fixed);
}
else
{
System.out.println("Wiring.read_wire_scope: unexpected Path subclass");
return null;
}
if (result != null && result.net_count() == 0)
{
try_correct_net(result);
}
return result;
}
/**
* Maybe trace of type turret without net in Mentor design.
* Try to assig the net by calculating the overlaps.
*/
private void try_correct_net(Item p_item)
{
if (!(p_item instanceof Trace))
{
return;
}
Trace curr_trace = (Trace) p_item;
java.util.Set<Item> contacts = curr_trace.get_normal_contacts(curr_trace.first_corner(), true);
contacts.addAll(curr_trace.get_normal_contacts(curr_trace.last_corner(), true));
int corrected_net_no = 0;
for (Item curr_contact : contacts)
{
if (curr_contact.net_count() == 1)
{
corrected_net_no = curr_contact.get_net_no(0);
break;
}
}
if (corrected_net_no != 0)
{
p_item.assign_net_no(corrected_net_no);
}
}
private static Collection<rules.Net> get_subnets(Net.Id p_net_id, rules.BoardRules p_rules)
{
Collection<rules.Net> found_nets = new LinkedList<rules.Net>();
if (p_net_id != null)
{
if (p_net_id.subnet_number > 0)
{
rules.Net found_net = p_rules.nets.get(p_net_id.name, p_net_id.subnet_number);
if (found_net != null)
{
found_nets.add(found_net);
}
}
else
{
found_nets = p_rules.nets.get(p_net_id.name);
}
}
return found_nets;
}
private boolean read_via_scope(ReadScopeParameter p_par)
{
try
{
board.FixedState fixed = board.FixedState.UNFIXED;
// read the padstack name
Object next_token = p_par.scanner.next_token();
if (!(next_token instanceof String))
{
System.out.println("Wiring.read_via_scope: padstack name expected");
return false;
}
String padstack_name = (String) next_token;
// read the location
double []location = new double [2];
for (int i = 0; i < 2; ++i)
{
next_token = p_par.scanner.next_token();
if (next_token instanceof Double)
{
location[i] = ((Double) next_token).doubleValue();
}
else if (next_token instanceof Integer)
{
location[i] = ((Integer) next_token).intValue();
}
else
{
System.out.println("Wiring.read_via_scope: number expected");
return false;
}
}
Net.Id net_id = null;
String clearance_class_name = null;
for (;;)
{
Object prev_token = next_token;
next_token = p_par.scanner.next_token();
if (next_token == null)
{
System.out.println("Wiring.read_via_scope: unexpected end of file");
return false;
}
if (next_token == CLOSED_BRACKET)
{
// end of scope
break;
}
if (prev_token == OPEN_BRACKET)
{
if (next_token == Keyword.NET)
{
net_id = read_net_id(p_par.scanner);
}
else if (next_token == Keyword.CLEARANCE_CLASS)
{
clearance_class_name = DsnFile.read_string_scope(p_par.scanner);
}
else if (next_token == Keyword.TYPE)
{
fixed = calc_fixed(p_par.scanner);
}
else
{
skip_scope(p_par.scanner);
}
}
}
RoutingBoard board = p_par.board_handling.get_routing_board();
library.Padstack curr_padstack = board.library.padstacks.get(padstack_name);
if (curr_padstack == null)
{
System.out.println("Wiring.read_via_scope: via padstack not found");
return false;
}
rules.NetClass net_class = board.rules.get_default_net_class();
Collection<rules.Net> found_nets = get_subnets(net_id, board.rules);
if (net_id != null && found_nets.isEmpty())
{
System.out.print("Wiring.read_via_scope: net with name ");
System.out.print(net_id.name);
System.out.println(" not found");
}
int[] net_no_arr = new int[found_nets.size()];
int curr_index = 0;
for (rules.Net curr_net : found_nets)
{
net_no_arr[curr_index] = curr_net.net_number;
net_class = curr_net.get_class();
}
int clearance_class_no = -1;
if (clearance_class_name != null)
{
clearance_class_no = board.rules.clearance_matrix.get_no(clearance_class_name);
}
if (clearance_class_no < 0)
{
clearance_class_no = net_class.default_item_clearance_classes.get(rules.DefaultItemClearanceClasses.ItemClass.VIA);
}
IntPoint board_location = p_par.coordinate_transform.dsn_to_board(location).round();
if (via_exists(board_location, curr_padstack, net_no_arr, board))
{
System.out.print("Multiple via skipped at (");
System.out.println(board_location.x + ", " + board_location.y + ")");
}
else
{
boolean attach_allowed = p_par.via_at_smd_allowed && curr_padstack.attach_allowed;
board.insert_via(curr_padstack, board_location, net_no_arr, clearance_class_no, fixed, attach_allowed);
}
return true;
}
catch (java.io.IOException e)
{
System.out.println("Wiring.read_via_scope: IO error scanning file");
return false;
}
}
private static boolean via_exists(IntPoint p_location, library.Padstack p_padstack,
int[] p_net_no_arr, board.BasicBoard p_board)
{
ItemSelectionFilter filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.VIAS);
int from_layer = p_padstack.from_layer();
int to_layer = p_padstack.to_layer();
Collection<Item> picked_items = p_board.pick_items(p_location, p_padstack.from_layer(), filter);
for (Item curr_item : picked_items)
{
Via curr_via = (Via) curr_item;
if (curr_via.nets_equal(p_net_no_arr) && curr_via.get_center().equals(p_location)
&& curr_via.first_layer() == from_layer && curr_via.last_layer() == to_layer)
{
return true;
}
}
return false;
}
static board.FixedState calc_fixed(Scanner p_scanner)
{
try
{
board.FixedState result = board.FixedState.UNFIXED;
Object next_token = p_scanner.next_token();
if (next_token == Keyword.SHOVE_FIXED)
{
result = board.FixedState.SHOVE_FIXED;
}
else if (next_token == Keyword.FIX)
{
result = board.FixedState.SYSTEM_FIXED;
}
else if (next_token != Keyword.NORMAL)
{
result = board.FixedState.USER_FIXED;
}
next_token = p_scanner.next_token();
if (next_token != Keyword.CLOSED_BRACKET)
{
System.out.println("Wiring.is_fixed: ) expected");
return board.FixedState.UNFIXED;
}
return result;
}
catch (java.io.IOException e)
{
System.out.println("Wiring.is_fixed: IO error scanning file");
return board.FixedState.UNFIXED;
}
}
/**
* Reads a net_id. The subnet_number of the net_id will be 0, if no subneet_number was found.
*/
private static Net.Id read_net_id(Scanner p_scanner)
{
try
{
int subnet_number = 0;
p_scanner.yybegin(SpecctraFileScanner.NAME);
Object next_token = p_scanner.next_token();
if (!(next_token instanceof String))
{
System.out.println("Wiring:read_net_id: String expected");
return null;
}
String net_name = (String) next_token;
next_token = p_scanner.next_token();
if (next_token instanceof Integer)
{
subnet_number = (Integer) next_token;
next_token = p_scanner.next_token();
}
if (next_token != Keyword.CLOSED_BRACKET)
{
System.out.println("Wiring.read_net_id: closing bracket expected");
}
return new Net.Id(net_name, subnet_number);
}
catch (java.io.IOException e)
{
System.out.println("DsnFile.read_string_scope: IO error scanning file");
return null;
}
}
}