AP1994 Temat założony przez niniejszego użytkownika |
Klasa kszrałtów 2d » 2023-03-19 00:11:41 Napisałem klasy dla punktu koła/elipsy, trójkąta czworokąta, ale nie umiem napisać klasy, która pozwalałaby przy pomocy pozostałych klas tworzyć dowolne kształty 2d np: ośmiokąt z dziurą w kształcie koła w samum środku, albo czworokąt postawiony na trójkącie. Miło by było gdyby ktoś coś doradził jak napisać taką klasę. Moje klasy: plik .h class Point { public: Point() = default; Point( double _x, double _y, double _z = 0 ); Point( const Point & other ); void set_point( double _x, double _y, double _z = 0 ); void set_x( double _x ); void set_y( double _y ); void set_z( double _y ); double get_x() const; double get_y() const; double get_z() const; void plus( double sign ); void minus( double sign ); void multiply( double sign ); void division( double sign ); Point operator +( const Point & p ) const; Point operator -( const Point & p ) const; Point operator *( const Point & p ) const; Point operator /( const Point & p ) const; Point & operator +=( const Point & p ); Point & operator -=( const Point & p ); Point & operator *=( const Point & p ); Point & operator /=( const Point & p ); Point & operator =( const Point & other ); private: double x, y, z; }; class Shape { public: virtual double area() const = 0; virtual double perimeter() const = 0; virtual void move( Point xyz ) = 0; virtual void rotate( double angle, Point axis = Point( 0, 0 ) ) = 0; virtual void scale( Point factor = Point( 1.0, 1.0, 1.0 ) ) = 0; protected: Point rotatePoint( Point p, double angle, Point axis ); }; class Circle : public Shape { public: Circle( Point _center, double _rx, double _ry ); virtual double area() const; virtual double perimeter() const; virtual void move( Point xyz ); virtual void rotate( double angle, Point axis = Point( 0.0, 0.0, 0.0 ) ); virtual void scale( Point factor = Point( 1.0, 1.0, 1.0 ) ); Point center; double rx; double ry; }; class Triangle : public Shape { public: Triangle( Point _a, Point _b, Point _c ); double area() const; double perimeter() const; void move( Point xyz ); void rotate( double angle, Point axis = Point( 0.0, 0.0, 0.0 ) ); void scale( Point factor = Point( 1.0, 1.0, 1.0 ) ); Point getCentroid() const; Point a, b, c; }; class Quadrilateral : public Shape { public: Quadrilateral( Point _a, Point _b, Point _c, Point _d ); double area() const; double perimeter() const; void move( Point xyz ); void rotate( double angle, Point axis = Point( 0.0, 0.0, 0.0 ) ); void scale( Point factor = Point( 1.0, 1.0, 1.0 ) ); Point getCentroid() const; Point a, b, c, d; };
plik .cpp Point::Point( double _x, double _y, double _z ) { this->x = _x; this->y = _y; this->z = _z; } Point::Point( const Point & other ) { if( this != & other ) { x = other.x; y = other.y; z = other.z; } } void Point::set_point( double _x, double _y, double _z ) { this->x = _x; this->y = _y; this->z = _z; } void Point::set_x( double _x ) { this->x = _x; } void Point::set_y( double _y ) { this->y = _y; } void Point::set_z( double _z ) { this->z = _z; } double Point::get_x() const { return x; } double Point::get_y() const { return y; } double Point::get_z() const { return z; } void Point::plus( double sign ) { x += sign; y += sign; z += sign; } void Point::minus( double sign ) { x -= sign; y -= sign; z -= sign; } void Point::multiply( double sign ) { x *= sign; y *= sign; z *= sign; } void Point::division( double sign ) { x /= sign; y /= sign; z /= sign; } Point Point::operator +( const Point & p ) const { return Point( x + p.x, y + p.y, z + p.z ); } Point Point::operator -( const Point & p ) const { return Point( x - p.x, y - p.y, z - p.z ); } Point Point::operator *( const Point & p ) const { return Point( x * p.x, y * p.y, z * p.z ); } Point Point::operator /( const Point & p ) const { if( p.get_x() == 0 || p.get_y() == 0 || p.get_z() == 0 ) { throw std::invalid_argument( "Dzielenie przez zero." ); } return Point( x / p.x, y / p.y, z / p.z ); } Point & Point::operator +=( const Point & p ) { x += p.x; y += p.y; z += p.z; return * this; } Point & Point::operator -=( const Point & p ) { x -= p.x; y -= p.y; z -= p.z; return * this; } Point & Point::operator *=( const Point & p ) { x *= p.x; y *= p.y; z *= p.z; return * this; } Point & Point::operator /=( const Point & p ) { if( p.get_x() == 0 || p.get_y() == 0 || p.get_z() == 0 ) { throw std::invalid_argument( "Dzielenie przez zero." ); } x /= p.get_x(); y /= p.get_y(); z /= p.get_z(); return * this; } Point & Point::operator =( const Point & other ) { if( this != & other ) { x = other.x; y = other.y; z = other.z; } return * this; } Point Shape::rotatePoint( Point p, double angle, Point axis ) { double dx = p.get_x() - axis.get_x(); double dy = p.get_y() - axis.get_y(); double dz = p.get_z() - axis.get_z(); p.set_point( dx * cos( angle ) - dy * sin( angle ) + axis.get_x(), dx * sin( angle ) + dy * cos( angle ) + axis.get_y(), dz ); return p; } Circle::Circle( Point _center, double _rx, double _ry ) { this->center = _center; this->rx = _rx; this->ry = _ry; } double Circle::area() const { return M_PI * rx * ry; } double Circle::perimeter() const { return M_PI *( rx + ry ); } void Circle::move( Point xyz ) { this->center += xyz; } void Circle::rotate( double angle, Point axis ) { this->center = rotatePoint( this->center, angle, axis ); } void Circle::scale( Point factor ) { rx *= factor.get_x(); ry *= factor.get_y(); } Triangle::Triangle( Point _a, Point _b, Point _c ) { this->a = _a; this->b = _b; this->c = _c; } double Triangle::area() const { return 0.5 * std::abs(( this->b.get_x() - this->a.get_x() ) *( this->c.get_y() - this->a.get_y() ) -( this->c.get_x() - this->a.get_x() ) *( this->b.get_y() - this->a.get_y() ) ); } double Triangle::perimeter() const { double ab = std::sqrt(( this->b.get_x() - this->a.get_x() ) *( this->b.get_x() - this->a.get_x() ) +( this->b.get_y() - this->a.get_y() ) *( this->b.get_y() - this->a.get_y() ) ); double bc = std::sqrt(( this->c.get_x() - this->b.get_x() ) *( this->c.get_x() - this->b.get_x() ) +( this->c.get_y() - this->b.get_y() ) *( this->c.get_y() - this->b.get_y() ) ); double ca = std::sqrt(( this->a.get_x() - this->c.get_x() ) *( this->a.get_x() - this->c.get_x() ) +( this->a.get_y() - this->c.get_y() ) *( this->a.get_y() - this->c.get_y() ) ); return ab + bc + ca; } void Triangle::move( Point xyz ) { this->a += xyz; this->b += xyz; this->c += xyz; } void Triangle::rotate( double angle, Point axis ) { this->a = rotatePoint( this->a, angle, axis ); this->b = rotatePoint( this->b, angle, axis ); this->c = rotatePoint( this->c, angle, axis ); } void Triangle::scale( Point factor ) { Point center = this->getCentroid(); this->a -= center; this->a *= factor; this->a += center; this->b -= center; this->b *= factor; this->b += center; this->c -= center; this->c *= factor; this->c += center; } Point Triangle::getCentroid() const { Point centroid; centroid.set_point(( this->a.get_x() + this->b.get_x() + this->c.get_x() ) / 3.0, ( this->a.get_y() + this->b.get_y() + this->c.get_y() ) / 3.0 ); return centroid; } Quadrilateral::Quadrilateral( Point _a, Point _b, Point _c, Point _d ) { this->a = _a; this->b = _b; this->c = _c; this->d = _d; } double Quadrilateral::area() const { Triangle t1( this->a, this->b, this->c ); Triangle t2( this->a, this->c, this->d ); return t1.area() + t2.area(); } double Quadrilateral::perimeter() const { double ab = std::sqrt(( this->b.get_x() - this->a.get_x() ) *( this->b.get_x() - this->a.get_x() ) +( this->b.get_y() - this->a.get_y() ) *( this->b.get_y() - this->a.get_y() ) ); double bc = std::sqrt(( this->c.get_x() - this->b.get_x() ) *( this->c.get_x() - this->b.get_x() ) +( this->c.get_y() - this->b.get_y() ) *( this->c.get_y() - this->b.get_y() ) ); double cd = std::sqrt(( this->d.get_x() - this->c.get_x() ) *( this->d.get_x() - this->c.get_x() ) +( this->d.get_y() - this->c.get_y() ) *( this->d.get_y() - this->c.get_y() ) ); double da = std::sqrt(( this->a.get_x() - this->d.get_x() ) *( this->a.get_x() - this->d.get_x() ) +( this->a.get_y() - this->d.get_y() ) *( this->a.get_y() - this->d.get_y() ) ); return ab + bc + cd + da; } void Quadrilateral::move( Point xyz ) { this->a += xyz; this->b += xyz; this->c += xyz; this->d += xyz; } void Quadrilateral::rotate( double angle, Point axis ) { this->a = rotatePoint( this->a, angle, axis ); this->b = rotatePoint( this->b, angle, axis ); this->c = rotatePoint( this->c, angle, axis ); this->d = rotatePoint( this->d, angle, axis ); } void Quadrilateral::scale( Point factor ) { Point center = this->getCentroid(); this->a -= center; this->a.set_point( this->a.get_x() * factor.get_x(), this->a.get_y() * factor.get_y() ); this->a += center; this->b -= center; this->b.set_point( this->b.get_x() * factor.get_x(), this->b.get_y() * factor.get_y() ); this->b += center; this->c -= center; this->c.set_point( this->c.get_x() * factor.get_x(), this->c.get_y() * factor.get_y() ); this->c += center; this->d -= center; this->d.set_point( this->d.get_x() * factor.get_x(), this->d.get_y() * factor.get_y() ); this->d += center; } Point Quadrilateral::getCentroid() const { Point centroid; centroid.set_point(( this->a.get_x() + this->b.get_x() + this->c.get_x() + this->d.get_x() ) / 4.0, ( this->a.get_y() + this->b.get_y() + this->c.get_y() + this->d.get_y() ) / 4.0 ); return centroid; }
|
|
befejak |
» 2023-03-20 08:41:03 Miło byłoby gdybyś powiedział nam też w jaki sposób chcesz je narysować?
- Potrzebujesz warunku if który wybierze tylko wybrane pixele do zamalowania? - Potrzebujesz metody która obliczy wszystkie punkty budujące figurę?...
Czy potrzebujesz czegoś jeszcze innego?
Widzę że w swoim kodzie masz klasę "Point" więc domyślam się że chodzi o uzyskanie "Point"-ów budujących te figury? Wystarczy użyć trójkątów prostokątnych, w końcu to one budują "puste" miejsca w twoich dwóch figurach.
Chociaż w pierwszym przypadku to ich nawet nie trzeba.
W ośmiokącie w "kropką" Point a; a.x = Width/2; - Ustawimy X na sam środek figury a.x -= SideLength*0.8; - Przestawimy X o 20% długości boku (szerokości) figury w "lewo"
podobnie dla pozostałych punktów na figurze, z tym że po prawej oczywiście += SideLength*0.8 W sumie jeśli zamiast 0.8 użyjemy też zmiennej będziemy mogli kontrolować jak długie są "proste boki" figury.
To dla górnych punktów, ale boczne to dokładnie tak samo ale Width zmieniamy z Height i X z Y :)
W drugim przypadku możesz użyć podobnego kodu ale wtedy Y będzie po prostu na Wysokość/2 ( aby był w środku ) a X pozostaje tak samo jak w wyższym przykładzie.
Jeśli chciałbyś aby był to warunek if który wybiera pixele do zamalowania, z tymi figurami będzie to dość spory warunek :P
Mam nadzieję że chociaż trochę pomogłem ^_^ |
|
AP1994 Temat założony przez niniejszego użytkownika |
» 2023-03-20 22:48:31 Do wyświetlania miałem zamiar użyć funkcji allegro 5 takich jak: al_draw_filled_rectangle, al_draw_filled_triangle, al_draw_filled_ellipse, al_draw_circle. Albo ich własnoręcznie napisanych odpowiedników. Sposób jest mało istotny chcę uzyskać taki efekt że kiedy mam czworokąt i dodam do niego koło wyjdzie mi kiedy natomiast odejmę koło od czworokąta to powstanie |
|
befejak |
» 2023-03-21 13:27:37 Nigdy nie używałem Allegro ale sprawdziłem nieco jego dokumentacje w internecie. void al_draw_filled_triangle( float x1, float y1, float x2, float y2, float x3, float y3, ALLEGRO_COLOR color ) Zgodnie z tym co mówią argumenty funkcji, do narysowania trójkąta potrzebujesz przekazać 7 wartości z czego 3 to pozycje X 3 punktów i 3 kolejne to pozycje Y tych samych 3 punktów, ostatni to kolor. Możesz więc obliczyć pozycje punktów zgodnie z tym co ci pokazałem wcześniej, wyżej. Zaznaczyłem tutaj "Punkty" ( wierzchołki ) których pozycje musimy obliczyć i później przekazać je do funkcji rysującej trójkąt. Przyjmijmy że mamy "Width" oraz "Height" które kontrolują szerokość oraz wysokość całej figury którą rysujemy. Pierwszy trójkąt i jego trzy wierzchołki to pierwszy trójkąt zbudujemy z a1 , a oraz h ( patrz grafika pow. ) z a1 będzie najprościej bo to po prostu 0 , 0 a1.x = 0; a1.y = 0;
wierzchołek a uzyskamy zgodnie z przykładem powyżej, ale tam się pomyliłem, jak chcieliśmy uzyskać 20% długości powinno być *0.2 a.y = 0; // Y pozostaje na 0, jest to górny bok.
a.x = Width/2; // Aby X znalazło się na środku figury a.x -= Width*0.2; // Przestawiamy X o 20% szerokości w lewo ( gdyby zrobić += to będzie to w prawo )
I mamy już pozycję a1 oraz a, teraz potrzebna nam pozycja h Zrobimy to tak samo ale dla osi Y ( bo to lewa ściana ) h.x = 0; // W tym przypadku X zawsze będzie 0
h.y = Height/2; // Aby Y znalazło się na środku wysokości figury h.y -= Height*0.2; // Aby przestawić Y o 20% wysokości w górę
Tak przygotowane 3 punkty możemy teraz podesłać do funkcji aby narysowała trójkąt: // Wcześniej narysuj Kwadra o wymiarach Height, Width !... i kolorze "wypełnienia" Surface.al_draw_filled_triangle( a1.x, a1.y, a.x, a.y, h.x, h.y, KolorPustego )
Pozostałe twójkąty robisz tak samo, koło w środku obliczyć możemy: Sphere.x = Width / 2 -( SphereWidth / 2 ); Sphere.y = Height / 2 -( SphereHeight / 2 );
Mam nadzieję że wszystkie znaczniki będą działać poprawnie, pierwszy raz używam ich na tym forum. |
|
pekfos |
» 2023-03-21 21:56:47 Chodzi tu o obliczenie wyniku operacji na figurach, czy narysowanie wyniku? Całkowicie różne rzeczy. |
|
AP1994 Temat założony przez niniejszego użytkownika |
» 2023-03-22 02:09:55 Chodziło mi raczej o obliczenie wyniku operacji na figurach, ponieważ potrzebuję mieć klasę, której obiekt będzie można użyć do mojej implementacji fizyki. Dlatego potrzebuję mieć możliwość dowolnie modyfikować kształt. |
|
pekfos |
» 2023-03-22 23:46:04 To twoje koła i trójkąty wygenerują więcej przypadków brzegowych niż są warte. Powinieneś myśleć o tych figurach jako o wielokątach, albo siatkach trójkątów - zależnie jak ta fizyka miałaby działać. |
|
« 1 » |