un cerchio di Bresenham in Scala (35)
L'algoritmo di Bresenham ha 2 punti principali:
- funziona senza peccato / coseno.
- calcoli solo ¼ * ½ cerchio, gli altri punti si trovano specchiando.
Come farlo:
2 1
DCBABCD
GFE | EFG
IJ y | ---- JI
GJ | / JG
F | / | F
DE | r / | ED
C | / | C
B 4 | / | B 3
A + ------- A
B 4 'x B 3'
CC
ATTO
FF
GJ JG
IJ JI
GFE EFG
DCBABCD
2'1'
- Calcoliamo solo i numeri da A nello zenit a I.
- Il punto I è a 45 °, definito da x == y.
- Ground zero è dove si trova +.
- La A nello zenit è il punto (x = 0, y = r), r = raggio.
- Per disegnare un cerchio chiuso ci spostiamo in senso orario (++ x), che è verso destra (x + = 1) o verso il basso al punto successivo, (y- = 1).
- ogni punto (x, y) sul cerchio è r lontano dal centro. Pitagora dice, r² = x² + y².
- Questo ha odore di radice quadrata ed equazioni con 2 soluzioni, ma attenzione!
- iniziamo da A e vogliamo sapere se dipingiamo il prossimo punto in basso o il punto in basso a destra.
- calcoliamo per entrambi i punti (x² + y²) e costruiamo sia per la differenza che per r² (che rimane ovviamente costante).
- poiché la differenza può essere negativa, prendiamo gli addominali da essa.
- quindi osserviamo quale punto è più vicino al risultato (r²), eo ipso più piccolo.
- a seconda di ciò disegniamo il vicino di destra o in basso.
- il punto così trovato
- 1 x, y viene specchiato
- 2 -x, y a sinistra
- 3 y, x in diagonale
- 4 -y, x da lì a sinistra
- tutti quei punti si rispecchiano di nuovo a sud
- 1 'x, -y
- 2 '-x, -y
- 3 'y, -x
- 4 '-y, -x fatto.
Questo non è un codice golf, ma tutti quei numeri in cima alle soluzioni esistenti mi hanno fatto pensare che lo sia, quindi ho trascorso del tempo inutile nel golfare la mia soluzione. Pertanto ho aggiunto anche un numero inutile in alto. È 11 volte Pi arrotondato.
object BresenhamCircle extends App {
var count = 0
val r = args(0).toInt
// ratio > 1 means expansion in horizontal direction
val ratio = args(1).toInt
val field = ((0 to 2 * r).map (i=> (0 to 2 * r * ratio).map (j=> ' ').toArray)).toArray
def square (x: Int, y: Int): Int = x * x + y * y
def setPoint (x: Int, y: Int) {
field (x)(y*ratio) = "Bresenham"(count)
field (y)(x*ratio) = "Bresenham"(count)
}
def points (x: Int, y: Int)
{
setPoint (r + x, r + y)
setPoint (r - x, r + y)
setPoint (r + x, r - y)
setPoint (r - x, r - y)
}
def bresenwalk () {
var x = 0;
var y = r;
val rxr = r * r
points (x, y);
do
{
val (dx, dy) = { if (math.abs (rxr - square ((x+1), y)) < math.abs (rxr - square (x, (y-1))))
(1, 0)
else
(0, -1)
}
count = (count + 1) % "Bresenham".length
x += dx
y += dy
points (x, y)
}while ((x <= y))
}
bresenwalk ()
println (field.map (_.mkString ("")).mkString ("\n"))
}
La domanda del carattere viene decisa dal server web dei siti e dalle impostazioni del browser. Ora, quello che sto guardando lo è
'Droid Sans Mono',Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif
La dimensione del carattere è di 12 pixel. Informazioni piuttosto inutili, se me lo chiedi, ma chi lo fa?
Bonus: ellissi e output di esempio:
L'invocazione è
scala BresenhamCircle SIZE RATIO
per esempio
scala BresenhamCircle 10 2
s e r B r e s
h n e e n h
e m a a m e
e r r e
m m
h a a h
n n
s e e s
e e
r r
B B
r r
e e
s e e s
n n
h a a h
m m
e r r e
e m a a m e
h n e e n h
s e r B r e s
A ratio of 2 will print a circular shape for most fonts which happen to be about twice as tall than wide. To compensate for that, we widen by 2.
# As smaller value than 2 only 1 is available:
scala BresenhamCircle 6 1
erBre
aes sea
ah ha
e e
es se
r r
B B
r r
es se
e e
ah ha
aes sea
erBre
# widening it has more freedom:
scala BresenhamCircle 12 5
s e r B r e s
a h n e e n h a
B m m B
e r r e
e s s e
B r r B
a m m a
h h
n n
s e e s
e e
r r
B B
r r
e e
s e e s
n n
h h
a m m a
B r r B
e s s e
e r r e
B m m B
a h n e e n h a
s e r B r e s
Ho limitato il parametro ratio per Int per renderlo semplice, ma può essere facilmente ampliato per consentire i float.