/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: DeltaMerge.java * Written by Dmitry Nadezhin, Sun Microsystems. * * Copyright (c) 2010, 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 java.io.DataOutputStream; import java.io.IOException; import java.util.Arrays; /** * */ public class DeltaMerge { private static class Segment { private Segment next; private int y; // begin of the segment private int val; // height at points below y } private static final Segment segLast = new Segment(); static { segLast.y = Integer.MAX_VALUE; } private Segment segPool; private Segment chain; private int[] inpA = new int[1]; private int inpC; private int[] outA = new int[1]; private int outC; private int pointsSize; private long[] points = new long[1]; private int curPoint; private int x; public DeltaMerge() { chain = new Segment(); chain.next = segLast; chain.y = Integer.MIN_VALUE; } public int loop(DataOutputStream out) throws IOException { Arrays.sort(points, 0, pointsSize); curPoint = 0; int totalOutPoints = 0; while (getLine()) { scanLine(); totalOutPoints += outC; printOut(out); printSegments(); } out.writeBoolean(false); return totalOutPoints; } public void put(int lx, int ly, int hx, int hy) { put(lx, ly, true); put(lx, hy, false); put(hx, ly, false); put(hx, hy, true); } public void put(int x, int y, boolean positive) { if (pointsSize >= points.length) { long[] newPoints = new long[points.length*2]; System.arraycopy(points, 0, newPoints, 0, points.length); points = newPoints; } if (y < -0x40000000 || y > 0x3fffffff) throw new IllegalArgumentException(); long p = ((long)x) << 32 | (((y + 0x40000000) << 1) & 0xfffffffeL); if (positive) p |= 1; points[pointsSize++] = p; } public int size() { return pointsSize; } public void clear() { points = new long[1]; pointsSize = 0; } private void printOut(DataOutputStream out) throws IOException { if (outC == 0) { return; } out.writeBoolean(true); // System.out.print("x=" + DBMath.gridToLambda(x)); out.writeInt(x); out.writeInt(outC); for (int i = 0; i < outC; i++) { int outVal = outA[i]; int y = outVal >> 1; boolean df = (outVal & 1) != 0; // System.out.print(" " + DBMath.gridToLambda(y) + (df?"^":"_")); out.writeInt(outVal); } // System.out.println(); } private boolean getLine() { resetInp(); if (curPoint >= pointsSize) { return false; } long p = points[curPoint++]; x = (int)(p >> 32); for (;;) { int y = (0x80000000 + (int)(p&0xffffffff)) >> 1; int sign = (p&1) != 0 ? 1 : -1; putPointInp(y, sign); if (curPoint >= pointsSize) { break; } p = points[curPoint]; if (x != (int)(p >> 32)) { break; } curPoint++; } return true; } private void printSegments() { for (Segment cp = chain; cp.next != segLast; cp = cp.next) { // System.out.println("y="+cp.y+" val="+cp.val); assert cp.y < cp.next.y; assert cp.val >= 0; } } private void checkSegments() { assert chain.y == Integer.MIN_VALUE; assert chain.val == 0; for (Segment cp = chain; cp.next != segLast; cp = cp.next) { assert cp.y < cp.next.y; assert cp.val >= 0; } assert segLast.y == Integer.MAX_VALUE; assert segLast.val == 0; } private void scanLine() { assert inpC > 0; int inpStep = 0; int outStep = 0; Segment cp = chain; resetOut(); for (int inpPos = 0; inpPos < inpC; ) { int inpVal = inpA[inpPos++]; int y = inpVal >> 1; assert cp.y < y; int df = (inpVal & 1) != 0 ? 1 : -1; while (inpPos < inpC && (inpA[inpPos] >> 1) == y) { if ((inpA[inpPos++] & 1) != 0) { df++; } else { df--; } } if (df == 0) { continue; } if (inpStep == 0) { while (cp.next.y < y) { cp = cp.next; } } else { while (cp.next.y < y) { Segment p = cp.next; int oldO = p.val == 0 ? 0 : 1; p.val += inpStep; int newO = p.val == 0 ? 0 : 1; int newOutStep = newO - oldO; if (newOutStep != outStep) { putPointOut(p.y, newOutStep - outStep); outStep = newOutStep; } cp = p; } } assert cp.y < y && y <= cp.next.y; Segment p; if (cp.next.y > y) { p = newSegment(cp.next); p.y = y; p.val = cp.val - inpStep; cp.next = p; } else { p = cp.next; } inpStep += df; assert p.y == y; int oldO = p.val == 0 ? 0 : 1; p.val += inpStep; int newO = p.val == 0 ? 0 : 1; int newOutStep = newO - oldO; if (newOutStep != outStep) { putPointOut(y, newOutStep - outStep); outStep = newOutStep; } if (cp.val == p.val) { cp.next = p.next; dispSegment(p); } else { cp = p; } assert cp.y <= y; } assert inpStep == 0; } 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 void resetOut() { outC = 0; } private void putPointOut(int y, int val) { if (outC >= outA.length) { int[] newOutA = new int[outA.length*2]; System.arraycopy(outA, 0, newOutA, 0, outA.length); outA = newOutA; } if (val == +1) { outA[outC++] = (y << 1) | 1; } else if (val == -1) { outA[outC++] = (y << 1); } else if (val == +2) { outA[outC++] = (y << 1) | 1; putPointOut(y, +1); } else if (val == -2) { outA[outC++] = (y << 1); putPointOut(y, -1); } else { throw new AssertionError(); } } private Segment newSegment(Segment next) { Segment result; if (segPool == null) { result = new Segment(); } else { result = segPool; segPool = segPool.next; } result.next = next; return result; } private void dispSegment(Segment p) { p.next = segPool; segPool = p; } }