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

447 lines
18 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.
*
* Library.java
*
* Created on 21. Mai 2004, 08:09
*/
package designformats.specctra;
import geometry.planar.IntVector;
import geometry.planar.Vector;
import geometry.planar.PolygonShape;
import geometry.planar.Simplex;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
/**
* Class for reading and writing library scopes from dsn-files.
*
* @author Alfons Wirtz
*/
public class Library extends ScopeKeyword
{
/** Creates a new instance of Library */
public Library()
{
super("library");
}
public boolean read_scope(ReadScopeParameter p_par)
{
board.RoutingBoard board = p_par.board_handling.get_routing_board();
board.library.padstacks = new library.Padstacks(p_par.board_handling.get_routing_board().layer_structure);
Collection<Package> package_list = new LinkedList<Package>();
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("Library.read_scope: IO error scanning file");
System.out.println(e);
return false;
}
if (next_token == null)
{
System.out.println("Library.read_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.PADSTACK)
{
if (!read_padstack_scope(p_par.scanner, p_par.layer_structure,
p_par.coordinate_transform, board.library.padstacks))
{
return false;
}
}
else if (next_token == Keyword.IMAGE)
{
Package curr_package = Package.read_scope(p_par.scanner, p_par.layer_structure);
if (curr_package == null)
{
return false;
}
package_list.add(curr_package);
}
else
{
skip_scope(p_par.scanner);
}
}
}
// Set the via padstacks.
if (p_par.via_padstack_names != null)
{
library.Padstack[] via_padstacks = new library.Padstack[p_par.via_padstack_names.size()];
Iterator<String> it = p_par.via_padstack_names.iterator();
int found_padstack_count = 0;
for (int i = 0; i < via_padstacks.length; ++i)
{
String curr_padstack_name = it.next();
library.Padstack curr_padstack = board.library.padstacks.get(curr_padstack_name);
if (curr_padstack != null)
{
via_padstacks[found_padstack_count] = curr_padstack;
++found_padstack_count;
}
else
{
System.out.print("Library.read_scope: via padstack with name ");
System.out.print(curr_padstack_name);
System.out.println(" not found");
}
}
if (found_padstack_count != via_padstacks.length)
{
// Some via padstacks were not found in the padstacks scope of the dsn-file.
library.Padstack[] corrected_padstacks = new library.Padstack[found_padstack_count];
System.arraycopy(via_padstacks, 0, corrected_padstacks, 0, found_padstack_count);
via_padstacks = corrected_padstacks;
}
board.library.set_via_padstacks(via_padstacks);
}
// Create the library packages on the board
board.library.packages = new library.Packages(board.library.padstacks);
Iterator<Package> it = package_list.iterator();
while (it.hasNext())
{
Package curr_package = it.next();
library.Package.Pin[] pin_arr = new library.Package.Pin[curr_package.pin_info_arr.length];
for (int i = 0; i < pin_arr.length; ++i)
{
Package.PinInfo pin_info = curr_package.pin_info_arr[i];
int rel_x = (int) Math.round(p_par.coordinate_transform.dsn_to_board(pin_info.rel_coor[0]));
int rel_y = (int) Math.round(p_par.coordinate_transform.dsn_to_board(pin_info.rel_coor[1]));
Vector rel_coor = new IntVector(rel_x, rel_y);
library.Padstack board_padstack = board.library.padstacks.get(pin_info.padstack_name);
if (board_padstack == null)
{
System.out.println("Library.read_scope: board padstack not found");
return false;
}
pin_arr[i] = new library.Package.Pin(pin_info.pin_name, board_padstack.no, rel_coor, pin_info.rotation);
}
geometry.planar.Shape[] outline_arr = new geometry.planar.Shape[curr_package.outline.size()];
Iterator<Shape> it3 = curr_package.outline.iterator();
for (int i = 0; i < outline_arr.length; ++i)
{
Shape curr_shape = it3.next();
if (curr_shape != null)
{
outline_arr[i] = curr_shape.transform_to_board_rel(p_par.coordinate_transform);
}
else
{
System.out.println("Library.read_scope: outline shape is null");
}
}
generate_missing_keepout_names("keepout_", curr_package.keepouts);
generate_missing_keepout_names("via_keepout_", curr_package.via_keepouts);
generate_missing_keepout_names("place_keepout_", curr_package.place_keepouts);
library.Package.Keepout [] keepout_arr = new library.Package.Keepout [curr_package.keepouts.size()];
Iterator<Shape.ReadAreaScopeResult> it2 = curr_package.keepouts.iterator();
for (int i = 0; i < keepout_arr.length; ++i)
{
Shape.ReadAreaScopeResult curr_keepout = it2.next();
Layer curr_layer = curr_keepout.shape_list.iterator().next().layer;
geometry.planar.Area curr_area = Shape.transform_area_to_board_rel(curr_keepout.shape_list, p_par.coordinate_transform);
keepout_arr[i] = new library.Package.Keepout(curr_keepout.area_name, curr_area, curr_layer.no);
}
library.Package.Keepout [] via_keepout_arr = new library.Package.Keepout [curr_package.via_keepouts.size()];
it2 = curr_package.via_keepouts.iterator();
for (int i = 0; i < via_keepout_arr.length; ++i)
{
Shape.ReadAreaScopeResult curr_keepout = it2.next();
Layer curr_layer = (curr_keepout.shape_list.iterator().next()).layer;
geometry.planar.Area curr_area = Shape.transform_area_to_board_rel(curr_keepout.shape_list, p_par.coordinate_transform);
via_keepout_arr[i] = new library.Package.Keepout(curr_keepout.area_name, curr_area, curr_layer.no);
}
library.Package.Keepout [] place_keepout_arr = new library.Package.Keepout [curr_package.place_keepouts.size()];
it2 = curr_package.place_keepouts.iterator();
for (int i = 0; i < place_keepout_arr.length; ++i)
{
Shape.ReadAreaScopeResult curr_keepout = it2.next();
Layer curr_layer = (curr_keepout.shape_list.iterator().next()).layer;
geometry.planar.Area curr_area = Shape.transform_area_to_board_rel(curr_keepout.shape_list, p_par.coordinate_transform);
place_keepout_arr[i] = new library.Package.Keepout(curr_keepout.area_name, curr_area, curr_layer.no);
}
board.library.packages.add(curr_package.name, pin_arr, outline_arr,
keepout_arr, via_keepout_arr, place_keepout_arr, curr_package.is_front);
}
return true;
}
public static void write_scope(WriteScopeParameter p_par) throws java.io.IOException
{
p_par.file.start_scope();
p_par.file.write("library");
for (int i = 1; i <= p_par.board.library.packages.count(); ++i)
{
Package.write_scope(p_par, p_par.board.library.packages.get(i));
}
for (int i = 1; i <= p_par.board.library.padstacks.count(); ++i)
{
write_padstack_scope(p_par, p_par.board.library.padstacks.get(i));
}
p_par.file.end_scope();
}
public static void write_padstack_scope(WriteScopeParameter p_par, library.Padstack p_padstack) throws java.io.IOException
{
// search the layer range of the padstack
int first_layer_no = 0;
while (first_layer_no < p_par.board.get_layer_count())
{
if (p_padstack.get_shape(first_layer_no) != null)
{
break;
}
++first_layer_no;
}
int last_layer_no = p_par.board.get_layer_count() - 1;
while (last_layer_no >= 0 )
{
if (p_padstack.get_shape(last_layer_no) != null)
{
break;
}
--last_layer_no;
}
if (first_layer_no >= p_par.board.get_layer_count() || last_layer_no < 0)
{
System.out.println("Library.write_padstack_scope: padstack shape not found");
return;
}
p_par.file.start_scope();
p_par.file.write("padstack ");
p_par.identifier_type.write(p_padstack.name, p_par.file);
for (int i = first_layer_no; i <= last_layer_no; ++i)
{
geometry.planar.Shape curr_board_shape = p_padstack.get_shape(i);
if (curr_board_shape == null)
{
continue;
}
board.Layer board_layer = p_par.board.layer_structure.arr[i];
Layer curr_layer = new Layer(board_layer.name, i, board_layer.is_signal);
Shape curr_shape = p_par.coordinate_transform.board_to_dsn_rel(curr_board_shape, curr_layer);
p_par.file.start_scope();
p_par.file.write("shape");
curr_shape.write_scope(p_par.file, p_par.identifier_type);
p_par.file.end_scope();
}
if (!p_padstack.attach_allowed)
{
p_par.file.new_line();
p_par.file.write("(attach off)");
}
if (p_padstack.placed_absolute)
{
p_par.file.new_line();
p_par.file.write("(absolute on)");
}
p_par.file.end_scope();
}
static boolean read_padstack_scope(Scanner p_scanner, LayerStructure p_layer_structure,
CoordinateTransform p_coordinate_transform, library.Padstacks p_board_padstacks)
{
String padstack_name = null;
boolean is_drilllable = true;
boolean placed_absolute = false;
Collection<Shape> shape_list = new LinkedList<Shape>();
try
{
Object next_token = p_scanner.next_token();
if (next_token instanceof String)
{
padstack_name = (String) next_token;
}
else
{
System.out.println("Library.read_padstack_scope: unexpected padstack identifier");
return false;
}
while (next_token != Keyword.CLOSED_BRACKET)
{
Object prev_token = next_token;
next_token = p_scanner.next_token();
if (prev_token == Keyword.OPEN_BRACKET)
{
if (next_token == Keyword.SHAPE)
{
Shape curr_shape = Shape.read_scope(p_scanner, p_layer_structure);
if (curr_shape != null)
{
shape_list.add(curr_shape);
}
// overread the closing bracket and unknown scopes.
Object curr_next_token = p_scanner.next_token();
while (curr_next_token == Keyword.OPEN_BRACKET)
{
ScopeKeyword.skip_scope(p_scanner);
curr_next_token = p_scanner.next_token();
}
if (curr_next_token != Keyword.CLOSED_BRACKET)
{
System.out.println("Library.read_padstack_scope: closing bracket expected");
return false;
}
}
else if (next_token == Keyword.ATTACH)
{
is_drilllable = DsnFile.read_on_off_scope(p_scanner);
}
else if (next_token == Keyword.ABSOLUTE)
{
placed_absolute = DsnFile.read_on_off_scope(p_scanner);
}
else
{
ScopeKeyword.skip_scope(p_scanner);
}
}
}
}
catch (java.io.IOException e)
{
System.out.println("Library.read_padstack_scope: IO error scanning file");
System.out.println(e);
return false;
}
if (p_board_padstacks.get(padstack_name) != null)
{
// Padstack exists already
return true;
}
if (shape_list.isEmpty())
{
System.out.print("Library.read_padstack_scope: shape not found for padstack with name ");
System.out.println(padstack_name);
return true;
}
geometry.planar.ConvexShape[] padstack_shapes = new geometry.planar.ConvexShape[p_layer_structure.arr.length];
Iterator<Shape> it = shape_list.iterator();
while (it.hasNext())
{
Shape pad_shape = it.next();
geometry.planar.Shape curr_shape = pad_shape.transform_to_board_rel(p_coordinate_transform);
geometry.planar.ConvexShape convex_shape;
if (curr_shape instanceof geometry.planar.ConvexShape)
{
convex_shape = (geometry.planar.ConvexShape) curr_shape;
}
else
{
if (curr_shape instanceof PolygonShape)
{
curr_shape = ((PolygonShape)curr_shape).convex_hull();
}
geometry.planar.TileShape[] convex_shapes = curr_shape.split_to_convex();
if (convex_shapes.length != 1)
{
System.out.println("Library.read_padstack_scope: convex shape expected");
}
convex_shape = convex_shapes[0];
if (convex_shape instanceof Simplex)
{
convex_shape = ((Simplex) convex_shape).simplify();
}
}
geometry.planar.ConvexShape padstack_shape = convex_shape;
if (padstack_shape != null)
{
if (padstack_shape.dimension() < 2)
{
System.out.print("Library.read_padstack_scope: shape is not an area ");
// enllarge the shape a little bit, so that it is an area
padstack_shape = padstack_shape.offset(1);
if (padstack_shape.dimension() < 2)
{
padstack_shape = null;
}
}
}
if (pad_shape.layer == Layer.PCB || pad_shape.layer == Layer.SIGNAL)
{
for (int i = 0; i < padstack_shapes.length; ++i)
{
padstack_shapes[i] = padstack_shape;
}
}
else
{
int shape_layer = p_layer_structure.get_no(pad_shape.layer.name);
if (shape_layer < 0 || shape_layer >= padstack_shapes.length)
{
System.out.println("Library.read_padstack_scope: layer number found");
return false;
}
padstack_shapes[shape_layer] = padstack_shape;
}
}
p_board_padstacks.add(padstack_name, padstack_shapes, is_drilllable, placed_absolute);
return true;
}
private void generate_missing_keepout_names(String p_keepout_type, Collection<Shape.ReadAreaScopeResult> p_keepout_list)
{
boolean all_names_existing = true;
for (Shape.ReadAreaScopeResult curr_keepout : p_keepout_list)
{
if (curr_keepout.area_name == null)
{
all_names_existing = false;
break;
}
}
if (all_names_existing)
{
return;
}
// generate names
Integer curr_name_index = 1;
for (Shape.ReadAreaScopeResult curr_keepout : p_keepout_list)
{
curr_keepout.area_name = p_keepout_type + curr_name_index.toString();
++curr_name_index;
}
}
}