package org.apache.batik.gvt.flow;
import java.awt.Shape;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import org.apache.batik.ext.awt.geom.SegmentList;
import org.apache.batik.ext.awt.geom.Segment;
public class FlowRegions {
Shape flowShape;
SegmentList sl;
SegmentList.SplitResults sr;
List validRanges;
int currentRange;
double currentY, lineHeight;
public FlowRegions(Shape s) {
this(s, s.getBounds2D().getY());
}
public FlowRegions(Shape s, double startY) {
this.flowShape = s;
sl = new SegmentList(s);
currentY = startY-1;
gotoY(startY);
}
public double getCurrentY() { return currentY; }
public double getLineHeight() { return lineHeight; }
public boolean gotoY(double y) {
if (y < currentY)
throw new IllegalArgumentException
("New Y can not be lower than old Y\n" +
"Old Y: " + currentY + " New Y: " + y);
if (y == currentY) return false;
sr = sl.split(y);
sl = sr.getBelow();
sr = null;
currentY = y;
if (sl == null) return true;
newLineHeight(lineHeight);
return false;
}
public void newLineHeight(double lineHeight) {
this.lineHeight = lineHeight;
sr = sl.split(currentY+lineHeight);
if (sr.getAbove() != null) {
sortRow(sr.getAbove());
}
currentRange = 0;
}
public int getNumRangeOnLine() {
if (validRanges == null) return 0;
return validRanges.size();
}
public void resetRange() {
currentRange = 0;
}
public double [] () {
if (currentRange >= validRanges.size())
return null;
return (double [])validRanges.get(currentRange++);
}
public void endLine() {
sl = sr.getBelow();
sr = null;
currentY += lineHeight;
}
public boolean newLine() {
return newLine(lineHeight);
}
public boolean newLine(double lineHeight) {
if (sr != null) {
sl = sr.getBelow();
}
sr = null;
if (sl == null) return false;
currentY += this.lineHeight;
newLineHeight(lineHeight);
return true;
}
public boolean newLineAt(double y, double lineHeight) {
if (sr != null) {
sl = sr.getBelow();
}
sr = null;
if (sl == null) return false;
currentY = y;
newLineHeight(lineHeight);
return true;
}
public boolean done() {
return (sl == null);
}
public void sortRow(SegmentList sl) {
Transition [] segs = new Transition[sl.size()*2];
Iterator iter = sl.iterator();
int i=0;
while (iter.hasNext()) {
Segment seg = (Segment)iter.next();
segs[i++] = new Transition(seg.minX(), true);
segs[i++] = new Transition(seg.maxX(), false);
}
Arrays.sort(segs, TransitionComp.COMP);
validRanges = new ArrayList();
int count = 1;
double openStart =0;
for (i=1; i<segs.length; i++) {
Transition t = segs[i];
if (t.up) {
if (count == 0) {
double cx = (openStart + t.loc)/2;
double cy = currentY + lineHeight/2;
if (flowShape.contains( cx, cy )) {
validRanges.add(new double[]{openStart, t.loc});
}
}
count++;
} else {
count--;
if (count == 0)
openStart = t.loc;
}
}
}
static class Transition {
public double loc;
public boolean up;
public Transition(double loc, boolean up) {
this.loc = loc;
this.up = up;
}
}
static class TransitionComp implements Comparator {
public static Comparator COMP = new TransitionComp();
TransitionComp() { }
public int compare(Object o1, Object o2) {
Transition t1 = (Transition)o1;
Transition t2 = (Transition)o2;
if (t1.loc < t2.loc) return -1;
if (t1.loc > t2.loc) return 1;
if (t1.up) {
if (t2.up) return 0;
return -1;
}
if (t2.up) return 1;
return 0;
}
public boolean equals(Object comp) {
return (this == comp);
}
}
}