/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: UnloadPolys.java
* Written by Dmitry Nadezhin, Sun Microsystems.
*
* Copyright (c) 2005, 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.database.geometry.bool;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.geometry.PolyBase;
import com.sun.electric.util.math.DBMath;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
*
*/
public class UnloadPolys {
private static class Polys {
Polys next;
int x, y;
}
Polys polyPool;
private static final int IN = 1;
private static final int OUT = 0;
private static final int B = OUT;
private static final int W = IN;
private static class Arc {
Arc next;
int[] y = new int[2];
Arc[] b = new Arc[2], t = new Arc[2];
List<PolyBase.PolyBaseTreeImpl> sons;
Polys pol;
private void addSon(PolyBase.PolyBaseTreeImpl son) {
if (sons == null)
sons = new ArrayList<PolyBase.PolyBaseTreeImpl>();
sons.add(son);
}
private void addSons(List<PolyBase.PolyBaseTreeImpl> newSons) {
if (newSons == null || newSons.isEmpty())
return;
if (sons == null)
sons = new ArrayList<PolyBase.PolyBaseTreeImpl>();
sons.addAll(newSons);
}
}
Arc arcPool;
private int[] inpA = new int[1];
private int inpC;
private int x;
private Arc mainArc;
private Arc top;
private List<Arc> stack = new ArrayList<Arc>();
private int v, nv;
private boolean rotated;
@SuppressWarnings("unchecked")
public Iterable<PolyBase.PolyBaseTree> loop(DataInputStream inpS, boolean rotated) throws IOException {
this.rotated = rotated;
mainArc = newArc();
mainArc.y[IN] = Integer.MIN_VALUE;
mainArc.y[OUT] = Integer.MAX_VALUE;
mainArc.t[IN] = mainArc;
mainArc.b[OUT] = mainArc;
while (getLine(inpS)) {
// printInp();
scanLine();
}
assert mainArc.t[IN] == mainArc && mainArc.b[OUT] == mainArc;
Collection result = mainArc.sons != null ? Collections.unmodifiableCollection(mainArc.sons) : Collections.emptyList();
dispArc(mainArc);
return result;
}
private boolean getLine(DataInputStream inpS) throws IOException {
resetInp();
boolean eof = inpS.readBoolean();
if (!eof) {
return false;
}
x = inpS.readInt();
int count = inpS.readInt();
while (count > inpA.length) {
int[] newInpA = new int[inpA.length*2];
System.arraycopy(inpA, 0, newInpA, 0, inpA.length);
inpA = newInpA;
}
while (inpC < count) {
inpA[inpC++] = inpS.readInt();
}
return true;
}
/* +->----! OUT */
/* | main ! */
/* | ! W */
/* | #-<-!.. IN */
/* | |***! . */
/* | |***! . */
/* | |***! . B */
/* | +->-!.# OUT */
/* | ! poly */
/* +-<----! IN */
private void scanLine() {
stack.clear();
top = mainArc;
v = W; nv = B;
/* top->y[v] < top->y[!v] */
Arc al = top;
int y = 0;
int d = 0;
for (int inpPos = 0; inpPos < inpC; ) {
if (Math.abs(d) == 2) {
d >>= 1;
} else {
int inpVal = inpA[inpPos++];
y = inpVal >> 1;
d = (inpVal & 1) != 0 ? 1 : -1;
while (inpPos < inpC && (inpA[inpPos] >> 1) == y) {
if ((inpA[inpPos++] & 1) != 0) {
d++;
} else {
d--;
}
}
}
assert d == 1 || d == -1;
assert v + nv == 1;
while (y >= top.y[nv]) {
al = top;
POP();
}
assert top.y[v] <= y && y < top.y[nv];
for (;;) {
while (al.t[v] != top && y >= al.t[v].y[v]) {
al = al.t[v];
}
if (al.t[v] == top || y < al.t[v].y[nv]) {
break;
}
al = al.t[v];
PUSH( al );
}
assert top.y[v] <= y && y < top.y[nv];
Arc ar = al.t[v];
if (y > al.y[v]) {
Polys pl = newPolys();
pl.y = y;
pl.next = pl;
Arc at = newArc();
at.y[nv] = at.y[v] = y;
at.pol = pl;
GLUE(al, at, v);
GLUE(at, at, nv);
GLUE(at, ar, v);
al = at;
}
assert y == al.y[v];
assert ar == al.t[v];
assert al == ar.b[nv];
{
int inpVal = inpA[inpPos++];
y = inpVal >> 1;
d = (inpVal & 1) != 0 ? 1 : -1;
while (inpPos < inpC && (inpA[inpPos] >> 1) == y) {
if ((inpA[inpPos++] & 1) != 0) {
d++;
} else {
d--;
}
}
assert d == 1 || d == -1 || d == 2 || d == -2;
}
assert y <= ar.y[nv];
if ( y < ar.y[nv] /*|| Math.abs(d) == 2*/) {
al.y[v] = y;
Polys pl = newPolys();
pl.y = y;
pl.next = pl;
al.pol = CAT( al.pol, v, pl);
} else {
Arc aln = al.b[v];
Arc arn = ar.t[nv];
GLUE(aln, arn, nv);
if (al == ar) {
assert al == top;
top.pol.x = x;
PolyBase.PolyBaseTreeImpl t = outTree(top.pol);
if (top.sons != null) {
for (PolyBase.PolyBaseTree s: top.sons)
t.addSonLowLevel(s);
}
// out(top.pol,v);
dispArc(top);
POP();
top.addSon(t);
} else if (al == top) {
top.pol = CAT(top.pol, v, ar.pol);
REPLACE(ar,top,v);
arn = aln.t[nv];
List<PolyBase.PolyBaseTreeImpl> sons = ar.sons;
dispArc(ar);
POP();
top.addSons(sons);
} else if (ar == top) {
top.pol = CAT(top.pol, nv, al.pol);
REPLACE(al, top, nv);
aln = arn.b[v];
List<PolyBase.PolyBaseTreeImpl> sons = al.sons;
dispArc(al);
POP();
top.addSons(sons);
} else {
al.pol = CAT(al.pol, v, ar.pol);
REPLACE(ar, al, v);
arn = aln.t[nv];
List<PolyBase.PolyBaseTreeImpl> sons = ar.sons;
dispArc(ar);
al.addSons(sons);
PUSH(al);
}
al = aln;
ar = arn;
}
}
}
private void out(Polys pl, int v) {
Polys pg = pl;
int n = 0;
int lx = Integer.MAX_VALUE, ly = Integer.MAX_VALUE, hx = Integer.MIN_VALUE, hy = Integer.MIN_VALUE;
do {
lx = Math.min(lx, pg.x);
hx = Math.max(hx, pg.x);
ly = Math.min(ly, pg.y);
hy = Math.max(hy, pg.y);
pg = pg.next;
n++;
} while (pg != pl);
if (v == B && n == 2 && ((lx + hx)&1) == 0) {
System.out.println("WIRE " + prCoord(false, (lx + hx)/2) + " " + prCoord(true, ly) +
" w=" + DBMath.gridToLambda(hx - lx) + " " + prCoord(true, hy));
// System.out.println("BOX " + prPoint(lx, ly) + " " + prPoint(hx, hy));
return;
}
if (v == B) {
Polys top = pl;
while (top.y != hy) {
top = top.next;
}
List<Polys> left = new ArrayList<Polys>();
Polys bottom = top;
while (bottom.next.y < bottom.y) {
left.add(bottom);
bottom = bottom.next;
}
left.add(bottom);
List<Polys> right = new ArrayList<Polys>();
Polys p = bottom;
while (p.next.y > p.y) {
right.add(p);
p = p.next;
}
right.add(p);
if (p == top) {
int mx = (lx + hx)/2;
System.out.print("WIRE " + prCoord(false, mx) + " " + prCoord(true, ly));
int leftI = left.size() - 1;
int rightI = 0;
for (;;) {
int leftW = mx - left.get(leftI - 1).x;
int rightW = right.get(rightI).x - mx;
System.out.print(" w=");
if (leftW == rightW) {
System.out.print(DBMath.gridToLambda(leftW + rightW));
} else {
System.out.print(DBMath.gridToLambda(leftW) + "+" + DBMath.gridToLambda(rightW));
}
int nextY = Math.min(left.get(leftI - 1).y, right.get(rightI + 1).y);
System.out.print(" " + prCoord(true, nextY));
if (nextY == hy) {
assert leftI == 1 && rightI == right.size() - 2;
break;
}
if (nextY == left.get(leftI - 1).y) {
leftI--;
}
if (nextY == right.get(rightI + 1).y) {
rightI++;
}
}
System.out.println();
// System.out.print("POLY");
// do {
// System.out.print(" " + prPoint(pg.x, pg.y));
// System.out.print(" " + prPoint(pg.x, pg.next.y));
// pg = pg.next;
// } while (pg != pl);
// System.out.println();
return;
}
}
if (v == B) {
System.out.print("POLY");
} else {
System.out.print("NEGATIVE POLY");
}
do {
System.out.print(" " + prPoint(pg.x, pg.y));
System.out.print(" " + prPoint(pg.x, pg.next.y));
pg = pg.next;
} while (pg != pl);
System.out.println();
}
PolyBase.PolyBaseTreeImpl outTree(Polys pl) {
Polys pg = pl;
int n = 0;
do {
pg = pg.next;
n++;
} while (pg != pl);
EPoint[] pts = new EPoint[n*2];
if (rotated) {
int k = pts.length;
do {
pts[--k] = EPoint.fromGrid(pg.y, pg.x);
pts[--k] = EPoint.fromGrid(pg.next.y, pg.x);
pg = pg.next;
} while (pg != pl);
assert k == 0;
} else {
int k = 0;
do {
pts[k++] = EPoint.fromGrid(pg.x, pg.y);
pts[k++] = EPoint.fromGrid(pg.x, pg.next.y);
pg = pg.next;
} while (pg != pl);
assert k == pts.length;
}
PolyBase p = new PolyBase(pts);
return new PolyBase.PolyBaseTreeImpl(p);
}
private String prPoint(int x, int y) {
return rotated ? prCoord(y) + "," + prCoord(x) : prCoord(x) + "," + prCoord(y);
}
private String prCoord(boolean isY, int v) {
return (isY^rotated ? "y=" : "x=") + prCoord(v);
}
private String prCoord(int v) {
double period = 144*400;
int n = (int)Math.floor(v/period);
return n+"#"+DBMath.gridToLambda(v - n*period);
}
private void GLUE(Arc al, Arc ar, int v) {
al.t[v] = ar;
ar.b[1 - v] = al;
}
private void REPLACE(Arc so, Arc sn, int v) {
int nv = 1 - v;
sn.y[v] = so.y[v];
so.b[v].t[nv] = sn;
so.t[v].b[nv] = sn;
sn.b[v] = so.b[v];
sn.t[v] = so.t[v];
}
private void PUSH(Arc a) {
stack.add(top);
top = a;
nv = v;
v = 1 - v;
}
private void POP() {
nv = v;
v = 1 - v;
top = stack.remove(stack.size() - 1);
}
private Polys CAT(Polys pl, int v, Polys pg) {
(v == IN ? pg : pl ).x = x;
Polys pt = pl.next;
pl.next = pg.next;
pg.next = pt;
/*pl=*/ return v == IN ? pl : pg;
}
private void printInp() throws IOException {
System.out.print("x=" + DBMath.gridToLambda(x));
for (int i = 0; i < inpC; i++) {
int inpVal = inpA[i];
int y = inpVal >> 1;
boolean df = (inpVal & 1) != 0;
System.out.print(" " + DBMath.gridToLambda(y) + (df?"^":"_"));
}
System.out.println();
}
private void resetInp() {
inpC = 0;
}
private void putPointInp(int y, int val) {
if (inpC >= inpA.length) {
int[] newInpA = new int[inpA.length*2];
System.arraycopy(inpA, 0, newInpA, 0, inpA.length);
inpA = newInpA;
}
// System.out.println("putPointInp " + y + " " + val);
inpA[inpC++] = (y << 1) | (val > 0 ? 1 : 0);
}
private Polys newPolys() {
Polys result;
if (polyPool == null) {
result = new Polys();
} else {
result = polyPool;
polyPool = polyPool.next;
}
// result.next = next;
return result;
}
private void dispPolys(Polys p) {
p.next = polyPool;
polyPool = p;
}
private Arc newArc() {
Arc result;
if (arcPool == null) {
result = new Arc();
} else {
result = arcPool;
arcPool = arcPool.next;
}
// result.next = next;
return result;
}
private void dispArc(Arc p) {
p.next = arcPool;
arcPool = p;
p.sons = null;
}
}