Top.Mail.Ru

Qt и QML. mtPaint3D. Создаем утилиту для 3D-рисования. День 7.

Все доброго времени суток! Так вот планомерно, систематизированно и не сильно перенапрягаясь мы пришли к тому, что для 3D-объекта вида кубоид на данный момент реализована полная поддержка необходимого функционала. Поэтому сегодня по аналогичной схеме добавим остальные объекты. Чуть более подробно рассмотрим на каком-то одном из них, пусть на сфере, например, без разницы.

Собственно, уже четко определено, какие именно методы должен переопределять каждый из создаваемых 3D-объектов, так что sphere.h имеет такой вид:

#ifndef SPHERE_H
#define SPHERE_H



#include <QObject>
#include "paintobject.h"



class Sphere : public PaintObject
{
    Q_OBJECT
public:
    Sphere(Qt3DCore::QEntity *parentEntity, quint32 objectId, const QVector3D &coordinate = QVector3D(0, 0, 0));
    void onMouseMoved(const QVector3D &coordinate);
    void update(const QVector<qreal> &parameters);
    QVector<qreal> getParameters();

};

#endif // SPHERE_H

И реализация, sphere.cpp:

Sphere::Sphere(Qt3DCore::QEntity *parentEntity, quint32 objectId, const QVector3D &coordinate) :
    PaintObject(parentEntity, objectId)
{
    type = PaintObject::Type::Sphere;

    Qt3DExtras::QSphereMesh *mesh = new Qt3DExtras::QSphereMesh();
    Qt3DCore::QTransform *transform = new Qt3DCore::QTransform();

    mesh->setRadius(0);
    mesh->setSlices(50);

    transform->setTranslation(QVector3D(coordinate.x(), coordinate.y(), constants::basePlaneZExtent / 2));
    initialCoordinate = coordinate;

    entity->addComponent(mesh);
    entity->addComponent(transform);

    addMaterial();
}



void Sphere::onMouseMoved(const QVector3D &coordinate)
{
    Qt3DExtras::QSphereMesh *currentMesh = entity->componentsOfType<Qt3DExtras::QSphereMesh>().at(0);

    QVector3D mouseMoveVector = QVector3D(qAbs(coordinate.x() - initialCoordinate.x()),
                                          qAbs(coordinate.y() - initialCoordinate.y()),
                                          0);

    currentMesh->setRadius(mouseMoveVector.length());
}



QVector<qreal> Sphere::getParameters()
{
    QVector<qreal> parameters;

    for (int i = 0; i < parametersVectorSize; i++)
    {
        parameters.append(0);
    }

    Qt3DExtras::QSphereMesh *currentMesh = entity->componentsOfType<Qt3DExtras::QSphereMesh>().at(0);
    parameters[0] = currentMesh->radius();

    return parameters;
}



void Sphere::update(const QVector<qreal> &parameters)
{
    if (parameters.size() >= parametersVectorSize)
    {
        Qt3DExtras::QSphereMesh *currentMesh = entity->componentsOfType<Qt3DExtras::QSphereMesh>().at(0);
        currentMesh->setRadius(parameters.at(0));
    }
}

Схема один в один, как и для кубоида, ну для того и создавалась четкая архитектура приложения. В PaintEntity добавляем типы инструментов, причем закинем сразу не только для сферы, но и для остальных объектов:

enum class ToolType {
	Select = 0,
	Delete,
	Cuboid,
	Sphere,
	Cone,
	Cylinder,
	Torus,
	ExtrudedText
};
Q_ENUM(ToolType)

Следом же расширяем ToolPanel, чтобы добавить новые инструменты в интерфейс:

Rectangle {
    id: rootRectangle
    color: "transparent"
    height: buttonsGrid.height

    property int selectedTool: PaintEntity.ToolType.Cuboid

    property var buttonsModel: [
        {name: qsTr("select"), type: PaintEntity.ToolType.Select},
        {name: qsTr("delete"), type: PaintEntity.ToolType.Delete},
        {name: qsTr("cuboid"), type: PaintEntity.ToolType.Cuboid},
        {name: qsTr("sphere"), type: PaintEntity.ToolType.Sphere},
        {name: qsTr("cone"), type: PaintEntity.ToolType.Cone},
        {name: qsTr("cylinder"), type: PaintEntity.ToolType.Cylinder},
        {name: qsTr("torus"), type: PaintEntity.ToolType.Torus},
        {name: qsTr("text"), type: PaintEntity.ToolType.ExtrudedText}
    ]
// ...............

Дизайн нас все еще не интересует, так что результат устраивает полностью 👍 Остается внедрить логику отрисовки сферы везде, где это требуется. Во-первых, при создании объекта:

void PaintEntity::onBasePlaneMousePressed(const QVector3D &coordinate)
{
    switch (activeTool)
    {
        case PaintEntity::ToolType::Cuboid:
            paintObjects.append(QSharedPointer<PaintObject>(new Cuboid(this, paintObjects.size(), coordinate)));
            break;
            
        case PaintEntity::ToolType::Sphere:
            paintObjects.append(QSharedPointer<PaintObject>(new Sphere(this, paintObjects.size(), coordinate)));
            break;

        default:
            // This branch should never be executed
            break;
    }

    int currentIndex = paintObjects.size() - 1;
    paintObjects.at(currentIndex)->setColor(activeColor);
    QObject::connect(paintObjects.at(currentIndex).data(), &PaintObject::picked,
                     this, &PaintEntity::paintObjectPicked);
    QObject::connect(paintObjects.at(currentIndexcurrentIndex).data(), &PaintObject::readyForDeletion,
                     this, &PaintEntity::removePaintObject);
}

И, в принципе, сейчас уже сфера будет отрисовываться как положено. Еще пара дополнений требуется только в интерфейсной части main.qml:

PaintEntity {
	id: paintEntity

	function hideObjectControls() {
		for (var i = 0; i < objectsPanels.visibleChildren.length; i++) {
			objectsPanels.visibleChildren[i].visible = false;
		}

		transformPanel.visible = false;
		commonObjectPanel.visible = false;
	}

	onActivePaintObjectChanged: {
		hideObjectControls();

		if (activePaintObject !== null) {
			colorPanel.setCurrentItem(activePaintObject.color);

			transformPanel.initialPosition = activePaintObject.position;
			transformPanel.reset();
			transformPanel.visible = true;

			switch(activePaintObject.type) {
				case PaintObject.Type.Cuboid:
					commonObjectPanel.controlsModel = [
							{text: "X extent", sliderMin: 0.1, sliderMax: baseCuboid.xExtent, sliderCurrent: activePaintObject.parameters[0]},
							{text: "Y extent", sliderMin: 0.1, sliderMax: baseCuboid.yExtent, sliderCurrent: activePaintObject.parameters[1]},
							{text: "Z extent", sliderMin: 0.1, sliderMax: 10, sliderCurrent: activePaintObject.parameters[2]}
						];
					break;

				case PaintObject.Type.Sphere:
					commonObjectPanel.controlsModel = [
							{text: "Radius", sliderMin: 0.1, sliderMax: 10, sliderCurrent: activePaintObject.parameters[0]}
						];

					break;

				default:
					break;
			}

			commonObjectPanel.visible = true;
		}
	}
}

Ровно как и планировали, поведение панели свойств объекта полностью определяется в одном месте и одним свойством - commonObjectPanel.controlsModel. На этом процедура добавления нового 3D-объекта заканчивается. Только для редактирования текста я добавил еще одну панель - ExtrudedTextPanel, исключительно в целях редактирования непосредственно текста. Полученный результат:

3D-объектв в Qt и QML.

И далее, как обещал, полный код для всех текущих объектов, последовательно:

  • конус
  • кубоид
  • цилиндр
  • объемный текст
  • сфера
  • тор

Список уникальных свойств, доступных для редактирования для каждого из них:

3D объект Параметры
Конус Длина, радиус основания, радиус верхнего основания (для усеченного конуса)
Кубоид Длина, ширина, высота
Цилиндр Длина, радиус
Текст Размер, текст
Сфера Радиус
Тор Радиус образующей окружности, радиус

Текущая структура проекта, на всякий:

И да, я упаковал все панели в ScrollView, на случай если пространства окна им не хватит, что, в общем-то и произошло )

QML ScrollView.

Все, теперь добавленный код для объектов и ссылка на полный проект:

#include <QDebug>
#include "paintentity.h"
#include "objects/cuboid.h"
#include "objects/cone.h"
#include "objects/sphere.h"
#include "objects/cylinder.h"
#include "objects/torus.h"
#include "objects/extrudedtext.h"



PaintEntity::PaintEntity(QNode *parent) : Qt3DCore::QEntity(parent),
    activeTool(ToolType::Cuboid),
    activePaintObject(nullptr),
    activeColor("#b22222")
{
}



void PaintEntity::paintObjectPicked(quint32 pickedId)
{
    if (activeTool == PaintEntity::ToolType::Select)
    {
        paintObjects.at(pickedId)->startSelectAnimation();
        activePaintObject = paintObjects.at(pickedId).data();
        emit activePaintObjectChanged();
    }
    else
    {
        if (activeTool == PaintEntity::ToolType::Delete)
        {
            paintObjects.at(pickedId)->startDeleteAnimation();
        }
    }
}



void PaintEntity::removePaintObject(quint32 objectId)
{
    if (activePaintObject != nullptr)
    {
        if (objectId == activePaintObject->getId())
        {
            activePaintObject = nullptr;
            emit activePaintObjectChanged();
        }
    }

    paintObjects.remove(objectId);
    updatePaintObjectIds(objectId);
}



void PaintEntity::updatePaintObjectIds(int deletedIndex)
{
    for (int i = deletedIndex; i < paintObjects.size(); i++)
    {
        paintObjects.at(i)->setId(i);
    }
}



void PaintEntity::onBasePlaneMousePressed(const QVector3D &coordinate)
{
    switch (activeTool)
    {
        case PaintEntity::ToolType::Cuboid:
            paintObjects.append(QSharedPointer<PaintObject>(new Cuboid(this, paintObjects.size(), coordinate)));
            break;

        case PaintEntity::ToolType::Sphere:
            paintObjects.append(QSharedPointer<PaintObject>(new Sphere(this, paintObjects.size(), coordinate)));
            break;

        case PaintEntity::ToolType::Cone:
            paintObjects.append(QSharedPointer<PaintObject>(new Cone(this, paintObjects.size(), coordinate)));
            break;

        case PaintEntity::ToolType::Cylinder:
            paintObjects.append(QSharedPointer<PaintObject>(new Cylinder(this, paintObjects.size(), coordinate)));
            break;

        case PaintEntity::ToolType::Torus:
            paintObjects.append(QSharedPointer<PaintObject>(new Torus(this, paintObjects.size(), coordinate)));
            break;

        case PaintEntity::ToolType::ExtrudedText:
            paintObjects.append(QSharedPointer<PaintObject>(new ExtrudedText(this, paintObjects.size(), coordinate)));
            break;

        default:
            // This branch should never be executed
            break;
    }

    int currentIndex = paintObjects.size() - 1;
    paintObjects.at(currentIndex)->setColor(activeColor);
    QObject::connect(paintObjects.at(currentIndex).data(), &PaintObject::picked,
                     this, &PaintEntity::paintObjectPicked);
    QObject::connect(paintObjects.at(currentIndex).data(), &PaintObject::readyForDeletion,
                     this, &PaintEntity::removePaintObject);
}



void PaintEntity::onBasePlaneMouseMoved(const QVector3D &coordinate)
{
    paintObjects.at(paintObjects.size() - 1)->onMouseMoved(coordinate);
}



void PaintEntity::setActiveColor(const QString &color)
{
    activeColor = color;

    if (activeTool == PaintEntity::ToolType::Select)
    {
        if (activePaintObject != nullptr)
        {
            activePaintObject->setColor(activeColor);
        }
    }
}



PaintEntity::ToolType PaintEntity::getActiveTool()
{
    return activeTool;
}



void PaintEntity::setActiveTool(ToolType tool)
{
    activeTool = tool;
    bool pickerState = false;

    if ((activeTool == PaintEntity::ToolType::Select) ||
        (activeTool == PaintEntity::ToolType::Delete))
    {
        pickerState = true;
    }

    for (int i = 0; i < paintObjects.size(); i++)
    {
        paintObjects.at(i)->setPickerEnabled(pickerState);
    }
}



PaintObject* PaintEntity::getPaintObject()
{
    return activePaintObject;
}
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQml.Models 2.15
import QtQuick.Layouts 1.15
import QtQuick.Shapes 1.15



Rectangle {
    id: rootRectangle
    color: "#606065"
    height: controlsColumn.height

    property string textInput: qsTr("Text")
    property string initialText: qsTr("Text")

    Column {
        id: controlsColumn
        spacing: 2
        anchors.horizontalCenter: parent.horizontalCenter

        TextInput {
            color: "white"
            font.pointSize: 16

            onVisibleChanged: {
                if (visible === true) {
                    text = initialText;
                }
            }

            onTextEdited: {
                if (text === "") {
                    text = "-";
                }

                textInput = text;
            }
        }
    }
}
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import Qt3D.Core 2.15
import QtQuick3D 1.15
import QtQuick.Scene3D 2.15
import Qt3D.Render 2.15
import Qt3D.Input 2.15
import Qt3D.Extras 2.15
import QtQuick3D.Materials 1.15
import "../qml/objects"

import microtechnics.paintEntity 1.0
import microtechnics.paintObject 1.0



ApplicationWindow {
    id: window
    width: Screen.width * 3 / 4
    height: Screen.height * 3 / 4
    visible: true
    title: qsTr("mtPaint3D")
    color: "#505050"

    onClosing: {
        paintEntity.destroy();
    }

    GridLayout {
        id: mainLayout
        rows: 12
        columns: 6
        flow: GridLayout.TopToBottom
        anchors.fill: parent

        component GridRectangle : Rectangle {
            Layout.fillHeight: true
            Layout.fillWidth: true
            Layout.preferredWidth: Layout.columnSpan
            Layout.preferredHeight: Layout.rowSpan

            color: "#808080"
            border.color: Qt.darker(color)
            border.width: 1
        }

        GridRectangle {
            id: objectBlock

            Layout.row: 0
            Layout.column: 0
            Layout.rowSpan: 12
            Layout.columnSpan: 1

            ScrollView {
                clip: true
                anchors.fill: parent
                contentHeight: toolPanel.height + colorPanel.height + colorPanel.anchors.topMargin +
                               transformPanel.height + transformPanel.anchors.topMargin + objectsPanels.childrenRect.height +
                               extrudedTextPanel.anchors.topMargin

                ToolPanel {
                    id: toolPanel
                    anchors.left: parent.left
                    anchors.right: parent.right
                    anchors.top: parent.top

                    onSelectedToolChanged: {
                        if ((toolPanel.selectedTool === PaintEntity.ToolType.Select) ||
                            (toolPanel.selectedTool === PaintEntity.ToolType.Delete)) {
                            baseCuboidPicker.paintEnabled = false;
                        } else {
                            baseCuboidPicker.paintEnabled = true;
                        }

                        paintEntity.activeTool = toolPanel.selectedTool;
                    }
                }

                ColorPanel {
                    id: colorPanel
                    anchors.left: parent.left
                    anchors.right: parent.right
                    anchors.top: toolPanel.bottom
                    anchors.topMargin: 10
                    visible: true

                    onSelectedColorChanged: {
                        paintEntity.setActiveColor(selectedColor);
                    }
                }

                TransformPanel {
                    id: transformPanel
                    anchors.left: parent.left
                    anchors.right: parent.right
                    anchors.top: colorPanel.bottom
                    anchors.topMargin: 10

                    visible: false

                    positionLimits: Qt.vector3d(baseCuboid.xExtent, baseCuboid.yExtent, 20)

                    onAngleChanged: {
                        if (paintEntity.activePaintObject !== null) {
                            paintEntity.activePaintObject.rotate(angle);
                        }
                    }

                    onPositionChanged: {
                        if (paintEntity.activePaintObject !== null) {
                            paintEntity.activePaintObject.move(position);
                        }
                    }
                }

                Item {
                    id: objectsPanels
                    anchors.left: parent.left
                    anchors.right: parent.right
                    anchors.top: transformPanel.bottom

                    CommonObjectPanel {
                        id: commonObjectPanel
                        anchors.left: parent.left
                        anchors.right: parent.right
                        visible: false

                        onParametersChanged: {
                            if (paintEntity.activePaintObject !== null) {
                                paintEntity.activePaintObject.update(parameters);
                            }
                        }
                    }

                    ExtrudedTextPanel {
                        id: extrudedTextPanel
                        anchors.left: parent.left
                        anchors.right: parent.right
                        anchors.top: commonObjectPanel.bottom
                        anchors.topMargin: 20
                        visible: false

                        onTextInputChanged: {
                            if (paintEntity.activePaintObject !== null) {
                                paintEntity.activePaintObject.updateText(textInput);
                            }
                        }
                    }
                }
            }
        }

        GridRectangle {
            id: viewBlock

            Layout.row: 0
            Layout.column: 1
            Layout.rowSpan: 1
            Layout.columnSpan: 5

            Row {
                id: viewButtonsRow
                spacing: 2
                anchors.horizontalCenter: parent.horizontalCenter
                anchors.verticalCenter: parent.verticalCenter

                Button {
                    id: topViewButton
                    text: qsTr("Top View")

                    onClicked:
                        ParallelAnimation {
                            PropertyAnimation { target: camera; property: "position"; to: Qt.vector3d(0.0, 0.0, 35.0); duration: 675; }
                            PropertyAnimation { target: camera; property: "upVector"; to: Qt.vector3d(0.0, 1.0, 0.0); duration: 675; }
                    }
                }

                Button {
                    id: frontViewButton
                    text: qsTr("Front View")

                    onClicked:
                        ParallelAnimation {
                            PropertyAnimation { target: camera; property: "position"; to: Qt.vector3d(0.0, -25.0, 25.0); duration: 675; }
                            PropertyAnimation { target: camera; property: "upVector"; to: Qt.vector3d(0.0, 0.0, 1.0); duration: 675; }
                    }
                }
            }
        }

        GridRectangle {
            id: paintBlock

            Layout.row: 1
            Layout.column: 1
            Layout.rowSpan: 11
            Layout.columnSpan: 5

            Scene3D {
                id: scene3D
                anchors.fill: parent
                focus: true
                aspects: ["input", "logic"]

                Entity {
                    id: rootEntity

                    Entity {
                        id: lightEntity
                        components: [
                          PointLight {
                              color: "#ffffa7"
                              intensity: 0.5
                              enabled: true
                          },
                          Transform {
                              translation: Qt.vector3d(10, 0, 10)
                          }
                        ]
                    }

                    Camera {
                        id: camera

                        projectionType: CameraLens.PerspectiveProjection
                        fieldOfView: 45
                        nearPlane : 0.1
                        farPlane : 100
                        aspectRatio: 1
                        position: Qt.vector3d(0.0, -25.0, 25.0)
                        upVector: Qt.vector3d(0.0, 0.0, 1.0)
                        viewCenter: Qt.vector3d(0.0, 0.0, 0.0)
                    }

                    PaintCameraController {
                        camera: camera
                        lookSpeed: 35
                    }

                    RenderSettings {
                        id: renderSettings
                        activeFrameGraph: ForwardRenderer {
                            camera: camera
                            clearColor: "transparent"
                        }
                        pickingSettings.pickMethod: PickingSettings.TrianglePicking
                    }

                    InputSettings { id: inputSettings }

                    Entity {
                        id: baseCuboidEntity

                        CuboidMesh {
                            id: baseCuboid

                            xExtent: 35
                            yExtent: 25
                            zExtent: basePlaneZExtent
                        }

                        Transform {
                            id: baseCuboidTransform
                        }

                        DiffuseSpecularMaterial {
                            id: baseCuboidMaterial
                            ambient: "#ffffff"
                            shininess: 100
                        }

                        ObjectPicker {
                            id: baseCuboidPicker
                            hoverEnabled: true
                            dragEnabled: true
                            enabled: true
                            property bool isAddingPaintObject: false
                            property bool paintEnabled: true

                            onPressed: {
                                if (paintEnabled === true) {
                                    if (pick.buttons === Qt.LeftButton) {
                                        isAddingPaintObject = true;
                                        paintEntity.onBasePlaneMousePressed(pick.worldIntersection);
                                    }
                                }
                            }

                            onMoved: {
                                var hoverCoordinate = Qt.vector3d(pick.worldIntersection.x, pick.worldIntersection.y, basePlaneHoverTransform.translation.z);
                                basePlaneHoverTransform.translation = hoverCoordinate;

                                if (paintEnabled === true) {
                                    if (isAddingPaintObject === true) {
                                        paintEntity.onBasePlaneMouseMoved(pick.worldIntersection);
                                    }
                                }
                            }

                            onReleased: {
                                isAddingPaintObject = false;
                            }
                        }

                        components: [
                            baseCuboid,
                            baseCuboidMaterial,
                            baseCuboidTransform,
                            baseCuboidPicker
                        ]
                    }

                    Entity {
                        id: basePlaneHoverEntity
                        enabled: true
                        property var zCoordinate: 0.01

                        PlaneMesh {
                            id: basePlaneHoverMesh
                            width: 0.3
                            height: 0.3
                        }

                        Transform {
                            id: basePlaneHoverTransform
                            translation: Qt.vector3d(0, 0, baseCuboid.zExtent + basePlaneHoverEntity.zCoordinate)
                            rotationX: 90
                        }

                        GoochMaterial {
                            id: basePlaneHoverMaterial
                            alpha: 1
                            cool: "#0000b0"
                        }

                        components: [
                            basePlaneHoverMesh,
                            basePlaneHoverMaterial,
                            basePlaneHoverTransform
                        ]
                    }

                    PaintEntity {
                        id: paintEntity

                        function hideObjectControls() {
                            for (var i = 0; i < objectsPanels.visibleChildren.length; i++) {
                                objectsPanels.visibleChildren[i].visible = false;
                            }

                            transformPanel.visible = false;
                            extrudedTextPanel.visible = false;
                            commonObjectPanel.visible = false;
                        }

                        onActivePaintObjectChanged: {
                            hideObjectControls();

                            if (activePaintObject !== null) {
                                colorPanel.setCurrentItem(activePaintObject.color);

                                transformPanel.initialPosition = activePaintObject.position;
                                transformPanel.reset();
                                transformPanel.visible = true;

                                switch(activePaintObject.type) {
                                    case PaintObject.Type.Cuboid:
                                        commonObjectPanel.controlsModel = [
                                                {text: qsTr("X extent"), sliderMin: 0.1, sliderMax: baseCuboid.xExtent, sliderCurrent: activePaintObject.parameters[0]},
                                                {text: qsTr("Y extent"), sliderMin: 0.1, sliderMax: baseCuboid.yExtent, sliderCurrent: activePaintObject.parameters[1]},
                                                {text: qsTr("Z extent"), sliderMin: 0.1, sliderMax: 10, sliderCurrent: activePaintObject.parameters[2]}
                                            ];
                                        break;

                                    case PaintObject.Type.Cone:
                                        commonObjectPanel.controlsModel = [
                                                {text: qsTr("Length"), sliderMin: 0.1, sliderMax: 10, sliderCurrent: activePaintObject.parameters[0]},
                                                {text: qsTr("Bottom radius"), sliderMin: 0.1, sliderMax: 10, sliderCurrent: activePaintObject.parameters[1]},
                                                {text: qsTr("Top radius"), sliderMin: 0.1, sliderMax: 8, sliderCurrent: activePaintObject.parameters[2]}
                                            ];

                                        break;

                                    case PaintObject.Type.Sphere:
                                        commonObjectPanel.controlsModel = [
                                                {text: qsTr("Radius"), sliderMin: 0.1, sliderMax: 10, sliderCurrent: activePaintObject.parameters[0]}
                                            ];

                                        break;

                                    case PaintObject.Type.Cylinder:
                                        commonObjectPanel.controlsModel = [
                                                {text: qsTr("Length"), sliderMin: 0.1, sliderMax: 10, sliderCurrent: activePaintObject.parameters[0]},
                                                {text: qsTr("Radius"), sliderMin: 0.1, sliderMax: 10, sliderCurrent: activePaintObject.parameters[1]}
                                            ];

                                        break;

                                    case PaintObject.Type.Torus:
                                        commonObjectPanel.controlsModel = [
                                                {text: qsTr("Minor radius"), sliderMin: 0.1, sliderMax: 1, sliderCurrent: activePaintObject.parameters[0]},
                                                {text: qsTr("Radius"), sliderMin: 0.1, sliderMax: 10, sliderCurrent: activePaintObject.parameters[1]}
                                            ];

                                        break;

                                    case PaintObject.Type.ExtrudedText:
                                        commonObjectPanel.controlsModel = [
                                                {text: qsTr("Scale"), sliderMin: 0.1, sliderMax: 5, sliderCurrent: activePaintObject.parameters[0]}
                                            ];

                                        extrudedTextPanel.initialText = activePaintObject.text;
                                        extrudedTextPanel.visible = true;
                                        break;

                                    default:
                                        break;
                                }

                                commonObjectPanel.visible = true;
                            }
                        }
                    }
                }
            }
        }
    }
}
#include "cone.h"



constexpr int parametersVectorSize = 3;
constexpr qreal defaultLength = 5;
constexpr qreal defaultRadiusRatio = 0.1;



Cone::Cone(Qt3DCore::QEntity *parentEntity, quint32 objectId, const QVector3D &coordinate) :
    PaintObject(parentEntity, objectId)
{
    type = PaintObject::Type::Cone;

    Qt3DExtras::QConeMesh *mesh = new Qt3DExtras::QConeMesh();
    Qt3DCore::QTransform *transform = new Qt3DCore::QTransform();

    mesh->setHasBottomEndcap(true);
    mesh->setHasTopEndcap(true);
    mesh->setLength(defaultLength);
    mesh->setBottomRadius(0);
    mesh->setTopRadius(mesh->bottomRadius() * defaultRadiusRatio);
    mesh->setSlices(50);

    transform->setTranslation(QVector3D(coordinate.x(), coordinate.y(), constants::basePlaneZExtent / 2 + defaultLength / 2));
    transform->setRotationX(90);
    initialCoordinate = coordinate;

    entity->addComponent(mesh);
    entity->addComponent(transform);

    addMaterial();
}



void Cone::onMouseMoved(const QVector3D &coordinate)
{
    Qt3DExtras::QConeMesh *currentMesh = entity->componentsOfType<Qt3DExtras::QConeMesh>().at(0);

    QVector3D mouseMoveVector = QVector3D(qAbs(coordinate.x() - initialCoordinate.x()),
                                          qAbs(coordinate.y() - initialCoordinate.y()),
                                          0);

    currentMesh->setBottomRadius(mouseMoveVector.length());
    currentMesh->setTopRadius(currentMesh->bottomRadius() * defaultRadiusRatio);
}



QVector<qreal> Cone::getParameters()
{
    QVector<qreal> parameters;

    for (int i = 0; i < parametersVectorSize; i++)
    {
        parameters.append(0);
    }

    Qt3DExtras::QConeMesh *currentMesh = entity->componentsOfType<Qt3DExtras::QConeMesh>().at(0);

    parameters[0] = currentMesh->length();
    parameters[1] = currentMesh->bottomRadius();
    parameters[2] = currentMesh->topRadius();

    return parameters;
}



void Cone::update(const QVector<qreal> &parameters)
{
    if (parameters.size() >= parametersVectorSize)
    {

        Qt3DExtras::QConeMesh *currentMesh = entity->componentsOfType<Qt3DExtras::QConeMesh>().at(0);

        qreal deltaLength = parameters.at(0) - currentMesh->length();

        currentMesh->setLength(parameters.at(0));
        currentMesh->setBottomRadius(parameters.at(1));
        currentMesh->setTopRadius(parameters.at(2));

        Qt3DCore::QTransform *currentTransform = entity->componentsOfType<Qt3DCore::QTransform>().at(0);
        currentTransform->setTranslation(currentTransform->translation() +
                                         currentTransform->rotation().rotatedVector(QVector3D(0, deltaLength / 2, 0)));
    }
}
#include "cylinder.h"



constexpr int parametersVectorSize = 3;
constexpr qreal defaultLength = 5;



Cylinder::Cylinder(Qt3DCore::QEntity *parentEntity, quint32 objectId, const QVector3D &coordinate) :
    PaintObject(parentEntity, objectId)
{
    type = PaintObject::Type::Cylinder;

    Qt3DExtras::QCylinderMesh *mesh = new Qt3DExtras::QCylinderMesh();
    Qt3DCore::QTransform *transform = new Qt3DCore::QTransform();

    mesh->setLength(defaultLength);
    mesh->setRadius(0);
    mesh->setSlices(50);

    transform->setTranslation(QVector3D(coordinate.x(), coordinate.y(), constants::basePlaneZExtent / 2 + defaultLength / 2));
    transform->setRotationX(90);
    initialCoordinate = coordinate;

    entity->addComponent(mesh);
    entity->addComponent(transform);

    addMaterial();
}



void Cylinder::onMouseMoved(const QVector3D &coordinate)
{
    Qt3DExtras::QCylinderMesh *currentMesh = entity->componentsOfType<Qt3DExtras::QCylinderMesh>().at(0);

    QVector3D mouseMoveVector = QVector3D(qAbs(coordinate.x() - initialCoordinate.x()),
                                          qAbs(coordinate.y() - initialCoordinate.y()),
                                          0);

    currentMesh->setRadius(mouseMoveVector.length());
}



QVector<qreal> Cylinder::getParameters()
{
    QVector<qreal> parameters;

    for (int i = 0; i < parametersVectorSize; i++)
    {
        parameters.append(0);
    }

    Qt3DExtras::QCylinderMesh *currentMesh = entity->componentsOfType<Qt3DExtras::QCylinderMesh>().at(0);

    parameters[0] = currentMesh->length();
    parameters[1] = currentMesh->radius();

    return parameters;
}



void Cylinder::update(const QVector<qreal> &parameters)
{
    if (parameters.size() >= parametersVectorSize)
    {
        Qt3DExtras::QCylinderMesh *currentMesh = entity->componentsOfType<Qt3DExtras::QCylinderMesh>().at(0);

        qreal deltaLength = parameters.at(0) - currentMesh->length();

        currentMesh->setLength(parameters.at(0));
        currentMesh->setRadius(parameters.at(1));

        Qt3DCore::QTransform *currentTransform = entity->componentsOfType<Qt3DCore::QTransform>().at(0);
        currentTransform->setTranslation(currentTransform->translation() +
                                         currentTransform->rotation().rotatedVector(QVector3D(0, deltaLength / 2, 0)));
    }
}
#include "extrudedtext.h"



constexpr int parametersVectorSize = 1;
constexpr qreal defaultDepth = 0.25;
constexpr qreal mouseScaleRatio = 2.5;



ExtrudedText::ExtrudedText(Qt3DCore::QEntity *parentEntity, quint32 objectId, const QVector3D &coordinate) :
    PaintObject(parentEntity, objectId)
{
    type = PaintObject::Type::ExtrudedText;

    Qt3DExtras::QExtrudedTextMesh *mesh = new Qt3DExtras::QExtrudedTextMesh();
    Qt3DCore::QTransform *transform = new Qt3DCore::QTransform();

    mesh->setDepth(defaultDepth);
    mesh->setText("Text");

    transform->setTranslation(QVector3D(coordinate.x(), coordinate.y(), constants::basePlaneZExtent / 2));
    transform->setScale(0);
    transform->setRotationX(45);
    initialCoordinate = coordinate;

    entity->addComponent(mesh);
    entity->addComponent(transform);

    addMaterial();
}



void ExtrudedText::onMouseMoved(const QVector3D &coordinate)
{
    Qt3DCore::QTransform *currentTransform = entity->componentsOfType<Qt3DCore::QTransform>().at(0);
    QVector3D mouseMoveVector = QVector3D(qAbs(coordinate.x() - initialCoordinate.x()),
                                          0,
                                          0);

    currentTransform->setScale(mouseMoveVector.length() / mouseScaleRatio);
}



QVector<qreal> ExtrudedText::getParameters()
{
    QVector<qreal> parameters;

    for (int i = 0; i < parametersVectorSize; i++)
    {
        parameters.append(0);
    }

    Qt3DCore::QTransform *currentTransform = entity->componentsOfType<Qt3DCore::QTransform>().at(0);
    parameters[0] = currentTransform->scale();

    return parameters;
}



void ExtrudedText::update(const QVector<qreal> &parameters)
{
    if (parameters.size() >= parametersVectorSize)
    {
        Qt3DCore::QTransform *currentTransform = entity->componentsOfType<Qt3DCore::QTransform>().at(0);
        currentTransform->setScale(parameters.at(0));
    }
}



QString ExtrudedText::getText()
{
    Qt3DExtras::QExtrudedTextMesh *currentMesh = entity->componentsOfType<Qt3DExtras::QExtrudedTextMesh>().at(0);
    return currentMesh->text();
}



void ExtrudedText::updateText(QString text)
{
    Qt3DExtras::QExtrudedTextMesh *currentMesh = entity->componentsOfType<Qt3DExtras::QExtrudedTextMesh>().at(0);

    if (text.isEmpty() == true)
    {
        text = "-";
    }

    currentMesh->setText(text);
}
#include "torus.h"



constexpr int parametersVectorSize = 3;
constexpr qreal defaultMinorRadius = 0.5;



Torus::Torus(Qt3DCore::QEntity *parentEntity, quint32 objectId, const QVector3D &coordinate) :
    PaintObject(parentEntity, objectId)
{
    type = PaintObject::Type::Torus;

    Qt3DExtras::QTorusMesh *mesh = new Qt3DExtras::QTorusMesh();
    Qt3DCore::QTransform *transform = new Qt3DCore::QTransform();

    mesh->setMinorRadius(defaultMinorRadius);
    mesh->setRadius(0);
    mesh->setRings(50);

    transform->setTranslation(QVector3D(coordinate.x(), coordinate.y(), constants::basePlaneZExtent / 2 + defaultMinorRadius));
    initialCoordinate = coordinate;

    entity->addComponent(mesh);
    entity->addComponent(transform);

    addMaterial();
}



void Torus::onMouseMoved(const QVector3D &coordinate)
{
    Qt3DExtras::QTorusMesh *currentMesh = entity->componentsOfType<Qt3DExtras::QTorusMesh>().at(0);

    QVector3D mouseMoveVector = QVector3D(qAbs(coordinate.x() - initialCoordinate.x()),
                                          qAbs(coordinate.y() - initialCoordinate.y()),
                                          0);

    currentMesh->setRadius(mouseMoveVector.length());
}



QVector<qreal> Torus::getParameters()
{
    QVector<qreal> parameters;

    for (int i = 0; i < parametersVectorSize; i++)
    {
        parameters.append(0);
    }

    Qt3DExtras::QTorusMesh *currentMesh = entity->componentsOfType<Qt3DExtras::QTorusMesh>().at(0);

    parameters[0] = currentMesh->minorRadius();
    parameters[1] = currentMesh->radius();

    return parameters;
}



void Torus::update(const QVector<qreal> &parameters)
{
    if (parameters.size() >= parametersVectorSize)
    {
        Qt3DExtras::QTorusMesh *currentMesh = entity->componentsOfType<Qt3DExtras::QTorusMesh>().at(0);

        qreal deltaLength = 0;//parameters.at(0) - currentMesh->length();

        currentMesh->setMinorRadius(parameters.at(0));
        currentMesh->setRadius(parameters.at(1));

        Qt3DCore::QTransform *currentTransform = entity->componentsOfType<Qt3DCore::QTransform>().at(0);
        currentTransform->setTranslation(currentTransform->translation() +
                                         currentTransform->rotation().rotatedVector(QVector3D(0, deltaLength / 2, 0)));
    }
}

Исходный код и проект: mtPaint3D_day_7

Подписаться
Уведомление о
guest
0 комментариев
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x