Лабораторная работа № 1
Вариант 27
по дисциплине “ Компьютерная графика”
Выполнил | ____________________ | Ларионов В. С. |
студент гр. 33534/4 | <подпись> | |
Преподаватель | ____________________ | Леонтьева Т. В. |
<подпись> |
Оглавление
1. Задание. 3
2. Реализация. 3
2.1. Изображение конусов. 3
2.2. Поворот конусов на a=90° относительно начала координат вокруг оси X. 4
2.3. Изображение тора и цилиндра. 6
2.4. Поворот тора на a=-45° относительно начала координат вокруг оси Z и масштабирование цилиндра в 2 раза относительно начала координат. 7
3. Код программы.. 8
Задание
· Изобразить два каркасных конуса высотой 25 и 50 соответственно, основание конуса - окружность с радиусом 10 и центром в точке O (20,20).
· Осуществить поворот конусов на угол a=90° относительно начала координат вокруг оси Х.
· Изобразить тор и цилиндр. Размеры и местоположение примитивов задать самостоятельно.
· Повернуть тор на a=-45° вокруг оси Z относительно начала координат, промасштабировать конус с коэффициентом 2 относительно начала координат
Реализация
Для реализации задачи был создан абстрактный класс Shape3D, который содержит основной функционал для данной лабораторной работы. Shape3D содержит следующий список реализованных методов:
rotateAroundLocalAxis | Вращение фигуры относительно ее локальных осей |
rotateAroundAttributeAxis | Вращение фигуры относительно ее осей координат |
scaleRelativeToLocalAxis | Масштабирование фигуры относительно ее локальных осей |
scaleRelativeToAttributeAxis | Масштабирование фигуры относительно осей координат |
setCenter | Установка / получение координат центра фигуры |
setFilling | Установка заливки фигуры, либо Wire, либо Solid |
setColor | Установка цвета фигуры (доступные цвета внутри структуры Color) |
drawShape | Отрисовка фигуры, для каждой фигуры свое определение метода |
Для каждой фигуры переопределяется метод прорисовки drawShape(), в котором используются выбранные ранее параметры отрисовки, цвета.
|
Изображение конусов
Shape3D<T>::setColor(Shape3D<T>::getColor()); Shape3D<T>::setAction(Action::DRAW); if(Shape3D<T>::getFilling() == WIRE) glutWireCone(radius_, height_, slices_, stacks_); elseglutSolidCone(radius_, height_, slices_, stacks_); |
На рисунках обозначены оси X, Y, Z. Можно увидеть, что центр фигур находится в точке (20, 20). Для удобства в обозрении фигуры были повернуты на -90 градусов.
2.2. Поворот конусов на a=90° относительно начала координат вокруг оси X
Процедура вращения фигуры относительно начала координат вокруг конкретной оси:
T sinA = sin(angle * M_PI / 180); T cosA = cos(angle * M_PI / 180); std::vector<T> rotation_matrix; switch(axis) { caseX: rotation_matrix = { 1, 0, 0, 0, cosA, -sinA, 0, sinA, cosA }; break; caseY: rotation_matrix = { cosA, 0, sinA, 0, 1, 0, -sinA, 0, cosA }; break; caseZ: rotation_matrix = { cosA, -sinA, 0, sinA, cosA, 0, 0, 0, 1 }; } point3d_t<T> new_center = { rotation_matrix[0] * center_.x + rotation_matrix[1] * center_.y + rotation_matrix[2] * center_.z, rotation_matrix[3] * center_.x + rotation_matrix[4] * center_.y + rotation_matrix[5] * center_.z, rotation_matrix[6] * center_.x + rotation_matrix[7] * center_.y + rotation_matrix[8] * center_.z, }; // Reset rotations to set local axis similar to attribute axis reapplyRotations(true); setCenter(new_center); glRotated(angle, axis == X, axis == Y, axis == Z); // Reapply previous rotations reapplyRotations(false); // Write new rotation to the list rotations_.emplace_back(axis, angle); |
После поворота можно заметить, что центр фигур на рисунках теперь находится в точке (20, 0, 20), а сами фигуры сменили положение после поворота.
Изображение тора и цилиндра
Отрисовка тора:
Shape3D<T>::setColor(Shape3D<T>::getColor()); Shape3D<T>::setAction(Action::DRAW); if(Shape3D<T>::getFilling() == WIRE) glutWireTorus(inner_radius_, outer_radius_, sides_, rings_); elseglutSolidTorus(inner_radius_, outer_radius_, sides_, rings_); |
Отрисовка цилиндра:
|
Shape3D<T>::setColor(Shape3D<T>::getColor()); Shape3D<T>::setAction(Action::DRAW); if(Shape3D<T>::getFilling() == WIRE) gluQuadricDrawStyle(quadObj_, GLU_LINE); elsegluQuadricDrawStyle(quadObj_, GLU_FILL); // Like GL_POLYGON gluCylinder(quadObj_, bottom_radius_, top_radius_, height_, slices_, stacks_); gluDeleteQuadric(quadObj_); |
Для отрисовки тора были выбраны следующие параметры:
· Внутренний радиус = 6, внешний радиус = 10, сторон – 25, колец – 25
Для отрисовки цилиндра были выбраны следующие параметры:
· Нижний радиус – 4, верхний радиус – 4, высота – 30, кол-во подразделений вокруг оси Z – 25, кол-во подразделений по оси Z – 25.
2.4. Поворот тора на a=-45° относительно начала координат вокруг оси Z и масштабирование цилиндра в 2 раза относительно начала координат
Процедура масштабирования:
// reset rotations to set local axis similar to attribute axis reapplyRotations(true); setCenter({center_.x * coeffX, center_.y * coeffY, center_.z * coeffZ}); glScaled(coeffX, coeffY, coeffZ); // reapply rotations reapplyRotations(false); |
Код программы
#include <GL/glut.h> #include "GL/gl.h"
#include <cmath>
#include <stdexcept> #include <cstdarg>
#include <cstdio> #include <vector>
#include <utility> #include <memory>
enum Action
{
TRANSLATE,
ROTATE,
SCALE,
SET_COLOR,
SET_FILLING,
DRAW
};
enum Axis
{
X,
Y,
Z
};
enum Color
{
RED,
BLUE,
YELLOW,
GREEN,
WHITE,
PURPLE,
CYAN,
ORANGE,
VIOLET
};
enum Filling
{
SOLID,
WIRE
};
template < typename T>
struct point3d_t
{
T x;
T y;
T z;
point3d_t<T> operator +=(const point3d_t<T>& lp);
point3d_t<T> operator -=(const point3d_t<T>& lp);
point3d_t<T> operator *(const T& coeff);
};
template struct point3d_t< float >;
template struct point3d_t< double >;
template < typename T>
point3d_t<T> point3d_t<T>:: operator +=(const point3d_t<T>& lp)
{
return { this ->x + lp.x, this ->y + lp.y, this ->z + lp.z};
}
template < typename T>
point3d_t<T> point3d_t<T>:: operator -=(const point3d_t<T>& lp)
{
return { this ->x - lp.x, this ->y - lp.y, this ->z - lp.z};
}
|
template < typename T>
point3d_t<T> point3d_t<T>:: operator *(const T& coeff)
{
return { this ->x * coeff, this ->y * coeff, this ->z * coeff};
}
void printv(va_list args, const char * format)
{
int LENGTH = 500;
char buf[LENGTH];
char * ch = buf;
vsnprintf(buf, LENGTH, format, args);
while (*ch)
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, *ch++);
}
void print(const char * format,...)
{
va_list args;
va_start(args, format);
printv(args, format);
va_end(args);
}
template < typename T>
class Shape3D
{
public:
virtual ~Shape3D() = default;
void rotateAroundLocalAxis(const Axis& axis, const T& angle);
void rotateAroundAttributeAxis(const Axis& axis, const T& angle);
void scaleRelativeToLocalAxis(const T& coeff);
void scaleRelativeToAttributeAxis(const T& coeff);
void scaleRelativeToLocalAxis(const T& coeffX, const T& coeffY, const T& coeffZ);
void scaleRelativeToAttributeAxis(const T& coeffX, const T& coeffY, const T& coeffZ);
point3d_t<T> getCenter() const;
Color getColor() const;
Filling getFilling() const;
void setCenter(const T& x, const T& y, const T& z, const bool firstInit = false);
void setCenter(const point3d_t<T>& center, const bool firstInit = false);
void setColor(const Color& color);
void setFilling(const Filling& filling);
void setDrawnStatus();
void resetDrawnStatus();
void checkIfDrawn();
void setAction(const Action& action);
virtual void drawShape() = 0;
private:
void reapplyRotations(const bool inverse);
Color color_;
bool isDrawn_;
Action action_;
Filling filling_;
point3d_t<T> center_;
std::vector<std::pair<Axis,T>> rotations_;
};
template class Shape3D< float >;
template class Shape3D< double >;
template < typename T>
void Shape3D<T>::rotateAroundLocalAxis(const Axis& axis, const T& angle)
{
setAction(Action::ROTATE);
checkIfDrawn();
if (!rotations_.empty() && rotations_.back().first == axis)
rotations_.back().second += angle;
else
rotations_.emplace_back(axis, angle);
glRotated(angle, axis == X, axis == Y, axis == Z);
}
template < typename T>
void Shape3D<T>::rotateAroundAttributeAxis(const Axis& axis, const T& angle)
{
setAction(Action::ROTATE);
checkIfDrawn();
T sinA = sin(angle * M_PI / 180);
T cosA = cos(angle * M_PI / 180);
std::vector<T> rotation_matrix;
switch (axis)
{
case X:
rotation_matrix = { 1, 0, 0,
0, cosA, -sinA,
0, sinA, cosA };
break;
case Y:
rotation_matrix = { cosA, 0, sinA,
0, 1, 0,
-sinA, 0, cosA };
break;
case Z:
rotation_matrix = { cosA, -sinA, 0,
sinA, cosA, 0,
0, 0, 1 };
}
point3d_t<T> new_center = {
rotation_matrix[0] * center_.x + rotation_matrix[1] * center_.y + rotation_matrix[2] * center_.z,
rotation_matrix[3] * center_.x + rotation_matrix[4] * center_.y + rotation_matrix[5] * center_.z,
rotation_matrix[6] * center_.x + rotation_matrix[7] * center_.y + rotation_matrix[8] * center_.z,
};
reapplyRotations(true);
setCenter(new_center);
glRotated(angle, axis == X, axis == Y, axis == Z);
reapplyRotations(false);
rotations_.emplace_back(axis, angle);
}
template < typename T>
void Shape3D<T>::scaleRelativeToLocalAxis(const T& coeff)
{
scaleRelativeToLocalAxis(coeff, coeff, coeff);
}
template < typename T>
void Shape3D<T>::scaleRelativeToAttributeAxis(const T& coeff)
{
scaleRelativeToAttributeAxis(coeff, coeff, coeff);
}
template < typename T>
void Shape3D<T>::scaleRelativeToLocalAxis(const T& coeffX, const T& coeffY, const T& coeffZ)
{
glScaled(coeffX, coeffY, coeffZ);
}
template < typename T>
void Shape3D<T>::scaleRelativeToAttributeAxis(const T& coeffX, const T& coeffY, const T& coeffZ)
{
setAction(Action::SCALE);
checkIfDrawn();
reapplyRotations(true);
setCenter({center_.x * coeffX, center_.y * coeffY, center_.z * coeffZ});
glScaled(coeffX, coeffY, coeffZ);
reapplyRotations(false);
}
template < typename T>
point3d_t<T> Shape3D<T>::getCenter() const
{
return center_;
}
template < typename T>
Color Shape3D<T>::getColor() const
{
return color_;
}
template < typename T>
Filling Shape3D<T>::getFilling() const
{
return filling_;
}
template < typename T>
void Shape3D<T>::setCenter(const T& x, const T& y, const T& z, const bool firstInit)
{
setAction(Action::TRANSLATE);
checkIfDrawn();
if (!firstInit)
glTranslated(x - center_.x, y - center_.y, z - center_.z);
else
glTranslated(x, y, z);
center_.x = x;
center_.y = y;
center_.z = z;
}
template < typename T>
void Shape3D<T>::setCenter(const point3d_t<T>& center, const bool firstInit)
{
setCenter(center.x, center.y, center.z, firstInit);
}
template < typename T>
void Shape3D<T>::setColor(const Color& color)
{
setAction(Action::SET_COLOR);
checkIfDrawn();
if (color_!= color)
color_ = color;
point3d_t<T> rgb = {}; // x - 'r', y - 'g', z - 'b'
switch (color_)
{
case RED:
rgb = {1.0, 0.0, 0.0};
break;
case BLUE:
rgb = {0.0, 0.0, 1.0};
break;
case YELLOW:
rgb = {1.0, 1.0, 0.0};
break;
case GREEN:
rgb = {0.0, 1.0, 0.0};
break;
case WHITE:
rgb = {1.0, 1.0, 1.0};
break;
case PURPLE:
rgb = {1.0, 0.0, 1.0};
break;
case CYAN:
rgb = {0.0, 1.0, 1.0};
break;
case ORANGE:
rgb = {1.0, 0.5, 0.0};
break;
case VIOLET:
rgb = {0.6, 0.3, 0.6};
break;
}
glColor3d(rgb.x, rgb.y, rgb.z);
}
template < typename T>
void Shape3D<T>::setFilling(const Filling& filling)
{
setAction(Action::SET_FILLING);
checkIfDrawn();
filling_ = filling;
}
template < typename T>
void Shape3D<T>::setDrawnStatus()
{
isDrawn_ = true;
}
template < typename T>
void Shape3D<T>::resetDrawnStatus()
{
isDrawn_ = false;
}
template < typename T>
void Shape3D<T>::checkIfDrawn()
{
if (isDrawn_)
{
std::string curAction;
switch (action_)
{
case TRANSLATE:
curAction = "TRANSLATE";
break;
case ROTATE:
curAction = "ROTATE";
break;
case SCALE:
curAction = "SCALE";
break;
case SET_COLOR:
curAction = "SET_COLOR";
break;
case SET_FILLING:
curAction = "SET_FILLING";
break;
case DRAW:
curAction = "DRAW";
break;
}
std::string error_msg = "Cannot [" + curAction + "] because shape has already drawn";
throw std::logic_error(error_msg);
}
}
template < typename T>
void Shape3D<T>::setAction(const Action& action)
{
action_ = action;
}
template < typename T>
void Shape3D<T>::reapplyRotations(const bool inverse)
{
for (auto it = rotations_.end() - 1; it!= rotations_.begin() - 1; --it)
glRotated((*it).second * (inverse? -1.: 1), (*it).first == X, (*it).first == Y, (*it).first == Z);
}
template < typename T>
class Cone: public Shape3D<T>
{
public:
Cone(const point3d_t<T>& center, const T& radius, const T& height, const T& slices, const T& stacks);
~Cone() = default;
virtual void drawShape();
private:
T radius_;
T height_;
T slices_;
T stacks_;
};
template class Cone< float >;
template class Cone< double >;
template < typename T>
Cone<T>::Cone(const point3d_t<T>& center, const T& radius, const T& height, const T& slices, const T& stacks):
radius_(radius),
height_(height),
slices_(slices),
stacks_(stacks)
{
glPushMatrix();
Shape3D<T>::resetDrawnStatus();
Shape3D<T>::setCenter(center, true);
}
template < typename T>
void Cone<T>::drawShape()
{
Shape3D<T>::setColor(Shape3D<T>::getColor());
Shape3D<T>::setAction(Action::DRAW);
if (Shape3D<T>::getFilling() == WIRE)
glutWireCone(radius_, height_, slices_, stacks_);
else
glutSolidCone(radius_, height_, slices_, stacks_);
Shape3D<T>::setDrawnStatus();
glPopMatrix();
}
template < typename T>
class Torus: public Shape3D<T>
{
public:
Torus(const point3d_t<T>& center, const T& inner_radius, const T& outer_radius, const T& sides, const T& rings);
~Torus() = default;
virtual void drawShape();
private:
T inner_radius_;
T outer_radius_;
T sides_;
T rings_;
};
template class Torus< float >;
template class Torus< double >;
template < typename T>
Torus<T>::Torus(const point3d_t<T>& center, const T& inner_radius, const T& outer_radius, const T& sides, const T& rings):
inner_radius_(inner_radius),
outer_radius_(outer_radius),
sides_(sides),
rings_(rings)
{
glPushMatrix();
Shape3D<T>::resetDrawnStatus();
Shape3D<T>::setCenter(center, true);
}
template < typename T>
void Torus<T>::drawShape()
{
Shape3D<T>::setColor(Shape3D<T>::getColor());
Shape3D<T>::setAction(Action::DRAW);
if (Shape3D<T>::getFilling() == WIRE)
glutWireTorus(inner_radius_, outer_radius_, sides_, rings_);
else
glutSolidTorus(inner_radius_, outer_radius_, sides_, rings_);
Shape3D<T>::setDrawnStatus();
glPopMatrix();
}
template < typename T>
class Cylinder: public Shape3D<T>
{
public:
Cylinder(const point3d_t<T>& center, const T& bottom_radius, const T& top_radius, const T& height, const T& slices, const T& stacks);
~Cylinder() = default;
virtual void drawShape();
private:
T bottom_radius_;
T top_radius_;
T height_;
T slices_;
T stacks_;
GLUquadricObj *quadObj_;
};
template class Cylinder< float >;
template class Cylinder< double >;
template < typename T>
Cylinder<T>::Cylinder(const point3d_t<T>& center, const T& bottom_radius, const T& top_radius, const T& height, const T& slices, const T& stacks):
bottom_radius_(bottom_radius),
top_radius_(top_radius),
height_(height),
slices_(slices),
stacks_(stacks)
{
glPushMatrix();
Shape3D<T>::resetDrawnStatus();
Shape3D<T>::setCenter(center, true);
quadObj_ = gluNewQuadric();
}
template < typename T>
void Cylinder<T>::drawShape()
{
Shape3D<T>::setColor(Shape3D<T>::getColor());
Shape3D<T>::setAction(Action::DRAW);
if (Shape3D<T>::getFilling() == WIRE)
gluQuadricDrawStyle(quadObj_, GLU_LINE);
else
gluQuadricDrawStyle(quadObj_, GLU_FILL);
gluCylinder(quadObj_, bottom_radius_, top_radius_, height_, slices_, stacks_);
gluDeleteQuadric(quadObj_);
Shape3D<T>::setDrawnStatus();
glPopMatrix();
}
int tx = 0;
int ty = 0;
void reshape(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// glOrtho() - orthogonal projection on objects inside its borders:
// first argument - coordinate of the left side (X)
// second argument - coordinate of the right side (X)
// third argument - coordinate of bottom side (Y)
// fourth argument - coordinate of top side (Y)
// fifth argument - zNear (for us must be < 0, or we won't see some shapes which will be closer to us on positive coordinates)
// sixth argument - zFar (as long as we want to render objects rotations/scaling/translating inside the projection)
glOrtho(-40., 40, -80, +80, -100, +200);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void rotateAxis()
{
glRotated(tx, 1.0, 0.0, 0.0);
glRotated(ty, 0.0, 1.0, 0.0);
}
void drawAxis(const double line_size)
{
glPushMatrix();
// set white color to axis
glColor3d(1.0, 1.0, 1.0);
//............ X axis..............
glBegin(GL_LINES);
glVertex3d(0., 0., 0.);
glVertex3d(line_size, 0., 0.);
glEnd();
glRasterPos3d(line_size, 0.0, 0.0);
print("X");
glBegin(GL_LINES);
glVertex3d(0., 0., 0.);
glVertex3d(-line_size, 0., 0.);
glEnd();
//..................................
//........... Y axis..............
glBegin(GL_LINES);
glVertex3d(0., 0., 0.);
glVertex3d(0., line_size, 0.);
glEnd();
glRasterPos3d(0.0, line_size, 0.0);
print("Y");
//................................
//........... Z axis.............
glBegin(GL_LINES);
glVertex3d(0., 0., 0.);
glVertex3d(0., 0., line_size);
glEnd();
glRasterPos3d(0.0, 0.0, line_size);
print("Z");
glBegin(GL_LINES);
glVertex3d(0., 0., 0.);
glVertex3d(0., 0., -line_size);
glEnd();
//................................
glPopMatrix();
}
void windowKey(unsigned char key, int width, int height)
{
int angle = 5;
switch (key)
{
case 'w':
tx -= angle;
break;
case 's':
tx += angle;
break;
case 'a':
ty -= angle;
break;
case 'd':
ty += angle;
break;
default:
break;
}
tx %= 360;
ty %= 360;
glutPostRedisplay();
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
rotateAxis();
drawAxis(40.);
point3d_t< double > center = {20.0, 20.0, 0.0};
std::shared_ptr<Shape3D< double >> shape1 = std::make_shared<Cone< double >>(center, 10, 25, 16., 16.);
shape1->setFilling(Filling::WIRE);
shape1->setColor(Color::VIOLET);
shape1->rotateAroundLocalAxis(Axis::X, -90.);
shape1->rotateAroundAttributeAxis(Axis::X, 90.);
shape1->drawShape();
std::shared_ptr<Shape3D< double >> shape2 = std::make_shared<Cone< double >>(center, 10, 50, 16., 16.);
shape2->setFilling(Filling::WIRE);
shape2->setColor(Color::BLUE);
shape2->rotateAroundLocalAxis(Axis::X, -90.);
shape2->rotateAroundAttributeAxis(Axis::X, 90.);
shape2->drawShape();
center = {-10., 0., 0.};
std::shared_ptr<Shape3D< double >> shape3 = std::make_shared<Torus< double >>(center, 6, 10, 25, 25);
shape3->setFilling(Filling::WIRE);
shape3->setColor(Color::CYAN);
shape3->rotateAroundLocalAxis(Axis::X, 90.);
shape3->rotateAroundAttributeAxis(Axis::Z, -45.);
shape3->drawShape();
center = {10., 0., 0.};
std::shared_ptr<Shape3D< double >> shape4 = std::make_shared<Cylinder< double >>(center, 4, 4, 30, 25, 25);
shape4->setFilling(Filling::WIRE);
shape4->setColor(Color::ORANGE);
shape4->rotateAroundLocalAxis(Axis::X, -90.);
shape4->scaleRelativeToAttributeAxis(2);
shape4->drawShape();
glutSwapBuffers();
}
int main(int argc, char * argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(800, 600);
glutCreateWindow("Sas");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutKeyboardFunc(windowKey);
glutMainLoop();
}