Warning: session_start(): open(/var/lib/php/sessions/sess_4gljgqc2c15gsg6a65t4r7oaeh, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
// SSI - Simple Scanline Image
// A partial image consisting of exactly one horizontal line per row.
// All pixels are of the same color.
// The important values are y1 and data
persistable sclass SSI extends AbstractSSI is HasBounds, G2Drawable, ByteIO {
replace X with short.
replace Y with short.
replace toX with toShort_enforce.
replace toY with toShort_enforce.
replace newXArray with newShortArrayOrNull.
// core value (mandatory): first row occupied
settable Y y1;
// core value (mandatory): x coordinates per row
// x_left is inclusive, x_right is exclusive
//
// Order in array:
// x_left at y1, x_right at y1,
// x_left at y1+1, x_right at y1+1, ,,,
settable X[] data;
*(int y1, int y2) {
init(y1, y2);
}
void init(int y1, int y2) {
this.y1 = toY(y1);
data = newXArray((y2-y1)*2);
}
void set(int y, int xLeft, int xRight) {
data[(y-y1)*2] = toX(xLeft);
data[(y-y1)*2+1] = toX(xRight);
}
// bounds can be calculated quickly from core values & are then cached
public simplyCached Rect bounds() {
int x1 = Int.MAX_VALUE, x2 = 0;
for (int i = 0; i < l(data); i += 2) {
x1 = min(x1, data[i]);
x2 = max(x2, data[i+1]);
}
ret rectFromPoints(x1, y1, x2, y2());
}
// same with number of pixels
int numberOfPixels_cache = -1;
public int numberOfPixels() {
if (numberOfPixels_cache < 0) {
int n = 0;
for (int i = 0; i < l(data); i += 2)
n += max(0, data[i+1]-data[i]);
numberOfPixels_cache = n;
}
ret numberOfPixels_cache;
}
public int getHeight() { ret l(data)/2; }
int y2() { ret y1+height(); }
bool contains(Pt p) { ret contains(p.x, p.y); }
bool contains(int x, int y) {
if (y < y1) false;
int i = (y-y1)*2;
if (i >= l(data)) false;
ret x >= data[i] && x < data[i+1];
}
selfType color(RGB color) { super.color(color); this; }
public selfType hi15color(short hi15color) { super.hi15color(hi15color); this; }
public void drawOn(Graphics2D g) {
g.setColor(color());
int h = height();
for y to h: {
int x1 = data[y*2], x2 = data[y*2+1];
if (x1 < x2)
g.drawLine(x1, y1+y, x2-1, y1+y);
}
}
// doesn't set a color
// TODO
public void drawOutline(Graphics2D g) {
int h = height();
IntRange last = intRange(0, 0);
for y to h: {
IntRange r = intRange(data[y*2], data[y*2+1]);
// anything to draw in this line?
if (nempty(r)) {
if (empty(last))
// draw full line if just starting
g.drawLine(r.start, y1+y, r.end-1, y1+y);
else {
// We make a line from the left boundary that if possible goes only to last.start but is at least 1 pixel wide
int xleft = max(r.start, last.start-1);
// Same from the right boundary
int xright = min(r.end-1, last.end);
g.drawLine(r.start, y1+y, xleft, y1+y);
g.drawLine(xright, y1+y, r.end-1, y1+y);
}
}
last = r;
}
}
SSI topPart(int nLines) {
SSI ssi = new SSI(y1, toShort_enforce(y1+nLines)).hi15color(hi15color);
arrayCopy(data, ssi.data, 0, l(ssi.data));
ret ssi;
}
// an SSI is coherent if all scanlines are non-empty
// and the SSI is one region
bool coherent(bool withDiagonals default false) {
int h = height();
for y to h: {
int i = y*2;
int x1 = data[i], x2 = data[i+1];
if (x1 >= x2) false;
if (y > 0) {
int lastx1 = data[i-2], lastx2 = data[i-1];
if (withDiagonals) { lastx1--; lastx2++; }
if (!intRangesOverlap(x1, x2, lastx1, lastx2))
false;
}
}
true;
}
public void readWrite(ByteHead head) {
head.exchangeShort(-> hi15color, color -> hi15color = color);
head.exchangeShort(-> y1, y1 -> this.y1 = y1);
head.exchangeShort(-> toShort_enforce(y2()), y2 -> init(y1, y2));
for i over data: {
reMutable i;
head.exchangeShort(-> data[i], x -> data[i] = x);
}
}
SSI toSSI() { this; }
}