/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: DefaultLayoutCell.java
*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) 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.
*
* Electric(tm) 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 Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.api.minarea.launcher;
import com.sun.electric.api.minarea.LayoutCell;
import com.sun.electric.api.minarea.ManhattanOrientation;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
*
*/
public class DefaultLayoutCell implements LayoutCell, Serializable {
private String name;
private transient int[] rectCoords = new int[4];
private int numRectangles = 0;
private static class CellInst implements Serializable {
private final LayoutCell subCell;
private final int anchorX;
private final int anchorY;
private final ManhattanOrientation orient;
private CellInst(LayoutCell subCell, int anchorX, int anchorY, ManhattanOrientation orient) {
this.subCell = subCell;
this.anchorX = anchorX;
this.anchorY = anchorY;
this.orient = orient;
}
}
private final List<CellInst> subCells = new ArrayList<CellInst>();
private int boundingMinX;
private int boundingMinY;
private int boundingMaxX;
private int boundingMaxY;
private transient boolean finished;
public DefaultLayoutCell(String name) {
this.name = name;
}
// cell name
public String getName() {
return name;
}
// rectangles
public int getNumRectangles() {
return numRectangles;
}
/**
* Traverse all rectangles by specified handler
* @param h handler
*/
public void traverseRectangles(RectangleHandler h) {
for (int i = 0; i < numRectangles; i++) {
int minX = rectCoords[i * 4 + 0];
int minY = rectCoords[i * 4 + 1];
int maxX = rectCoords[i * 4 + 2];
int maxY = rectCoords[i * 4 + 3];
h.apply(minX, minY, maxX, maxY);
}
}
/**
* Traverse part of rectangles by specified handler
* @param h handler
* @param offset the first rectangle
* @param count the number of rectangle
*/
public void traverseRectangles(RectangleHandler h, int offset, int count) {
if (offset < 0 || count < 0 || count > numRectangles - offset) {
throw new IndexOutOfBoundsException();
}
for (int i = 0; i < count; i++) {
int minX = rectCoords[(i + offset) * 4 + 0];
int minY = rectCoords[(i + offset) * 4 + 1];
int maxX = rectCoords[(i + offset) * 4 + 2];
int maxY = rectCoords[(i + offset) * 4 + 3];
h.apply(minX, minY, maxX, maxY);
}
}
/**
* Read coordinates of part of rectangles into int array.
* The length of the result array must be at least 4*count .
* The coordinates are placed into the result array in such an order:
* (minX0, minY0, maxX0, maxY0, minX1, minY1, maxX1, maxY1, ...)
* This is the same layout as in ManhattanOrientation.transoformRects method.
* @param result
* @param offset The first rectangle
* @param count The number of rectangles
*/
public void readRectangleCoords(int[] result, int offset, int count) {
if (count > numRectangles - offset) {
throw new IndexOutOfBoundsException();
}
System.arraycopy(rectCoords, offset * 4, result, 0, count * 4);
}
// subcells
public int getNumSubcells() {
return subCells.size();
}
/**
* Traverse all subcell instances by specified handler
* @param h handler
*/
public void traverseSubcellInstances(LayoutCell.SubcellHandler h) {
for (CellInst ci : subCells) {
h.apply(ci.subCell, ci.anchorX, ci.anchorY, ci.orient);
}
}
/**
* Traverse part of subcell instances by specified handler
* @param h handler
* @param offset the first subcell instance
* @param count the number of subcell instances
*/
public void traverseSubcellInstances(SubcellHandler h, int offset, int count) {
if (offset < 0 || count < 0 || count > subCells.size() - offset) {
throw new IndexOutOfBoundsException();
}
for (int i = 0; i < count; i++) {
CellInst ci = subCells.get(offset + i);
h.apply(ci.subCell, ci.anchorX, ci.anchorY, ci.orient);
}
}
// bounding box
public int getBoundingMinX() {
if (!finished) {
computeBoundingBox();
}
return boundingMinX;
}
public int getBoundingMinY() {
if (!finished) {
computeBoundingBox();
}
return boundingMinY;
}
public int getBoundingMaxX() {
if (!finished) {
computeBoundingBox();
}
return boundingMaxX;
}
public int getBoundingMaxY() {
if (!finished) {
computeBoundingBox();
}
return boundingMaxY;
}
private void computeBoundingBox() {
long lx = Long.MAX_VALUE;
long ly = Long.MAX_VALUE;
long hx = Long.MIN_VALUE;
long hy = Long.MIN_VALUE;
for (int i = 0; i < numRectangles; i++) {
lx = Math.min(lx, rectCoords[i * 4 + 0]);
ly = Math.min(ly, rectCoords[i * 4 + 1]);
hx = Math.max(hx, rectCoords[i * 4 + 2]);
hy = Math.max(hy, rectCoords[i * 4 + 3]);
}
int[] bounds = new int[4];
for (CellInst ci : subCells) {
long x = ci.anchorX;
long y = ci.anchorY;
bounds[0] = ci.subCell.getBoundingMinX();
bounds[1] = ci.subCell.getBoundingMinY();
bounds[2] = ci.subCell.getBoundingMaxX();
bounds[3] = ci.subCell.getBoundingMaxY();
ci.orient.transformRects(bounds, 0, 1);
lx = Math.min(lx, x + bounds[0]);
ly = Math.min(ly, y + bounds[1]);
hx = Math.max(hx, x + bounds[2]);
hy = Math.max(hy, y + bounds[3]);
}
if (lx <= hx && ly <= hy) {
if (lx < -LayoutCell.MAX_COORD
|| hx > LayoutCell.MAX_COORD
|| ly < -LayoutCell.MAX_COORD
|| hy > LayoutCell.MAX_COORD) {
throw new IllegalArgumentException("Too large bounding box");
}
boundingMinX = (int) lx;
boundingMinY = (int) ly;
boundingMaxX = (int) hx;
boundingMaxY = (int) hy;
}
finished = true;
}
public void setName(String name) {
if (finished) {
throw new IllegalStateException();
}
this.name = name;
}
public void addRectangle(int minX, int minY, int maxX, int maxY) {
if (finished) {
throw new IllegalStateException();
}
if (minX >= maxX || minY >= maxY) {
throw new IllegalArgumentException();
}
if (numRectangles * 4 >= rectCoords.length) {
int[] newRectCoords = new int[rectCoords.length * 2];
System.arraycopy(rectCoords, 0, newRectCoords, 0, rectCoords.length);
rectCoords = newRectCoords;
}
rectCoords[numRectangles * 4 + 0] = minX;
rectCoords[numRectangles * 4 + 1] = minY;
rectCoords[numRectangles * 4 + 2] = maxX;
rectCoords[numRectangles * 4 + 3] = maxY;
numRectangles++;
System.out.println("\"" + name + "\".addRectangle(" + minX + "," + minY + "," + maxX + "," + maxY
+ ")");
}
public void addSubCell(LayoutCell subCell, int anchorX, int anchorY, ManhattanOrientation orient) {
if (finished) {
throw new IllegalStateException();
}
subCells.add(new CellInst(subCell, anchorX, anchorY, orient));
System.out.println("\"" + name + "\".addSubCell(\"" + subCell.getName() + "\"," + anchorX + ","
+ anchorY + "," + orient + ");");
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
rectCoords = new int[numRectangles * 4];
for (int i = 0; i < rectCoords.length; i++) {
rectCoords[i] = in.readInt();
}
}
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
for (int i = 0; i < numRectangles * 4; i++) {
out.writeInt(rectCoords[i]);
}
}
}