L'approccio pixel-painting (come suggerito da @Loadmaster) è superiore alla soluzione matematica in una varietà di modi:
- L'implementazione è molto più semplice. Il problema di cui sopra può essere risolto in meno di 100 righe di codice, come dimostra questa soluzione JSFiddle (principalmente perché è concettualmente molto più semplice e non ha casi limite o eccezioni da affrontare).
- Si adatta facilmente a problemi più generali. Funziona con qualsiasi forma, indipendentemente dalla morfologia, purché sia renderizzabile con le librerie di disegno 2D (cioè, "tutte!") - cerchi, ellissi, spline, poligoni, come lo chiami. Diamine, anche immagini bitmap.
- La complessità della soluzione di pixel painting è ~ O [n], rispetto a ~ O [n * n] per la soluzione matematica. Ciò significa che funzionerà meglio all'aumentare del numero di forme.
- E parlando di prestazioni, spesso otterrai l'accelerazione hardware gratuitamente, poiché la maggior parte delle moderne librerie 2D (come la tela di HTML5, credo) scaricherà il lavoro di rendering sugli acceleratori grafici.
L'unico svantaggio del pixel-painting è l'accuratezza finita della soluzione. Ma questo è sintonizzabile semplicemente eseguendo il rendering su tele più grandi o più piccole a seconda della situazione. Si noti inoltre che l' anti-aliasing nel codice di rendering 2D (spesso attivato per impostazione predefinita) produrrà una precisione a livello di pixel migliore. Quindi, ad esempio, il rendering di una figura 100x100 in una tela delle stesse dimensioni dovrebbe, credo, fornire una precisione dell'ordine di 1 / (100 x 100 x 255) = 0,000039% ... che è probabilmente "abbastanza buono" per tutti tranne i problemi più impegnativi.
<p>Area computation of arbitrary figures as done thru pixel-painting, in which a complex shape is drawn into an HTML5 canvas and the area determined by comparing the number of white pixels found in the resulting bitmap. See javascript source for details.</p>
<canvas id="canvas" width="80" height="100"></canvas>
<p>Area = <span id="result"></span></p>
// Get HTML canvas element (and context) to draw into
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// Lil' circle drawing utility
function circle(x,y,r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI*2);
ctx.fill();
}
// Clear canvas (to black)
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Fill shape (in white)
ctx.fillStyle = 'white';
circle(40, 50, 40);
circle(40, 10, 10);
circle(25, 15, 12);
circle(35, 90, 10);
// Get bitmap data
var id = ctx.getImageData(0, 0, canvas.width, canvas.height);
var pixels = id.data; // Flat array of RGBA bytes
// Determine area by counting the white pixels
for (var i = 0, area = 0; i < pixels.length; i += 4) {
area += pixels[i]; // Red channel (same as green and blue channels)
}
// Normalize by the max white value of 255
area /= 255;
// Output result
document.getElementById('result').innerHTML = area.toFixed(2);