Refactor: Abstract dimension input and finalize creation logic to SketchTool

Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
2026-02-17 14:58:02 -07:00
parent d66f7aaf56
commit e1327b2caa
6 changed files with 243 additions and 269 deletions

View File

@@ -14,20 +14,17 @@ LineTool::LineTool(ViewportWidget* viewport)
void LineTool::activate()
{
m_isDefiningLine = false;
SketchTool::activate();
m_dimensionModes << "length" << "angle";
m_dimensionPropertyNames["length"] = "dimensionInput";
m_dimensionPropertyNames["angle"] = "angleInput";
m_viewport->setProperty("dimensionInput", "");
m_viewport->setProperty("angleInput", "");
m_viewport->setProperty("dimensionEditMode", "length");
m_viewport->setProperty("isChainedLine", false);
}
void LineTool::deactivate()
{
m_isDefiningLine = false;
m_viewport->setProperty("dimensionInput", "");
m_viewport->setProperty("angleInput", "");
}
void LineTool::mousePressEvent(QMouseEvent *event)
{
gp_Pnt p;
@@ -38,7 +35,7 @@ void LineTool::mousePressEvent(QMouseEvent *event)
double inputLength = 0;
double inputAngleDegrees = 0;
if (m_isDefiningLine) {
if (m_isDefining) {
if (!dimInput.isEmpty()) {
bool ok;
inputLength = dimInput.toDouble(&ok);
@@ -51,7 +48,7 @@ void LineTool::mousePressEvent(QMouseEvent *event)
}
}
if (m_isDefiningLine && (lengthFromInput || angleFromInput)) {
if (m_isDefining && (lengthFromInput || angleFromInput)) {
QVector3D worldPos;
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
@@ -130,9 +127,9 @@ void LineTool::mousePressEvent(QMouseEvent *event)
}
}
if (!m_isDefiningLine) {
if (!m_isDefining) {
m_firstLinePoint = p;
m_isDefiningLine = true;
m_isDefining = true;
m_viewport->setProperty("dimensionInput", QVariant(""));
m_viewport->setProperty("angleInput", QVariant(""));
m_viewport->setProperty("dimensionEditMode", "length");
@@ -158,7 +155,7 @@ void LineTool::mouseMoveEvent(QMouseEvent *event)
m_viewport->setSnappingHorizontal(false);
m_viewport->setSnappingVertical(false);
if (m_isDefiningLine && !m_viewport->isSnappingOrigin() && !m_viewport->isSnappingVertex()) {
if (m_isDefining && !m_viewport->isSnappingOrigin() && !m_viewport->isSnappingVertex()) {
QVector3D worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
QVector3D delta = worldPos - startPos;
@@ -188,148 +185,103 @@ void LineTool::mouseMoveEvent(QMouseEvent *event)
}
}
void LineTool::keyPressEvent(QKeyEvent *event)
void LineTool::finalizeCreation()
{
if (m_isDefiningLine) {
if (event->key() == Qt::Key_Tab) {
QString currentMode = m_viewport->property("dimensionEditMode").toString();
if (currentMode == "length") {
m_viewport->setProperty("dimensionEditMode", "angle");
} else {
m_viewport->setProperty("dimensionEditMode", "length");
}
m_viewport->update();
return;
}
QVector3D worldPos;
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
// This is duplicated from paintGL to ensure consistent line creation
QString dimInput = m_viewport->property("dimensionInput").toString();
QString angleInput = m_viewport->property("angleInput").toString();
bool lengthFromInput = false;
bool angleFromInput = false;
double inputLength = 0;
double inputAngleDegrees = 0;
QString editMode = m_viewport->property("dimensionEditMode").toString();
const char* propertyName = (editMode == "length") ? "dimensionInput" : "angleInput";
QString currentInput = m_viewport->property(propertyName).toString();
if (event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9) {
currentInput += event->text();
m_viewport->setProperty(propertyName, currentInput);
m_viewport->update();
return;
} else if (event->key() == Qt::Key_Period) {
if (!currentInput.contains('.')) {
currentInput += '.';
m_viewport->setProperty(propertyName, currentInput);
m_viewport->update();
}
return;
} else if (event->key() == Qt::Key_Backspace) {
if (!currentInput.isEmpty()) {
currentInput.chop(1);
m_viewport->setProperty(propertyName, currentInput);
m_viewport->update();
}
return;
} else if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
QVector3D worldPos;
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
// This is duplicated from paintGL to ensure consistent line creation
QString dimInput = m_viewport->property("dimensionInput").toString();
QString angleInput = m_viewport->property("angleInput").toString();
bool lengthFromInput = false;
bool angleFromInput = false;
double inputLength = 0;
double inputAngleDegrees = 0;
if (!dimInput.isEmpty()) {
bool ok;
inputLength = dimInput.toDouble(&ok);
if (ok) lengthFromInput = true;
}
if (!angleInput.isEmpty()) {
bool ok;
inputAngleDegrees = angleInput.toDouble(&ok);
if (ok) angleFromInput = true;
}
if (angleFromInput) {
QVector3D refDir;
if (m_viewport->property("isChainedLine").toBool()) {
refDir = m_viewport->property("previousLineDirection").value<QVector3D>();
} else {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refDir = QVector3D(1, 0, 0);
else refDir = QVector3D(0, 0, -1);
}
QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
QVector3D mouseVec = currentMouseWorldPos - startPos;
double mouseAngle;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.y(), mouseVec.x()));
else mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.y()));
double refAngle;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngle = qRadiansToDegrees(atan2(refDir.y(), refDir.x()));
else refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.y()));
double relativeMouseAngle = mouseAngle - refAngle;
while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0;
while (relativeMouseAngle > 180.0) relativeMouseAngle -= 360.0;
double snappedAngle = 0;
if (relativeMouseAngle >= 0 && relativeMouseAngle < 90) { // Quadrant 1
snappedAngle = inputAngleDegrees;
} else if (relativeMouseAngle >= 90 && relativeMouseAngle <= 180) { // Quadrant 2
snappedAngle = 180.0 - inputAngleDegrees;
} else if (relativeMouseAngle < -90) { // Quadrant 3
snappedAngle = -180.0 + inputAngleDegrees;
} else { // Quadrant 4
snappedAngle = -inputAngleDegrees;
}
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
QVector3D finalDir;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0);
else finalDir = QVector3D(0, cos(finalAngleRad), sin(finalAngleRad));
double lineLength;
if (lengthFromInput) lineLength = inputLength;
else {
lineLength = QVector3D::dotProduct(mouseVec, finalDir);
if (lineLength < 0) lineLength = 0;
}
worldPos = startPos + lineLength * finalDir;
} else if (lengthFromInput) {
QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
QVector3D dir = (currentMouseWorldPos - startPos);
if (dir.length() > 1e-6) {
dir.normalize();
worldPos = startPos + inputLength * dir;
} else {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos = startPos + QVector3D(inputLength, 0, 0);
else worldPos = startPos + QVector3D(0, inputLength, 0);
}
} else {
worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
}
gp_Pnt p;
p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z());
QVector3D prevDir = (worldPos - startPos).normalized();
m_viewport->setProperty("previousLineDirection", QVariant::fromValue(prevDir));
m_viewport->addLine(m_firstLinePoint, p);
m_firstLinePoint = p;
m_viewport->setProperty("dimensionInput", QVariant(""));
m_viewport->setProperty("angleInput", QVariant(""));
m_viewport->setProperty("dimensionEditMode", "length");
m_viewport->setProperty("isChainedLine", true);
m_viewport->update();
return;
} else if (event->key() == Qt::Key_Escape) {
deactivate();
m_viewport->deactivateActiveTool();
m_viewport->update();
return;
}
if (!dimInput.isEmpty()) {
bool ok;
inputLength = dimInput.toDouble(&ok);
if (ok) lengthFromInput = true;
}
if (!angleInput.isEmpty()) {
bool ok;
inputAngleDegrees = angleInput.toDouble(&ok);
if (ok) angleFromInput = true;
}
if (angleFromInput) {
QVector3D refDir;
if (m_viewport->property("isChainedLine").toBool()) {
refDir = m_viewport->property("previousLineDirection").value<QVector3D>();
} else {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refDir = QVector3D(1, 0, 0);
else refDir = QVector3D(0, 0, -1);
}
QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
QVector3D mouseVec = currentMouseWorldPos - startPos;
double mouseAngle;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.y(), mouseVec.x()));
else mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.y()));
double refAngle;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngle = qRadiansToDegrees(atan2(refDir.y(), refDir.x()));
else refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.y()));
double relativeMouseAngle = mouseAngle - refAngle;
while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0;
while (relativeMouseAngle > 180.0) relativeMouseAngle -= 360.0;
double snappedAngle = 0;
if (relativeMouseAngle >= 0 && relativeMouseAngle < 90) { // Quadrant 1
snappedAngle = inputAngleDegrees;
} else if (relativeMouseAngle >= 90 && relativeMouseAngle <= 180) { // Quadrant 2
snappedAngle = 180.0 - inputAngleDegrees;
} else if (relativeMouseAngle < -90) { // Quadrant 3
snappedAngle = -180.0 + inputAngleDegrees;
} else { // Quadrant 4
snappedAngle = -inputAngleDegrees;
}
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
QVector3D finalDir;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0);
else finalDir = QVector3D(0, cos(finalAngleRad), sin(finalAngleRad));
double lineLength;
if (lengthFromInput) lineLength = inputLength;
else {
lineLength = QVector3D::dotProduct(mouseVec, finalDir);
if (lineLength < 0) lineLength = 0;
}
worldPos = startPos + lineLength * finalDir;
} else if (lengthFromInput) {
QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
QVector3D dir = (currentMouseWorldPos - startPos);
if (dir.length() > 1e-6) {
dir.normalize();
worldPos = startPos + inputLength * dir;
} else {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos = startPos + QVector3D(inputLength, 0, 0);
else worldPos = startPos + QVector3D(0, inputLength, 0);
}
} else {
worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
}
gp_Pnt p;
p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z());
QVector3D prevDir = (worldPos - startPos).normalized();
m_viewport->setProperty("previousLineDirection", QVariant::fromValue(prevDir));
m_viewport->addLine(m_firstLinePoint, p);
m_firstLinePoint = p;
m_viewport->setProperty("dimensionInput", QVariant(""));
m_viewport->setProperty("angleInput", QVariant(""));
m_viewport->setProperty("dimensionEditMode", "length");
m_viewport->setProperty("isChainedLine", true);
}
void LineTool::paintGL()
{
if (m_isDefiningLine) {
if (m_isDefining) {
QVector<GLfloat> vertices;
QVector3D worldPos;
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
@@ -662,7 +614,7 @@ void LineTool::paintGL()
void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection)
{
if (m_isDefiningLine) {
if (m_isDefining) {
QVector3D worldPos;
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
QString dimText;