Compare commits

..

14 Commits

Author SHA1 Message Date
1be782b88d fix: Improve face creation from edges using BRepOffsetAPI_MakeFilling
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-02-18 12:23:29 -07:00
3444e9e183 chore: Add debug logging for sketch face creation
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-02-18 12:18:58 -07:00
fdd972b286 fix: Improve face creation for wire-based shapes by inferring plane
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-02-18 12:16:45 -07:00
768eed2f39 Adjust sketch grid 2026-02-18 12:11:06 -07:00
41639882db fix: Correct face generation and resolve tool preview glitches
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-02-18 12:11:06 -07:00
fa6e4662a6 fix: Generate faces for sketch objects and fix tool preview state
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-02-18 12:11:06 -07:00
a7ad78e103 fix: Correct coordinate system for sketch plane geometry and rendering
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-02-18 12:11:06 -07:00
0798cd2a6c fix: Correct sketch face rendering, orientation, and complex wire generation
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-02-18 12:11:06 -07:00
ce6975cc44 feat: Add Blinn-Phong shading for faces
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-02-18 12:10:59 -07:00
b9860f3de0 fix: Prevent crash from failed sketch geometry creation
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-02-17 18:12:08 -07:00
6e729183ef fix: Update OpenCASCADE triangulation API usage
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-02-17 17:57:13 -07:00
d5d430e80d fix: Add edges to wire builder individually
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-02-17 17:56:15 -07:00
95b4db5191 feat: Render OpenCASCADE faces in viewport
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-02-17 17:54:59 -07:00
e2dfdf1600 feat: Generate faces from closed sketch wires
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-02-17 17:52:17 -07:00
21 changed files with 475 additions and 346 deletions

View File

@@ -28,33 +28,11 @@ endif()
message(STATUS "OpenCASCADE_INCLUDE_DIRS: ${OpenCASCADE_INCLUDE_DIRS}")
message(STATUS "OpenCASCADE_LIBRARIES: ${OpenCASCADE_LIBRARIES}")
# Automatically find resource files and generate resources.qrc
set(GENERATED_QRC_FILE "${CMAKE_CURRENT_BINARY_DIR}/resources.qrc")
set(QRC_CONTENT "")
file(GLOB ICON_FILES "icons/*.svg")
string(APPEND QRC_CONTENT " <qresource prefix=\"/icons\">\n")
foreach(ICON_FILE IN LISTS ICON_FILES)
get_filename_component(ICON_ALIAS ${ICON_FILE} NAME)
string(APPEND QRC_CONTENT " <file alias=\"${ICON_ALIAS}\">${ICON_FILE}</file>\n")
endforeach()
string(APPEND QRC_CONTENT " </qresource>\n")
file(GLOB SHADER_FILES "src/shaders/*")
string(APPEND QRC_CONTENT " <qresource prefix=\"/shaders\">\n")
foreach(SHADER_FILE IN LISTS SHADER_FILES)
get_filename_component(SHADER_ALIAS ${SHADER_FILE} NAME)
string(APPEND QRC_CONTENT " <file alias=\"${SHADER_ALIAS}\">${SHADER_FILE}</file>\n")
endforeach()
string(APPEND QRC_CONTENT " </qresource>\n")
file(WRITE ${GENERATED_QRC_FILE} "<RCC>\n${QRC_CONTENT}</RCC>\n")
file(GLOB SOURCES "src/*.cpp")
add_executable(OpenCAD
${SOURCES}
${GENERATED_QRC_FILE}
resources.qrc
)
target_include_directories(OpenCAD SYSTEM PRIVATE ${OpenCASCADE_INCLUDE_DIRS})

20
resources.qrc Normal file
View File

@@ -0,0 +1,20 @@
<RCC>
<qresource prefix="/">
<file>icons/create-sketch.svg</file>
<file>icons/extrude.svg</file>
<file>icons/line.svg</file>
<file>icons/rectangle.svg</file>
<file>icons/circle.svg</file>
<file>icons/save-sketch.svg</file>
<file>icons/cursor.svg</file>
<file>icons/home.svg</file>
</qresource>
<qresource prefix="/shaders">
<file alias="simple.vert">src/shaders/simple.vert</file>
<file alias="simple.frag">src/shaders/simple.frag</file>
<file alias="texture.vert">src/shaders/texture.vert</file>
<file alias="texture.frag">src/shaders/texture.frag</file>
<file alias="lit.vert">src/shaders/lit.vert</file>
<file alias="lit.frag">src/shaders/lit.frag</file>
</qresource>
</RCC>

View File

@@ -158,6 +158,9 @@ void ApplicationController::addCircle(const gp_Pnt& center, double radius)
void ApplicationController::endSketch()
{
if (m_activeSketch) {
m_activeSketch->buildShape();
}
m_activeSketch = nullptr;
setActiveTool(ToolType::None);
emit sketchModeEnded();

View File

@@ -67,7 +67,6 @@ void Camera::wheelEvent(QWheelEvent* event, const QVector3D& worldPos)
QMatrix4x4 rotation;
rotation.rotate(m_xRot / 16.0f, 1, 0, 0);
rotation.rotate(m_yRot / 16.0f, 0, 1, 0);
rotation.rotate(-90.0f, 1, 0, 0);
QVector3D p_camera = rotation.map(worldPos);
if (std::abs(p_camera.z() + oldZoom) < 1e-6) {
@@ -91,20 +90,14 @@ QMatrix4x4 Camera::modelViewMatrix() const
QMatrix4x4 model;
model.translate(m_panX, m_panY, m_zoom);
QMatrix4x4 zup_rotation;
zup_rotation.rotate(-90.0f, 1, 0, 0);
QVector3D pivot_yup = zup_rotation.map(m_rotationPivot);
if (m_isRotating) {
model.translate(pivot_yup);
model.translate(m_rotationPivot);
}
model.rotate(m_xRot / 16.0f, 1, 0, 0);
model.rotate(m_yRot / 16.0f, 0, 1, 0);
if (m_isRotating) {
model.translate(-pivot_yup);
model.translate(-m_rotationPivot);
}
model.rotate(-90.0f, 1, 0, 0); // For Z-up system
return model;
}
@@ -348,16 +341,12 @@ void Camera::startRotation(const QVector3D& pivot)
}
m_stableZoom = m_zoom;
QMatrix4x4 zup_rotation;
zup_rotation.rotate(-90.0f, 1, 0, 0);
QVector3D pivot_yup = zup_rotation.map(m_rotationPivot);
QMatrix4x4 rotation;
rotation.rotate(m_xRot / 16.0f, 1, 0, 0);
rotation.rotate(m_yRot / 16.0f, 0, 1, 0);
QVector3D p_rotated = rotation.map(pivot_yup);
QVector3D p_diff = p_rotated - pivot_yup;
QVector3D p_rotated = rotation.map(m_rotationPivot);
QVector3D p_diff = p_rotated - m_rotationPivot;
setPanX(m_panX + p_diff.x());
setPanY(m_panY + p_diff.y());
@@ -372,16 +361,12 @@ void Camera::stopRotation()
return;
}
QMatrix4x4 zup_rotation;
zup_rotation.rotate(-90.0f, 1, 0, 0);
QVector3D pivot_yup = zup_rotation.map(m_rotationPivot);
QMatrix4x4 rotation;
rotation.rotate(m_xRot / 16.0f, 1, 0, 0);
rotation.rotate(m_yRot / 16.0f, 0, 1, 0);
QVector3D p_rotated = rotation.map(pivot_yup);
QVector3D p_diff = p_rotated - pivot_yup;
QVector3D p_rotated = rotation.map(m_rotationPivot);
QVector3D p_diff = p_rotated - m_rotationPivot;
setPanX(m_panX - p_diff.x());
setPanY(m_panY - p_diff.y());

View File

@@ -172,19 +172,19 @@ void CircleTool::paintGL()
QVector3D p1, p2;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
p1.setX(centerPos.x() + radius * qCos(angle1));
p1.setY(centerPos.y() + radius * qSin(angle1));
p1.setZ(centerPos.z());
p2.setX(centerPos.x() + radius * qCos(angle2));
p2.setY(centerPos.y() + radius * qSin(angle2));
p2.setZ(centerPos.z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
p1.setX(centerPos.x() + radius * qCos(angle1));
p1.setY(centerPos.y());
p1.setZ(centerPos.z() + radius * qSin(angle1));
p2.setX(centerPos.x() + radius * qCos(angle2));
p2.setY(centerPos.y());
p2.setZ(centerPos.z() + radius * qSin(angle2));
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
p1.setX(centerPos.x() + radius * qCos(angle1));
p1.setY(centerPos.y() + radius * qSin(angle1));
p1.setZ(centerPos.z());
p2.setX(centerPos.x() + radius * qCos(angle2));
p2.setY(centerPos.y() + radius * qSin(angle2));
p2.setZ(centerPos.z());
} else { // YZ
p1.setX(centerPos.x());
p1.setY(centerPos.y() + radius * qCos(angle1));

View File

@@ -1,48 +0,0 @@
#include "DebugWindow.h"
#include "Camera.h"
#include <QVBoxLayout>
#include <QTextEdit>
#include <QString>
DebugWindow::DebugWindow(QWidget *parent)
: QDialog(parent)
{
setWindowTitle("Debug Info");
resize(600, 400);
QVBoxLayout* layout = new QVBoxLayout(this);
m_textEdit = new QTextEdit();
m_textEdit->setReadOnly(true);
m_textEdit->setText("Debug window is active.");
layout->addWidget(m_textEdit);
setLayout(layout);
}
DebugWindow::~DebugWindow()
{
}
void DebugWindow::updateCameraInfo(const Camera* camera)
{
if (!camera) {
m_textEdit->setText("Camera not available.");
return;
}
QString info;
info += "Camera Info:\n";
info += "----------------\n";
info += QString("Rotation (X, Y): (%1, %2)\n").arg(camera->xRotation()).arg(camera->yRotation());
info += QString("Zoom: %1\n").arg(camera->zoom());
info += QString("Pan (X, Y): (%1, %2)\n").arg(camera->panX()).arg(camera->panY());
info += QString("UI Camera Distance: %1\n").arg(camera->uiCameraDistance());
info += "\n";
info += "Saved State:\n";
info += "----------------\n";
info += QString("Rotation (X, Y): (%1, %2)\n").arg(camera->savedXRot()).arg(camera->savedYRot());
info += QString("Zoom: %1\n").arg(camera->savedZoom());
info += QString("Pan (X, Y): (%1, %2)\n").arg(camera->savedPanX()).arg(camera->savedPanY());
m_textEdit->setText(info);
}

View File

@@ -1,23 +0,0 @@
#ifndef DEBUGWINDOW_H
#define DEBUGWINDOW_H
#include <QDialog>
class QTextEdit;
class Camera;
class DebugWindow : public QDialog
{
Q_OBJECT
public:
explicit DebugWindow(QWidget *parent = nullptr);
~DebugWindow();
void updateCameraInfo(const Camera* camera);
private:
QTextEdit* m_textEdit;
};
#endif // DEBUGWINDOW_H

View File

@@ -58,17 +58,17 @@ void LineTool::mousePressEvent(QMouseEvent *event)
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, 1, 0);
else refDir = QVector3D(0, 0, -1);
}
QVector3D currentMouseWorldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane());
QVector3D mouseVec = currentMouseWorldPos - startPos;
double mouseAngle;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVec.y(), mouseVec.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x()));
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.y(), refDir.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
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;
@@ -85,8 +85,8 @@ void LineTool::mousePressEvent(QMouseEvent *event)
}
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
QVector3D finalDir;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0);
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad));
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;
@@ -115,8 +115,8 @@ void LineTool::mousePressEvent(QMouseEvent *event)
} else {
QVector3D worldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane());
if (m_viewport->isSnappingHorizontal()) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setY(m_firstLinePoint.Y());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setZ(m_firstLinePoint.Z());
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setZ(m_firstLinePoint.Z());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setY(m_firstLinePoint.Y());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) worldPos.setZ(m_firstLinePoint.Z());
} else if (m_viewport->isSnappingVertical()) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setX(m_firstLinePoint.X());
@@ -165,9 +165,9 @@ void LineTool::mouseMoveEvent(QMouseEvent *event)
double angle = 0;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
angle = atan2(delta.y(), delta.x());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
angle = atan2(delta.z(), delta.x());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
angle = atan2(delta.y(), delta.x());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
angle = atan2(delta.z(), delta.y());
}
@@ -214,17 +214,17 @@ void LineTool::finalizeCreation()
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, 1, 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.y(), mouseVec.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x()));
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.y(), refDir.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
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;
@@ -241,8 +241,8 @@ void LineTool::finalizeCreation()
}
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
QVector3D finalDir;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0);
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad));
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;
@@ -312,7 +312,7 @@ void LineTool::paintGL()
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
refDir = QVector3D(1, 0, 0);
} else { // YZ
refDir = QVector3D(0, 1, 0);
refDir = QVector3D(0, 0, -1);
}
}
@@ -321,13 +321,13 @@ void LineTool::paintGL()
// Quadrant snapping
double mouseAngle;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVec.y(), mouseVec.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x()));
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.y(), refDir.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
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;
@@ -347,8 +347,8 @@ void LineTool::paintGL()
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
QVector3D finalDir;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0);
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad));
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;
@@ -380,8 +380,8 @@ void LineTool::paintGL()
} else if (m_viewport->isSnappingVertex()) {
worldPos.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z());
} else if (m_viewport->isSnappingHorizontal()) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setY(m_firstLinePoint.Y());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setZ(m_firstLinePoint.Z());
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setZ(m_firstLinePoint.Z());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setY(m_firstLinePoint.Y());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) worldPos.setZ(m_firstLinePoint.Z());
} else if (m_viewport->isSnappingVertical()) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setX(m_firstLinePoint.X());
@@ -410,7 +410,7 @@ void LineTool::paintGL()
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, 1, 0);
else refDir = QVector3D(0, 0, -1);
}
if (angleFromInput) {
@@ -418,13 +418,13 @@ void LineTool::paintGL()
QVector3D mouseVec = currentMouseWorldPos - startPos;
double mouseAngle;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVec.y(), mouseVec.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x()));
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 refAngleForQuadrant;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.y(), refDir.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.y(), refDir.x()));
else refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.z(), refDir.y()));
double relativeMouseAngle = mouseAngle - refAngleForQuadrant;
@@ -441,11 +441,11 @@ void LineTool::paintGL()
}
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
refAngle = atan2(refDir.y(), refDir.x());
lineAngle = atan2(lineVec.y(), lineVec.x());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
refAngle = atan2(refDir.z(), refDir.x());
lineAngle = atan2(lineVec.z(), lineVec.x());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
refAngle = atan2(refDir.y(), refDir.x());
lineAngle = atan2(lineVec.y(), lineVec.x());
} else { // YZ
refAngle = atan2(refDir.z(), refDir.y());
lineAngle = atan2(lineVec.z(), lineVec.y());
@@ -461,9 +461,9 @@ void LineTool::paintGL()
QVector3D perpVec;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
perpVec = QVector3D(-lineVec.y(), lineVec.x(), 0).normalized();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
perpVec = QVector3D(-lineVec.z(), 0, lineVec.x()).normalized();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
perpVec = QVector3D(-lineVec.y(), lineVec.x(), 0).normalized();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
perpVec = QVector3D(0, -lineVec.z(), lineVec.y()).normalized();
}
@@ -513,8 +513,8 @@ void LineTool::paintGL()
for (int i = 0; i <= numSegments; ++i) {
double angle = refAngle + (lineAngle - refAngle) * i / numSegments;
QVector3D p;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) p = startPos + radius * QVector3D(cos(angle), sin(angle), 0);
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) p = startPos + radius * QVector3D(cos(angle), 0, sin(angle));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) p = startPos + radius * QVector3D(cos(angle), 0, sin(angle));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) p = startPos + radius * QVector3D(cos(angle), sin(angle), 0);
else p = startPos + radius * QVector3D(0, cos(angle), sin(angle));
vertices << p.x() << p.y() << p.z();
}
@@ -535,11 +535,11 @@ void LineTool::paintGL()
double endAngle = lineAngle;
QVector3D radialDir_end, tangentDir_end;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
radialDir_end = QVector3D(cos(endAngle), sin(endAngle), 0);
tangentDir_end = QVector3D(-sin(endAngle), cos(endAngle), 0);
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
radialDir_end = QVector3D(cos(endAngle), 0, sin(endAngle));
tangentDir_end = QVector3D(-sin(endAngle), 0, cos(endAngle));
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
radialDir_end = QVector3D(cos(endAngle), sin(endAngle), 0);
tangentDir_end = QVector3D(-sin(endAngle), cos(endAngle), 0);
} else {
radialDir_end = QVector3D(0, cos(endAngle), sin(endAngle));
tangentDir_end = QVector3D(0, -sin(endAngle), cos(endAngle));
@@ -555,11 +555,11 @@ void LineTool::paintGL()
double startAngle = refAngle;
QVector3D radialDir_start, tangentDir_start;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
radialDir_start = QVector3D(cos(startAngle), sin(startAngle), 0);
tangentDir_start = QVector3D(-sin(startAngle), cos(startAngle), 0);
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
radialDir_start = QVector3D(cos(startAngle), 0, sin(startAngle));
tangentDir_start = QVector3D(-sin(startAngle), 0, cos(startAngle));
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
radialDir_start = QVector3D(cos(startAngle), sin(startAngle), 0);
tangentDir_start = QVector3D(-sin(startAngle), cos(startAngle), 0);
} else {
radialDir_start = QVector3D(0, cos(startAngle), sin(startAngle));
tangentDir_start = QVector3D(0, -sin(startAngle), cos(startAngle));
@@ -584,22 +584,22 @@ void LineTool::paintGL()
const float indicatorOffset = 0.02f * -m_viewport->camera()->zoom();
if (m_viewport->isSnappingHorizontal()) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
vertices << midPoint.x() - indicatorSize << midPoint.y() + indicatorOffset << midPoint.z();
vertices << midPoint.x() + indicatorSize << midPoint.y() + indicatorOffset << midPoint.z();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
vertices << midPoint.x() - indicatorSize << midPoint.y() << midPoint.z() + indicatorOffset;
vertices << midPoint.x() + indicatorSize << midPoint.y() << midPoint.z() + indicatorOffset;
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
vertices << midPoint.x() - indicatorSize << midPoint.y() + indicatorOffset << midPoint.z();
vertices << midPoint.x() + indicatorSize << midPoint.y() + indicatorOffset << midPoint.z();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
vertices << midPoint.x() << midPoint.y() - indicatorSize << midPoint.z() + indicatorOffset;
vertices << midPoint.x() << midPoint.y() + indicatorSize << midPoint.z() + indicatorOffset;
}
} else { // m_isSnappingVertical
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
vertices << midPoint.x() + indicatorOffset << midPoint.y() - indicatorSize << midPoint.z();
vertices << midPoint.x() + indicatorOffset << midPoint.y() + indicatorSize << midPoint.z();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
vertices << midPoint.x() + indicatorOffset << midPoint.y() << midPoint.z() - indicatorSize;
vertices << midPoint.x() + indicatorOffset << midPoint.y() << midPoint.z() + indicatorSize;
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
vertices << midPoint.x() + indicatorOffset << midPoint.y() - indicatorSize << midPoint.z();
vertices << midPoint.x() + indicatorOffset << midPoint.y() + indicatorSize << midPoint.z();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
vertices << midPoint.x() << midPoint.y() + indicatorOffset << midPoint.z() - indicatorSize;
vertices << midPoint.x() << midPoint.y() + indicatorOffset << midPoint.z() + indicatorSize;
@@ -647,7 +647,7 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
refDir = QVector3D(1, 0, 0);
} else { // YZ
refDir = QVector3D(0, 1, 0);
refDir = QVector3D(0, 0, -1);
}
}
@@ -655,13 +655,13 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
QVector3D mouseVec = currentMouseWorldPos - startPos;
double mouseAngle;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVec.y(), mouseVec.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x()));
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.y(), refDir.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
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;
@@ -681,8 +681,8 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
QVector3D finalDir;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0);
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad));
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));
if (lengthFromInput) {
@@ -714,8 +714,8 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
} else if (m_viewport->isSnappingVertex()) {
worldPos.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z());
} else if (m_viewport->isSnappingHorizontal()) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setY(m_firstLinePoint.Y());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setZ(m_firstLinePoint.Z());
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setZ(m_firstLinePoint.Z());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setY(m_firstLinePoint.Y());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) worldPos.setZ(m_firstLinePoint.Z());
} else if (m_viewport->isSnappingVertical()) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setX(m_firstLinePoint.X());
@@ -733,7 +733,7 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
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, 1, 0);
else refDir = QVector3D(0, 0, -1);
}
QVector3D currentMouseWorldPosForText = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
@@ -742,13 +742,13 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
if (angleFromInput) {
if (mouseVecForText.length() > 1e-6) {
double mouseAngle;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVecForText.y(), mouseVecForText.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVecForText.z(), mouseVecForText.x()));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVecForText.z(), mouseVecForText.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVecForText.y(), mouseVecForText.x()));
else mouseAngle = qRadiansToDegrees(atan2(mouseVecForText.z(), mouseVecForText.y()));
double refAngleForQuadrant;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.y(), refDir.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.y(), refDir.x()));
else refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.z(), refDir.y()));
double relativeMouseAngle = mouseAngle - refAngleForQuadrant;
@@ -766,11 +766,11 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
}
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
refAngle = atan2(refDir.y(), refDir.x());
lineAngle = atan2(lineVec.y(), lineVec.x());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
refAngle = atan2(refDir.z(), refDir.x());
lineAngle = atan2(lineVec.z(), lineVec.x());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
refAngle = atan2(refDir.y(), refDir.x());
lineAngle = atan2(lineVec.y(), lineVec.x());
} else { // YZ
refAngle = atan2(refDir.z(), refDir.y());
lineAngle = atan2(lineVec.z(), lineVec.y());
@@ -783,9 +783,9 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
QVector3D perpVec;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
perpVec = QVector3D(-lineVec.y(), lineVec.x(), 0).normalized();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
perpVec = QVector3D(-lineVec.z(), 0, lineVec.x()).normalized();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
perpVec = QVector3D(-lineVec.y(), lineVec.x(), 0).normalized();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
perpVec = QVector3D(0, -lineVec.z(), lineVec.y()).normalized();
}
@@ -831,8 +831,8 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
QVector3D textPos3DAngle;
float textOffset = 0.035f * -m_viewport->camera()->zoom();
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) textPos3DAngle = startPos + (radius + textOffset) * QVector3D(cos(midAngle), sin(midAngle), 0);
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) textPos3DAngle = startPos + (radius + textOffset) * QVector3D(cos(midAngle), 0, sin(midAngle));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) textPos3DAngle = startPos + (radius + textOffset) * QVector3D(cos(midAngle), 0, sin(midAngle));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) textPos3DAngle = startPos + (radius + textOffset) * QVector3D(cos(midAngle), sin(midAngle), 0);
else textPos3DAngle = startPos + (radius + textOffset) * QVector3D(0, cos(midAngle), sin(midAngle));
QVector3D screenPosAngle = m_viewport->project(textPos3DAngle, modelView, projection, m_viewport->rect());

View File

@@ -4,8 +4,6 @@
#include "SketchFeature.h"
#include "Feature.h"
#include "ApplicationController.h"
#include "DebugWindow.h"
#include "Camera.h"
#include <QMenuBar>
#include <QMenu>
@@ -21,7 +19,6 @@
#include <QStringList>
#include <QKeyEvent>
#include <QApplication>
#include <QProcessEnvironment>
MainWindow::MainWindow(ApplicationController* appController, QWidget *parent)
: QMainWindow(parent)
@@ -44,10 +41,6 @@ MainWindow::MainWindow(ApplicationController* appController, QWidget *parent)
QAction *saveAsAction = fileMenu->addAction("Save &As...");
connect(saveAsAction, &QAction::triggered, this, &MainWindow::saveAs);
QMenu *helpMenu = menuBar()->addMenu("&Help");
QAction *debugAction = helpMenu->addAction("&Debug");
connect(debugAction, &QAction::triggered, this, &MainWindow::showDebugWindow);
QToolBar* mainToolBar = addToolBar("Main Toolbar");
mainToolBar->setMovable(false);
@@ -158,13 +151,6 @@ MainWindow::MainWindow(ApplicationController* appController, QWidget *parent)
connect(m_viewport, &ViewportWidget::planeSelected, m_appController, &ApplicationController::onPlaneSelected);
connect(m_viewport, &ViewportWidget::toolDeactivated, m_appController, [this]() { m_appController->setActiveTool(ApplicationController::ToolType::None); });
connect(m_viewport->camera(), &Camera::cameraChanged, this, &MainWindow::updateDebugInfo);
m_debugWindow = new DebugWindow(this);
if (QProcessEnvironment::systemEnvironment().value("DEBUG") == "true") {
showDebugWindow();
}
updateWindowTitle(QString());
}
@@ -198,17 +184,6 @@ bool MainWindow::saveAs()
return m_appController->saveDocumentAs();
}
void MainWindow::showDebugWindow()
{
updateDebugInfo();
m_debugWindow->show();
}
void MainWindow::updateDebugInfo()
{
m_debugWindow->updateCameraInfo(m_viewport->camera());
}
void MainWindow::enterSketchMode()
{
m_tabWidget->removeTab(m_tabWidget->indexOf(m_toolsTab));

View File

@@ -10,7 +10,6 @@ class Feature;
class QTabWidget;
class QWidget;
class ApplicationController;
class DebugWindow;
class MainWindow : public QMainWindow
{
@@ -27,9 +26,6 @@ private slots:
void createSketch();
void saveSketch();
void showDebugWindow();
void updateDebugInfo();
void enterSketchMode();
void exitSketchMode();
void updateWindowTitle(const QString& filePath);
@@ -40,7 +36,6 @@ protected:
private:
ApplicationController* m_appController;
ViewportWidget *m_viewport;
DebugWindow* m_debugWindow;
QTabWidget *m_tabWidget;
QWidget *m_solidTab;

View File

@@ -69,10 +69,10 @@ void RectangleTool::mousePressEvent(QMouseEvent *event)
double current_w, current_h;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.y());
current_h = qAbs(mouseDir.z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.z());
current_h = qAbs(mouseDir.y());
} else { // YZ
current_w = qAbs(mouseDir.y());
current_h = qAbs(mouseDir.z());
@@ -85,10 +85,10 @@ void RectangleTool::mousePressEvent(QMouseEvent *event)
worldPos = startPos;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
worldPos.setX(startPos.x() + signX * rect_w);
worldPos.setY(startPos.y() + signY * rect_h);
worldPos.setZ(startPos.z() + signZ * rect_h);
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
worldPos.setX(startPos.x() + signX * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
worldPos.setY(startPos.y() + signY * rect_h);
} else { // YZ
worldPos.setY(startPos.y() + signY * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
@@ -140,10 +140,10 @@ void RectangleTool::finalizeCreation()
double current_w, current_h;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.y());
current_h = qAbs(mouseDir.z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.z());
current_h = qAbs(mouseDir.y());
} else { // YZ
current_w = qAbs(mouseDir.y());
current_h = qAbs(mouseDir.z());
@@ -156,10 +156,10 @@ void RectangleTool::finalizeCreation()
worldPos = startPos;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
worldPos.setX(startPos.x() + signX * rect_w);
worldPos.setY(startPos.y() + signY * rect_h);
worldPos.setZ(startPos.z() + signZ * rect_h);
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
worldPos.setX(startPos.x() + signX * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
worldPos.setY(startPos.y() + signY * rect_h);
} else { // YZ
worldPos.setY(startPos.y() + signY * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
@@ -206,10 +206,10 @@ void RectangleTool::paintGL()
double current_w, current_h;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.y());
current_h = qAbs(mouseDir.z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.z());
current_h = qAbs(mouseDir.y());
} else { // YZ
current_w = qAbs(mouseDir.y());
current_h = qAbs(mouseDir.z());
@@ -222,10 +222,10 @@ void RectangleTool::paintGL()
worldPos = startPos;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
worldPos.setX(startPos.x() + signX * rect_w);
worldPos.setY(startPos.y() + signY * rect_h);
worldPos.setZ(startPos.z() + signZ * rect_h);
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
worldPos.setX(startPos.x() + signX * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
worldPos.setY(startPos.y() + signY * rect_h);
} else { // YZ
worldPos.setY(startPos.y() + signY * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
@@ -245,10 +245,10 @@ void RectangleTool::paintGL()
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
p2.setX(p3.x()); p2.setY(p1.y()); p2.setZ(p1.z());
p4.setX(p1.x()); p4.setY(p3.y()); p4.setZ(p1.z());
p4.setX(p1.x()); p4.setY(p1.y()); p4.setZ(p3.z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
p2.setX(p3.x()); p2.setY(p1.y()); p2.setZ(p1.z());
p4.setX(p1.x()); p4.setY(p1.y()); p4.setZ(p3.z());
p4.setX(p1.x()); p4.setY(p3.y()); p4.setZ(p1.z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
p2.setX(p1.x()); p2.setY(p3.y()); p2.setZ(p1.z());
p4.setX(p1.x()); p4.setY(p1.y()); p4.setZ(p3.z());
@@ -300,10 +300,10 @@ void RectangleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, cons
double current_w, current_h;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.y());
current_h = qAbs(mouseDir.z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.z());
current_h = qAbs(mouseDir.y());
} else { // YZ
current_w = qAbs(mouseDir.y());
current_h = qAbs(mouseDir.z());
@@ -316,10 +316,10 @@ void RectangleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, cons
worldPos = p1_3d;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
worldPos.setX(p1_3d.x() + signX * rect_w);
worldPos.setY(p1_3d.y() + signY * rect_h);
worldPos.setZ(p1_3d.z() + signZ * rect_h);
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
worldPos.setX(p1_3d.x() + signX * rect_w);
worldPos.setZ(p1_3d.z() + signZ * rect_h);
worldPos.setY(p1_3d.y() + signY * rect_h);
} else { // YZ
worldPos.setY(p1_3d.y() + signY * rect_w);
worldPos.setZ(p1_3d.z() + signZ * rect_h);
@@ -338,15 +338,15 @@ void RectangleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, cons
double w, h;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
p2_3d.setX(p3_3d.x()); p2_3d.setY(p1_3d.y()); p2_3d.setZ(p1_3d.z());
p4_3d.setX(p1_3d.x()); p4_3d.setY(p3_3d.y()); p4_3d.setZ(p1_3d.z());
w = qAbs(p3_3d.x() - p1_3d.x());
h = qAbs(p3_3d.y() - p1_3d.y());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
p2_3d.setX(p3_3d.x()); p2_3d.setY(p1_3d.y()); p2_3d.setZ(p1_3d.z());
p4_3d.setX(p1_3d.x()); p4_3d.setY(p1_3d.y()); p4_3d.setZ(p3_3d.z());
w = qAbs(p3_3d.x() - p1_3d.x());
h = qAbs(p3_3d.z() - p1_3d.z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
p2_3d.setX(p3_3d.x()); p2_3d.setY(p1_3d.y()); p2_3d.setZ(p1_3d.z());
p4_3d.setX(p1_3d.x()); p4_3d.setY(p3_3d.y()); p4_3d.setZ(p1_3d.z());
w = qAbs(p3_3d.x() - p1_3d.x());
h = qAbs(p3_3d.y() - p1_3d.y());
} else { // YZ
p2_3d.setX(p1_3d.x()); p2_3d.setY(p3_3d.y()); p2_3d.setZ(p1_3d.z());
p4_3d.setX(p1_3d.x()); p4_3d.setY(p1_3d.y()); p4_3d.setZ(p3_3d.z());

View File

@@ -2,8 +2,24 @@
#include "SketchObject.h"
#include "SketchLine.h"
#include "SketchRectangle.h"
#include "SketchCircle.h"
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRep_Builder.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS.hxx>
#include <gp_Circ.hxx>
#include <gp_Ax2.hxx>
#include <TopExp_Explorer.hxx>
#include <ShapeAnalysis_FreeBounds.hxx>
#include <gp_Pln.hxx>
#include <BRepOffsetAPI_MakeFilling.hxx>
#include <GeomAbs_Shape.hxx>
#include <QJsonArray>
#include <QDebug>
SketchFeature::SketchFeature(const QString& name)
: Feature(name)
@@ -35,6 +51,119 @@ const TopoDS_Shape& SketchFeature::shape() const
return m_shape;
}
void SketchFeature::buildShape()
{
m_shape.Nullify();
QList<TopoDS_Edge> lineEdges;
QList<TopoDS_Face> faces;
gp_Pln sketchPlane;
switch (m_plane) {
case SketchPlane::XY: sketchPlane = gp_Pln(gp::Origin(), gp::DY()); break;
case SketchPlane::XZ: sketchPlane = gp_Pln(gp::Origin(), gp::DZ()); break;
case SketchPlane::YZ: sketchPlane = gp_Pln(gp::Origin(), gp::DX()); break;
}
for (SketchObject* obj : m_objects) {
if (auto line = dynamic_cast<SketchLine*>(obj)) {
BRepBuilderAPI_MakeEdge makeEdge(line->startPoint(), line->endPoint());
if (makeEdge.IsDone()) {
lineEdges.append(makeEdge.Edge());
}
} else if (auto rect = dynamic_cast<SketchRectangle*>(obj)) {
const gp_Pnt& c1 = rect->corner1();
const gp_Pnt& c2 = rect->corner2();
gp_Pnt other_corner1, other_corner2;
if (m_plane == SketchPlane::XY) {
other_corner1.SetCoord(c2.X(), c1.Y(), c1.Z());
other_corner2.SetCoord(c1.X(), c1.Y(), c2.Z());
} else if (m_plane == SketchPlane::XZ) {
other_corner1.SetCoord(c2.X(), c1.Y(), c1.Z());
other_corner2.SetCoord(c1.X(), c2.Y(), c1.Z());
} else { // YZ
other_corner1.SetCoord(c1.X(), c2.Y(), c1.Z());
other_corner2.SetCoord(c1.X(), c1.Y(), c2.Z());
}
BRepBuilderAPI_MakeEdge me1(c1, other_corner1);
BRepBuilderAPI_MakeEdge me2(other_corner1, c2);
BRepBuilderAPI_MakeEdge me3(c2, other_corner2);
BRepBuilderAPI_MakeEdge me4(other_corner2, c1);
if (me1.IsDone() && me2.IsDone() && me3.IsDone() && me4.IsDone()) {
BRepBuilderAPI_MakeWire wireBuilder(me1.Edge(), me2.Edge(), me3.Edge(), me4.Edge());
if (wireBuilder.IsDone()) {
BRepBuilderAPI_MakeFace faceBuilder(sketchPlane, wireBuilder.Wire());
if (faceBuilder.IsDone()) {
faces.append(faceBuilder.Face());
}
}
}
} else if (auto circle = dynamic_cast<SketchCircle*>(obj)) {
const gp_Pnt& center = circle->center();
double radius = circle->radius();
gp_Dir normal;
switch (m_plane) {
case SketchPlane::XY: normal = gp::DY(); break;
case SketchPlane::XZ: normal = gp::DZ(); break;
case SketchPlane::YZ: normal = gp::DX(); break;
}
gp_Ax2 axis(center, normal);
gp_Circ circ(axis, radius);
BRepBuilderAPI_MakeEdge makeEdge(circ);
if (makeEdge.IsDone()) {
TopoDS_Edge edge = makeEdge.Edge();
BRepBuilderAPI_MakeWire wireBuilder(edge);
if(wireBuilder.IsDone()) {
BRepBuilderAPI_MakeFace faceBuilder(sketchPlane, wireBuilder.Wire());
if (faceBuilder.IsDone()) {
faces.append(faceBuilder.Face());
}
}
}
}
}
if (!lineEdges.isEmpty()) {
qDebug() << "buildShape: processing" << lineEdges.size() << "line edges";
BRepOffsetAPI_MakeFilling faceMaker;
for (const TopoDS_Edge& edge : lineEdges) {
faceMaker.Add(edge, GeomAbs_C0);
}
faceMaker.Build();
if (faceMaker.IsDone()) {
TopExp_Explorer explorer(faceMaker.Shape(), TopAbs_FACE);
int facesAdded = 0;
for (; explorer.More(); explorer.Next()) {
faces.append(TopoDS::Face(explorer.Current()));
facesAdded++;
}
qDebug() << "buildShape: added" << facesAdded << "face(s) using MakeFilling";
} else {
qDebug() << "buildShape: MakeFilling failed";
}
}
qDebug() << "buildShape: total faces created:" << faces.size();
if (faces.isEmpty()) {
return;
}
if (faces.size() == 1) {
m_shape = faces.first();
} else {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for (const auto& face : faces) {
builder.Add(compound, face);
}
m_shape = compound;
}
}
void SketchFeature::addObject(SketchObject* object)
{
m_objects.append(object);

View File

@@ -26,6 +26,8 @@ public:
const TopoDS_Shape& shape() const;
void buildShape();
void addObject(SketchObject* object);
const QList<SketchObject*>& objects() const;

View File

@@ -23,9 +23,9 @@ GridParams getGridParams(float distance)
} else if (distance > 50.0f) {
return { 5.0f, 25.0f, 1000 };
} else if (distance > 10.0f) {
return { 1.0f, 5.0f, 100 };
return { 1.0f, 5.0f, 1000 };
} else { // zoomed in
return { 0.2f, 1.0f, 10 };
return { 0.2f, 1.0f, 1000 };
}
}
} // namespace
@@ -87,11 +87,11 @@ void SketchGrid::drawGridLines(SketchPlane plane, QOpenGLShaderProgram* shaderPr
float pos = i * minorIncrement;
QVector<GLfloat>& current_vector = (i % 5 == 0) ? majorLines : minorLines;
if (plane == XY) {
current_vector << pos << -gridSize << 0 << pos << gridSize << 0;
current_vector << -gridSize << pos << 0 << gridSize << pos << 0;
} else if (plane == XZ) {
current_vector << pos << 0 << -gridSize << pos << 0 << gridSize;
current_vector << -gridSize << 0 << pos << gridSize << 0 << pos;
} else if (plane == XZ) {
current_vector << pos << -gridSize << 0 << pos << gridSize << 0;
current_vector << -gridSize << pos << 0 << gridSize << pos << 0;
} else { // YZ
current_vector << 0 << pos << -gridSize << 0 << pos << gridSize;
current_vector << 0 << -gridSize << pos << 0 << gridSize << pos;
@@ -133,7 +133,7 @@ void SketchGrid::drawAxes(SketchPlane plane, QOpenGLShaderProgram* shaderProgram
// Y Axis (Green)
if (plane == XY || plane == YZ) {
vertices.clear();
vertices << 0 << -axisLength << 0 << 0 << axisLength << 0;
vertices << 0 << 0 << -axisLength << 0 << 0 << axisLength;
shaderProgram->setUniformValue(colorLoc, QVector4D(0.0f, 1.0f, 0.0f, 1.0f));
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glDrawArrays(GL_LINES, 0, 2);
@@ -141,7 +141,7 @@ void SketchGrid::drawAxes(SketchPlane plane, QOpenGLShaderProgram* shaderProgram
// Z Axis (Blue)
if (plane == XZ || plane == YZ) {
vertices.clear();
vertices << 0 << 0 << -axisLength << 0 << 0 << axisLength;
vertices << 0 << -axisLength << 0 << 0 << axisLength << 0;
shaderProgram->setUniformValue(colorLoc, QVector4D(0.0f, 0.0f, 1.0f, 1.0f));
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glDrawArrays(GL_LINES, 0, 2);
@@ -184,10 +184,10 @@ void SketchGrid::paintAxisLabels(QPainter& painter, SketchGrid::SketchPlane plan
if (plane == SketchGrid::XY) {
drawLabelsForAxis(0); // X
drawLabelsForAxis(1); // Y
drawLabelsForAxis(2); // Y
} else if (plane == SketchGrid::XZ) {
drawLabelsForAxis(0); // X
drawLabelsForAxis(2); // Z
drawLabelsForAxis(1); // Z
} else if (plane == SketchGrid::YZ) {
drawLabelsForAxis(1); // Y
drawLabelsForAxis(2); // Z

View File

@@ -29,10 +29,10 @@ bool Snapping::update(const QPoint& mousePos)
switch (m_viewport->currentPlane()) {
case ViewportWidget::SketchPlane::XY:
shouldSnap = qAbs(worldPos.x()) < snapRectHalfSize && qAbs(worldPos.y()) < snapRectHalfSize;
shouldSnap = qAbs(worldPos.x()) < snapRectHalfSize && qAbs(worldPos.z()) < snapRectHalfSize;
break;
case ViewportWidget::SketchPlane::XZ:
shouldSnap = qAbs(worldPos.x()) < snapRectHalfSize && qAbs(worldPos.z()) < snapRectHalfSize;
shouldSnap = qAbs(worldPos.x()) < snapRectHalfSize && qAbs(worldPos.y()) < snapRectHalfSize;
break;
case ViewportWidget::SketchPlane::YZ:
shouldSnap = qAbs(worldPos.y()) < snapRectHalfSize && qAbs(worldPos.z()) < snapRectHalfSize;
@@ -62,10 +62,10 @@ bool Snapping::update(const QPoint& mousePos)
bool isClose = false;
switch (m_viewport->currentPlane()) {
case ViewportWidget::SketchPlane::XY:
isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize;
isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize;
break;
case ViewportWidget::SketchPlane::XZ:
isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize;
isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize;
break;
case ViewportWidget::SketchPlane::YZ:
isClose = qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize;
@@ -88,10 +88,10 @@ bool Snapping::update(const QPoint& mousePos)
if (sketch->plane() == SketchFeature::SketchPlane::XY) {
p2.SetCoord(p3.X(), p1.Y(), p1.Z());
p4.SetCoord(p1.X(), p3.Y(), p1.Z());
p4.SetCoord(p1.X(), p1.Y(), p3.Z());
} else if (sketch->plane() == SketchFeature::SketchPlane::XZ) {
p2.SetCoord(p3.X(), p1.Y(), p1.Z());
p4.SetCoord(p1.X(), p1.Y(), p3.Z());
p4.SetCoord(p1.X(), p3.Y(), p1.Z());
} else if (sketch->plane() == SketchFeature::SketchPlane::YZ) {
p2.SetCoord(p1.X(), p3.Y(), p1.Z());
p4.SetCoord(p1.X(), p1.Y(), p3.Z());
@@ -102,10 +102,10 @@ bool Snapping::update(const QPoint& mousePos)
bool isClose = false;
switch (m_viewport->currentPlane()) {
case ViewportWidget::SketchPlane::XY:
isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize;
isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize;
break;
case ViewportWidget::SketchPlane::XZ:
isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize;
isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize;
break;
case ViewportWidget::SketchPlane::YZ:
isClose = qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize;
@@ -140,15 +140,15 @@ void Snapping::paintGL() const
if (m_isSnappingOrigin) {
const float rectSize = 0.0075f * -m_viewport->camera()->zoom();
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
vertices << -rectSize << -rectSize << 0 << rectSize << -rectSize << 0;
vertices << rectSize << -rectSize << 0 << rectSize << rectSize << 0;
vertices << rectSize << rectSize << 0 << -rectSize << rectSize << 0;
vertices << -rectSize << rectSize << 0 << -rectSize << -rectSize << 0;
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
vertices << -rectSize << 0 << -rectSize << rectSize << 0 << -rectSize;
vertices << rectSize << 0 << -rectSize << rectSize << 0 << rectSize;
vertices << rectSize << 0 << rectSize << -rectSize << 0 << rectSize;
vertices << -rectSize << 0 << rectSize << -rectSize << 0 << -rectSize;
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
vertices << -rectSize << -rectSize << 0 << rectSize << -rectSize << 0;
vertices << rectSize << -rectSize << 0 << rectSize << rectSize << 0;
vertices << rectSize << rectSize << 0 << -rectSize << rectSize << 0;
vertices << -rectSize << rectSize << 0 << -rectSize << -rectSize << 0;
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
vertices << 0 << -rectSize << -rectSize << 0 << rectSize << -rectSize;
vertices << 0 << rectSize << -rectSize << 0 << rectSize << rectSize;
@@ -159,15 +159,15 @@ void Snapping::paintGL() const
const float rectSize = 0.0075f * -m_viewport->camera()->zoom();
const auto& v = m_snapVertex;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
vertices << v.X() - rectSize << v.Y() - rectSize << v.Z() << v.X() + rectSize << v.Y() - rectSize << v.Z();
vertices << v.X() + rectSize << v.Y() - rectSize << v.Z() << v.X() + rectSize << v.Y() + rectSize << v.Z();
vertices << v.X() + rectSize << v.Y() + rectSize << v.Z() << v.X() - rectSize << v.Y() + rectSize << v.Z();
vertices << v.X() - rectSize << v.Y() + rectSize << v.Z() << v.X() - rectSize << v.Y() - rectSize << v.Z();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
vertices << v.X() - rectSize << v.Y() << v.Z() - rectSize << v.X() + rectSize << v.Y() << v.Z() - rectSize;
vertices << v.X() + rectSize << v.Y() << v.Z() - rectSize << v.X() + rectSize << v.Y() << v.Z() + rectSize;
vertices << v.X() + rectSize << v.Y() << v.Z() + rectSize << v.X() - rectSize << v.Y() << v.Z() + rectSize;
vertices << v.X() - rectSize << v.Y() << v.Z() + rectSize << v.X() - rectSize << v.Y() << v.Z() - rectSize;
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
vertices << v.X() - rectSize << v.Y() - rectSize << v.Z() << v.X() + rectSize << v.Y() - rectSize << v.Z();
vertices << v.X() + rectSize << v.Y() - rectSize << v.Z() << v.X() + rectSize << v.Y() + rectSize << v.Z();
vertices << v.X() + rectSize << v.Y() + rectSize << v.Z() << v.X() - rectSize << v.Y() + rectSize << v.Z();
vertices << v.X() - rectSize << v.Y() + rectSize << v.Z() << v.X() - rectSize << v.Y() - rectSize << v.Z();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
vertices << v.X() << v.Y() - rectSize << v.Z() - rectSize << v.X() << v.Y() + rectSize << v.Z() - rectSize;
vertices << v.X() << v.Y() + rectSize << v.Z() - rectSize << v.X() << v.Y() + rectSize << v.Z() + rectSize;

View File

@@ -7,7 +7,6 @@
#include <QScreen>
#include <QSvgRenderer>
#include <QVector>
#include <QVector3D>
namespace
{
@@ -75,35 +74,6 @@ void ViewCube::paintGL(QOpenGLShaderProgram* simpleShader, int simpleShaderColor
drawViewCube(viewCubeProjection, viewMatrix, opacity);
drawAxes(simpleShader, simpleShaderColorLoc, viewCubeProjection, viewMatrix);
QMatrix4x4 mvp = viewCubeProjection * viewMatrix;
const float axisLen = 1.7f;
QVector3D xAxisEnd(axisLen, 0.0f, 0.0f);
QVector3D yAxisEnd(0.0f, 0.0f, axisLen);
QVector3D zAxisEnd(0.0f, axisLen, 0.0f);
QVector3D xAxisNdc = mvp.map(xAxisEnd);
QVector3D yAxisNdc = mvp.map(yAxisEnd);
QVector3D zAxisNdc = mvp.map(zAxisEnd);
const int vpX = width - viewCubeSize;
const int vpY = 0;
const int vpW = viewCubeSize;
const int vpH = viewCubeSize;
const float dpr = QGuiApplication::primaryScreen()->devicePixelRatio();
m_xAxisLabelPos.setX( (xAxisNdc.x() + 1.0f) * vpW / 2.0f + vpX );
m_xAxisLabelPos.setY( (1.0f - xAxisNdc.y()) * vpH / 2.0f + vpY );
m_xAxisLabelPos /= dpr;
m_yAxisLabelPos.setX( (yAxisNdc.x() + 1.0f) * vpW / 2.0f + vpX );
m_yAxisLabelPos.setY( (1.0f - yAxisNdc.y()) * vpH / 2.0f + vpY );
m_yAxisLabelPos /= dpr;
m_zAxisLabelPos.setX( (zAxisNdc.x() + 1.0f) * vpW / 2.0f + vpX );
m_zAxisLabelPos.setY( (1.0f - zAxisNdc.y()) * vpH / 2.0f + vpY );
m_zAxisLabelPos /= dpr;
glDisable(GL_BLEND);
}
@@ -259,23 +229,6 @@ void ViewCube::drawAxes(QOpenGLShaderProgram* simpleShader, int colorLoc, const
void ViewCube::paint2D(QPainter& painter, int widgetWidth, int widgetHeight)
{
QFont font("Arial", 10, QFont::Bold);
painter.setFont(font);
painter.setPen(Qt::white);
QFontMetrics fm(font);
QRect xRect = fm.boundingRect("X");
xRect.moveCenter(m_xAxisLabelPos);
painter.drawText(xRect, Qt::AlignCenter, "X");
QRect yRect = fm.boundingRect("Y");
yRect.moveCenter(m_yAxisLabelPos);
painter.drawText(yRect, Qt::AlignCenter, "Y");
QRect zRect = fm.boundingRect("Z");
zRect.moveCenter(m_zAxisLabelPos);
painter.drawText(zRect, Qt::AlignCenter, "Z");
if (!m_isHovered) {
return;
}

View File

@@ -34,10 +34,6 @@ private:
QRect m_homeButtonRect;
QSvgRenderer* m_homeButtonRenderer = nullptr;
QPoint m_xAxisLabelPos;
QPoint m_yAxisLabelPos;
QPoint m_zAxisLabelPos;
QOpenGLTexture* m_faceTextures[6];
QOpenGLShaderProgram* m_textureShaderProgram = nullptr;

View File

@@ -30,6 +30,15 @@
#include <QVector>
#include <map>
#include <BRepMesh_IncrementalMesh.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Face.hxx>
#include <Poly_Triangulation.hxx>
#include <BRep_Tool.hxx>
#include <gp_Dir.hxx>
#include <gp_Trsf.hxx>
struct PntComparator {
bool operator()(const gp_Pnt& a, const gp_Pnt& b) const {
// A tolerance is needed for floating point comparisons
@@ -72,6 +81,7 @@ ViewportWidget::~ViewportWidget()
{
makeCurrent();
delete m_shaderProgram;
delete m_litShaderProgram;
delete m_viewCube;
delete m_sketchGrid;
m_vbo.destroy();
@@ -489,8 +499,8 @@ QVector3D ViewportWidget::unproject(const QPoint& screenPos, SketchPlane plane)
QVector3D planeNormal;
switch (plane) {
case SketchPlane::XY: planeNormal = QVector3D(0, 0, 1); break;
case SketchPlane::XZ: planeNormal = QVector3D(0, 1, 0); break;
case SketchPlane::XY: planeNormal = QVector3D(0, 1, 0); break;
case SketchPlane::XZ: planeNormal = QVector3D(0, 0, 1); break;
case SketchPlane::YZ: planeNormal = QVector3D(1, 0, 0); break;
case SketchPlane::NONE: return QVector3D();
}
@@ -532,15 +542,15 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch)
const int numSegments = 64;
QVector3D u_axis, v_axis;
switch (sketch->plane()) {
case SketchFeature::SketchPlane::XY: // Top
u_axis = QVector3D(1, 0, 0);
v_axis = QVector3D(0, 1, 0);
break;
case SketchFeature::SketchPlane::XZ: // Front
case SketchFeature::SketchPlane::XY:
u_axis = QVector3D(1, 0, 0);
v_axis = QVector3D(0, 0, 1);
break;
case SketchFeature::SketchPlane::YZ: // Right
case SketchFeature::SketchPlane::XZ:
u_axis = QVector3D(1, 0, 0);
v_axis = QVector3D(0, 1, 0);
break;
case SketchFeature::SketchPlane::YZ:
u_axis = QVector3D(0, 1, 0);
v_axis = QVector3D(0, 0, 1);
break;
@@ -564,10 +574,10 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch)
gp_Pnt p2, p4;
if (sketch->plane() == SketchFeature::SketchPlane::XY) {
p2.SetCoord(p3.X(), p1.Y(), p1.Z());
p4.SetCoord(p1.X(), p3.Y(), p1.Z());
p4.SetCoord(p1.X(), p1.Y(), p3.Z());
} else if (sketch->plane() == SketchFeature::SketchPlane::XZ) {
p2.SetCoord(p3.X(), p1.Y(), p1.Z());
p4.SetCoord(p1.X(), p1.Y(), p3.Z());
p4.SetCoord(p1.X(), p3.Y(), p1.Z());
} else if (sketch->plane() == SketchFeature::SketchPlane::YZ) {
p2.SetCoord(p1.X(), p3.Y(), p1.Z());
p4.SetCoord(p1.X(), p1.Y(), p3.Z());
@@ -594,6 +604,9 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch)
if (!lineVertices.isEmpty()) {
m_vbo.allocate(lineVertices.constData(), lineVertices.size() * sizeof(GLfloat));
m_shaderProgram->enableAttributeArray(0);
m_shaderProgram->setAttributeBuffer(0, GL_FLOAT, 0, 3, 0);
m_shaderProgram->disableAttributeArray(1);
glDrawArrays(GL_LINES, 0, lineVertices.size() / 3);
}
@@ -649,13 +662,88 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch)
}
}
// Draw faces
if (!sketch->shape().IsNull()) {
glDisable(GL_CULL_FACE);
BRepMesh_IncrementalMesh(sketch->shape(), 0.1, Standard_False, 0.5, Standard_True); // Linear deflection, compute normals
QVector<GLfloat> faceData;
TopExp_Explorer explorer(sketch->shape(), TopAbs_FACE);
for (; explorer.More(); explorer.Next()) {
TopoDS_Face face = TopoDS::Face(explorer.Current());
TopLoc_Location location;
Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation(face, location);
if (!triangulation.IsNull()) {
gp_Trsf locTrsf = location.Transformation();
if (triangulation->HasNormals()) {
for (int i = 1; i <= triangulation->NbTriangles(); ++i) {
const Poly_Triangle& triangle = triangulation->Triangle(i);
for (int j = 1; j <= 3; ++j) {
int nodeIdx = triangle.Value(j);
gp_Pnt p = triangulation->Node(nodeIdx).Transformed(location);
gp_Dir n = triangulation->Normal(nodeIdx);
n.Transform(locTrsf);
if (face.Orientation() == TopAbs_REVERSED) {
n.Reverse();
}
faceData << p.X() << p.Y() << p.Z();
faceData << n.X() << n.Y() << n.Z();
}
}
} else {
for (int i = 1; i <= triangulation->NbTriangles(); ++i) {
const Poly_Triangle& triangle = triangulation->Triangle(i);
gp_Pnt p1 = triangulation->Node(triangle.Value(1)).Transformed(location);
gp_Pnt p2 = triangulation->Node(triangle.Value(2)).Transformed(location);
gp_Pnt p3 = triangulation->Node(triangle.Value(3)).Transformed(location);
QVector3D v1(p1.X(), p1.Y(), p1.Z());
QVector3D v2(p2.X(), p2.Y(), p2.Z());
QVector3D v3(p3.X(), p3.Y(), p3.Z());
QVector3D faceNormal = QVector3D::crossProduct(v2 - v1, v3 - v1).normalized();
if (face.Orientation() == TopAbs_REVERSED) {
faceNormal = -faceNormal;
}
faceData << p1.X() << p1.Y() << p1.Z() << faceNormal.x() << faceNormal.y() << faceNormal.z();
faceData << p2.X() << p2.Y() << p2.Z() << faceNormal.x() << faceNormal.y() << faceNormal.z();
faceData << p3.X() << p3.Y() << p3.Z() << faceNormal.x() << faceNormal.y() << faceNormal.z();
}
}
}
}
if (!faceData.isEmpty()) {
m_litShaderProgram->bind();
m_litShaderProgram->setUniformValue(m_litProjMatrixLoc, projection);
m_litShaderProgram->setUniformValue(m_litMvMatrixLoc, m_camera->modelViewMatrix());
m_litShaderProgram->setUniformValue(m_litNormalMatrixLoc, m_camera->modelViewMatrix().normalMatrix());
m_vbo.bind();
m_vbo.allocate(faceData.constData(), faceData.size() * sizeof(GLfloat));
m_litShaderProgram->enableAttributeArray(0);
m_litShaderProgram->setAttributeBuffer(0, GL_FLOAT, 0, 3, 6 * sizeof(GLfloat));
m_litShaderProgram->enableAttributeArray(1);
m_litShaderProgram->setAttributeBuffer(1, GL_FLOAT, 3 * sizeof(GLfloat), 3, 6 * sizeof(GLfloat));
glDrawArrays(GL_TRIANGLES, 0, faceData.size() / 6);
m_litShaderProgram->disableAttributeArray(1);
m_shaderProgram->bind(); // rebind simple shader for subsequent draws
m_shaderProgram->setAttributeBuffer(0, GL_FLOAT, 0, 3, 0);
}
glEnable(GL_CULL_FACE);
}
glEnable(GL_DEPTH_TEST);
}
void ViewportWidget::initShaders()
{
// Simple shader for lines and grids
m_shaderProgram = new QOpenGLShaderProgram(this);
if (!m_shaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/simple.vert")) {
qCritical() << "Vertex shader compilation failed:" << m_shaderProgram->log();
return;
@@ -668,10 +756,27 @@ void ViewportWidget::initShaders()
qCritical() << "Shader program linking failed:" << m_shaderProgram->log();
return;
}
m_projMatrixLoc = m_shaderProgram->uniformLocation("projectionMatrix");
m_mvMatrixLoc = m_shaderProgram->uniformLocation("modelViewMatrix");
m_colorLoc = m_shaderProgram->uniformLocation("objectColor");
// Lit shader for faces
m_litShaderProgram = new QOpenGLShaderProgram(this);
if (!m_litShaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/lit.vert")) {
qCritical() << "Lit vertex shader compilation failed:" << m_litShaderProgram->log();
return;
}
if (!m_litShaderProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/lit.frag")) {
qCritical() << "Lit fragment shader compilation failed:" << m_litShaderProgram->log();
return;
}
if (!m_litShaderProgram->link()) {
qCritical() << "Lit shader program linking failed:" << m_litShaderProgram->log();
return;
}
m_litProjMatrixLoc = m_litShaderProgram->uniformLocation("projectionMatrix");
m_litMvMatrixLoc = m_litShaderProgram->uniformLocation("modelViewMatrix");
m_litNormalMatrixLoc = m_litShaderProgram->uniformLocation("normalMatrix");
}
void ViewportWidget::drawSelectionPlanes()
@@ -686,6 +791,9 @@ void ViewportWidget::drawSelectionPlanes()
glDisable(GL_DEPTH_TEST);
m_vbo.bind();
m_shaderProgram->enableAttributeArray(0);
m_shaderProgram->setAttributeBuffer(0, GL_FLOAT, 0, 3, 0);
m_shaderProgram->disableAttributeArray(1);
QVector<GLfloat> vertices;
auto drawPlane = [&](const QVector<GLfloat>& quadVerts, bool highlighted) {
@@ -702,18 +810,18 @@ void ViewportWidget::drawSelectionPlanes()
};
// XY Plane (Top)
QVector<GLfloat> xyQuad = { planeOffset, -planeOffset, 0, planeOffset + planeSize, -planeOffset, 0,
planeOffset + planeSize, -planeOffset - planeSize, 0, planeOffset, -planeOffset - planeSize, 0 };
QVector<GLfloat> xyQuad = { planeOffset, 0, planeOffset, planeOffset + planeSize, 0, planeOffset,
planeOffset + planeSize, 0, planeOffset + planeSize, planeOffset, 0, planeOffset + planeSize };
drawPlane(xyQuad, m_highlightedPlane == SketchPlane::XY);
// XZ Plane (Front)
QVector<GLfloat> xzQuad = { planeOffset, 0, planeOffset, planeOffset + planeSize, 0, planeOffset,
planeOffset + planeSize, 0, planeOffset + planeSize, planeOffset, 0, planeOffset + planeSize };
QVector<GLfloat> xzQuad = { planeOffset, planeOffset, 0, planeOffset + planeSize, planeOffset, 0,
planeOffset + planeSize, planeOffset + planeSize, 0, planeOffset, planeOffset + planeSize, 0 };
drawPlane(xzQuad, m_highlightedPlane == SketchPlane::XZ);
// YZ Plane (Right)
QVector<GLfloat> yzQuad = { 0, -planeOffset, planeOffset, 0, -planeOffset, planeOffset + planeSize,
0, -planeOffset - planeSize, planeOffset + planeSize, 0, -planeOffset - planeSize, planeOffset };
QVector<GLfloat> yzQuad = { 0, planeOffset, planeOffset, 0, planeOffset + planeSize, planeOffset,
0, planeOffset + planeSize, planeOffset + planeSize, 0, planeOffset, planeOffset + planeSize };
drawPlane(yzQuad, m_highlightedPlane == SketchPlane::YZ);
glEnable(GL_CULL_FACE);
@@ -731,7 +839,7 @@ ViewportWidget::SketchPlane ViewportWidget::checkPlaneSelection(const QPoint& sc
// Check front to back to handle overlaps
// YZ plane (Right)
intersection = unproject(screenPos, SketchPlane::YZ);
if (intersection.y() >= -planeOffset - planeSize && intersection.y() <= -planeOffset &&
if (intersection.y() >= planeOffset && intersection.y() <= planeOffset + planeSize &&
intersection.z() >= planeOffset && intersection.z() <= planeOffset + planeSize) {
return SketchPlane::YZ;
}
@@ -739,14 +847,14 @@ ViewportWidget::SketchPlane ViewportWidget::checkPlaneSelection(const QPoint& sc
// XZ plane (Front)
intersection = unproject(screenPos, SketchPlane::XZ);
if (intersection.x() >= planeOffset && intersection.x() <= planeOffset + planeSize &&
intersection.z() >= planeOffset && intersection.z() <= planeOffset + planeSize) {
intersection.y() >= planeOffset && intersection.y() <= planeOffset + planeSize) {
return SketchPlane::XZ;
}
// XY plane (Top)
intersection = unproject(screenPos, SketchPlane::XY);
if (intersection.x() >= planeOffset && intersection.x() <= planeOffset + planeSize &&
intersection.y() >= -planeOffset - planeSize && intersection.y() <= -planeOffset) {
intersection.z() >= planeOffset && intersection.z() <= planeOffset + planeSize) {
return SketchPlane::XY;
}

View File

@@ -97,6 +97,7 @@ private:
QMatrix4x4 projection;
QOpenGLShaderProgram* m_shaderProgram = nullptr;
QOpenGLShaderProgram* m_litShaderProgram = nullptr;
QOpenGLVertexArrayObject m_vao;
QOpenGLBuffer m_vbo;
@@ -104,6 +105,11 @@ private:
int m_projMatrixLoc = -1;
int m_mvMatrixLoc = -1;
int m_colorLoc = -1;
// Lit shader uniform locations
int m_litProjMatrixLoc = -1;
int m_litMvMatrixLoc = -1;
int m_litNormalMatrixLoc = -1;
Camera* m_camera = nullptr;
ViewCube* m_viewCube;
SketchGrid* m_sketchGrid = nullptr;

33
src/shaders/lit.frag Normal file
View File

@@ -0,0 +1,33 @@
#version 330 core
out vec4 FragColor;
in vec3 FragPos;
in vec3 Normal;
void main()
{
vec3 viewPos = vec3(0.0, 0.0, 0.0); // View position is origin in view space
vec3 lightPos = vec3(0.0, 10.0, 5.0); // Light position in view space
vec3 lightColor = vec3(1.0, 1.0, 1.0);
vec3 objectColor = vec3(0.5, 0.5, 1.0);
// Ambient
float ambientStrength = 0.3;
vec3 ambient = ambientStrength * lightColor;
// Diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
// Specular
float specularStrength = 0.5;
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = specularStrength * spec * lightColor;
vec3 result = (ambient + diffuse + specular) * objectColor;
FragColor = vec4(result, 1.0);
}

17
src/shaders/lit.vert Normal file
View File

@@ -0,0 +1,17 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
out vec3 FragPos;
out vec3 Normal;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;
void main()
{
FragPos = vec3(modelViewMatrix * vec4(aPos, 1.0));
Normal = normalMatrix * aNormal;
gl_Position = projectionMatrix * modelViewMatrix * vec4(aPos, 1.0);
}