Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Klasa kszrałtów 2d

Ostatnio zmodyfikowano 2023-03-22 23:46
Autor Wiadomość
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
C/C++
class Point // klasa punktu w 2D
{
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 // bazowa klasa kształtu 2D
{
public:
   
virtual double area() const = 0; // metoda obliczająca pole powierzchni kształtu
   
virtual double perimeter() const = 0; // metoda obliczająca obwód kształtu
   
virtual void move( Point xyz ) = 0; //przesuwa kształt
   
virtual void rotate( double angle, Point axis = Point( 0, 0 ) ) = 0; // metoda obracająca kształt o podany kąt
   
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 // klasa koła
{
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 // klasa trójkąta
{
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 //klasa czworokąta
{
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
C/C++
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;
}
P-180061
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 ^_^
P-180062
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
czworokąt z półkolem zamiast jednej ściany,
czworokąt z półkolem zamiast jednej ściany,
kiedy natomiast odejmę koło od czworokąta to powstanie
czworokąt z dziurą w kształcie półkola.
czworokąt z dziurą w kształcie półkola.
P-180063
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.

Ośmiokąt z kulą
Ośmiokąt z kulą

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:

C/C++
Sphere.x = Width / 2 -( SphereWidth / 2 ); // Ustawiamy X na środku i odejmujemy połowę szerokości koła w środku figury
Sphere.y = Height / 2 -( SphereHeight / 2 );


Mam nadzieję że wszystkie znaczniki będą działać poprawnie, pierwszy raz używam ich na tym forum.
P-180067
pekfos
» 2023-03-21 21:56:47
Chodzi tu o obliczenie wyniku operacji na figurach, czy narysowanie wyniku? Całkowicie różne rzeczy.
P-180069
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.
P-180070
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ć.
P-180077
« 1 »
  Strona 1 z 1