feat: Implement circle drawing tool

Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
2026-02-17 15:15:24 -07:00
parent 4b0a903052
commit 7f6c01c8a0
8 changed files with 131 additions and 1 deletions

View File

@@ -3,6 +3,7 @@
#include "SketchFeature.h"
#include "SketchLine.h"
#include "SketchRectangle.h"
#include "SketchCircle.h"
#include "MainWindow.h"
#include <QInputDialog>
@@ -148,6 +149,13 @@ void ApplicationController::addRectangle(const gp_Pnt& corner1, const gp_Pnt& co
}
}
void ApplicationController::addCircle(const gp_Pnt& center, double radius)
{
if (m_activeSketch) {
m_activeSketch->addObject(new SketchCircle(center, radius));
}
}
void ApplicationController::endSketch()
{
m_activeSketch = nullptr;

View File

@@ -33,6 +33,7 @@ public slots:
void setActiveTool(ToolType tool);
void addLine(const gp_Pnt& start, const gp_Pnt& end);
void addRectangle(const gp_Pnt& corner1, const gp_Pnt& corner2);
void addCircle(const gp_Pnt& center, double radius);
void newDocument();
bool openDocument();
bool saveDocument();

View File

@@ -147,6 +147,7 @@ MainWindow::MainWindow(ApplicationController* appController, QWidget *parent)
connect(m_viewport, &ViewportWidget::lineAdded, m_appController, &ApplicationController::addLine);
connect(m_viewport, &ViewportWidget::rectangleAdded, m_appController, &ApplicationController::addRectangle);
connect(m_viewport, &ViewportWidget::circleAdded, m_appController, &ApplicationController::addCircle);
connect(m_viewport, &ViewportWidget::planeSelected, m_appController, &ApplicationController::onPlaneSelected);
connect(m_viewport, &ViewportWidget::toolDeactivated, m_appController, [this]() { m_appController->setActiveTool(ApplicationController::ToolType::None); });

56
src/SketchCircle.cpp Normal file
View File

@@ -0,0 +1,56 @@
#include "SketchCircle.h"
#include <QJsonArray>
namespace
{
void pointToJson(const gp_Pnt& p, QJsonArray& arr)
{
arr.append(p.X());
arr.append(p.Y());
arr.append(p.Z());
}
gp_Pnt jsonToPoint(const QJsonArray& arr)
{
return gp_Pnt(arr[0].toDouble(), arr[1].toDouble(), arr[2].toDouble());
}
}
SketchCircle::SketchCircle() : m_radius(0.0)
{
}
SketchCircle::SketchCircle(const gp_Pnt& center, double radius)
: m_center(center), m_radius(radius)
{
}
SketchObject::ObjectType SketchCircle::type() const
{
return ObjectType::Circle;
}
void SketchCircle::read(const QJsonObject& json)
{
m_center = jsonToPoint(json["center"].toArray());
m_radius = json["radius"].toDouble();
}
void SketchCircle::write(QJsonObject& json) const
{
QJsonArray centerArr;
pointToJson(m_center, centerArr);
json["center"] = centerArr;
json["radius"] = m_radius;
json["type"] = "Circle";
}
const gp_Pnt& SketchCircle::center() const
{
return m_center;
}
double SketchCircle::radius() const
{
return m_radius;
}

26
src/SketchCircle.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef SKETCHCIRCLE_H
#define SKETCHCIRCLE_H
#include "SketchObject.h"
#include <gp_Pnt.hxx>
class SketchCircle : public SketchObject
{
public:
SketchCircle();
SketchCircle(const gp_Pnt& center, double radius);
ObjectType type() const override;
void read(const QJsonObject& json) override;
void write(QJsonObject& json) const override;
const gp_Pnt& center() const;
double radius() const;
private:
gp_Pnt m_center;
double m_radius;
};
#endif // SKETCHCIRCLE_H

View File

@@ -8,7 +8,8 @@ class SketchObject
public:
enum class ObjectType {
Line,
Rectangle
Rectangle,
Circle
};
SketchObject() = default;

View File

@@ -8,10 +8,12 @@
#include "SketchFeature.h"
#include "SketchLine.h"
#include "SketchRectangle.h"
#include "SketchCircle.h"
#include "SketchObject.h"
#include "ApplicationController.h"
#include "RectangleTool.h"
#include "LineTool.h"
#include "CircleTool.h"
#include <QMouseEvent>
#include <QKeyEvent>
#include <QWheelEvent>
@@ -61,6 +63,7 @@ ViewportWidget::ViewportWidget(QWidget *parent)
m_sketchTools.insert(static_cast<int>(ApplicationController::ToolType::Line), new LineTool(this));
m_sketchTools.insert(static_cast<int>(ApplicationController::ToolType::Rectangle), new RectangleTool(this));
m_sketchTools.insert(static_cast<int>(ApplicationController::ToolType::Circle), new CircleTool(this));
m_snapping = new Snapping(this);
}
@@ -511,6 +514,39 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch)
vertexCounts[start]++;
vertexCounts[end]++;
} else if (obj->type() == SketchObject::ObjectType::Circle) {
auto circle = static_cast<const SketchCircle*>(obj);
const auto& center = circle->center();
double radius = circle->radius();
QVector3D centerPos(center.X(), center.Y(), center.Z());
const int numSegments = 64;
QVector3D u_axis, v_axis;
switch (sketch->plane()) {
case SketchFeature::SketchPlane::XY:
u_axis = QVector3D(1, 0, 0);
v_axis = QVector3D(0, 1, 0);
break;
case SketchFeature::SketchPlane::XZ:
u_axis = QVector3D(1, 0, 0);
v_axis = QVector3D(0, 0, 1);
break;
case SketchFeature::SketchPlane::YZ:
u_axis = QVector3D(0, 1, 0);
v_axis = QVector3D(0, 0, 1);
break;
}
for (int i = 0; i < numSegments; ++i) {
double angle1 = 2.0 * M_PI * double(i) / double(numSegments);
QVector3D p1 = centerPos + radius * (cos(angle1) * u_axis + sin(angle1) * v_axis);
double angle2 = 2.0 * M_PI * double(i + 1) / double(numSegments);
QVector3D p2 = centerPos + radius * (cos(angle2) * u_axis + sin(angle2) * v_axis);
lineVertices << p1.x() << p1.y() << p1.z();
lineVertices << p2.x() << p2.y() << p2.z();
}
} else if (obj->type() == SketchObject::ObjectType::Rectangle) {
auto rect = static_cast<const SketchRectangle*>(obj);
const auto& p1 = rect->corner1();

View File

@@ -70,6 +70,7 @@ public slots:
signals:
void lineAdded(const gp_Pnt& start, const gp_Pnt& end);
void rectangleAdded(const gp_Pnt& corner1, const gp_Pnt& corner2);
void circleAdded(const gp_Pnt& center, double radius);
void planeSelected(SketchPlane plane);
void toolDeactivated();