koło Bresenham w Scali (35)
Algorytm Bresenhama ma 2 główne punkty:
- działa bez sin / cosin.
- obliczasz tylko okrąg ¼ * ½, pozostałe punkty można znaleźć przez odbicie lustrzane.
Jak to zrobić:
2 1
DCBABCD
GFE | EFG
IJ y | ---- JI
GJ | / JG
F | / | F
DE | r / | ED
C | / | do
B 4 | / | B 3
A + ------- A
B 4 'x B 3'
CC
DE ED
FF
GJ JG
IJ JI
GFE EFG
DCBABCD
2'1 '
- Liczymy tylko liczby od A w zenicie do I.
- Punkt I wynosi 45 °, zdefiniowany przez x == y.
- Punkt zerowy jest tam, gdzie jest +.
- A w zenicie to punkt (x = 0, y = r), r = promień.
- Aby narysować zamknięty okrąg, poruszamy się zgodnie z ruchem wskazówek zegara (++ x), czyli w prawo (x + = 1) lub w dół do następnego punktu, (y- = 1).
- każdy punkt (x, y) na okręgu jest r od środka. Pitagoras mówi: r² = x² + y².
- To pachnie jak pierwiastek kwadratowy i równania z 2 rozwiązaniami, ale uwaga!
- zaczynamy od litery A i chcemy wiedzieć, czy malujemy następny punkt poniżej, czy punkt poniżej po prawej.
- obliczamy dla obu punktów (x² + y²) i budujemy dla obu różnic do r² (co pozostaje oczywiście stałe).
- ponieważ różnica może być ujemna, bierzemy z niej abs.
- następnie sprawdzamy, który punkt jest bliższy wynikowi (r²), eo ipso mniejszy.
- w zależności od tego rysujemy prawego lub dolnego sąsiada.
- tak znaleziony punkt
- 1 x, zostanie dublowany
- 2 -x, y w lewo
- 3 lata, x na przekątnej
- 4 -y, x stamtąd po lewej stronie
- wszystkie te punkty zostają ponownie odzwierciedlone na południu
- 1 'x, -y
- 2 '-x, -y
- 3 'y, -x
- 4 '-y, -x gotowe.
To nie jest kod golfowy, ale wszystkie te liczby na szczycie istniejących rozwiązań sprawiły, że tak pomyślałem, więc spędziłem bezużyteczny czas na grze w golfa. Dlatego też dodałem bezużyteczną liczbę na górze. Zaokrągla się 11 razy Pi.
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"))
}
Pytanie o czcionkę określa serwer witryn i ustawienia przeglądarki. Teraz to szukam
'Droid Sans Mono',Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif
Rozmiar czcionki to 12 pikseli. Dość bezużyteczne informacje, jeśli mnie pytasz, ale kto to robi?
Bonus: elipsy i wyjście próbki:
Wywołanie to
scala BresenhamCircle SIZE RATIO
na przykład
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
Ogranicziłem parametr ratio dla Int, aby było to proste, ale można go łatwo rozszerzyć, aby umożliwić float.