/
Team8
/
kittycad
Обзор
Документация
Войти
/
Team8
/
kittycad
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/gui/view_cube.cpp
296 строк
12 KB
levovix
add: pretty-printing (dumping) any ISerializable
31 дек 2025, 04:46
31 дек 2025, 04:46
073eaeb
Код
Авторство
О чём код?
#include "view_cube.h" #include "data/serialization.h" #include "gui/strings.h" #include "gui/vision/widget.h" #include <qevent.h> #include <qpainter.h> #include <qpainterpath.h> #include "gui/document_view.h" QColor mix(QColor src, QColor dest) { float alpha = (float)src.alpha() / 255; return QColor( // C = C1 * A1 + C2 * (1 - A1) src.red() * alpha + dest.red() * (1 - alpha), src.green() * alpha + dest.green() * (1 - alpha), src.blue() * alpha + dest.blue() * (1 - alpha), // A = A1 + A2 * (1 - A1) src.alpha() + int(dest.alpha() * (1 - alpha)) ); } ViewCube::ViewCube(DocumentView* docview, QWidget* parent) : m_docview(docview) { initUi(); } ViewCube::~ViewCube() {} void ViewCube::paintEvent(QPaintEvent *event) { // 100x100 QWidget::paintEvent(event); QPainter p(this); p.setRenderHint(QPainter::Antialiasing, true); p.setBrush(QBrush(QColor(76, 201, 255))); p.setPen(QPen(p.brush(), 2)); auto z = -m_scene->viewport()->GetCamera()->GetForward().Normalized(); auto y = m_scene->viewport()->GetCamera()->GetUpVector().Normalized(); auto x = crossProduct(z, y); Mat3 matrix; matrix.SetAxisX() = -x; matrix.SetAxisY() = -y; matrix.SetAxisZ() = -z; { // получить обратную матрицу Mat3 div_matrix; matrix = matrix.Div(div_matrix); } // 3D Точки points = { WorldPoint3(-1, -1, -1), WorldPoint3(1, -1, -1), WorldPoint3(1, 1, -1), WorldPoint3(-1, 1, -1), WorldPoint3(-1, -1, 1), WorldPoint3(1, -1, 1), WorldPoint3(1, 1, 1), WorldPoint3(-1, 1, 1), }; // Грани и цвета faces = {{ {FaceIndex::Back, {0, 1, 2, 3}, {0, 0, 128, 192}}, // Задняя грань (z = -1) {FaceIndex::Front, {4, 5, 6, 7}, {0, 0, 255, 192}}, // Передняя грань (z = 1) {FaceIndex::Right, {1, 5, 6, 2}, {255, 0, 0, 192}}, // Правая грань (x = 1) {FaceIndex::Left, {0, 4, 7, 3}, {128, 0, 0, 192}}, // Левая грань (x = -1) {FaceIndex::Bottom, {0, 1, 5, 4}, {0, 128, 0, 192}}, // Нижняя грань (y = -1) {FaceIndex::Top, {2, 3, 7, 6}, {0, 255, 0, 192}}, // Верхняя грань (y = 1) }}; for (auto& i : points) { i.Transform(matrix); } auto camera = WorldPoint3 (0, 0, 5); std::ranges::sort(faces, [&, this](std::tuple <int, std::array<int, 4>, QColor> face_a, std::tuple <int, std::array<int, 4>, QColor> face_b) -> bool { WorldPoint3 center_a; for (auto i : std::get<1>(face_a)) center_a += points[i]; center_a /= 4; double distance_a = (center_a - camera).Length(); WorldPoint3 center_b; for (auto i : std::get<1>(face_b)) center_b += points[i]; center_b /= 4; double distance_b = (center_b - camera).Length(); return distance_a < distance_b; }); QPolygonF polygon; for (int i = 0; i < 6; i++) { polygon.clear(); for (auto j : std::get<1>(faces[i])) polygon << normalizedPointToQPoint(points[j]); p.setBrush(QBrush(selected_face == i ? QColor(76, 201, 255) : std::get<2>(faces[i]))); p.drawPolygon(polygon); } } void ViewCube::initUi() { connect(m_docview, &DocumentView::mouseMoved, this, &ViewCube::on_mouseMoveEvent); connect(m_docview, &DocumentView::mousePressed, this, &ViewCube::on_mousePressEvent); connect(m_docview, &DocumentView::mouseReleased, this, &ViewCube::on_mouseReleaseEvent); } QScreenPoint2 ViewCube::normalizedPointToQPoint(WorldPoint3 p) { auto _p = normalizedPointTo2DPoint(p); return QPointF(_p.x, _p.y); } ScreenPoint2 ViewCube::normalizedPointTo2DPoint(WorldPoint3 p) { return ScreenPoint2(50 + p.x * 25, 50 + p.y * 25); } ScreenPoint2 ViewCube::qPointToScreenPoint(QPointF p) { return ScreenPoint2(p.x(), p.y()); } QVector3D ViewCube::cubePos() { return QVector3D( m_scene->viewport()->GetCamera()->GetPosition().x, m_scene->viewport()->GetCamera()->GetPosition().y, m_scene->viewport()->GetCamera()->GetPosition().z ); } QVector3D ViewCube::cubeUpVector() { return QVector3D( m_scene->viewport()->GetCamera()->GetUpVector().x, m_scene->viewport()->GetCamera()->GetUpVector().y, m_scene->viewport()->GetCamera()->GetUpVector().z ); } void ViewCube::setCubePos(const QVector3D &cubePos) { m_scene->viewport()->GetCamera()->SetPosition(Point3(cubePos.x(), cubePos.y(), cubePos.z())); emit cubePosChanged(); } void ViewCube::setCubeUpVector(const QVector3D &cubePos) { m_scene->viewport()->GetCamera()->SetUpVector(Vec3(cubePos.x(), cubePos.y(), cubePos.z())); } void ViewCube::on_mouseMoveEvent(QMouseEvent *event) { auto relative_position = this->mapFromGlobal( m_docview->mapToGlobal(event->position()) ); if (isPressed) { isMoved = true; auto targetPos = m_scene->viewport()->GetCamera()->GetTargetPosition(); auto upVector = -m_scene->viewport()->GetCamera()->GetUpVector().Normalized(); auto forwardVector = m_scene->viewport()->GetCamera()->GetForward().Normalized(); auto sideVector = crossProduct(forwardVector, upVector); auto delta = QPointF{ (relative_position.x() - old_position.x()) / width(), (relative_position.y() - old_position.y()) / height(), }; m_scene->viewport()->GetCamera()->RotateAbout(upVector, (delta.x()), targetPos); m_scene->viewport()->GetCamera()->RotateAbout(sideVector, (delta.y()), targetPos); m_scene->viewport()->GetCamera()->RotateAbout(forwardVector, (delta.y() * -start_position.x() * 3), targetPos); m_scene->viewport()->GetCamera()->RotateAbout(forwardVector, (delta.x() * start_position.y() * 3), targetPos); old_position = relative_position; update(); } if (rect().toRectF().contains(relative_position) && !isAnimated) { auto polygonContainsPoint = [this](ScreenPoint2 p, bool selBackFaces = false) -> std::optional<int> { for (int i = (selBackFaces ? 0 : 3); i < (selBackFaces ? 3 : 6); i++) { // Проход по граням (в зависимости от зажатой shift) bool collision = false; for (int j = 0; j < 4; j++) { // Проход по точкам грани auto vc = normalizedPointTo2DPoint(points[std::get<1>(faces[i])[j]]); // Начало отрезка auto vn = normalizedPointTo2DPoint(points[std::get<1>(faces[i])[(j + 1) % 4]]); // Конец отрезка if (((vc.y >= p.y and vn.y < p.y) or (vc.y < p.y and vn.y >= p.y)) and (p.x < (vn.x - vc.x) * (p.y - vc.y) / (vn.y - vc.y) + vc.x)) { collision = not collision; } } if (collision) return i; // вернуть грань с которой найдено пересечение } return std::nullopt; }; auto face = polygonContainsPoint(qPointToScreenPoint(relative_position), QApplication::keyboardModifiers() == Qt::ShiftModifier); if (selected_face != face) { selected_face = face; update(); } } else { if (selected_face != std::nullopt) { selected_face = std::nullopt; update(); } } } void ViewCube::on_mousePressEvent(QMouseEvent *event) { auto relative_position = this->mapFromGlobal( m_docview->mapToGlobal(event->position()) ); if (rect().toRectF().contains(relative_position)) { isPressed = true; old_position = relative_position; start_position = QPointF{ relative_position.x() / width() - 0.5, relative_position.y() / height() - 0.5 }; } } void ViewCube::on_mouseReleaseEvent(QMouseEvent *event) { auto relative_position = this->mapFromGlobal( m_docview->mapToGlobal(event->position()) ); if (rect().toRectF().contains(relative_position)) { if (isPressed && !isMoved) { auto startPos = m_scene->viewport()->GetCamera()->GetPosition(); auto startUpVector = m_scene->viewport()->GetCamera()->GetUpVector(); auto endPos = Point3(); auto endUpVector = Vec3(); auto radius = (startPos).DistanceToPoint(m_scene->viewport()->GetCamera()->GetTargetPosition()); auto targetPos = m_scene->viewport()->GetCamera()->GetTargetPosition(); cubePosAnimation = new QPropertyAnimation(this, "cubePos", this); cubeUpVectorAnimation = new QPropertyAnimation(this, "cubeUpVector", this); if (selected_face.has_value()) { int clicked_face = std::get<0>(faces[selected_face.value()]); if (clicked_face == FaceIndex::Back) { endPos = targetPos + Vec3(0, 0, -1) * radius; endUpVector = Vec3(0, 1, 0); // m_scene->viewport()->GetCamera()->SetPosition(targetPos + Vec3(0, 0, -1) * radius); // m_scene->viewport()->GetCamera()->SetUpVector(Vec3(0, 1, 0)); } else if (clicked_face == FaceIndex::Front) { endPos = targetPos + Vec3(0, 0, 1) * radius; endUpVector = Vec3(0, 1, 0); // m_scene->viewport()->GetCamera()->SetPosition(targetPos + Vec3(0, 0, 1) * radius); // m_scene->viewport()->GetCamera()->SetUpVector(Vec3(0, 1, 0)); } else if (clicked_face == FaceIndex::Right) { endPos = targetPos + Vec3(1, 0, 0) * radius; endUpVector = Vec3(0, 1, 0); // m_scene->viewport()->GetCamera()->SetPosition(targetPos + Vec3(1, 0, 0) * radius); // m_scene->viewport()->GetCamera()->SetUpVector(Vec3(0, 1, 0)); } else if (clicked_face == FaceIndex::Left) { endPos = targetPos + Vec3(-1, 0, 0) * radius; endUpVector = Vec3(0, 1, 0); // m_scene->viewport()->GetCamera()->SetPosition(targetPos + Vec3(-1, 0, 0) * radius); // m_scene->viewport()->GetCamera()->SetUpVector(Vec3(0, 1, 0)); } else if (clicked_face == FaceIndex::Bottom) { endPos = targetPos + Vec3(0, -1, 0) * radius; endUpVector = Vec3(0, 0, 1); // m_scene->viewport()->GetCamera()->SetPosition(targetPos + Vec3(0, -1, 0) * radius); // m_scene->viewport()->GetCamera()->SetUpVector(Vec3(0, 0, -1)); } else if (clicked_face == FaceIndex::Top) { endPos = targetPos + Vec3(0, 1, 0) * radius; endUpVector = Vec3(0, 0, -1); // m_scene->viewport()->GetCamera()->SetPosition(targetPos + Vec3(0, 1, 0) * radius); // m_scene->viewport()->GetCamera()->SetUpVector(Vec3(0, 0, 1)); } //m_docview->documentUpdated(); } else { if (QApplication::keyboardModifiers() == Qt::ShiftModifier) { endPos = targetPos + Vec3(-1, -1, -1).GetNormalized() * radius; endUpVector = Vec3(0, 1, 0); // m_scene->viewport()->GetCamera()->SetPosition(targetPos + Vec3(-1, -1, -1).GetNormalized() * radius); // m_scene->viewport()->GetCamera()->SetUpVector(Vec3(0, 1, 0)); } else { endPos = targetPos + Vec3(1, 1, 1).GetNormalized() * radius; endUpVector = Vec3(0, 1, 0); // m_scene->viewport()->GetCamera()->SetPosition(targetPos + Vec3(1, 1, 1).GetNormalized() * radius); // m_scene->viewport()->GetCamera()->SetUpVector(Vec3(0, 1, 0)); } } selected_face = std::nullopt; isAnimated = true; cubePosAnimation->setDuration(300); cubePosAnimation->setStartValue(QVector3D(startPos.x, startPos.y, startPos.z)); cubePosAnimation->setEndValue(QVector3D(endPos.x, endPos.y, endPos.z)); cubePosAnimation->setLoopCount(1); cubePosAnimation->setEasingCurve(QEasingCurve::OutCubic); cubePosAnimation->start(); cubeUpVectorAnimation->setDuration(300); cubeUpVectorAnimation->setStartValue(QVector3D(startUpVector.x, startUpVector.y, startUpVector.z)); cubeUpVectorAnimation->setEndValue(QVector3D(endUpVector.x, endUpVector.y, endUpVector.z)); cubeUpVectorAnimation->setLoopCount(1); cubeUpVectorAnimation->setEasingCurve(QEasingCurve::OutCubic); cubeUpVectorAnimation->start(); connect(cubeUpVectorAnimation, &QPropertyAnimation::finished, this, [this](){ isAnimated = false; }); } } isMoved = false; isPressed = false; }