/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: SimpleChecker.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.plugins.minarea.deltamerge0;
import com.sun.electric.api.minarea.LayoutCell;
import com.sun.electric.api.minarea.ManhattanOrientation;
import com.sun.electric.api.minarea.MinAreaChecker;
import com.sun.electric.api.minarea.geometry.Point;
import com.sun.electric.database.geometry.PolyBase;
import com.sun.electric.database.geometry.bool.DeltaMerge;
import com.sun.electric.database.geometry.bool.UnloadPolys;
import com.sun.electric.util.math.DBMath;
import java.awt.geom.Point2D;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Properties;
/**
* Simple MinAreaChecker
*/
public class SimpleChecker implements MinAreaChecker {
private final int DEBUG = 1;
private long totalArea;
/**
*
* @return the algorithm name
*/
public String getAlgorithmName() {
return "DeltaMerge0";
}
/**
*
* @return the names and default values of algorithm parameters
*/
public Properties getDefaultParameters() {
return new Properties();
}
/**
* @param topCell
* top cell of the layout
* @param minArea
* minimal area of valid polygon
* @param parameters
* algorithm parameters
* @param errorLogger
* an API to report violations
*/
public void check(LayoutCell topCell, long minArea, Properties parameters, ErrorLogger errorLogger) {
DeltaMerge dm = new DeltaMerge();
collect(dm, topCell, 0, 0, ManhattanOrientation.R0);
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(bout);
dm.loop(out);
out.close();
byte[] ba = bout.toByteArray();
bout = null;
DataInputStream inpS = new DataInputStream(new ByteArrayInputStream(ba));
UnloadPolys up = new UnloadPolys();
Iterable<PolyBase.PolyBaseTree> trees = up.loop(inpS, false);
inpS.close();
totalArea = 0;
for (PolyBase.PolyBaseTree tree : trees) {
traversePolyTree(tree, 0, minArea, errorLogger);
}
if (DEBUG >= 1) {
System.out.println("Total Area "+totalArea);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void collect(final DeltaMerge dm, LayoutCell cell, final int x, final int y, final ManhattanOrientation orient) {
int bufSize = Math.max(1, Math.min(16, cell.getNumRectangles()));
int[] coords = new int[4 * bufSize];
int ir = 0;
while (ir < cell.getNumRectangles()) {
int sz = Math.min(bufSize, cell.getNumRectangles() - ir);
cell.readRectangleCoords(coords, ir, sz);
orient.transformRects(coords, 0, 1);
for (int j = 0; j < sz; j++) {
// The coordinates will fit into ints, because bounding box
// of LayoutCell is limited within [-MAX_Coord,+MAX_COORD]
int lx = coords[j * 4 + 0] + x;
int ly = coords[j * 4 + 1] + y;
int hx = coords[j * 4 + 2] + x;
int hy = coords[j * 4 + 3] + y;
dm.put(lx, ly, hx, hy);
}
ir += sz;
}
if (cell.getNumSubcells() > 0) {
cell.traverseSubcellInstances(new LayoutCell.SubcellHandler() {
public void apply(LayoutCell subCell, int anchorX, int anchorY, ManhattanOrientation subOrient) {
Point p = new Point(anchorX, anchorY).transform(orient);
collect(dm, subCell, p.getX() + x, p.getY() + y, orient.concatenate(subOrient));
}
});
}
}
private void traversePolyTree(PolyBase.PolyBaseTree obj, int level, long minArea, ErrorLogger errorLogger) {
if (level % 2 == 0) {
PolyBase poly = obj.getPoly();
if (DEBUG >= 4) {
for (Point2D p: poly.getPoints()) {
System.out.print(" ("+DBMath.lambdaToGrid(p.getX())+","+DBMath.lambdaToGrid(p.getY())+")");
}
System.out.println();
}
double area = poly.getArea();
for (PolyBase.PolyBaseTree son : obj.getSons()) {
PolyBase hole = son.getPoly();
if (DEBUG >= 4) {
System.out.print(" hole");
for (Point2D p: hole.getPoints()) {
System.out.print(" ("+DBMath.lambdaToGrid(p.getX())+","+DBMath.lambdaToGrid(p.getY())+")");
}
System.out.println();
}
area -= hole.getArea();
}
long larea = DBMath.lambdaToGrid(area * DBMath.GRID);
totalArea += larea;
if (larea < minArea) {
Point2D p = poly.getPoints()[1];
errorLogger.reportMinAreaViolation(larea, (int)DBMath.lambdaToGrid(p.getX()), (int)DBMath.lambdaToGrid(p.getY()));
}
}
for (PolyBase.PolyBaseTree son : obj.getSons()) {
traversePolyTree(son, level + 1, minArea, errorLogger);
}
}
}