6d92349938
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
207 lines
5.4 KiB
C++
207 lines
5.4 KiB
C++
// 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 <BRepBuilderAPI_MakeEdge.hxx>
|
|
#include <BRepBuilderAPI_MakeWire.hxx>
|
|
#include <GC_MakeSegment.hxx>
|
|
#include <ElCLib.hxx>
|
|
#include <gp_Ax2.hxx>
|
|
#include <gp_Circ.hxx>
|
|
#include <gp_Dir.hxx>
|
|
#include <gp_Vec.hxx>
|
|
#include <gp_Pnt2d.hxx>
|
|
|
|
#include <QInputDialog>
|
|
#include <QFileDialog>
|
|
#include <QMessageBox>
|
|
#include <QDir>
|
|
#include <QFileInfo>
|
|
|
|
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(gp_Vec(plane.Location(), corner1).Dot(plane.XDirection()), gp_Vec(plane.Location(), corner1).Dot(plane.YDirection()));
|
|
gp_Pnt2d p3_2d(gp_Vec(plane.Location(), corner2).Dot(plane.XDirection()), gp_Vec(plane.Location(), corner2).Dot(plane.YDirection()));
|
|
|
|
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(plane, p2_2d);
|
|
gp_Pnt p4_3d = ElCLib::To3d(plane, p4_2d);
|
|
|
|
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);
|
|
}
|