505 lines
19 KiB
Java
505 lines
19 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.
|
|
*
|
|
* Package.java
|
|
*
|
|
* Created on 21. Mai 2004, 09:31
|
|
*/
|
|
|
|
package designformats.specctra;
|
|
|
|
import java.util.Collection;
|
|
import java.util.Iterator;
|
|
import java.util.LinkedList;
|
|
|
|
import board.Item;
|
|
|
|
/**
|
|
* Class for reading and writing package scopes from dsn-files.
|
|
*
|
|
* @author alfons
|
|
*/
|
|
public class Package
|
|
{
|
|
|
|
/** Creates a new instance of Package */
|
|
public Package(String p_name, PinInfo[] p_pin_info_arr, Collection<Shape> p_outline, Collection<Shape.ReadAreaScopeResult> p_keepouts,
|
|
Collection<Shape.ReadAreaScopeResult> p_via_keepouts, Collection<Shape.ReadAreaScopeResult> p_place_keepouts, boolean p_is_front)
|
|
{
|
|
name = p_name;
|
|
pin_info_arr = p_pin_info_arr;
|
|
outline = p_outline;
|
|
keepouts = p_keepouts;
|
|
via_keepouts = p_via_keepouts;
|
|
place_keepouts = p_place_keepouts;
|
|
is_front = p_is_front;
|
|
}
|
|
|
|
public static Package read_scope(Scanner p_scanner, LayerStructure p_layer_structure)
|
|
{
|
|
try
|
|
{
|
|
boolean is_front = true;
|
|
Collection <Shape> outline = new LinkedList<Shape>();
|
|
Collection<Shape.ReadAreaScopeResult> keepouts = new LinkedList<Shape.ReadAreaScopeResult>();
|
|
Collection<Shape.ReadAreaScopeResult> via_keepouts = new LinkedList<Shape.ReadAreaScopeResult>();
|
|
Collection<Shape.ReadAreaScopeResult> place_keepouts = new LinkedList<Shape.ReadAreaScopeResult>();
|
|
Object next_token = p_scanner.next_token();
|
|
if ( !(next_token instanceof String))
|
|
{
|
|
System.out.println("Package.read_scope: String expected");
|
|
return null;
|
|
}
|
|
String package_name = (String) next_token;
|
|
Collection<PinInfo> pin_info_list = new LinkedList<PinInfo>();
|
|
for (;;)
|
|
{
|
|
Object prev_token = next_token;
|
|
next_token = p_scanner.next_token();
|
|
|
|
if (next_token == null)
|
|
{
|
|
System.out.println("Package.read_scope: unexpected end of file");
|
|
return null;
|
|
}
|
|
if (next_token == Keyword.CLOSED_BRACKET)
|
|
{
|
|
// end of scope
|
|
break;
|
|
}
|
|
if (prev_token == Keyword.OPEN_BRACKET)
|
|
{
|
|
if (next_token == Keyword.PIN)
|
|
{
|
|
PinInfo next_pin = read_pin_info(p_scanner);
|
|
if (next_pin == null)
|
|
{
|
|
return null;
|
|
}
|
|
pin_info_list.add(next_pin);
|
|
}
|
|
else if (next_token == Keyword.SIDE)
|
|
{
|
|
is_front = read_placement_side(p_scanner);
|
|
}
|
|
else if (next_token == Keyword.OUTLINE)
|
|
{
|
|
Shape curr_shape = Shape.read_scope(p_scanner, p_layer_structure);
|
|
if (curr_shape != null)
|
|
{
|
|
outline.add(curr_shape);
|
|
}
|
|
// overread closing bracket
|
|
next_token = p_scanner.next_token();
|
|
if (next_token != Keyword.CLOSED_BRACKET)
|
|
{
|
|
System.out.println("Package.read_scope: closed bracket expected");
|
|
return null;
|
|
}
|
|
}
|
|
else if (next_token == Keyword.KEEPOUT)
|
|
{
|
|
Shape.ReadAreaScopeResult keepout_area = Shape.read_area_scope(p_scanner, p_layer_structure, false);
|
|
if (keepout_area != null)
|
|
{
|
|
keepouts.add(keepout_area);
|
|
}
|
|
}
|
|
else if (next_token == Keyword.VIA_KEEPOUT)
|
|
{
|
|
Shape.ReadAreaScopeResult keepout_area = Shape.read_area_scope(p_scanner, p_layer_structure, false);
|
|
if (keepout_area != null)
|
|
{
|
|
via_keepouts.add(keepout_area);
|
|
}
|
|
}
|
|
else if (next_token == Keyword.PLACE_KEEPOUT)
|
|
{
|
|
Shape.ReadAreaScopeResult keepout_area = Shape.read_area_scope(p_scanner, p_layer_structure, false);
|
|
if (keepout_area != null)
|
|
{
|
|
place_keepouts.add(keepout_area);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ScopeKeyword.skip_scope(p_scanner);
|
|
}
|
|
}
|
|
}
|
|
PinInfo [] pin_info_arr = new PinInfo[pin_info_list.size()];
|
|
Iterator<PinInfo> it = pin_info_list.iterator();
|
|
for (int i = 0; i < pin_info_arr.length; ++i)
|
|
{
|
|
pin_info_arr[i] = it.next();
|
|
}
|
|
return new Package(package_name, pin_info_arr, outline, keepouts, via_keepouts, place_keepouts, is_front);
|
|
}
|
|
catch (java.io.IOException e)
|
|
{
|
|
System.out.println("Package.read_scope: IO error scanning file");
|
|
System.out.println(e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static void write_scope(WriteScopeParameter p_par, library.Package p_package) throws java.io.IOException
|
|
{
|
|
p_par.file.start_scope();
|
|
p_par.file.write("image ");
|
|
p_par.identifier_type.write(p_package.name, p_par.file);
|
|
// write the placement side of the package
|
|
p_par.file.new_line();
|
|
p_par.file.write("(side ");
|
|
if (p_package.is_front)
|
|
{
|
|
p_par.file.write("front)");
|
|
}
|
|
else
|
|
{
|
|
p_par.file.write("back)");
|
|
}
|
|
// write the pins of the package
|
|
for (int i = 0; i < p_package.pin_count(); ++i)
|
|
{
|
|
library.Package.Pin curr_pin = p_package.get_pin(i);
|
|
p_par.file.new_line();
|
|
p_par.file.write("(pin ");
|
|
library.Padstack curr_padstack = p_par.board.library.padstacks.get(curr_pin.padstack_no);
|
|
p_par.identifier_type.write(curr_padstack.name, p_par.file);
|
|
p_par.file.write(" ");
|
|
p_par.identifier_type.write(curr_pin.name, p_par.file);
|
|
double [] rel_coor = p_par.coordinate_transform.board_to_dsn(curr_pin.relative_location);
|
|
for(int j = 0; j < rel_coor.length; ++j)
|
|
{
|
|
p_par.file.write(" ");
|
|
p_par.file.write((new Double(rel_coor[j])).toString());
|
|
}
|
|
int rotation = (int) Math.round(curr_pin.rotation_in_degree);
|
|
if (rotation != 0)
|
|
{
|
|
p_par.file.write("(rotate ");
|
|
p_par.file.write((new Integer(rotation)).toString());
|
|
p_par.file.write(")");
|
|
}
|
|
p_par.file.write(")");
|
|
}
|
|
// write the keepouts belonging to the package.
|
|
for (int i = 0; i < p_package.keepout_arr.length; ++i)
|
|
{
|
|
write_package_keepout(p_package.keepout_arr[i], p_par, false);
|
|
}
|
|
for (int i = 0; i < p_package.via_keepout_arr.length; ++i)
|
|
{
|
|
write_package_keepout(p_package.via_keepout_arr[i], p_par, true);
|
|
}
|
|
// write the package outline.
|
|
for (int i = 0; i < p_package.outline.length; ++i)
|
|
{
|
|
p_par.file.start_scope();
|
|
p_par.file.write("outline");
|
|
Shape curr_outline = p_par.coordinate_transform.board_to_dsn_rel(p_package.outline[i], Layer.SIGNAL);
|
|
curr_outline.write_scope(p_par.file, p_par.identifier_type);
|
|
p_par.file.end_scope();
|
|
}
|
|
p_par.file.end_scope();
|
|
}
|
|
|
|
private static void write_package_keepout(library.Package.Keepout p_keepout, WriteScopeParameter p_par,
|
|
boolean p_is_via_keepout) throws java.io.IOException
|
|
{
|
|
Layer keepout_layer;
|
|
if (p_keepout.layer >= 0)
|
|
{
|
|
board.Layer board_layer = p_par.board.layer_structure.arr[p_keepout.layer];
|
|
keepout_layer = new Layer(board_layer.name, p_keepout.layer, board_layer.is_signal);
|
|
}
|
|
else
|
|
{
|
|
keepout_layer = Layer.SIGNAL;
|
|
}
|
|
geometry.planar.Shape boundary_shape;
|
|
geometry.planar.Shape [] holes;
|
|
if (p_keepout.area instanceof geometry.planar.Shape)
|
|
{
|
|
boundary_shape = (geometry.planar.Shape) p_keepout.area ;
|
|
holes = new geometry.planar.Shape [0];
|
|
}
|
|
else
|
|
{
|
|
boundary_shape = p_keepout.area .get_border();
|
|
holes = p_keepout.area .get_holes();
|
|
}
|
|
p_par.file.start_scope();
|
|
if (p_is_via_keepout)
|
|
{
|
|
p_par.file.write("via_keepout");
|
|
}
|
|
else
|
|
{
|
|
p_par.file.write("keepout");
|
|
}
|
|
Shape dsn_shape = p_par.coordinate_transform.board_to_dsn(boundary_shape, keepout_layer);
|
|
if (dsn_shape != null)
|
|
{
|
|
dsn_shape.write_scope(p_par.file, p_par.identifier_type);
|
|
}
|
|
for (int j = 0; j < holes.length; ++j)
|
|
{
|
|
Shape dsn_hole = p_par.coordinate_transform.board_to_dsn(holes[j], keepout_layer);
|
|
dsn_hole.write_hole_scope(p_par.file, p_par.identifier_type);
|
|
}
|
|
p_par.file.end_scope();
|
|
}
|
|
|
|
/** Reads the information of a single pin in a package. */
|
|
private static PinInfo read_pin_info(Scanner p_scanner)
|
|
{
|
|
try
|
|
{
|
|
// Read the padstack name.
|
|
p_scanner.yybegin(SpecctraFileScanner.NAME);
|
|
String padstack_name = null;
|
|
Object next_token = p_scanner.next_token();
|
|
if ( next_token instanceof String)
|
|
{
|
|
padstack_name = (String) next_token;
|
|
}
|
|
else if ( next_token instanceof Integer)
|
|
{
|
|
padstack_name = ((Integer) next_token).toString();
|
|
}
|
|
else
|
|
{
|
|
System.out.println("Package.read_pin_info: String or Integer expected");
|
|
return null;
|
|
}
|
|
double rotation = 0;
|
|
|
|
p_scanner.yybegin(SpecctraFileScanner.NAME); // to be able to handle pin names starting with a digit.
|
|
next_token = p_scanner.next_token();
|
|
if (next_token == Keyword.OPEN_BRACKET)
|
|
{
|
|
// read the padstack rotation
|
|
next_token = p_scanner.next_token();
|
|
if (next_token == Keyword.ROTATE)
|
|
{
|
|
rotation = read_rotation(p_scanner);
|
|
}
|
|
else
|
|
{
|
|
ScopeKeyword.skip_scope(p_scanner);
|
|
}
|
|
p_scanner.yybegin(SpecctraFileScanner.NAME);
|
|
next_token = p_scanner.next_token();
|
|
}
|
|
// Read the pin name.
|
|
String pin_name = null;
|
|
if ( next_token instanceof String)
|
|
{
|
|
pin_name = (String) next_token;
|
|
}
|
|
else if ( next_token instanceof Integer)
|
|
{
|
|
pin_name = ((Integer) next_token).toString();
|
|
}
|
|
else
|
|
{
|
|
System.out.println("Package.read_pin_info: String or Integer expected");
|
|
return null;
|
|
}
|
|
|
|
double [] pin_coor = new double [2];
|
|
for (int i = 0; i < 2; ++i)
|
|
{
|
|
next_token = p_scanner.next_token();
|
|
if (next_token instanceof Double)
|
|
{
|
|
pin_coor[i] = ((Double) next_token).doubleValue();
|
|
}
|
|
else if (next_token instanceof Integer)
|
|
{
|
|
pin_coor[i] = ((Integer) next_token).intValue();
|
|
}
|
|
else
|
|
{
|
|
System.out.println("Package.read_pin_info: number expected");
|
|
return null;
|
|
}
|
|
}
|
|
// Handle scopes at the end of the pin scope.
|
|
for (;;)
|
|
{
|
|
Object prev_token = next_token;
|
|
next_token = p_scanner.next_token();
|
|
|
|
if (next_token == null)
|
|
{
|
|
System.out.println("Package.read_pin_info: unexpected end of file");
|
|
return null;
|
|
}
|
|
if (next_token == Keyword.CLOSED_BRACKET)
|
|
{
|
|
// end of scope
|
|
break;
|
|
}
|
|
if (prev_token == Keyword.OPEN_BRACKET)
|
|
{
|
|
if (next_token == Keyword.ROTATE)
|
|
{
|
|
rotation = read_rotation(p_scanner);
|
|
}
|
|
else
|
|
{
|
|
ScopeKeyword.skip_scope(p_scanner);
|
|
}
|
|
}
|
|
}
|
|
return new PinInfo(padstack_name, pin_name, pin_coor, rotation);
|
|
}
|
|
catch (java.io.IOException e)
|
|
{
|
|
System.out.println("Package.read_pin_info: IO error while scanning file");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private static double read_rotation(Scanner p_scanner)
|
|
{
|
|
double result = 0;
|
|
try
|
|
{
|
|
Object next_token = p_scanner.next_token();
|
|
if (next_token instanceof Integer)
|
|
{
|
|
result = ((Integer)next_token).intValue();
|
|
}
|
|
else if (next_token instanceof Double)
|
|
{
|
|
result = ((Double)next_token).doubleValue();
|
|
}
|
|
else
|
|
{
|
|
System.out.println("Package.read_rotation: number expected");
|
|
}
|
|
// Overread The closing bracket.
|
|
next_token = p_scanner.next_token();
|
|
if (next_token != Keyword.CLOSED_BRACKET)
|
|
{
|
|
System.out.println("Package.read_rotation: closing bracket expected");
|
|
}
|
|
}
|
|
catch (java.io.IOException e)
|
|
{
|
|
System.out.println("Package.read_rotation: IO error while scanning file");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Writes the placements of p_package to a Specctra dsn-file.
|
|
*/
|
|
public static void write_placement_scope(WriteScopeParameter p_par, library.Package p_package)
|
|
throws java.io.IOException
|
|
{
|
|
Collection<Item> board_items = p_par.board.get_items();
|
|
boolean component_found = false;
|
|
for (int i = 1; i <= p_par.board.components.count(); ++i)
|
|
{
|
|
board.Component curr_component = p_par.board.components.get(i);
|
|
if (curr_component.get_package() == p_package)
|
|
{
|
|
// check, if not all items of the component are deleted
|
|
boolean undeleted_item_found = false;
|
|
Iterator<Item> it = board_items.iterator();
|
|
while (it.hasNext())
|
|
{
|
|
Item curr_item = it.next();
|
|
if (curr_item.get_component_no() == curr_component.no)
|
|
{
|
|
undeleted_item_found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (undeleted_item_found || !curr_component.is_placed())
|
|
{
|
|
if (!component_found)
|
|
{
|
|
// write the scope header
|
|
p_par.file.start_scope();
|
|
p_par.file.write("component ");
|
|
p_par.identifier_type.write(p_package.name, p_par.file);
|
|
component_found = true;
|
|
}
|
|
Component.write_scope(p_par, curr_component);
|
|
}
|
|
}
|
|
}
|
|
if (component_found)
|
|
{
|
|
p_par.file.end_scope();
|
|
}
|
|
}
|
|
|
|
private static boolean read_placement_side(Scanner p_scanner) throws java.io.IOException
|
|
{
|
|
Object next_token = p_scanner.next_token();
|
|
boolean result = (next_token != Keyword.BACK);
|
|
|
|
next_token = p_scanner.next_token();
|
|
if (next_token != Keyword.CLOSED_BRACKET)
|
|
{
|
|
System.out.println("Package.read_placement_side: closing bracket expected");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
public final String name;
|
|
/** List of objects of type PinInfo. */
|
|
public final PinInfo[] pin_info_arr;
|
|
/** The outline of the package. */
|
|
public final Collection<Shape> outline;
|
|
/** Collection of keepoouts belonging to this package */
|
|
public final Collection<Shape.ReadAreaScopeResult> keepouts;
|
|
/** Collection of via keepoouts belonging to this package */
|
|
public final Collection<Shape.ReadAreaScopeResult> via_keepouts;
|
|
/** Collection of place keepoouts belonging to this package */
|
|
public final Collection<Shape.ReadAreaScopeResult> place_keepouts;
|
|
/** If false, the package is placed on the back side of the board */
|
|
public final boolean is_front;
|
|
|
|
|
|
/** Describes the Iinformation of a pin in a package. */
|
|
static public class PinInfo
|
|
{
|
|
PinInfo(String p_padstack_name, String p_pin_name, double [] p_rel_coor, double p_rotation)
|
|
{
|
|
padstack_name = p_padstack_name;
|
|
pin_name = p_pin_name;
|
|
rel_coor = p_rel_coor;
|
|
rotation = p_rotation;
|
|
}
|
|
/** Phe name of the pastack of this pin. */
|
|
public final String padstack_name;
|
|
/** Phe name of this pin. */
|
|
public final String pin_name;
|
|
/** The x- and y-coordinates relative to the package location. */
|
|
public final double [] rel_coor;
|
|
/** The rotation of the pin relative to the package. */
|
|
public final double rotation;
|
|
}
|
|
}
|