CAM: show new cam simulator in main window

This commit is contained in:
jffmichi
2025-06-03 21:49:43 +02:00
parent 61de0ffa8f
commit 184c977677
19 changed files with 514 additions and 256 deletions

View File

@@ -69,9 +69,6 @@ public:
);
void SetBaseShape(const Part::TopoShape& baseShape, float resolution);
void AddCommand(Command* cmd);
public:
std::unique_ptr<SimStock> m_stock;
};
} // namespace CAMSimulator

View File

@@ -24,6 +24,8 @@ SET(CAMSimulator_SRCS_Module
DlgCAMSimulator.cpp
DlgCAMSimulator.h
PreCompiled.h
ViewCAMSimulator.cpp
ViewCAMSimulator.h
)
SET(CAMSimulator_SRCS_Core

View File

@@ -24,13 +24,19 @@
#include "DlgCAMSimulator.h"
#include "ViewCAMSimulator.h"
#include "MillSimulation.h"
#include "Gui/View3DInventorViewer.h"
#include <Mod/Part/App/BRepMesh.h>
#include <QDateTime>
#include <QSurfaceFormat>
#include <QPoint>
#include <QTimerEvent>
#include <App/Document.h>
#include <Gui/MainWindow.h>
#include <Gui/MDIView.h>
#include <QHBoxLayout>
#include <QPointer>
using namespace MillSim;
@@ -39,9 +45,17 @@ namespace CAMSimulator
static const float MouseScrollDelta = 120.0F;
DlgCAMSimulator::DlgCAMSimulator(QWidget* parent)
static QPointer<ViewCAMSimulator> viewCAMSimulator;
DlgCAMSimulator::DlgCAMSimulator(ViewCAMSimulator& view, QWidget* parent)
: QOpenGLWidget(parent)
, mView(view)
{
// Under certain conditions, e.g. when docking/undocking the cam simulator, we need to create a
// new widget (due to some OpenGL bug). The new widget becomes THE cam simulator.
viewCAMSimulator = &view;
QSurfaceFormat format;
format.setVersion(4, 1); // Request OpenGL 4.1 - for MacOS
format.setProfile(QSurfaceFormat::CoreProfile); // Use the core profile = for MacOS
@@ -56,48 +70,85 @@ DlgCAMSimulator::DlgCAMSimulator(QWidget* parent)
setMouseTracking(true);
mMillSimulator.reset(new MillSimulation());
mMillSimulator.reset(new MillSimulation);
mAnimatingTimer.setInterval(0);
connect(
&mAnimatingTimer,
&QTimer::timeout,
this,
static_cast<void (DlgCAMSimulator::*)()>(&DlgCAMSimulator::update)
);
}
DlgCAMSimulator::~DlgCAMSimulator()
{
// nothing to do but need to keep this destructor because of forward declared MillSimulation
makeCurrent();
mMillSimulator = nullptr;
}
void DlgCAMSimulator::cloneFrom(const DlgCAMSimulator& from)
{
mNeedsInitialize = true;
mNeedsClear = true;
setAnimating(from.mAnimating);
mQuality = from.mQuality;
mGCode = from.mGCode;
mTools = from.mTools;
mStock = from.mStock;
mStock.needsUpdate = true;
mBase = from.mBase;
mBase.needsUpdate = true;
const auto state = from.mMillSimulator->GetState();
mState = std::make_unique<MillSim::MillSimulationState>(state);
}
DlgCAMSimulator* DlgCAMSimulator::instance()
{
if (mInstance == nullptr) {
mInstance = new DlgCAMSimulator();
mInstance->resize(MillSim::gWindowSizeW, MillSim::gWindowSizeH);
mInstance->setWindowModality(Qt::ApplicationModal);
mInstance->setMinimumWidth(700);
mInstance->setMinimumHeight(400);
if (!viewCAMSimulator) {
auto view = new ViewCAMSimulator(nullptr, nullptr);
viewCAMSimulator = view;
Gui::getMainWindow()->addWindow(view);
}
return mInstance;
return &viewCAMSimulator->dlg();
}
void DlgCAMSimulator::setAnimating(bool animating)
{
if (animating == mAnimating) {
return;
}
mAnimating = animating;
if (mAnimating) {
update();
if (animating) {
mAnimatingTimer.start();
}
else {
mAnimatingTimer.stop();
}
}
void DlgCAMSimulator::startSimulation(const Part::TopoShape& stock, float quality)
{
App::Document* doc = App::GetApplication().getActiveDocument();
setWindowTitle(tr("%1 - New CAM Simulator").arg(QString::fromUtf8(doc->getName())));
mView.setWindowTitle(tr("%1 - New CAM Simulator").arg(QString::fromUtf8(doc->getName())));
mQuality = quality;
mNeedsInitialize = true;
setStockShape(stock, 1);
show();
setAnimating(true);
Gui::getMainWindow()->setActiveWindow(&mView);
mView.show();
}
void DlgCAMSimulator::resetSimulation()
@@ -201,7 +252,7 @@ void DlgCAMSimulator::mouseMoveEvent(QMouseEvent* ev)
QPoint pnt = ev->position().toPoint();
#endif
const qreal ratio = devicePixelRatio();
const qreal ratio = devicePixelRatioF();
mMillSimulator->MouseMove(pnt.x() * ratio, pnt.y() * ratio, modifiers);
update();
@@ -215,7 +266,7 @@ void DlgCAMSimulator::mousePressEvent(QMouseEvent* ev)
QPoint pnt = ev->position().toPoint();
#endif
const qreal ratio = devicePixelRatio();
const qreal ratio = devicePixelRatioF();
mMillSimulator->MousePress(ev->button(), true, pnt.x() * ratio, pnt.y() * ratio);
update();
@@ -229,7 +280,7 @@ void DlgCAMSimulator::mouseReleaseEvent(QMouseEvent* ev)
QPoint pnt = ev->position().toPoint();
#endif
const qreal ratio = devicePixelRatio();
const qreal ratio = devicePixelRatioF();
mMillSimulator->MousePress(ev->button(), false, pnt.x() * ratio, pnt.y() * ratio);
update();
@@ -248,16 +299,18 @@ void DlgCAMSimulator::updateResources()
if (mNeedsClear) {
mMillSimulator->Clear();
mLastGCode = 0;
mNeedsClear = false;
}
// update gcode
for (const auto& cmd : mGCode) {
for (int i = mLastGCode; i < (int)mGCode.size(); i++) {
const std::string& cmd = mGCode[i];
mMillSimulator->AddGcodeLine(cmd.c_str());
}
mGCode.clear();
mLastGCode = mGCode.size();
// update tools
@@ -267,8 +320,6 @@ void DlgCAMSimulator::updateResources()
}
}
mTools.clear();
// initialize simulator
if (mNeedsInitialize) {
@@ -280,13 +331,26 @@ void DlgCAMSimulator::updateResources()
if (mStock.needsUpdate) {
mMillSimulator->SetArbitraryStock(mStock.verts, mStock.indices);
mStock = {};
mStock.needsUpdate = false;
}
if (mBase.needsUpdate) {
mMillSimulator->SetBaseObject(mBase.verts, mBase.indices);
mBase = {};
mBase.needsUpdate = false;
}
// update state
if (mState) {
mMillSimulator->SetState(*mState);
mState = nullptr;
}
}
void DlgCAMSimulator::updateWindowScale()
{
const qreal ratio = devicePixelRatioF();
mMillSimulator->UpdateWindowScale(width() * ratio, height() * ratio);
}
void DlgCAMSimulator::initializeGL()
@@ -297,34 +361,17 @@ void DlgCAMSimulator::initializeGL()
void DlgCAMSimulator::paintGL()
{
updateResources();
mMillSimulator->ProcessSim((unsigned int)(QDateTime::currentMSecsSinceEpoch()));
if (mAnimating) {
update();
}
// We need to call updateWindowScale on every render since the devicePixelRatio we get in
// resizeGL might be wrong on the first resize.
updateWindowScale();
mMillSimulator->ProcessSim((unsigned int)(QDateTime::currentMSecsSinceEpoch()));
}
void DlgCAMSimulator::resizeGL(int w, int h)
{
const qreal ratio = devicePixelRatio();
mMillSimulator->UpdateWindowScale(w * ratio, h * ratio);
}
DlgCAMSimulator* DlgCAMSimulator::mInstance = nullptr;
//************************************************************************************************************
// stock
//************************************************************************************************************
SimStock::SimStock(float px, float py, float pz, float lx, float ly, float lz, float res)
: mPx(px)
, mPy(py)
, mPz(pz + 0.005 * lz)
, mLx(lx)
, mLy(ly)
, mLz(1.01 * lz)
{
(void)res;
(void)w, (void)h;
}
} // namespace CAMSimulator

View File

@@ -36,6 +36,7 @@
#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QPainter>
#include <QTimer>
#include <QExposeEvent>
#include <QResizeEvent>
#include <QMouseEvent>
@@ -45,21 +46,19 @@ namespace MillSim
{
// use short declaration as using 'include' causes a header loop
class MillSimulation;
class MillSimulationState;
struct Vertex;
} // namespace MillSim
namespace Gui
{
class MDIView;
}
namespace CAMSimulator
{
struct SimStock
{
public:
SimStock(float px, float py, float pz, float lx, float ly, float lz, float res);
public:
float mPx, mPy, mPz; // stock zero position
float mLx, mLy, mLz; // stock dimensions
};
class ViewCAMSimulator;
struct SimShape
{
@@ -83,9 +82,11 @@ class DlgCAMSimulator: public QOpenGLWidget, public QOpenGLExtraFunctions
Q_OBJECT
public:
explicit DlgCAMSimulator(QWidget* parent = nullptr);
explicit DlgCAMSimulator(ViewCAMSimulator& view, QWidget* parent = nullptr);
~DlgCAMSimulator() override;
void cloneFrom(const DlgCAMSimulator& from);
static DlgCAMSimulator* instance();
void setAnimating(bool animating);
@@ -110,24 +111,32 @@ protected:
void wheelEvent(QWheelEvent* ev) override;
void updateResources();
void updateWindowScale();
void initializeGL() override;
void paintGL() override;
void resizeGL(int w, int h) override;
private:
bool mAnimating = false;
bool mNeedsInitialize = false;
bool mNeedsClear = false;
bool mAnimating = false;
QTimer mAnimatingTimer;
std::unique_ptr<MillSim::MillSimulation> mMillSimulator;
static DlgCAMSimulator* mInstance;
float mQuality = 10;
std::vector<std::string> mGCode;
std::size_t mLastGCode = 0;
std::vector<SimTool> mTools;
SimShape mStock;
SimShape mBase;
ViewCAMSimulator& mView;
std::unique_ptr<MillSim::MillSimulationState> mState;
};
} // namespace CAMSimulator

View File

@@ -27,12 +27,8 @@
namespace MillSim
{
int gWindowSizeW = 800;
int gWindowSizeH = 600;
int gDebug = -1;
mat4x4 identityMat = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}};
const mat4x4 identityMat = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}};
void GLClearError()
{
@@ -50,11 +46,4 @@ bool GLLogError()
return isError;
}
typedef struct Vertex
{
vec3 pos;
vec3 col;
} Vertex;
} // namespace MillSim

View File

@@ -24,10 +24,10 @@
#ifndef __glutils_h__
#define __glutils_h__
#include "OpenGlWrapper.h"
#include "linmath.h"
constexpr auto EPSILON = 0.00001f;
#define EQ_FLOAT(x, y) (fabs((x) - (y)) < EPSILON)
@@ -46,7 +46,6 @@ constexpr auto EPSILON = 0.00001f;
__debugbreak(); \
}
#define GLDELETE(type, x) \
{ \
if (x != 0) \
@@ -62,11 +61,12 @@ constexpr auto EPSILON = 0.00001f;
namespace MillSim
{
extern const mat4x4 identityMat;
void GLClearError();
bool GLLogError();
extern mat4x4 identityMat;
extern int gDebug;
extern int gWindowSizeW;
extern int gWindowSizeH;
} // namespace MillSim
#endif // !__glutils_h__

View File

@@ -30,12 +30,11 @@
#include <QPoint>
#include <QCoreApplication>
using namespace MillSim;
// clang-format off
// NOLINTBEGIN(*-magic-numbers)
GuiItem guiItems[] = {
static const std::vector<DefaultGuiItem> defaultGuiItems = {
{.name=eGuiItemSlider, .vbo=0, .vao=0, .sx=28, .sy=-80, .actionKey=0, .hidden=false, .flags=0},
{.name=eGuiItemThumb, .vbo=0, .vao=0, .sx=328, .sy=-94, .actionKey=1, .hidden=false, .flags=0},
{.name=eGuiItemPause, .vbo=0, .vao=0, .sx=28, .sy=-50, .actionKey='P', .hidden=true, .flags=0},
@@ -58,10 +57,9 @@ GuiItem guiItems[] = {
// NOLINTEND(*-magic-numbers)
// clang-format on
#define NUM_GUI_ITEMS (sizeof(guiItems) / sizeof(GuiItem))
#define TEX_SIZE 256
std::vector<std::string> guiFileNames = {
static const std::vector<std::string> guiFileNames = {
"Slider.png",
"Thumb.png",
"Pause.png",
@@ -82,17 +80,49 @@ std::vector<std::string> guiFileNames = {
"Home.png"
};
GuiItem::GuiItem(const DefaultGuiItem& item, GuiDisplay& d)
: DefaultGuiItem(item)
, display(d)
{}
int GuiItem::posx()
{
return sx >= 0 ? sx : display.width() + sx;
}
int GuiItem::posy()
{
return sy >= 0 ? sy : display.height() + sy;
}
void GuiItem::setPosx(int x)
{
sx = sx >= 0 ? x : x - display.width();
}
void GuiItem::setPosy(int y)
{
sy = sy >= 0 ? y : y - display.height();
}
GuiDisplay::GuiDisplay()
{
for (auto& item : defaultGuiItems) {
mItems.emplace_back(item, *this);
}
}
void GuiDisplay::UpdateProjection()
{
mat4x4 projmat;
// mat4x4 viewmat;
mat4x4_ortho(projmat, 0, gWindowSizeW, gWindowSizeH, 0, -1, 1);
mat4x4_ortho(projmat, 0, mWidth, mHeight, 0, -1, 1);
mShader.Activate();
mShader.UpdateProjectionMat(projmat);
mThumbMaxMotion = guiItems[eGuiItemAmbientOclusion].posx()
+ guiItems[eGuiItemAmbientOclusion].texItem.w
- guiItems[eGuiItemSlider].posx(); // - guiItems[eGuiItemThumb].texItem.w;
HStretchGlItem(&(guiItems[eGuiItemSlider]), mThumbMaxMotion, 10.0f);
mThumbMaxMotion = mItems[eGuiItemAmbientOclusion].posx()
+ mItems[eGuiItemAmbientOclusion].texItem.w
- mItems[eGuiItemSlider].posx(); // - guiItems[eGuiItemThumb].texItem.w;
HStretchGlItem(&(mItems[eGuiItemSlider]), mThumbMaxMotion, 10.0f);
}
bool GuiDisplay::GenerateGlItem(GuiItem* guiItem)
@@ -127,7 +157,7 @@ bool GuiDisplay::GenerateGlItem(GuiItem* guiItem)
return true;
}
bool MillSim::GuiDisplay::HStretchGlItem(GuiItem* guiItem, float newWidth, float edgeWidth)
bool GuiDisplay::HStretchGlItem(GuiItem* guiItem, float newWidth, float edgeWidth)
{
if (guiItem->vbo == 0) {
return false;
@@ -190,6 +220,7 @@ bool GuiDisplay::InitGui()
if (guiInitiated) {
return true;
}
// index buffer
SetupTooltips();
glGenBuffers(1, &mIbo);
@@ -202,29 +233,32 @@ bool GuiDisplay::InitGui()
return false;
}
mTexture.LoadImage(buffer, TEX_SIZE, TEX_SIZE);
for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) {
guiItems[i].texItem = *tLoader.GetTextureItem(i);
GenerateGlItem(&(guiItems[i]));
for (unsigned int i = 0; i < mItems.size(); i++) {
auto& item = mItems[i];
item.texItem = *tLoader.GetTextureItem(i);
GenerateGlItem(&item);
}
mThumbStartX = guiItems[eGuiItemSlider].posx() - guiItems[eGuiItemThumb].texItem.w / 2;
mThumbMaxMotion = (float)guiItems[eGuiItemSlider].texItem.w;
mThumbStartX = mItems[eGuiItemSlider].posx() - mItems[eGuiItemThumb].texItem.w / 2;
mThumbMaxMotion = (float)mItems[eGuiItemSlider].texItem.w;
// init shader
mShader.CompileShader("GuiDisplay", (char*)VertShader2DTex, (char*)FragShader2dTex);
mShader.UpdateTextureSlot(0);
UpdatePlayState(false);
UpdateSimSpeed(1);
UpdateProjection();
guiInitiated = true;
UpdateWindowScale(800, 600);
return true;
}
void GuiDisplay::ResetGui()
{
mShader.Destroy();
for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) {
DestroyGlItem(&(guiItems[i]));
for (auto& item : mItems) {
DestroyGlItem(&item);
}
mTexture.DestroyTexture();
GLDELETE_BUFFER(mIbo);
@@ -233,13 +267,13 @@ void GuiDisplay::ResetGui()
void GuiDisplay::RenderItem(int itemId)
{
GuiItem* item = &(guiItems[itemId]);
GuiItem* item = &(mItems[itemId]);
if (item->hidden) {
return;
}
mat4x4 model;
mat4x4_translate(model, (float)item->posx(), (float)item->posy(), 0);
mShader.UpdateModelMat(model, nullptr);
mShader.UpdateModelMat(model, {});
if (item == mPressedItem) {
mShader.UpdateObjColor(mPressedColor);
}
@@ -262,33 +296,33 @@ void GuiDisplay::RenderItem(int itemId)
glDrawElements(GL_TRIANGLES, nTriangles, GL_UNSIGNED_SHORT, nullptr);
}
void MillSim::GuiDisplay::SetupTooltips()
void GuiDisplay::SetupTooltips()
{
guiItems[eGuiItemPause].toolTip
mItems[eGuiItemPause].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Pause simulation", nullptr);
guiItems[eGuiItemPlay].toolTip
mItems[eGuiItemPlay].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Play simulation", nullptr);
guiItems[eGuiItemSingleStep].toolTip
mItems[eGuiItemSingleStep].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Single step simulation", nullptr);
guiItems[eGuiItemSlower].toolTip
mItems[eGuiItemSlower].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Decrease simulation speed", nullptr);
guiItems[eGuiItemFaster].toolTip
mItems[eGuiItemFaster].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Increase simulation speed", nullptr);
guiItems[eGuiItemPath].toolTip
mItems[eGuiItemPath].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Show/Hide tool path", nullptr);
guiItems[eGuiItemRotate].toolTip = QCoreApplication::translate(
mItems[eGuiItemRotate].toolTip = QCoreApplication::translate(
"CAM:Simulator:Tooltips",
"Toggle turn table animation",
nullptr
);
guiItems[eGuiItemAmbientOclusion].toolTip
mItems[eGuiItemAmbientOclusion].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Toggle ambient occlusion", nullptr);
guiItems[eGuiItemView].toolTip = QCoreApplication::translate(
mItems[eGuiItemView].toolTip = QCoreApplication::translate(
"CAM:Simulator:Tooltips",
"Toggle view simulation/model",
nullptr
);
guiItems[eGuiItemHome].toolTip
mItems[eGuiItemHome].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Reset camera", nullptr);
}
@@ -296,24 +330,25 @@ void GuiDisplay::MouseCursorPos(int x, int y)
{
GuiItem* prevMouseOver = mMouseOverItem;
mMouseOverItem = nullptr;
for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) {
GuiItem* g = &(guiItems[i]);
if (g->actionKey == 0) {
for (auto& item : mItems) {
if (item.actionKey == 0) {
continue;
}
bool mouseCursorContained = x > g->posx() && x < (g->posx() + g->texItem.w) && y > g->posy()
&& y < (g->posy() + g->texItem.h);
bool mouseCursorContained = x > item.posx() && x < (item.posx() + item.texItem.w)
&& y > item.posy() && y < (item.posy() + item.texItem.h);
g->mouseOver = !g->hidden && mouseCursorContained;
item.mouseOver = !item.hidden && mouseCursorContained;
if (g->mouseOver) {
mMouseOverItem = g;
if (item.mouseOver) {
mMouseOverItem = &item;
}
}
if (mMouseOverItem != prevMouseOver) {
if (mMouseOverItem != nullptr && !mMouseOverItem->toolTip.isEmpty()) {
QPoint pos(x, y);
QPoint globPos = CAMSimulator::DlgCAMSimulator::instance()->mapToGlobal(pos);
const QWidget* w = CAMSimulator::DlgCAMSimulator::instance();
const float ratio = w->devicePixelRatioF();
const QPoint pos(x / ratio, y / ratio);
const QPoint globPos = w->mapToGlobal(pos);
QToolTip::showText(globPos, mMouseOverItem->toolTip);
}
else {
@@ -322,7 +357,7 @@ void GuiDisplay::MouseCursorPos(int x, int y)
}
}
void MillSim::GuiDisplay::HandleActionItem(GuiItem* guiItem)
void GuiDisplay::HandleActionItem(GuiItem* guiItem)
{
if (guiItem->actionKey >= ' ') {
if (guiItem->flags & GUIITEM_CHECKABLE) {
@@ -373,45 +408,66 @@ void GuiDisplay::MouseDrag(int /* buttons */, int dx, int /* dy */)
}
}
void GuiDisplay::SetMillSimulator(MillSimulation* millSim)
{
mMillSim = millSim;
}
void GuiDisplay::UpdatePlayState(bool isRunning)
{
guiItems[eGuiItemPause].hidden = !isRunning;
guiItems[eGuiItemPlay].hidden = isRunning;
mItems[eGuiItemPause].hidden = !isRunning;
mItems[eGuiItemPlay].hidden = isRunning;
}
void MillSim::GuiDisplay::UpdateSimSpeed(int speed)
void GuiDisplay::UpdateSimSpeed(int speed)
{
guiItems[eGuiItem1].hidden = speed != 1;
guiItems[eGuiItem5].hidden = speed != 5;
guiItems[eGuiItem10].hidden = speed != 10;
guiItems[eGuiItem25].hidden = speed != 25;
guiItems[eGuiItem50].hidden = speed != 50;
mItems[eGuiItem1].hidden = speed != 1;
mItems[eGuiItem5].hidden = speed != 5;
mItems[eGuiItem10].hidden = speed != 10;
mItems[eGuiItem25].hidden = speed != 25;
mItems[eGuiItem50].hidden = speed != 50;
}
void MillSim::GuiDisplay::HandleKeyPress(int key)
void GuiDisplay::HandleKeyPress(int key)
{
for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) {
GuiItem* g = &(guiItems[i]);
if (g->actionKey == key) {
HandleActionItem(g);
for (auto& item : mItems) {
if (item.actionKey == key) {
HandleActionItem(&item);
}
}
}
bool MillSim::GuiDisplay::IsChecked(eGuiItems item)
bool GuiDisplay::IsChecked(eGuiItems item)
{
return (guiItems[item].flags & GUIITEM_CHECKED) != 0;
return (mItems[item].flags & GUIITEM_CHECKED) != 0;
}
void MillSim::GuiDisplay::UpdateWindowScale()
void GuiDisplay::UpdateWindowScale(int width, int height)
{
if (!guiInitiated || (width == mWidth && height == mHeight)) {
return;
}
mWidth = width;
mHeight = height;
UpdateProjection();
}
int GuiDisplay::width() const
{
return mWidth;
}
int GuiDisplay::height() const
{
return mHeight;
}
void GuiDisplay::Render(float progress)
{
if (mPressedItem == nullptr || mPressedItem->name != eGuiItemThumb) {
guiItems[eGuiItemThumb].setPosx((int)(mThumbMaxMotion * progress) + mThumbStartX);
mItems[eGuiItemThumb].setPosx((int)(mThumbMaxMotion * progress) + mThumbStartX);
}
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
@@ -421,7 +477,7 @@ void GuiDisplay::Render(float progress)
mShader.UpdateTextureSlot(0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for (int i = 0; i < (int)NUM_GUI_ITEMS; i++) {
for (int i = 0; i < (int)mItems.size(); i++) {
RenderItem(i);
}
}

View File

@@ -58,7 +58,7 @@ enum eGuiItems
eGuiItemMax // this element must be the last item always
};
struct GuiItem
struct DefaultGuiItem
{
eGuiItems name;
unsigned int vbo, vao;
@@ -66,33 +66,32 @@ struct GuiItem
int actionKey; // action key when item pressed
bool hidden {}; // is item hidden
unsigned int flags {};
};
class GuiDisplay;
class GuiItem: public DefaultGuiItem
{
public:
explicit GuiItem(const DefaultGuiItem& item, GuiDisplay& d);
int posx();
int posy();
void setPosx(int x);
void setPosy(int y);
public:
bool mouseOver {};
TextureItem texItem {};
QString toolTip {};
int posx()
{
return sx >= 0 ? sx : gWindowSizeW + sx;
}
int posy()
{
return sy >= 0 ? sy : gWindowSizeH + sy;
}
void setPosx(int x)
{
sx = sx >= 0 ? x : x - gWindowSizeW;
}
void setPosy(int y)
{
sy = sy >= 0 ? y : y - gWindowSizeH;
}
GuiDisplay& display;
};
#define GUIITEM_CHECKABLE 0x01
#define GUIITEM_CHECKED 0x02
#define GUIITEM_STRETCHED 0x04
struct Vertex2D
{
float x, y;
@@ -102,7 +101,8 @@ struct Vertex2D
class GuiDisplay
{
public:
// GuiDisplay() {};
GuiDisplay();
bool InitGui();
void ResetGui();
void Render(float progress);
@@ -110,15 +110,15 @@ public:
void HandleActionItem(GuiItem* guiItem);
void MousePressed(int button, bool isPressed, bool isRunning);
void MouseDrag(int buttons, int dx, int dy);
void SetMillSimulator(MillSimulation* millSim)
{
mMillSim = millSim;
}
void SetMillSimulator(MillSimulation* millSim);
void UpdatePlayState(bool isRunning);
void UpdateSimSpeed(int speed);
void HandleKeyPress(int key);
bool IsChecked(eGuiItems item);
void UpdateWindowScale();
void UpdateWindowScale(int width, int height);
int width() const;
int height() const;
public:
bool guiInitiated = false;
@@ -131,6 +131,11 @@ private:
void RenderItem(int itemId);
void SetupTooltips();
std::vector<GuiItem> mItems;
int mWidth = -1;
int mHeight = -1;
vec3 mStdColor = {0.8f, 0.8f, 0.4f};
vec3 mToggleColor = {0.9f, 0.6f, 0.2f};
vec3 mHighlightColor = {1.0f, 1.0f, 0.9f};

View File

@@ -55,8 +55,8 @@ struct MillMotion
float x, y, z;
float i, j, k;
float r;
char retract_mode;
float retract_z;
char retract_mode = 0;
float retract_z = NAN;
};
static inline void MotionPosToVec(vec3 vec, const MillMotion* motion)

View File

@@ -93,7 +93,7 @@ void MillSimulation::InitSimulation(float quality)
{
ClearMillPathSegments();
millPathLine.Clear();
simDisplay.applySSAO = guiDisplay.IsChecked(eGuiItemAmbientOclusion);
mViewSSAO = guiDisplay.IsChecked(eGuiItemAmbientOclusion);
mDestMotion = mZeroPos;
// gDestPos = curMillOperation->startPos;
@@ -163,6 +163,11 @@ void MillSimulation::AddTool(const std::vector<float>& toolProfile, int toolid,
mToolTable.push_back(tool);
}
bool MillSimulation::ToolExists(int toolid)
{
return GetTool(toolid) != nullptr;
}
void MillSimulation::GlsimStart()
{
glDisable(GL_BLEND);
@@ -340,7 +345,7 @@ void MillSimulation::RenderTool()
void MillSimulation::RenderPath()
{
if (!guiDisplay.IsChecked(eGuiItemPath)) {
if (!mViewPath) {
return;
}
simDisplay.SetupLinePathPass(mPathStep, false);
@@ -378,10 +383,10 @@ void MillSimulation::Render()
RenderBaseShape();
RenderPath();
simDisplay.updateDisplay = false;
simDisplay.RenderResult(true);
simDisplay.RenderResult(true, mViewSSAO);
}
else {
simDisplay.RenderResult(false);
simDisplay.RenderResult(false, mViewSSAO);
}
/* if (mDebug > 0) {
@@ -446,7 +451,6 @@ void MillSimulation::HandleKeyPress(int key)
}
else if (key == 'K') {
mDebug2++;
gDebug = mNPathSteps - mDebug2;
}
else {
guiDisplay.HandleKeyPress(key);
@@ -502,11 +506,12 @@ void MillSimulation::HandleGuiAction(eGuiItems actionItem, bool checked)
break;
case eGuiItemPath:
mViewPath = checked;
simDisplay.updateDisplay = true;
break;
case eGuiItemAmbientOclusion:
simDisplay.applySSAO = checked;
mViewSSAO = checked;
simDisplay.updateDisplay = true;
break;
@@ -536,6 +541,10 @@ void MillSimulation::InitDisplay(float quality)
mToolTable[i]->GenerateDisplayLists(quality);
}
// Make sure the next call to UpdateWindowScale will not return early.
mWidth = -1;
mHeight = -1;
// init 3d display
simDisplay.InitGL();
@@ -642,13 +651,16 @@ void MillSimulation::Zoom(float factor)
void MillSimulation::UpdateWindowScale(int width, int height)
{
if (width == gWindowSizeW && height == gWindowSizeH) {
if (width == mWidth && height == mHeight) {
return;
}
gWindowSizeW = width;
gWindowSizeH = height;
simDisplay.UpdateWindowScale();
guiDisplay.UpdateWindowScale();
mWidth = width;
mHeight = height;
simDisplay.UpdateWindowScale(width, height);
guiDisplay.UpdateWindowScale(width, height);
simDisplay.updateDisplay = true;
}
@@ -679,4 +691,26 @@ void MillSimulation::SetSimulationStage(float stage)
CalcSegmentPositions();
}
void MillSimulation::SetState(const MillSimulationState& state)
{
mSimPlaying = state.mSimPlaying;
mSingleStep = state.mSingleStep;
guiDisplay.UpdatePlayState(mSimPlaying);
const float stage = (float)state.mCurStep / state.mNTotalSteps;
SetSimulationStage(stage);
mSimSpeed = state.mSimSpeed;
guiDisplay.UpdateSimSpeed(mSimSpeed);
mViewItems = state.mViewItems;
mViewPath = state.mViewPath;
mViewSSAO = state.mViewSSAO;
}
const MillSimulationState& MillSimulation::GetState() const
{
return *this;
}
} // namespace MillSim

View File

@@ -46,7 +46,23 @@
namespace MillSim
{
class MillSimulation
struct MillSimulationState
{
int mCurStep = 0;
int mNTotalSteps = 0;
int mPathStep = -1;
int mSubStep = 0;
int mNPathSteps = 0;
int mSimSpeed = 1;
int mViewItems = VIEWITEM_SIMULATION;
bool mViewPath = false;
bool mViewSSAO = false;
bool mSimPlaying = false;
bool mSingleStep = false;
};
class MillSimulation: private MillSimulationState
{
public:
MillSimulation();
@@ -57,10 +73,7 @@ public:
void InitSimulation(float quality);
void AddTool(EndMill* tool);
void AddTool(const std::vector<float>& toolProfile, int toolid, float diameter);
bool ToolExists(int toolid)
{
return GetTool(toolid) != nullptr;
}
bool ToolExists(int toolid);
void RenderSimulation();
void RenderTool();
void RenderPath();
@@ -72,6 +85,8 @@ public:
bool LoadGCodeFile(const char* fileName);
bool AddGcodeLine(const char* line);
void SetSimulationStage(float stage);
void SetState(const MillSimulationState& state);
const MillSimulationState& GetState() const;
void SetBoxStock(float x, float y, float z, float l, float w, float h);
void SetArbitraryStock(const std::vector<Vertex>& verts, const std::vector<GLushort>& indices);
void SetBaseObject(const std::vector<Vertex>& verts, const std::vector<GLushort>& indices);
@@ -83,7 +98,6 @@ public:
void Zoom(float factor);
void UpdateWindowScale(int width, int height);
protected:
void InitDisplay(float quality);
void GlsimStart();
@@ -99,7 +113,6 @@ protected:
EndMill* GetTool(int tool);
void RemoveTool(int toolId);
protected:
std::vector<EndMill*> mToolTable;
GCodeParser mCodeParser;
@@ -115,6 +128,9 @@ protected:
MillMotion mDestMotion = {.cmd=eNop, .tool=-1, .x=0, .y=0, .z=0, .i=0, .j=0, .k=0, .r=0, .retract_mode='\0', .retract_z=0.0};
// clang-format on
int mWidth = -1;
int mHeight = -1;
StockObject mStockObject;
SolidObject mBaseShape;
@@ -124,24 +140,15 @@ protected:
vec3 toolColor = {0.5f, 0.4f, 0.3f};
vec3 baseShapeColor = {0.7f, 0.6f, 0.5f};
int mCurStep = 0;
int mNTotalSteps = 0;
int mPathStep = 0;
int mSubStep = 0;
int mNPathSteps = 0;
int mDebug = 0;
int mDebug1 = 0;
int mDebug2 = 12;
int mSimSpeed = 1;
int mViewItems = VIEWITEM_SIMULATION;
int mLastMouseX = 0, mLastMouseY = 0;
int mMouseButtonState = 0;
int mLastModifiers = 0;
bool mIsInStock = false;
bool mSimPlaying = false;
bool mSingleStep = false;
};
} // namespace MillSim
#endif

View File

@@ -45,31 +45,31 @@ Shader::~Shader()
Destroy();
}
void Shader::UpdateModelMat(mat4x4 tmat, mat4x4 nmat)
void Shader::UpdateModelMat(const mat4x4& tmat, const mat4x4& nmat)
{
if (mModelPos >= 0) {
glUniformMatrix4fv(mModelPos, 1, GL_FALSE, (GLfloat*)tmat);
glUniformMatrix4fv(mModelPos, 1, GL_FALSE, (const GLfloat*)tmat);
}
if (mNormalRotPos >= 0) {
glUniformMatrix4fv(mNormalRotPos, 1, GL_FALSE, (GLfloat*)nmat);
glUniformMatrix4fv(mNormalRotPos, 1, GL_FALSE, (const GLfloat*)nmat);
}
}
void Shader::UpdateProjectionMat(mat4x4 mat)
void Shader::UpdateProjectionMat(const mat4x4& mat)
{
if (mProjectionPos >= 0) {
glUniformMatrix4fv(mProjectionPos, 1, GL_FALSE, (GLfloat*)mat);
glUniformMatrix4fv(mProjectionPos, 1, GL_FALSE, (const GLfloat*)mat);
}
}
void Shader::UpdateViewMat(mat4x4 mat)
void Shader::UpdateViewMat(const mat4x4& mat)
{
if (mViewPos >= 0) {
glUniformMatrix4fv(mViewPos, 1, GL_FALSE, (GLfloat*)mat);
glUniformMatrix4fv(mViewPos, 1, GL_FALSE, (const GLfloat*)mat);
}
}
void Shader::UpdateEnvColor(vec3 lightPos, vec3 lightColor, vec3 ambient, float linearity)
void Shader::UpdateEnvColor(const vec3& lightPos, const vec3& lightColor, const vec3& ambient, float linearity)
{
if (mLightPosPos >= 0) {
glUniform3fv(mLightPosPos, 1, lightPos);
@@ -95,14 +95,14 @@ void Shader::UpdateScreenDimension(int width, int height)
}
}
void Shader::UpdateObjColor(vec3 objColor)
void Shader::UpdateObjColor(const vec3& objColor)
{
if (mObjectColorPos >= 0) {
glUniform3fv(mObjectColorPos, 1, objColor);
}
}
void Shader::UpdateObjColorAlpha(vec4 objColor)
void Shader::UpdateObjColorAlpha(const vec4& objColor)
{
if (mObjectColorAlphaPos >= 0) {
glUniform4fv(mObjectColorAlphaPos, 1, objColor);

View File

@@ -39,13 +39,13 @@ public:
public:
unsigned int shaderId = 0;
void UpdateModelMat(mat4x4 transformMat, mat4x4 normalMat);
void UpdateProjectionMat(mat4x4 mat);
void UpdateViewMat(mat4x4 mat);
void UpdateEnvColor(vec3 lightPos, vec3 lightColor, vec3 ambient, float linearity);
void UpdateModelMat(const mat4x4& transformMat, const mat4x4& normalMat);
void UpdateProjectionMat(const mat4x4& mat);
void UpdateViewMat(const mat4x4& mat);
void UpdateEnvColor(const vec3& lightPos, const vec3& lightColor, const vec3& ambient, float linearity);
void UpdateScreenDimension(int width, int height);
void UpdateObjColor(vec3 objColor);
void UpdateObjColorAlpha(vec4 objColor);
void UpdateObjColor(const vec3& objColor);
void UpdateObjColorAlpha(const vec4& objColor);
void UpdateNormalState(bool isInverted);
void UpdateSsaoActive(bool isInverted);
void UpdateTextureSlot(int slot);

View File

@@ -131,7 +131,6 @@ void SimDisplay::UniformCircle(vec3& randVec)
randVec[2] = 0;
}
void SimDisplay::CreateDisplayFbos()
{
// setup frame buffer for simulation
@@ -178,7 +177,6 @@ void SimDisplay::CreateDisplayFbos()
void SimDisplay::CreateSsaoFbos()
{
mSsaoValid = true;
// setup framebuffer for SSAO processing
@@ -249,15 +247,12 @@ void SimDisplay::InitGL()
// setup light object
mlightObject.GenerateBoxStock(-0.5f, -0.5f, -0.5f, 1, 1, 1);
mWidth = gWindowSizeW;
mHeight = gWindowSizeH;
InitShaders();
CreateDisplayFbos();
CreateSsaoFbos();
CreateFboQuad();
UpdateProjection();
displayInitiated = true;
UpdateWindowScale(800, 600);
}
void SimDisplay::CleanFbos()
@@ -298,7 +293,7 @@ void SimDisplay::CleanGL()
displayInitiated = false;
}
void SimDisplay::PrepareDisplay(vec3 objCenter)
void SimDisplay::PrepareDisplay(const vec3& objCenter)
{
mat4x4_look_at(mMatLookAt, eye, target, upvec);
mat4x4_translate_in_place(mMatLookAt, mEyeX * mEyeXZFactor, 0, mEyeZ * mEyeXZFactor);
@@ -326,7 +321,7 @@ void SimDisplay::StartDepthPass()
shaderFlat.UpdateViewMat(mMatLookAt);
}
void SimDisplay::StartGeometryPass(vec3 objColor, bool invertNormals)
void SimDisplay::StartGeometryPass(const vec3& objColor, bool invertNormals)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
shaderGeom.Activate();
@@ -339,7 +334,7 @@ void SimDisplay::StartGeometryPass(vec3 objColor, bool invertNormals)
// A 'closer' geometry pass is similar to std geometry pass, but render the objects
// slightly closer to the camera. This mitigates overlapping faces artifacts.
void SimDisplay::StartCloserGeometryPass(vec3 objColor)
void SimDisplay::StartCloserGeometryPass(const vec3& objColor)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
shaderGeomCloser.Activate();
@@ -362,15 +357,18 @@ void SimDisplay::ScaleViewToStock(StockObject* obj)
mMaxStockDim = fmaxf(obj->size[0], obj->size[1]);
maxFar = mMaxStockDim * 16;
UpdateProjection();
vec3_set(eye, 0, 0, 0);
mEyeDistFactor = NAN;
UpdateEyeFactor(0.1f);
vec3_set(lightPos, obj->position[0], obj->position[1], obj->position[2] + mMaxStockDim / 3);
mlightObject.SetPosition(lightPos);
}
void SimDisplay::RenderResult(bool recalculate)
void SimDisplay::RenderResult(bool recalculate, bool ssao)
{
if (mSsaoValid && applySSAO) {
if (mSsaoValid && ssao) {
RenderResultSSAO(recalculate);
}
else {
@@ -548,12 +546,20 @@ void SimDisplay::UpdateEyeFactor(float factor)
eye[1] = -factor * maxFar;
}
void SimDisplay::UpdateWindowScale()
void SimDisplay::UpdateWindowScale(int width, int height)
{
mWidth = gWindowSizeW;
mHeight = gWindowSizeH;
glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
CleanFbos();
if (!displayInitiated || (width == mWidth && height == mHeight)) {
return;
}
mWidth = width;
mHeight = height;
if (mFbo != 0) {
glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
CleanFbos();
}
CreateDisplayFbos();
CreateSsaoFbos();
UpdateProjection();
@@ -563,7 +569,7 @@ void SimDisplay::UpdateProjection()
{
// Setup projection
mat4x4 projmat;
mat4x4_perspective(projmat, 0.7f, (float)gWindowSizeW / gWindowSizeH, 1.0f, maxFar);
mat4x4_perspective(projmat, 0.7f, (float)mWidth / mHeight, 1.0f, maxFar);
shader3D.Activate();
shader3D.UpdateProjectionMat(projmat);
shaderInv3D.Activate();
@@ -583,5 +589,9 @@ void SimDisplay::UpdateProjection()
shaderGeomCloser.UpdateProjectionMat(projmat);
}
float SimDisplay::GetEyeFactor()
{
return mEyeDistFactor;
}
} // namespace MillSim

View File

@@ -50,14 +50,14 @@ public:
void InitGL();
void CleanGL();
void CleanFbos();
void PrepareDisplay(vec3 objCenter);
void PrepareDisplay(const vec3& objCenter);
void PrepareFrameBuffer();
void StartDepthPass();
void StartGeometryPass(vec3 objColor, bool invertNormals);
void StartCloserGeometryPass(vec3 objColor);
void StartGeometryPass(const vec3& objColor, bool invertNormals);
void StartCloserGeometryPass(const vec3& objColor);
void RenderLightObject();
void ScaleViewToStock(StockObject* obj);
void RenderResult(bool recalculate);
void RenderResult(bool recalculate, bool ssao);
void RenderResultStandard();
void RenderResultSSAO(bool recalculate);
void SetupLinePathPass(int curSegment, bool isHidden);
@@ -66,16 +66,12 @@ public:
void MoveEye(float x, float z);
void MoveEyeCenter();
void UpdateEyeFactor(float factor);
void UpdateWindowScale();
void UpdateWindowScale(int width, int height);
void UpdateProjection();
float GetEyeFactor()
{
return mEyeDistFactor;
}
float GetEyeFactor();
public:
bool applySSAO = false;
bool updateDisplay = false;
float maxFar = 100;
bool displayInitiated = false;
@@ -108,13 +104,12 @@ protected:
mat4x4 mMatLookAt;
StockObject mlightObject;
int mWidth;
int mHeight;
int mWidth = -1;
int mHeight = -1;
std::mt19937 generator;
std::uniform_real_distribution<float> distr01;
float mEyeDistance = 30;
float mEyeRoration = 0;
float mEyeInclination = pi / 6; // 30 degree
@@ -128,22 +123,23 @@ protected:
float mEyeZ = 0.0f;
// base frame buffer
unsigned int mFbo;
unsigned int mFboColTexture;
unsigned int mFboPosTexture;
unsigned int mFboNormTexture;
unsigned int mRboDepthStencil;
unsigned int mFboQuadVAO, mFboQuadVBO;
unsigned int mFbo = 0;
unsigned int mFboColTexture = 0;
unsigned int mFboPosTexture = 0;
unsigned int mFboNormTexture = 0;
unsigned int mRboDepthStencil = 0;
unsigned int mFboQuadVAO = 0, mFboQuadVBO = 0;
// ssao frame buffers
bool mSsaoValid = false;
std::vector<Point3D> mSsaoKernel;
unsigned int mSsaoFbo;
unsigned int mSsaoBlurFbo;
unsigned int mFboSsaoTexture;
unsigned int mFboSsaoBlurTexture;
unsigned int mFboRandTexture;
unsigned int mSsaoFbo = 0;
unsigned int mSsaoBlurFbo = 0;
unsigned int mFboSsaoTexture = 0;
unsigned int mFboSsaoBlurTexture = 0;
unsigned int mFboRandTexture = 0;
};
} // namespace MillSim
#endif // !__simdisplay_h__

View File

@@ -354,7 +354,7 @@ void Shape::GenerateModel(const float* vbuffer, const GLushort* ibuffer, int num
numIndices = nIndices;
}
void MillSim::Shape::SetModelData(const std::vector<Vertex>& vbuffer, const std::vector<GLushort>& ibuffer)
void Shape::SetModelData(const std::vector<Vertex>& vbuffer, const std::vector<GLushort>& ibuffer)
{
GenerateModel((const float*)vbuffer.data(), ibuffer.data(), (int)vbuffer.size(), (int)ibuffer.size());
}
@@ -366,7 +366,7 @@ void Shape::Render()
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, nullptr);
}
void Shape::Render(mat4x4 modelMat, mat4x4 normallMat) // normals are rotated only
void Shape::Render(const mat4x4& modelMat, const mat4x4& normallMat) // normals are rotated only
{
CurrentShader->UpdateModelMat(modelMat, normallMat);
Render();

View File

@@ -83,7 +83,7 @@ public:
public:
void Render();
void Render(mat4x4 modelMat, mat4x4 normallMat);
void Render(const mat4x4& modelMat, const mat4x4& normallMat);
void FreeResources();
void SetModelData(const std::vector<Vertex>& vbuffer, const std::vector<GLushort>& ibuffer);
void RotateProfile(

View File

@@ -0,0 +1,53 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "ViewCAMSimulator.h"
#include "DlgCAMSimulator.h"
namespace CAMSimulator
{
ViewCAMSimulator::ViewCAMSimulator(Gui::Document* pcDocument, QWidget* parent, Qt::WindowFlags wflags)
: Gui::MDIView(pcDocument, parent, wflags)
{
mDlg = new DlgCAMSimulator(*this);
setCentralWidget(mDlg);
}
ViewCAMSimulator* ViewCAMSimulator::clone()
{
auto viewCam = new ViewCAMSimulator(_pcDocument, nullptr);
viewCam->cloneFrom(*this);
viewCam->mDlg->cloneFrom(*mDlg);
return viewCam;
}
DlgCAMSimulator& ViewCAMSimulator::dlg()
{
return *mDlg;
}
} // namespace CAMSimulator

View File

@@ -0,0 +1,53 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef PATHSIMULATOR_VIEWCAMSIMULATOR_H
#define PATHSIMULATOR_VIEWCAMSIMULATOR_H
#include <Gui/MDIView.h>
namespace CAMSimulator
{
class DlgCAMSimulator;
class ViewCAMSimulator: public Gui::MDIView
{
public:
ViewCAMSimulator(
Gui::Document* pcDocument,
QWidget* parent,
Qt::WindowFlags wflags = Qt::WindowFlags()
);
ViewCAMSimulator* clone() override;
DlgCAMSimulator& dlg();
protected:
DlgCAMSimulator* mDlg;
};
} // namespace CAMSimulator
#endif /* PATHSIMULATOR_VIEWCAMSIMULATOR_H */