Problem z "for" pętlą

0

Na początku przepraszam za błędy gramatyczne - nie jestem z Polski (jestem samoukiem).

Mój problem polega na tym, że t się zmniejsza, chociaż jego wartość powinna się zwiększać (co powoduje to, że program nie skończy). Dlatego mam w programie

cout << t << endl;
			cin.get();

O co chodzi w moim programie:
1. punkt okręgu
znajdę go dzięki równaniu parametrycznemu (dla t=0), znajdę sobie lewy dolny punkt tego pixla, gdzie się to znajduje, czyli bottom_x_0 , bottom_y_0 i wynik sobie zapisze do digitalized_x[0] i digitalized_y[0].

Dla reszty punktów:

  • Pierwszy punkt (dla t=0) już mam, wiec "for" się rozpoczyna od 2. punktu (t= 0+dt) i kończy się na "końcu" okręgu, czyli dla t=2*pi. Obliczę sobie kolejne x oraz y, znajdę lewy dolny punkt pixla i teraz:
  1. jeśli wynik x, y jest ten sam co poprzedni, to muszę zwiększyć dt i znów obliczyć nowe x,y (chcę mieć tylko różne punkty, nie te same) dla to same "k"
  2. jeśli wynik x, y nie jest ten sam co poprzedni, ale nowy pixel nie ma wspólną krawędź z poprzednim, to muszę zmniejszyć dt i znów obliczyć nowe x,y (dt było za duże) dla to same "k"
  3. jeśli wynik x, y nie jest ten sam co poprzedni i nowy pixel ma wspólną krawędź, to znalazłam nowy punkt i zapiszę sobie go do digitalized_x[k], digitalized_y[k] (najpierw muszę zwiększyć rozmiar tego wektora i tak sobie zapisać wynik) no i też zwiększę sobie "k" dla nowe wyniki.

Wszystko robię póki 1. punkt w digitalized_x, digitalized_y nie jest ten sam co ostatni obliczony (dlatego while).

No i na koniec chcę sobie wypisać całe digitalized_x, digitalized_y.

Czy ktoś widzi, na czym polega mój problem?

#define _USE_MATH_DEFINES
#include<iostream>
#include<math.h>
#include<vector>
#include<iomanip>	
#include<cmath>
using namespace std;

int main()
{
	double sx = 2;
	double sy = 2;
	double r = 10;
	double d = 2;
	double dt = 2 * M_PI / 300;
	double x, y;
	double bottom_x_0, bottom_y_0, bottom_x, bottom_y;
		
	vector<double> digitalized_x(2);	
	vector<double> digitalized_y(2);   

	//1.point
	x = sx + r * cos(0);
	y = sy + r * sin(0);
	bottom_x_0 = floor(x / d) * d;
	bottom_y_0 = floor(y / d) * d;
	digitalized_x[0] = bottom_x_0;
	digitalized_y[0] = bottom_y_0;
	int k = 1;
	
	//the rest
	while ((digitalized_x[0] != digitalized_x[k]) && (digitalized_y[0] != digitalized_y[k]))
	{		
		for (double t = dt; t <= (2 * M_PI); t += dt)
		{
			cout << t << endl;
			cin.get();

			x = sx + r * cos(t);
			y = sy + r * sin(t);

			bottom_x = floor(x / d) * d;
			bottom_y = floor(y / d) * d;

			if ((bottom_x == digitalized_x[k]) && (bottom_y == digitalized_y[k])) // the same value
			{
				dt *= 2;
				break;					// leaves the loop (if)
			}

			else if ( (digitalized_x[k] != ((bottom_x +d) || (bottom_x - d)) ) && (digitalized_y[k] != ((bottom_y + d) || (bottom_y - d)))) // different, but they do not have common edge
			{
				dt /= 3;
				break;				   // leaves the loop (if)
			}

			else
			{
				digitalized_x.push_back(1);					//new value in the vector, so we increase the size of it
				digitalized_y.push_back(1);					//new value in the vector, so we increase the size of it
				digitalized_x[k] = bottom_x;
				digitalized_y[k] = bottom_y;
				k++;
				continue;									//jumps back to the beginning of the loop (including the update in case of a for - loop).
			}				
		}		
	} 
		
	for (int i = 0; i < digitalized_x.size(); i++)
	{
		cout << "(" << digitalized_x[i]<< "," << digitalized_y[i] << ")" << endl;	
	}	
}
0

Ciągle trafiasz w dzielenie przez 3 i stąd Ci t maleje, dołóż loga w poszczególnych blokach if, https://godbolt.org/z/ETWP7rf6a

            if ((bottom_x == digitalized_x[k]) && (bottom_y == digitalized_y[k])) // the same value
            {
                dt *= 2;
                std::cout << "times2\n"; //LOG
                break;                  // leaves the loop (if)
            }

            else if ( (digitalized_x[k] != ((bottom_x +d) || (bottom_x - d)) ) && (digitalized_y[k] != ((bottom_y + d) || (bottom_y - d)))) // different, but they do not have common edge
            {
                dt /= 3;
                std::cout << "div3\n"; //LOG
                break;                 // leaves the loop (if)
            }

            else
            {
                std::cout << "cont\n";
1

else if ( (digitalized_x[k] != ((bottom_x +d) || (bottom_x - d)) ) && (digitalized_y[k] != ((bottom_y + d) || (bottom_y - d)))) // different, but they do not have common edge
opisz słownie ten warunek bo tu chyba coś jest nie tak. To chyba nie działa tak jak myślisz, że działa ;)

No i jeszcze: liczb zmiennoprzecinkowych się nie porównuje przez == tylko musisz np. odjąć je od siebie i sprawdzić czy wynik jest odpowiednio bliski zeru

template <typename T>
constexpr bool floating_point_eq(T x, T y) noexcept
{
    return abs(x - y) < std::numeric_limits<T>::epsilon();
}

EDIT:
ten warunek to czasem nie taki miał być?

else if( !floating_point_eq(digitalized_x[k],bottom_x+d) && 
            !floating_point_eq(digitalized_x[k],bottom_x-d) &&
            !floating_point_eq(digitalized_y[k],bottom_y+d) &&
            !floating_point_eq(digitalized_y[k],bottom_y-d))

...czyli chyba (sprawdź to 5 razy bo mogę się mylić)

!floating_point_eq(abs(digitalized_x[k] - bottom_x), abs(d)) //dla y analogicznie

EDIT2: po zmianie warunku przynajmniej raz udało mi się wejść do bloku else zawierającego continue, potem dalej to samo, ale chyba jest progres ;)

0

@Zrorpaczona: odpowiadaj proszę w postach, nie komentarzach :) BTW, możemy przejść na angielski jak Ci wygodniej tak. Chciałbym żebyś wyjaśniła mi
ten warunek else if ( (digitalized_x[k] != ((bottom_x +d) || (bottom_x - d)) ) && (digitalized_y[k] != ((bottom_y + d) || (bottom_y - d)))) // different, but they do not have common edge.
Dlaczego? Ponieważ (weźmy jego pierwszą połowę):
digitalized_x[k] != ((bottom_x +d) || (bottom_x - d) rozwinie Ci się do:

digitalized_x != (
   ((bottom_x+d)!=0) ||
   ((bottom_x-d)!=0)
)

a to chyba nie o to chodzi?
Włącz dodatkowe warningi to zobaczysz o co chodzi https://godbolt.org/z/758oYn1Kf

0

@alagner:
Mam "zielony" okrąg. Znajdę 1.punkt okręgu (fioletowy punkt). Potem znajdę lewy dolny punkt tego piksla, w którym się znajduje (czyli czerwony punkt) - to jest ten mój wzór z floor.

No i teraz zwiększam dt, by znaleźć nowy punkt okręgu, ale taki, który należy do piksla, który jest sąsiadem z poprzednim pikselem. Jeśli taki znajdę, to oblicze ten lewy dolny punkt piksa (czerwony) i zapiszę go do digitalized_x,digitalized_y. Ale problem polega na tym, że dt może być za małe albo za duże.

Naprzykład. Znajdę punkt okręgu, który jest w żółtym piksele. Zapiszę sobie go jak digitalized_x,digitalized_y. I staram się znaleźć kolejny punkt okręgu, który jest w pomarańczowym pikselu. Przy obliczaniu tego nowego punktu mogą się zdarzyć 3 sytuacje:

  1. nowy punkt okręgu znajduje się znów w żółtym pikselu i muszę zwiększyć dt, by "wyjść" z tego żółtego pikselu (to jest moje if)
  2. nowy punkt okręgu znajduje się w niebieskim pikselu, który nie jest sąsiadem z żółtym, czyli jestem za daleko i muszę zmniejszyć dt (to jest moje else if)
  3. nowy punkt okręgu znajduje się w pomarańczowym pikselu, który jest sąsiadem z żółtym, jestem szczęśliwa, znajdę sobie czerwony punkt tego pikselu ( czyli bottom_x, bottom_y), zapiszę do digitalized_x,digitalized_y. (to jest moje else)

No i jak się równa digitalized_x[0] z ostatnim obliczonym digitalized_x[k], tak samo z y, to znaczy, że już mam cały okrąg i wszystkie czerwone punkty i skończyłam (moje while).

20211212_005220.jpg

0

A przypadkiem nie masz dodawać na końcu wektora?

            else
            {
                digitalized_x.push_back(1);                 //new value in the vector, so we increase the size of it
                digitalized_y.push_back(1);                 //new value in the vector, so we increase the size of it
                k++; //przeniosłem tu 
                digitalized_x[k] = bottom_x;
                digitalized_y[k] = bottom_y;
                //k++; ;//bylo tu
                continue;                                   //jumps back to the beginning of the loop (including the update in case of a for - loop).
            }     

Jeśli tak, to poczyściłem trochę Twój kod i wyszło mi tak: https://godbolt.org/z/5qs7jhxjq

0

Masz jakieś dane testowe żeby dało się szybko to sprawdzać?

0

@alagner:
Tutaj mam dane testowe dla d=2 oraz d=3 (dla każde d mam inne dane).

#define _USE_MATH_DEFINES
#include<iostream>
#include<math.h>
#include<vector>
#include<iomanip>	
#include<cmath>
using namespace std;

int main()
{
	double sx, sy, r;
	int round_x, round_y;
	//double x_dig, y_dig;
	
	double delta = 2;
	double delta3 = 3;

	vector<double> x = { 6,9,8,5,-6,-9,-8,-5,-6,-9,-8,-5, 6,9,8,5 };
	vector<double> y = { 4,6,5,3,4,6,5,3,-4,-6,-5,-3,-4,-6,-5,-3 };

	vector<double> xx = { 6,7,3,10,-6,-7,-3,-10,-6,-7,-3,-10, 6,7,3,10 };
	vector<double> yy = { 6,3,5,8,6,3,5,8,-6,-3,-5,-8, -6,-3,-5,-8 };

	vector<double> x_dig(16);
	vector<double> y_dig(16);

	vector<double> xx_dig(16);
	vector<double> yy_dig(16);

	//===============================================================================================================================
	//delta = 2
	cout << "delta = 2" << endl;
	cout << endl;
	for (int i = 0; i < 16; i++)
	{
		x_dig[i] = floor(x[i] / delta ) * delta;
		y_dig[i] = floor(y[i] / delta ) * delta;
		cout << x[i] << setw(5) << y[i] << setw(5) << "(" << x_dig[i] << "," << y_dig[i] << ")" << endl;
	}
	//===============================================================================================================================
	// delta = 3
	cout << endl;
	cout << endl;
	cout << "delta = 3" << endl;
	cout << endl;
	for (int i = 0; i < 16; i++)
	{
		xx_dig[i] = floor(xx[i] / delta3) * delta3;
		yy_dig[i] = floor(yy[i] / delta3) * delta3;
		cout << xx[i] << setw(5) << yy[i] << setw(5) << "(" << xx_dig[i] << "," << yy_dig[i] << ")" << endl;
	}
}
0

Na pewno dla k==1 nie może być wynik (0,0), ponieważ mamy okrąg ze środkiem w 2,2 i promień jest 10. To znaczy, że żadna część okręgu nie leży w (0,0), czyli (digitalized_x, digitalized_y) też nie może być (0,0).

To (digitalized_x, digitalized_y) jest lewy dolny punkt tego piksela, w którym się znajduje punkt z okręgu.

Tutaj są przykłady tego, jak obliczyć (digitalized_x, digitalized_y) po tym, jak wiemy, w którym pikselu się punkt znajduję (dla wszyskie 4 kwadranty). Zielony rysunek jest dla delta=2.
20211212_021246[1].jpg

0

Pomarańczowy rysunek dla delta=3.
Jak się mój znaleziony punkt okręgu znajduje naprz. w niebieskim pikselu, to dla kolejne "k" musi się znajdować albo w czerwonym, albo w żółtym, albo we fioletowym albo w turkusowym pikselu.

To znaczy: jak lewy dolny punkt (digitalized_x, digitalized_y) niebieskiego pikselu jest (3,3), to kolejny punkt (digitalized_x, digitalized_y) jest albo czerwony (3,0), albo żółty (6,3), albo fioletowy (3,6) albo turkisowy (0,3). To jest to moje else.

20211212_022301[1].jpg

1 użytkowników online, w tym zalogowanych: 0, gości: 1