Libraryless. Click here for Pure Java version (9612L/54K).
// Optimal many-translucent-circles painter // [ O(w*h) + O(n*r) ] // // with // w = image width // h = image height // n = # circles // r = average height of a circle // // Comparison: // - Naive painting is O(w*h) + O(n*r*r) // - Naive raytracing is O(w*h*n) // // Loose proof of optimality: // - A term of O(w*h) is always required just to paint each pixel. // - And n*r is the minimum number of steps you have to do to actually // figure out each circle's shape (either by walking around it // or by calculating its width on each line). sclass ManyCirclePainter is MakesBufferedImage { settable int w; settable int h; settable new L<Circle> circles; int[] pixels; L<Circle>[] startCircle, stopCircle; bool ran; srecord Circle(Pt center, int radius) {} public int getWidth() { ret w; } public int getHeight() { ret h; } selfType addCircle(int x, int y, int radius) { circles.add(new Circle(pt(x, y), radius)); this; } run { if (ran) ret; set ran; pixels = new int[w*h]; if (pixels.length == 0) ret; int nCircles = l(circles); startCircle = new L[h]; stopCircle = new L[h]; for (circle : circles) { int y1 = max(0, circle.center.y-circle.radius); int y2 = circle.center.y+circle.radius+1; if (y1 >= y2) continue; startCircle[y1] = addOrCreate(startCircle[y1], circle); if (y2 < h) stopCircle[y2] = addOrCreate(stopCircle[y2], circle); } int[] startStop = new[w]; new Set<Circle> liveCircles; int iPixel = 0; for y to h: { fillArray(startStop, 0); addAll(liveCircles, startCircle[y]); removeAll(liveCircles, stopCircle[y]); for (c : liveCircles) { // width of circle at this line int width = iround(sqrt(sqr(c.radius)-sqr(y-c.center.y))); int x1 = c.center.x-width, x2 = c.center.x+width+1; if (x1 > w || x2 <= 0) continue; // not visible at all at this row startStop[max(x1, 0)]++; if (x2 < w) startStop[x2]--; } int count = 0; for x to w: { count += startStop[x]; pixels[iPixel++] = countToColor(count, nCircles); } } } int countToColor(int count, int nCircles) { ret rgbIntFromBrightness(doubleRatio(count, min(nCircles, 8))); } public BufferedImage getBufferedImage aka get() { run(); ret bufferedImageWithoutAlpha(w, h, pixels); } }
download show line numbers debug dex old transpilations
Travelled to 3 computer(s): ekrmjmnbrukm, mowyntqkapby, mqqgnosmbjvj
No comments. add comment
Snippet ID: | #1035476 |
Snippet name: | ManyCirclePainter |
Eternal ID of this version: | #1035476/20 |
Text MD5: | e6ba151aa0b3932b0b28394bfdd9b1c1 |
Transpilation MD5: | ca66c0ed4e268d33422ef7098be7d46b |
Author: | someone |
Category: | |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2022-05-22 23:52:19 |
Source code size: | 2552 bytes / 91 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 158 / 333 |
Version history: | 19 change(s) |
Referenced in: | #1003674 - Standard Classes + Interfaces (LIVE continued in #1034167) |