com.ctreber.acearth.scanbit.ScanBuf Maven / Gradle / Ivy
Show all versions of plantuml Show documentation
package com.ctreber.acearth.scanbit;
import java.util.ArrayList;
import java.util.List;
import com.ctreber.aclib.sort.CTSort;
import com.ctreber.aclib.sort.QuickSort;
/**
* 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.
*
*
© 2002 Christian Treber, [email protected]
* @author Christian Treber, [email protected]
*
*/
class ScanBuf
{
private List[] fScanbuf;
private int fLineMin;
private int fLineMax;
private final int fLines;
private final int fPoints;
private boolean fScanBufsAdded;
/**
*
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();
}
}
/**
*
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(new Double(lX));
lX += lDx;
}
fScanBufsAdded = true;
}
public boolean containsPoints()
{
return fScanBufsAdded;
}
/**
*
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].doubleValue() - 0.5);
// Round lLineTo, substract 1
// 1.5 - 2.4999 -> 1.0 - 1.9999 -> 1
int lXHi = (int)Math.floor(lScanLine[n + 1].doubleValue() - 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;
}
}