338 lines
12 KiB
C++
338 lines
12 KiB
C++
#include "backplotwidget.h"
|
|
|
|
#include <QWidget>
|
|
#include <QCamera>
|
|
#include <QCameraLens>
|
|
#include <QMaterial>
|
|
#include <QGeometry>
|
|
#include <Qt3DExtras/QCylinderMesh>
|
|
#include <Qt3DExtras/QPlaneMesh>
|
|
#include <Qt3DRender/qpointlight.h>
|
|
#include <QRenderSettings>
|
|
|
|
BackPlotWidget::BackPlotWidget(QWidget *parent, double xLimit, double yLimit, double zLimit)
|
|
: limits(xLimit, yLimit, zLimit),
|
|
QWidget(parent)
|
|
{
|
|
|
|
containerWdiget = QWidget::createWindowContainer(&view);
|
|
hLayout.addWidget(containerWdiget);
|
|
containerWdiget->setParent(this);
|
|
setLayout(&hLayout);
|
|
view.defaultFrameGraph()->setClearColor("Black");
|
|
|
|
reset();
|
|
}
|
|
|
|
void BackPlotWidget::reset()
|
|
{
|
|
view.setRootEntity(nullptr);
|
|
|
|
if(rootEntity)
|
|
delete rootEntity;
|
|
rootEntity = new Qt3DCore::QEntity();
|
|
view.setRootEntity(rootEntity);
|
|
view.renderSettings()->setRenderPolicy(Qt3DRender::QRenderSettings::OnDemand);
|
|
|
|
camController = new OrbitCameraController(QVector2D(100, 100), rootEntity);
|
|
camController->setLinearSpeed(200.0f);
|
|
camController->setLookSpeed(360.0f);
|
|
camController->setCamera(view.camera());
|
|
|
|
axisMaterial = new Qt3DExtras::QPhongMaterial(rootEntity);
|
|
rapidMaterial= new Qt3DExtras::QPhongMaterial(rootEntity);
|
|
pathMaterial = new Qt3DExtras::QPhongMaterial(rootEntity);
|
|
axisMaterial->setAmbient(QColorConstants::Red);
|
|
rapidMaterial->setAmbient(QColorConstants::Gray);
|
|
pathMaterial->setAmbient(QColorConstants::White);
|
|
|
|
view.camera()->setPosition(QVector3D(limits.x()/2, limits.y()/2, limits.z()*4));
|
|
view.camera()->setUpVector(QVector3D(0, 1, 0));
|
|
view.camera()->setViewCenter(QVector3D(limits.x()/2, limits.y()/2, 0));
|
|
|
|
Qt3DCore::QEntity *lightEntity = new Qt3DCore::QEntity(rootEntity);
|
|
Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight(lightEntity);
|
|
light->setColor(QColorConstants::White);
|
|
light->setIntensity(0.2);
|
|
lightEntity->addComponent(light);
|
|
Qt3DCore::QTransform *lightTransform = new Qt3DCore::QTransform(lightEntity);
|
|
lightTransform->setTranslation(QVector3D(0-limits.x()/2, 0-limits.y()/2, 1000.0f));
|
|
lightEntity->addComponent(lightTransform);
|
|
|
|
Qt3DCore::QEntity* xAxisEntity = new Qt3DCore::QEntity(rootEntity);
|
|
Qt3DCore::QEntity* yAxisEntity = new Qt3DCore::QEntity(rootEntity);
|
|
Qt3DCore::QEntity* zAxisEntity = new Qt3DCore::QEntity(rootEntity);
|
|
Qt3DExtras::QPhongMaterial* xAxisMaterial = new Qt3DExtras::QPhongMaterial(xAxisEntity);
|
|
Qt3DExtras::QPhongMaterial* yAxisMaterial = new Qt3DExtras::QPhongMaterial(yAxisEntity);
|
|
Qt3DExtras::QPhongMaterial* zAxisMaterial = new Qt3DExtras::QPhongMaterial(zAxisEntity);
|
|
xAxisMaterial->setAmbient(QColorConstants::Green);
|
|
yAxisMaterial->setAmbient(QColorConstants::Red);
|
|
zAxisMaterial->setAmbient(QColor(18,128,255));
|
|
touchoffTransform = new Qt3DCore::QTransform(rootEntity);
|
|
touchoffTransform->setTranslation(limits);
|
|
xAxisEntity->addComponent(touchoffTransform);
|
|
yAxisEntity->addComponent(touchoffTransform);
|
|
zAxisEntity->addComponent(touchoffTransform);
|
|
drawLine(QVector3D(0,0,0), QVector3D(-15,0,0), xAxisMaterial, xAxisEntity);
|
|
drawLine(QVector3D(0,0,0), QVector3D(0,-15,0), yAxisMaterial, yAxisEntity);
|
|
drawLine(QVector3D(0,0,0), QVector3D(0,0,15), zAxisMaterial, zAxisEntity);
|
|
|
|
drawBox(QVector3D(0, 0, 0), limits, axisMaterial, new Qt3DCore::QEntity(rootEntity));
|
|
|
|
Qt3DCore::QEntity* planeEntity = new Qt3DCore::QEntity(rootEntity);
|
|
Qt3DExtras::QPlaneMesh* plane = new Qt3DExtras::QPlaneMesh(planeEntity);
|
|
Qt3DCore::QTransform *planeTransform = new Qt3DCore::QTransform(planeEntity);
|
|
Qt3DExtras::QPhongMaterial* planeMaterial = new Qt3DExtras::QPhongMaterial(planeEntity);
|
|
planeMaterial->setDiffuse(QColorConstants::DarkGray);
|
|
planeTransform->setTranslation(QVector3D(limits.x()/2, limits.y()/2, -1));
|
|
planeTransform->setRotationX(90);
|
|
plane->setHeight(limits.y()*2);
|
|
plane->setWidth(limits.x()*2);
|
|
planeEntity->addComponent(plane);
|
|
planeEntity->addComponent(planeMaterial);
|
|
planeEntity->addComponent(planeTransform);
|
|
|
|
Qt3DCore::QEntity* planeRevEntity = new Qt3DCore::QEntity(rootEntity);
|
|
Qt3DExtras::QPlaneMesh* planeRev = new Qt3DExtras::QPlaneMesh(planeRevEntity);
|
|
Qt3DCore::QTransform *planeRevTransform = new Qt3DCore::QTransform(planeRevEntity);
|
|
planeRevTransform->setTranslation(QVector3D(limits.x()/2, limits.y()/2, -1));
|
|
planeRevTransform->setRotationX(-90);
|
|
planeRev->setHeight(limits.y()*2);
|
|
planeRev->setWidth(limits.x()*2);
|
|
planeRevEntity->addComponent(planeRev);
|
|
planeRevEntity->addComponent(planeMaterial);
|
|
planeRevEntity->addComponent(planeRevTransform);
|
|
|
|
toolEntity = new Qt3DCore::QEntity(rootEntity);
|
|
Qt3DExtras::QCylinderMesh* toolMesh = new Qt3DExtras::QCylinderMesh(toolEntity);
|
|
Qt3DExtras::QPhongMaterial* toolMaterial = new Qt3DExtras::QPhongMaterial(toolEntity);
|
|
toolTransform = new Qt3DCore::QTransform(toolEntity);
|
|
toolTransform->setTranslation(limits + QVector3D(0,0,5));
|
|
toolTransform->setRotationX(90);
|
|
toolMaterial->setDiffuse(QColorConstants::White);
|
|
toolMaterial->setAmbient(QColor(64,64,64));
|
|
toolMesh->setRadius(1);
|
|
toolMesh->setLength(10);
|
|
toolEntity->addComponent(toolMesh);
|
|
toolEntity->addComponent(toolMaterial);
|
|
toolEntity->addComponent(toolTransform);
|
|
}
|
|
|
|
void BackPlotWidget::showView(ViewPos viewPos)
|
|
{
|
|
if(viewPos == VIEW_TOP)
|
|
{
|
|
view.camera()->setPosition(QVector3D(limits.x()/2, limits.y()/2, limits.z()*4));
|
|
view.camera()->setUpVector(QVector3D(0, 1, 0));
|
|
}
|
|
else if(viewPos == VIEW_FRONT)
|
|
{
|
|
view.camera()->setPosition(QVector3D(limits.x()/2, 0-limits.y()*4, limits.z()/2));
|
|
view.camera()->setUpVector(QVector3D(0, 0, 1));
|
|
}
|
|
else if(viewPos == VIEW_LEFT)
|
|
{
|
|
view.camera()->setPosition(QVector3D(0-limits.x()*4, limits.y()/2, limits.z()/2));
|
|
view.camera()->setUpVector(QVector3D(0, 0, 1));
|
|
}
|
|
else if(viewPos == VIEW_RIGHT)
|
|
{
|
|
view.camera()->setPosition(QVector3D(limits.x()*4, limits.y()/2, limits.z()/2));
|
|
view.camera()->setUpVector(QVector3D(0, 0, 1));
|
|
}
|
|
|
|
if(viewPos == VIEW_TOP)
|
|
view.camera()->setViewCenter(QVector3D(limits.x()/2, limits.y()/2, 0));
|
|
else
|
|
view.camera()->setViewCenter(QVector3D(limits.x()/2, limits.y()/2, limits.z()/2));
|
|
camController->setZoomFactor(1);
|
|
}
|
|
|
|
void BackPlotWidget::positionUpdate(std::vector<int> position)
|
|
{
|
|
assert(position.size() >= 3);
|
|
toolTransform->setTranslation(limits - QVector3D(position[0]/1000.0, position[1]/1000.0, (position[2]/1000.0)-5));
|
|
}
|
|
|
|
void BackPlotWidget::resizeEvent(QResizeEvent *event)
|
|
{
|
|
QWidget::resizeEvent(event);
|
|
double aspectRatio = static_cast<double>(geometry().width())/geometry().height();
|
|
double screenWidth;
|
|
double screenHeight;
|
|
if(aspectRatio > 1.0)
|
|
{
|
|
screenWidth = 500.0;
|
|
screenHeight = screenWidth/aspectRatio;
|
|
}
|
|
else
|
|
{
|
|
screenHeight = 500;
|
|
screenWidth = aspectRatio*screenHeight;
|
|
}
|
|
camController->setOrthoSize(QVector2D(screenWidth, screenHeight));
|
|
}
|
|
|
|
void BackPlotWidget::drawBox(const QVector3D& a, const QVector3D& b, Qt3DRender::QMaterial* material, Qt3DCore::QEntity* parent)
|
|
{
|
|
drawLine(QVector3D(a.x(), a.y(), a.z()), QVector3D(b.x(), a.y(), a.z()), material, parent);
|
|
drawLine(QVector3D(a.x(), a.y(), a.z()), QVector3D(a.x(), b.y(), a.z()), material, parent);
|
|
drawLine(QVector3D(a.x(), a.y(), a.z()), QVector3D(a.x(), a.y(), b.z()), material, parent);
|
|
drawLine(QVector3D(b.x(), a.y(), a.z()), QVector3D(b.x(), b.y(), a.z()), material, parent);
|
|
drawLine(QVector3D(b.x(), a.y(), a.z()), QVector3D(b.x(), a.y(), b.z()), material, parent);
|
|
drawLine(QVector3D(a.x(), b.y(), a.z()), QVector3D(b.x(), b.y(), a.z()), material, parent);
|
|
drawLine(QVector3D(a.x(), b.y(), a.z()), QVector3D(a.x(), b.y(), b.z()), material, parent);
|
|
drawLine(QVector3D(a.x(), a.y(), b.z()), QVector3D(b.x(), a.y(), b.z()), material, parent);
|
|
drawLine(QVector3D(a.x(), a.y(), b.z()), QVector3D(a.x(), b.y(), b.z()), material, parent);
|
|
drawLine(QVector3D(b.x(), b.y(), a.z()), QVector3D(b.x(), b.y(), b.z()), material, parent);
|
|
drawLine(QVector3D(a.x(), b.y(), b.z()), QVector3D(b.x(), b.y(), b.z()), material, parent);
|
|
drawLine(QVector3D(b.x(), a.y(), b.z()), QVector3D(b.x(), b.y(), b.z()), material, parent);
|
|
}
|
|
|
|
QByteArray BackPlotWidget::removeComments(const QByteArray& program)
|
|
{
|
|
int commentCounter = 0;
|
|
QByteArray out;
|
|
for(char ch : program)
|
|
{
|
|
if(ch == '/')
|
|
++commentCounter;
|
|
else if(ch == '\\' && commentCounter > 0)
|
|
--commentCounter;
|
|
else if(commentCounter == 0)
|
|
out.push_back(ch);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
QList<int> BackPlotWidget::getFields(QByteArray command)
|
|
{
|
|
command.remove(0, 2);
|
|
QList<QByteArray> fieldsText = command.split(',');
|
|
QList<int> fields;
|
|
for(const QByteArray& field : fieldsText)
|
|
{
|
|
if(field.size() == 0)
|
|
fields.push_back(NO_FIELD);
|
|
else
|
|
fields.push_back(field.toInt());
|
|
}
|
|
return fields;
|
|
}
|
|
|
|
void BackPlotWidget::programChanged(QByteArray program)
|
|
{
|
|
for(Qt3DCore::QEntity* entitiy : pathEntitys)
|
|
delete entitiy;
|
|
pathEntitys.clear();
|
|
|
|
program = removeComments(program);
|
|
QList<QByteArray> commands = program.split(';');
|
|
|
|
QVector3D lastPos = touchoffPosition;
|
|
|
|
qDebug()<<__func__;
|
|
|
|
for(QByteArray& command : commands)
|
|
{
|
|
command = command.trimmed().toUpper();
|
|
if(command.size() < 2)
|
|
continue;
|
|
if(command[0] == 'P' || command[0] == 'G')
|
|
{
|
|
QList<int> fields = getFields(command);
|
|
QVector3D pos;
|
|
|
|
if(fields.size() <= 2 || fields[2] == NO_FIELD)
|
|
pos.setZ(command[1] != 'R' ? lastPos.z()-touchoffPosition.z() : 0);
|
|
else if(fields.size() > 2)
|
|
pos.setZ(fields[2]/1000.0);
|
|
|
|
if(fields.size() <= 1 || fields[1] == NO_FIELD)
|
|
pos.setY(command[1] != 'R' ? lastPos.y()-touchoffPosition.y() : 0);
|
|
else if(fields.size() > 1)
|
|
pos.setY(fields[1]/1000.0);
|
|
|
|
if(fields.size() <= 0 || fields[0] == NO_FIELD)
|
|
pos.setX(command[1] != 'R' ? lastPos.x()-touchoffPosition.x() : 0);
|
|
else if(fields.size() > 0)
|
|
pos.setX(fields[0]/1000.0);
|
|
|
|
if(command[1] == 'A')
|
|
pos = pos+touchoffPosition;
|
|
else if(command[1] == 'R')
|
|
pos = pos+lastPos;
|
|
|
|
pathEntitys.push_back(new Qt3DCore::QEntity(rootEntity));
|
|
drawLine(limits-lastPos, limits-pos, command[0] == 'G' ? rapidMaterial : pathMaterial, pathEntitys.back());
|
|
|
|
lastPos = pos;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BackPlotWidget::touchoffUpdate(std::vector<int> position)
|
|
{
|
|
assert(position.size() >= 3);
|
|
touchoffPosition.setX(position[0]/1000.0);
|
|
touchoffPosition.setY(position[1]/1000.0);
|
|
touchoffPosition.setZ(position[2]/1000.0);
|
|
touchoffTransform->setTranslation(limits-touchoffPosition);
|
|
}
|
|
|
|
void BackPlotWidget::drawLine(const QVector3D& start, const QVector3D& end, Qt3DRender::QMaterial* material, Qt3DCore::QEntity* parent)
|
|
{
|
|
Qt3DCore::QGeometry* geometry = new Qt3DCore::QGeometry(parent);
|
|
|
|
// position vertices (start and end)
|
|
QByteArray bufferBytes;
|
|
bufferBytes.resize(3 * 2 * sizeof(float)); // start.x, start.y, start.end, end.x, end.y, end.z
|
|
float* positions = reinterpret_cast<float*>(bufferBytes.data());
|
|
*positions++ = start.x();
|
|
*positions++ = start.y();
|
|
*positions++ = start.z();
|
|
*positions++ = end.x();
|
|
*positions++ = end.y();
|
|
*positions++ = end.z();
|
|
|
|
Qt3DCore::QBuffer* buf = new Qt3DCore::QBuffer(geometry);
|
|
buf->setData(bufferBytes);
|
|
|
|
auto *positionAttribute = new Qt3DCore::QAttribute(geometry);
|
|
positionAttribute->setName(Qt3DCore::QAttribute::defaultPositionAttributeName());
|
|
positionAttribute->setVertexBaseType(Qt3DCore::QAttribute::Float);
|
|
positionAttribute->setVertexSize(3);
|
|
positionAttribute->setAttributeType(Qt3DCore::QAttribute::VertexAttribute);
|
|
positionAttribute->setBuffer(buf);
|
|
positionAttribute->setByteStride(3 * sizeof(float));
|
|
positionAttribute->setCount(2);
|
|
geometry->addAttribute(positionAttribute); // We add the vertices in the geometry
|
|
|
|
// connectivity between vertices
|
|
QByteArray indexBytes;
|
|
indexBytes.resize(2 * sizeof(unsigned int)); // start to end
|
|
unsigned int *indices = reinterpret_cast<unsigned int*>(indexBytes.data());
|
|
*indices++ = 0;
|
|
*indices++ = 1;
|
|
|
|
Qt3DCore::QBuffer* indexBuffer = new Qt3DCore::QBuffer(geometry);
|
|
indexBuffer->setData(indexBytes);
|
|
|
|
Qt3DCore::QAttribute *indexAttribute = new Qt3DCore::QAttribute(geometry);
|
|
indexAttribute->setVertexBaseType(Qt3DCore::QAttribute::UnsignedInt);
|
|
indexAttribute->setAttributeType(Qt3DCore::QAttribute::IndexAttribute);
|
|
indexAttribute->setBuffer(indexBuffer);
|
|
indexAttribute->setCount(2);
|
|
geometry->addAttribute(indexAttribute); // We add the indices linking the points in the geometry
|
|
|
|
// mesh
|
|
auto *line = new Qt3DRender::QGeometryRenderer(parent);
|
|
line->setGeometry(geometry);
|
|
line->setPrimitiveType(Qt3DRender::QGeometryRenderer::Lines);
|
|
|
|
// entity
|
|
auto *lineEntity = new Qt3DCore::QEntity(parent);
|
|
lineEntity->addComponent(line);
|
|
lineEntity->addComponent(material);
|
|
}
|