mirror of
https://github.com/octoleo/plantuml.git
synced 2024-06-11 20:52:24 +00:00
194 lines
4.8 KiB
Java
194 lines
4.8 KiB
Java
package zext.plantuml.com.ctreber.acearth.scanbit;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import zext.plantuml.com.ctreber.aclib.sort.CTSort;
|
|
import zext.plantuml.com.ctreber.aclib.sort.QuickSort;
|
|
|
|
/**
|
|
* <p>For each line, the scanbuffer (= a raster divice) records the points hit
|
|
* I.e., line 5 (y=5) contains the values 2, 6, 40, and 46 (these line have
|
|
* been crossed). The values always come as pairs because we're dealing with
|
|
* polygons, which have a left and a right side which consists of a line.
|
|
* The points in between two values painted as filled.
|
|
*
|
|
* <p>© 2002 Christian Treber, ct@ctreber.com
|
|
* @author Christian Treber, ct@ctreber.com
|
|
*
|
|
*/
|
|
class ScanBuf
|
|
{
|
|
private List[] fScanbuf;
|
|
private int fLineMin;
|
|
private int fLineMax;
|
|
private final int fLines;
|
|
private final int fPoints;
|
|
private boolean fScanBufsAdded;
|
|
|
|
/**
|
|
* <p>Create a list for each line.
|
|
*
|
|
* @param pLines Number of lines aka screen height.
|
|
* @param pPoints Number of points per line aka screen width.
|
|
*/
|
|
public ScanBuf(int pLines, int pPoints)
|
|
{
|
|
fLines = pLines;
|
|
fPoints = pPoints;
|
|
|
|
fLineMin = Integer.MAX_VALUE;
|
|
fLineMax = Integer.MIN_VALUE;
|
|
fScanBufsAdded = false;
|
|
|
|
fScanbuf = new ArrayList[fLines];
|
|
for(int i = 0; i < fScanbuf.length; i++)
|
|
{
|
|
fScanbuf[i] = new ArrayList();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* <p>Add a line to the generateScanBits buffer.
|
|
*/
|
|
public void addLine(double pXFrom, double pYFrom, double pXTo, double pYTo)
|
|
{
|
|
int lYFrom;
|
|
int lYTo;
|
|
|
|
// Do some rounding (but not in the way we expect it), limit values
|
|
if(pYFrom < pYTo)
|
|
{
|
|
// Round lYFrom (but .5 is handled oddly)
|
|
// 1.5001 - 2.5 -> 1.0001 - 2.0 -> 2
|
|
lYFrom = (int)Math.ceil(pYFrom - 0.5);
|
|
// Round lYTo, substract 1
|
|
// 1.5 - 2.4999 -> 1.0 - 1.9999 -> 1
|
|
lYTo = (int)Math.floor(pYTo - 0.5);
|
|
|
|
/**
|
|
* I don't know if this is intended, but in Java 3 == 3.001 is false
|
|
* (the left arg is converted to double), so the expr is true only when
|
|
* pYTo - 0.5 is exactly lYTo
|
|
*/
|
|
if(lYTo == pYTo - 0.5)
|
|
{
|
|
lYTo--;
|
|
}
|
|
} else
|
|
{
|
|
lYFrom = (int)Math.ceil(pYTo - 0.5);
|
|
lYTo = (int)Math.floor(pYFrom - 0.5);
|
|
|
|
if(lYTo == pYFrom - 0.5)
|
|
{
|
|
lYTo--;
|
|
}
|
|
}
|
|
|
|
// Limit y to size of image
|
|
if(lYFrom < 0)
|
|
{
|
|
lYFrom = 0;
|
|
}
|
|
if(lYTo >= fLines)
|
|
{
|
|
lYTo = fLines - 1;
|
|
}
|
|
|
|
if(lYFrom > lYTo)
|
|
{
|
|
// No lines crossed.
|
|
return;
|
|
}
|
|
|
|
// Note min/max settings so far
|
|
if(lYFrom < fLineMin)
|
|
{
|
|
fLineMin = lYFrom;
|
|
}
|
|
if(lYTo > fLineMax)
|
|
{
|
|
fLineMax = lYTo;
|
|
}
|
|
|
|
// todo Curious: What happens if yFrom and yTo are equal? Shit? Or can't they be?
|
|
double lDx = (pXTo - pXFrom) / (pYTo - pYFrom);
|
|
double lX = pXFrom + lDx * ((lYFrom + 0.5) - pYFrom);
|
|
|
|
// Record the x value for every line (y).
|
|
for(int lLineNo = lYFrom; lLineNo <= lYTo; lLineNo++)
|
|
{
|
|
fScanbuf[lLineNo].add(Double.valueOf(lX));
|
|
lX += lDx;
|
|
}
|
|
fScanBufsAdded = true;
|
|
}
|
|
|
|
public boolean containsPoints()
|
|
{
|
|
return fScanBufsAdded;
|
|
}
|
|
|
|
/**
|
|
* <p>For each line, for each x value pair in line, create one ScanBit.
|
|
*/
|
|
public List getScanbits(int pCurveType)
|
|
{
|
|
final List fScanBits = new ArrayList();
|
|
|
|
// For each generateScanBits line containing points
|
|
for(int lLineNo = fLineMin; lLineNo <= fLineMax; lLineNo++)
|
|
{
|
|
// Sort so that lowest x values come first.
|
|
Double[] lScanLine = (Double[])fScanbuf[lLineNo].toArray(new Double[0]);
|
|
CTSort lSort = new QuickSort();
|
|
lSort.sort(lScanLine);
|
|
|
|
// The length will be divisible by 2 because we render closed polyons,
|
|
// so every generateScanBits line is crossed twice (left and right edge of polygon,
|
|
// no intersections allowed!).
|
|
for(int n = 0; n < lScanLine.length; n += 2)
|
|
{
|
|
// Round lLineFrom (but .5 is handled oddly)
|
|
// 1.5001 - 2.5 -> 1.0001 - 2.0 -> 2
|
|
int lXLo = (int)Math.ceil(lScanLine[n] - 0.5);
|
|
// Round lLineTo, substract 1
|
|
// 1.5 - 2.4999 -> 1.0 - 1.9999 -> 1
|
|
int lXHi = (int)Math.floor(lScanLine[n + 1] - 0.5);
|
|
|
|
// Limit low and high x to image dimensions
|
|
if(lXLo < 0)
|
|
{
|
|
lXLo = 0;
|
|
}
|
|
if(lXHi >= fPoints)
|
|
{
|
|
lXHi = fPoints - 1;
|
|
}
|
|
|
|
if(lXLo <= lXHi)
|
|
{
|
|
/**
|
|
* Shouldn't that always be true since we sorted? "Yes", BUT the
|
|
* rounding might create lo 3.6 -> 4.0 and hi 3.7 -> 3.0
|
|
*/
|
|
fScanBits.add(new ScanBit(lLineNo, lXLo, lXHi, pCurveType));
|
|
}
|
|
}
|
|
}
|
|
|
|
return fScanBits;
|
|
}
|
|
|
|
public int getYMax()
|
|
{
|
|
return fLineMax;
|
|
}
|
|
|
|
public int getYMin()
|
|
{
|
|
return fLineMin;
|
|
}
|
|
}
|