// Unnamed CAD Software // // License: GPLv3 (or later) // Language: C++17 // Notes: // - use a right-handed, Z-up coordinate system to match Open CASCADE #include "ApplicationController.h" #include "Document.h" #include "SketchFeature.h" #include "SketchLine.h" #include "SketchRectangle.h" #include "SketchCircle.h" #include "MainWindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include ApplicationController::ApplicationController(QObject *parent) : QObject(parent) { m_document = new Document(this); } ApplicationController::~ApplicationController() { } void ApplicationController::setMainWindow(MainWindow* mainWindow) { m_mainWindow = mainWindow; } Document* ApplicationController::document() const { return m_document; } SketchFeature* ApplicationController::activeSketch() const { return m_activeSketch; } ApplicationController::ToolType ApplicationController::activeTool() const { return m_activeTool; } void ApplicationController::setActiveTool(ToolType tool) { if (m_activeTool == tool) { return; } m_activeTool = tool; emit activeToolChanged(m_activeTool); } void ApplicationController::newDocument() { m_activeSketch = nullptr; m_document->clear(); setCurrentFile(QString()); } bool ApplicationController::openDocument() { const QString fileName = QFileDialog::getOpenFileName(m_mainWindow); if (!fileName.isEmpty()) { if (!m_document->load(fileName)) { QMessageBox::warning(m_mainWindow, tr("OpenCAD"), tr("Cannot read file %1").arg(QDir::toNativeSeparators(fileName))); return false; } setCurrentFile(fileName); m_activeSketch = nullptr; return true; } return false; } bool ApplicationController::saveDocument() { if (m_currentFile.isEmpty()) { return saveDocumentAs(); } else { if (!m_document->save(m_currentFile)) { QMessageBox::warning(m_mainWindow, tr("OpenCAD"), tr("Cannot write file %1").arg(QDir::toNativeSeparators(m_currentFile))); return false; } return true; } } bool ApplicationController::saveDocumentAs() { QFileDialog dialog(m_mainWindow); dialog.setWindowModality(Qt::WindowModal); dialog.setAcceptMode(QFileDialog::AcceptSave); if (dialog.exec() != QDialog::Accepted) return false; const QString fileName = dialog.selectedFiles().first(); setCurrentFile(fileName); return saveDocument(); } void ApplicationController::beginSketchCreation() { if (m_activeSketch) { return; } emit planeSelectionModeStarted(); } void ApplicationController::onPlaneSelected(const gp_Ax2& plane) { auto feature = new SketchFeature("Sketch"); m_activeSketch = feature; feature->setPlane(plane); m_document->addFeature(feature); emit sketchModeStarted(plane); } void ApplicationController::addLine(const gp_Pnt& start, const gp_Pnt& end) { if (m_activeSketch) { m_activeSketch->addObject(new SketchLine(start, end)); Handle(Geom_TrimmedCurve) segment = GC_MakeSegment(start, end); TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(segment); m_activeSketch->addShape(edge); } } void ApplicationController::addRectangle(const gp_Pnt& corner1, const gp_Pnt& corner2) { if (m_activeSketch) { m_activeSketch->addObject(new SketchRectangle(corner1, corner2)); const auto& plane = m_activeSketch->plane(); gp_Pnt2d p1_2d = ElCLib::To2d(corner1, plane); gp_Pnt2d p3_2d = ElCLib::To2d(corner2, plane); gp_Pnt2d p2_2d(p3_2d.X(), p1_2d.Y()); gp_Pnt2d p4_2d(p1_2d.X(), p3_2d.Y()); gp_Pnt p2_3d = ElCLib::To3d(p2_2d, plane); gp_Pnt p4_3d = ElCLib::To3d(p4_2d, plane); TopoDS_Edge e1 = BRepBuilderAPI_MakeEdge(corner1, p2_3d); TopoDS_Edge e2 = BRepBuilderAPI_MakeEdge(p2_3d, corner2); TopoDS_Edge e3 = BRepBuilderAPI_MakeEdge(corner2, p4_3d); TopoDS_Edge e4 = BRepBuilderAPI_MakeEdge(p4_3d, corner1); BRepBuilderAPI_MakeWire wireMaker(e1, e2, e3, e4); if (wireMaker.IsDone()) { m_activeSketch->addShape(wireMaker.Shape()); } } } void ApplicationController::addCircle(const gp_Pnt& center, double radius) { if (m_activeSketch) { m_activeSketch->addObject(new SketchCircle(center, radius)); const auto& sketchPlane = m_activeSketch->plane(); gp_Ax2 axis(center, sketchPlane.Direction()); gp_Circ circle(axis, radius); TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(circle); m_activeSketch->addShape(edge); } } void ApplicationController::endSketch() { m_activeSketch = nullptr; setActiveTool(ToolType::None); emit sketchModeEnded(); } void ApplicationController::setCurrentFile(const QString& fileName) { m_currentFile = fileName; m_document->setFileName(fileName); emit currentFileChanged(m_currentFile); }