nie wierzę działa algorytm punktu środkowego okręgu, na każdej warstwie dadzą pożądanych rezultatów po osiągnięciu bieguny, co będzie mieć luki w powierzchni, gdzie nie są diody oświetlony . Może to jednak dać pożądany rezultat, tak więc będzie to zależało od estetyki. Ten post opiera się na użyciu algorytmu okręgu środkowego w celu określenia promienia warstw przez dwa środkowe dwa pionowe oktanty, a następnie podczas rysowania każdego z tych okręgów również ustawienie punktów dla oktantów polarnych.
Myślę, że na podstawie komentarza @Nick Udall i odpowiedzi here za pomocą algorytmu okręgu do określenia promienia poziomego plasterka będzie działać z modyfikacją zaproponowałem w komentarzu do jego odpowiedzi. Algorytm koła powinien zostać zmodyfikowany, aby jako błąd wejściowy przyjąć błąd początkowy, a także narysować dodatkowe punkty dla oktantów biegunowych.
- Draw standardowe punkty algorytmu okrąg na
y0 + y1
i y0 - y1
: x0 +/- x, z0 +/- z, y0 +/- y1
, x0 +/- z, z0 +/- x, y0 +/- y1
, łącznie 16 punktów. Stanowi to większość pionu kuli.
- Dodatkowo narysuj punkty:
x0 +/- y1, z0 +/- x, y0 +/- z
i x0 +/- x, z0 +/- y1, y0 +/- z
, łącznie 16 punktów, które utworzą polarne czapki dla kuli.
Po przekazaniu błędu zewnętrznego algorytmu do algorytmu koła, umożliwi to dostosowanie podokroksu w okręgu każdej warstwy. Bez podania błędu do wewnętrznego algorytmu, równik koła będzie przybliżony do cylindra, a każda przybliżona powierzchnia czołowa na osiach x, yiz będzie tworzyć kwadrat. Po uwzględnieniu błędu każda twarz o wystarczająco dużym promieniu będzie przybliżona jako wypełnione koło.
Poniższy kod został zmodyfikowany z Wikipedii Midpoint circle algorithm. Algorytm DrawCircle
ma nomenklaturę zmienioną tak, aby działała w płaszczyźnie xz, dodawanie trzeciego początkowego punktu y0
, przesunięcie y y1
i początkowy błąd error0
. DrawSphere
została zmodyfikowana z tej samej funkcji do podjęcia trzeci punkt początkowy y0
i wzywa DrawCircle
zamiast DrawPixel
public static void DrawCircle(int x0, int y0, int z0, int y1, int radius, int error0)
{
int x = radius, z = 0;
int radiusError = error0; // Initial error state passed in, NOT 1-x
while(x >= z)
{
// draw the 32 points here.
z++;
if(radiusError<0)
{
radiusError+=2*z+1;
}
else
{
x--;
radiusError+=2*(z-x+1);
}
}
}
public static void DrawSphere(int x0, int y0, int z0, int radius)
{
int x = radius, y = 0;
int radiusError = 1-x;
while(x >= y)
{
// pass in base point (x0,y0,z0), this algorithm's y as y1,
// this algorithm's x as the radius, and pass along radius error.
DrawCircle(x0, y0, z0, y, x, radiusError);
y++;
if(radiusError<0)
{
radiusError+=2*y+1;
}
else
{
x--;
radiusError+=2*(y-x+1);
}
}
}
Na kuli o promieniu 4 (który rzeczywiście wymaga 9x9x9), byłoby to trzy iteracje DrawCircle
rutynowe, z pierwszym rysunkiem o typowym promieniu 4 koła (trzy kroki), drugim rysunkiem o promieniu 4 okręgu z początkowym błędem 0 (również trzema krokami), a następnie trzecim rysunkiem o promieniu 3 okręgu z początkowym błędem 0 (również trzy kroki). To kończy się jako dziewięć obliczonych punktów, z których każdy ma 32 piksele. To powoduje, że 32 (punkty na koło) x 3 (dodawanie lub odejmowanie operacji na punkt) + 6 (dodawanie, odejmowanie, operacje zmiany w iteracji) = 102 dodawanie, odejmowanie lub zmiana operacji na obliczony punkt. W tym przykładzie jest to 3 punkty za każdy krąg = 306 operacji na warstwę.Algorytm promienia dodaje również 6 operacji na warstwę i iteruje 3 razy, więc 306 + 6 * 3 = 936
podstawowe operacje arytmetyczne dla przykładowego promienia 4. Koszt tutaj polega na tym, że będziesz wielokrotnie ustawiał niektóre piksele bez dodatkowych sprawdzeń stanu (tj. X = 0, y = 0 lub z = 0), więc jeśli twoje I/O jest wolne, możesz lepiej dodać testy warunków. Zakładając, że wszystkie diody LED zostały wyczyszczone na początku, przykładowy okrąg ustawiłby 288 diod LED, podczas gdy istnieje znacznie mniej diod LED, które byłyby faktycznie oświetlone z powodu powtarzania zestawów.
Wygląda na to, że byłoby to lepsze niż metoda bruteforce dla wszystkich sfer, które pasowałyby do siatki 8x8x8, ale metoda bruteforce miałaby stały czas niezależnie od promienia, podczas gdy ta metoda będzie spowalniać podczas rysowania sfer o dużym promieniu, gdzie wyświetli się tylko część. Ponieważ sześcian wyświetlania rośnie w rozdzielczości, to algorytm synchronizacji czasu pozostanie niezmieniony, podczas gdy zwiększa się bruteforce.
Sądząc po kuli LED, powinniśmy założyć, że potrzebne jest również wnętrze wykreowanej sfery? – NominSim
@NominSim Nie sądzę. W tym przypadku nie chciał mówić o rasteryzacji okręgu Bresenhama i mógł po prostu użyć rozwiązania brutalnej siły japreiss. –
@Christian Właściwie, chciałbym mieć obie opcje. –