App 2.49.1: the Caterpillar looks more like the one in the book
It arches over the middle like the cover's: overlapping chunks of mottled green paper, a yellow fringe, olive feet, and a red-orange head with a yellow face and purple antennae. Still an original drawing. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
This commit is contained in:
+2
-2
@@ -34,8 +34,8 @@ android {
|
||||
applicationId "com.stinnesbeck.nilsmg4"
|
||||
minSdk 27
|
||||
targetSdk 36
|
||||
versionCode 166
|
||||
versionName "2.49.0"
|
||||
versionCode 167
|
||||
versionName "2.49.1"
|
||||
|
||||
// Nothing about the server ships in the APK: its URL and ingest token are entered in
|
||||
// the app's Server tab (ServerConfig), and the database is only reachable by the server.
|
||||
|
||||
@@ -17,9 +17,10 @@ import java.util.Locale;
|
||||
* The Caterpillar Overview style, after the picture book about a very hungry caterpillar (drawn
|
||||
* anew, not copied from it): cut-paper shapes in bright tissue colours on the book's night page.
|
||||
*
|
||||
* In the middle the caterpillar: its red head carries the speed, and its ten green segments are the
|
||||
* power, lit from the head backwards while drawing, blue while regenerating; it wiggles along while
|
||||
* the car moves. On the left the sun is the battery, filling with the charge, and turning into a
|
||||
* In the middle the caterpillar, arched like the one on the book's cover (overlapping chunks of
|
||||
* mottled green tissue paper, a yellow fringe along the back, a red-orange head with a yellow face):
|
||||
* the face carries the speed, and its ten segments are the power, lit from the head backwards while
|
||||
* drawing, blue while regenerating; its back humps up and down while the car moves. On the left the sun is the battery, filling with the charge, and turning into a
|
||||
* grey moon with "BATTERY LOW" blinking below 20 %; above it a big leaf holds trip, usage, climate
|
||||
* and odometer on paper labels. On the right the clock in a paper circle, and the
|
||||
* story's fruit: one apple, two pears, three plums, four strawberries and five oranges, a fruit
|
||||
@@ -442,54 +443,90 @@ final class CaterpillarView extends ClusterCanvasView {
|
||||
|
||||
// ---------- The caterpillar: speed and power ----------
|
||||
|
||||
/** Tissue-paper greens for a segment: base colours, a light patch and a teal patch, by state. */
|
||||
private static final int[][] DRAWING = { { 0xFF4CC15C, 0xFF38A94A, 0xFF66CC6A }, { 0xFF9BE08A, 0xFF2FA89A } };
|
||||
private static final int[][] REGEN = { { 0xFF2A8FC9, 0xFF1F78B4, 0xFF4AA8DA }, { 0xFF9BDCFF, 0xFF3AC8D0 } };
|
||||
private static final int[][] OFF = { { 0xFF2B7A40, 0xFF256B38, 0xFF328C4B }, { 0xFF3A9060, 0xFF2A8078 } };
|
||||
|
||||
/**
|
||||
* The caterpillar arches over the middle like the one on the book's cover: overlapping chunks of
|
||||
* mottled tissue paper in greens and teals, a fringe of yellow hair along its back, olive feet,
|
||||
* and a red-orange head with a yellow face, green eyes and purple antennae. Power lights the
|
||||
* segments (bright green, or blue when regenerating, dull when dark); the speed is on its face.
|
||||
*/
|
||||
private void drawCaterpillar(Canvas c, int w, float u, float pulse) {
|
||||
float hx = w / 2f + 250f * u, hy = 400f * u, hr = 76f * u;
|
||||
float hx = w / 2f + 250f * u, hy = 410f * u, hr = 76f * u;
|
||||
int lit = Tally.ofPower(v.powerKw, 150f, 50f, SEGMENTS);
|
||||
int colour = regen() ? ICE : GREEN;
|
||||
// The segments from the tail towards the head, the legs behind them.
|
||||
int[][] palette = regen() ? REGEN : DRAWING;
|
||||
// The arch: highest in the middle, and it humps up and down while the car moves.
|
||||
float arch = 92f * u + (float) Math.sin(time * 3.5f) * 16f * u;
|
||||
float[] xs = new float[SEGMENTS], ys = new float[SEGMENTS];
|
||||
for (int i = 0; i < SEGMENTS; i++) {
|
||||
xs[i] = hx - 92f * u - i * 48f * u;
|
||||
ys[i] = hy + 24f * u - arch * (float) Math.sin(Math.PI * (i + 0.7) / (SEGMENTS + 0.4));
|
||||
}
|
||||
// From the tail towards the head, each overlapping the one before.
|
||||
for (int i = SEGMENTS - 1; i >= 0; i--) {
|
||||
float x = hx - 100f * u - i * 54f * u;
|
||||
float y = hy + 10f * u + (float) Math.sin(time * 3.5f - i * 0.75f) * 12f * u;
|
||||
boolean on = i < lit;
|
||||
float rad = 32f * u * (1f + (on ? pulse * (i % 2 == 0 ? 0.18f : 0.12f) : 0f));
|
||||
line.setColor(HEAD);
|
||||
line.setStrokeWidth(4f * u);
|
||||
float foot = (i % 2 == 0 ? 6f : -6f) * u;
|
||||
c.drawLine(x, y + rad - 4f * u, x + foot, y + rad + 14f * u, line);
|
||||
fill.setColor(on ? colour : 0xFF3B7A4A);
|
||||
c.drawCircle(x, y, rad, fill);
|
||||
line.setColor(on ? GREEN_DARK : 0xFF2A5A36);
|
||||
line.setStrokeWidth(3f * u);
|
||||
c.drawCircle(x, y, rad, line);
|
||||
if (on) {
|
||||
fill.setColor(0x44FFFFFF);
|
||||
c.drawCircle(x - rad * 0.3f, y - rad * 0.35f, rad * 0.28f, fill);
|
||||
int[][] pal = on ? palette : OFF;
|
||||
float x = xs[i], y = ys[i];
|
||||
int prev = Math.max(0, i - 1), next = Math.min(SEGMENTS - 1, i + 1);
|
||||
float angle = (float) Math.toDegrees(Math.atan2(ys[prev] - ys[next], xs[prev] - xs[next]));
|
||||
float grow = 1f + (on ? pulse * (i % 2 == 0 ? 0.16f : 0.1f) : 0f);
|
||||
c.save();
|
||||
c.rotate(angle, x, y);
|
||||
c.scale(grow, grow, x, y);
|
||||
// The foot, under every other segment.
|
||||
if (i % 2 == 0) {
|
||||
line.setColor(0xFF8A7B2E);
|
||||
line.setStrokeWidth(8f * u);
|
||||
c.drawLine(x, y + 46f * u, x + 3f * u, y + 60f * u, line);
|
||||
}
|
||||
// The chunk of paper with two patches of other tissue on it.
|
||||
r.set(x - 37f * u, y - 48f * u, x + 37f * u, y + 48f * u);
|
||||
fill.setColor(pal[0][i % 3]);
|
||||
c.drawOval(r, fill);
|
||||
fill.setColor(AccentColor.withAlpha(pal[1][0], 0x80));
|
||||
r.set(x - 28f * u, y - (i % 2 == 0 ? 38f : 10f) * u, x + 4f * u, y + (i % 2 == 0 ? -4f : 36f) * u);
|
||||
c.drawOval(r, fill);
|
||||
fill.setColor(AccentColor.withAlpha(pal[1][1], 0x70));
|
||||
r.set(x - 2f * u, y - (i % 2 == 0 ? 8f : 40f) * u, x + 30f * u, y + (i % 2 == 0 ? 38f : 0f) * u);
|
||||
c.drawOval(r, fill);
|
||||
// The fringe of hair along the back.
|
||||
line.setColor(on ? 0xFFD9C84A : 0x80D9C84A);
|
||||
line.setStrokeWidth(2f * u);
|
||||
for (int k = -2; k <= 2; k++) {
|
||||
c.drawLine(x + k * 12f * u, y - (46f - Math.abs(k) * 4f) * u, x + k * 15f * u, y - (57f - Math.abs(k) * 4f) * u, line);
|
||||
}
|
||||
c.restore();
|
||||
}
|
||||
// The head, with antennae and eyes, and the speed.
|
||||
line.setColor(HEAD);
|
||||
line.setStrokeWidth(4f * u);
|
||||
c.drawLine(hx - 22f * u, hy - hr + 8f * u, hx - 40f * u, hy - hr - 30f * u, line);
|
||||
c.drawLine(hx + 22f * u, hy - hr + 8f * u, hx + 40f * u, hy - hr - 30f * u, line);
|
||||
fill.setColor(0xFFFFA726);
|
||||
c.drawCircle(hx - 40f * u, hy - hr - 32f * u, 7f * u, fill);
|
||||
c.drawCircle(hx + 40f * u, hy - hr - 32f * u, 7f * u, fill);
|
||||
fill.setColor(HEAD);
|
||||
c.drawCircle(hx, hy, hr * (1f + pulse * 0.04f), fill);
|
||||
fill.setColor(0x33FFFFFF);
|
||||
c.drawCircle(hx - hr * 0.35f, hy - hr * 0.4f, hr * 0.2f, fill);
|
||||
// The head: purple antennae, a red-orange head with a yellow face, green eyes, the speed.
|
||||
line.setColor(0xFF7B68C8);
|
||||
line.setStrokeWidth(8f * u);
|
||||
c.drawLine(hx - 24f * u, hy - hr + 10f * u, hx - 46f * u, hy - hr - 40f * u, line);
|
||||
c.drawLine(hx + 24f * u, hy - hr + 10f * u, hx + 46f * u, hy - hr - 40f * u, line);
|
||||
float hs = 1f + pulse * 0.04f;
|
||||
fill.setColor(0xFFE8452B);
|
||||
c.drawCircle(hx, hy, hr * hs, fill);
|
||||
r.set(hx - 52f * u, hy - 64f * u, hx + 52f * u, hy + 62f * u);
|
||||
fill.setColor(0xFFFFC21F);
|
||||
c.drawOval(r, fill);
|
||||
for (int side = -1; side <= 1; side += 2) {
|
||||
fill.setColor(0xFFFFFFFF);
|
||||
c.drawCircle(hx + side * 24f * u, hy - 34f * u, 14f * u, fill);
|
||||
r.set(hx + side * 26f * u - 11f * u, hy - 50f * u, hx + side * 26f * u + 11f * u, hy - 20f * u);
|
||||
fill.setColor(0xFF3F9A3A);
|
||||
c.drawOval(r, fill);
|
||||
line.setColor(INK);
|
||||
line.setStrokeWidth(2f * u);
|
||||
c.drawOval(r, line);
|
||||
fill.setColor(INK);
|
||||
c.drawCircle(hx + side * 24f * u + 3f * u, hy - 33f * u, 6f * u, fill);
|
||||
c.drawCircle(hx + side * 26f * u, hy - 38f * u, 3.5f * u, fill);
|
||||
}
|
||||
label(c, fmt(v.speedKmh, "%.0f", "—"), hx, hy + 38f * u, 58f * u, 0xFFFFFFFF, serif, Paint.Align.CENTER);
|
||||
label(c, "KM/H", hx, hy + 58f * u, 14f * u, 0xCCFFE9EA, face, Paint.Align.CENTER);
|
||||
label(c, fmt(v.speedKmh, "%.0f", "—"), hx, hy + 30f * u, 46f * u, INK, serif, Paint.Align.CENTER);
|
||||
label(c, "KM/H", hx, hy + 48f * u, 13f * u, 0xFF7A3A10, face, Paint.Align.CENTER);
|
||||
boolean regen = regen();
|
||||
String power = v.powerKw == null ? "— kW" : String.format(Locale.US, regen ? "+%.1f kW" : "%.1f kW",
|
||||
Math.abs(v.powerKw));
|
||||
outlined(c, power, hx - 100f * u - 4.5f * 54f * u, 556f * u, 34f * u, regen ? ICE : BONE, face, Paint.Align.CENTER, u);
|
||||
outlined(c, power, hx - 92f * u - 4.5f * 48f * u, 556f * u, 34f * u, regen ? ICE : BONE, face, Paint.Align.CENTER, u);
|
||||
}
|
||||
|
||||
// ---------- What plays: a butterfly or a ladybird tows it on tissue paper ----------
|
||||
|
||||
Reference in New Issue
Block a user