447 lines
18 KiB
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;
|
|
}
|
|
}
|
|
}
|