Skip to content

Commit

Permalink
feat: Enable Z-axis (#36)
Browse files Browse the repository at this point in the history
* Basic X and Y direction

* Properly use X and Y axis

* Add zAxis to ticks

* Allow Z-Axis

It's not correct, but it's a start

* Start giving thicker axes

They're not right, but at least it's not longer a single face

* Start getting proper extrusion

* Add end caps

* Connect axes via thickness

* Use old Vector3 code from Dissolve

* Replace Point with Vec3<float>

* Move constants into header file

* Start cleaning up scattering code

* Enable quad polygons

* Simplify drawing with quads

* Plot cubes for scatter plot

* Fix axis ticks

* Rotate Z axis ticks

* Fix Z-axis scaling

* Add copyright headers to solid
  • Loading branch information
rprospero authored Aug 23, 2024
1 parent cc4d3ac commit 788b2df
Show file tree
Hide file tree
Showing 18 changed files with 662 additions and 121 deletions.
3 changes: 2 additions & 1 deletion src/AxisModel.qml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ Node {
model: axis.tickLabels

delegate: Node {
position: axis.direction ? Qt.vector3d(-root.scl.x + tickX * root.scl.x, -root.scl.y - 210, 0) : Qt.vector3d(-root.scl.x - 30, -root.scl.y - 180 + tickY * root.scl.y, 0)
eulerRotation: axis.direction == Axis.Z ? Qt.vector3d(0, 90.0, 0) : Qt.vector3d(0, 0, 0)
position: axis.direction == Axis.X ? Qt.vector3d(-root.scl.x + tickX * root.scl.x, -root.scl.y - 210, 0) : Qt.vector3d(-root.scl.x - 30, -root.scl.y - 180 + tickY * root.scl.y, tickZ * root.scl.x)

Item {
anchors.centerIn: parent
Expand Down
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ qt_add_qml_module(
plotGeometry.cpp
scatterGeometry.cpp
scatterGeometry.h
solid.h
solid.cpp
triangle.cpp
QML_FILES
AxisModel.qml
Expand Down
63 changes: 18 additions & 45 deletions src/axis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@
#include "axis.h"
#include <algorithm>

#include "solid.h"
#include "vector3.h"
#include <cmath>
#include <iostream>

Axis::Axis() : minimum_(-1), maximum_(1), direction_(false), thickness_(0.001), tickLabels_(*this)
Axis::Axis() : minimum_(-1), maximum_(1), direction_(Axis::Direction::Y), thickness_(0.001), tickLabels_(*this)
{
updateData();
connect(this, &Axis::dataChanged, this, &Axis::updateData);
}

AxisTickLabels *Axis::tickLabels() { return &tickLabels_; }

bool Axis::direction() const { return direction_; }
Axis::Direction Axis::direction() const { return direction_; }
double Axis::minimum() const { return minimum_; }
void Axis::setMinimum(const double value) { minimum_ = value; }
double Axis::maximum() const { return maximum_; }
Expand Down Expand Up @@ -59,52 +61,23 @@ void Axis::updateData()

int stride = 3 * sizeof(float);

QByteArray vertexData(6 * stride, Qt::Initialization::Uninitialized);
QByteArray vertexData(6 * 6 * stride, Qt::Initialization::Uninitialized);
float *p = reinterpret_cast<float *>(vertexData.data());

if (direction_)
switch (direction_)
{
*p++ = -1.0;
*p++ = -1.0 - thickness_;
*p++ = 0;
*p++ = 1.0;
*p++ = -1.0 - thickness_;
*p++ = 0;
*p++ = 1.0;
*p++ = -1.0 + thickness_;
*p++ = 0;

*p++ = 1.0;
*p++ = -1.0 + thickness_;
*p++ = 0;
*p++ = -1.0;
*p++ = -1.0 + thickness_;
*p++ = 0;
*p++ = -1.0;
*p++ = -1.0 - thickness_;
*p++ = 0;
}
else
{
*p++ = -1.0 - thickness_;
*p++ = -1.0;
*p++ = 0;
*p++ = -1.0 + thickness_;
*p++ = 1.0;
*p++ = 0;
*p++ = -1.0 - thickness_;
*p++ = 1.0;
*p++ = 0;

*p++ = -1.0 - thickness_;
*p++ = -1.0;
*p++ = 0;
*p++ = -1.0 + thickness_;
*p++ = -1.0;
*p++ = 0;
*p++ = -1.0 + thickness_;
*p++ = 1.0;
*p++ = 0;
case Axis::Direction::X:
draw_tube(p, thickness_, Vec3<float>{-1.0f - (float)thickness_, -1.0, 0},
Vec3<float>{1.0f + (float)thickness_, -1.0, 0}, yhat, zhat);
break;
case Axis::Direction::Y:
draw_tube(p, thickness_, Vec3<float>{-1.0, -1.0f - (float)thickness_, 0},
Vec3<float>{-1.0, 1.0f + (float)thickness_, 0}, zhat, xhat);
break;
case Axis::Direction::Z:
draw_tube(p, thickness_, Vec3<float>{-1.0, -1.0, 0.0f - (float)thickness_},
Vec3<float>{-1.0, -1.0, 2.0f + (float)thickness_}, xhat, yhat);
break;
}

setVertexData(vertexData);
Expand Down
14 changes: 11 additions & 3 deletions src/axis.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,21 @@ class Axis : public QQuick3DGeometry
Q_PROPERTY(double thickness MEMBER thickness_ NOTIFY dataChanged)
Q_PROPERTY(double minimum READ minimum WRITE setMinimum NOTIFY dataChanged)
Q_PROPERTY(double maximum READ maximum WRITE setMaximum NOTIFY dataChanged)
Q_PROPERTY(bool direction MEMBER direction_ NOTIFY dataChanged)
Q_PROPERTY(Direction direction MEMBER direction_ NOTIFY dataChanged)
Q_PROPERTY(AxisTickLabels *tickLabels READ tickLabels NOTIFY dataChanged)
Q_PROPERTY(int tickCount READ tickCount NOTIFY dataChanged)

public:
Axis();

enum Direction
{
Z,
Y,
X
};
Q_ENUMS(Direction)

/** Translate data space values into plot space values.
Subclasses will overload this method to enable different
scaling methods (e.g. log scaling). */
Expand All @@ -32,7 +40,7 @@ class Axis : public QQuick3DGeometry

/** The direction in which the axis is pointing. \todo This needs
to be a proper enum to handle three dimensions */
bool direction() const;
Direction direction() const;
/** Get the minimum edge of the axis */
double minimum() const;
/** Set the minimum edge of the axis */
Expand Down Expand Up @@ -65,7 +73,7 @@ class Axis : public QQuick3DGeometry
virtual void updateTicks_();
/** Update the axis display in response to changes in the data.*/
void updateData();
bool direction_;
Direction direction_;
/** The line thickness of the axis */
double thickness_;
AxisTickLabels tickLabels_;
Expand Down
7 changes: 5 additions & 2 deletions src/axisTickLabels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ QVariant AxisTickLabels::data(const QModelIndex &index, int role) const
case Qt::UserRole:
return QString("%1").arg(parent_.tick(index.row()));
case (Qt::UserRole + 1):
return parent_.direction() ? parent_.tickCoord(index.row()) : 0;
return (parent_.direction() == Axis::Direction::X) ? parent_.tickCoord(index.row()) : 0;
case (Qt::UserRole + 2):
return parent_.direction() ? 0 : parent_.tickCoord(index.row());
return (parent_.direction() == Axis::Direction::Y) ? parent_.tickCoord(index.row()) : 0;
case (Qt::UserRole + 3):
return (parent_.direction() == Axis::Direction::Z) ? parent_.tickCoord(index.row()) : 0;
default:
return index.row();
}
Expand All @@ -30,6 +32,7 @@ QHash<int, QByteArray> AxisTickLabels::roleNames() const
roles[Qt::UserRole] = "tickLabel";
roles[Qt::UserRole + 1] = "tickX";
roles[Qt::UserRole + 2] = "tickY";
roles[Qt::UserRole + 3] = "tickZ";
return roles;
}

Expand Down
2 changes: 1 addition & 1 deletion src/lineGeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

LineGeometry::LineGeometry() : PlotGeometry() {}

std::vector<Triangle> LineGeometry::faces_(std::vector<Point> ps) const
std::vector<Triangle> LineGeometry::faces_(std::vector<Vec3<float>> ps) const
{
const int N = ps.size();

Expand Down
2 changes: 1 addition & 1 deletion src/lineGeometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ class LineGeometry : public PlotGeometry
LineGeometry();

private:
std::vector<Triangle> faces_(std::vector<Point> points) const override;
std::vector<Triangle> faces_(std::vector<Vec3<float>> points) const override;
};
22 changes: 19 additions & 3 deletions src/main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import "../ProjectDissolve"
ApplicationWindow {
id: root

property vector3d scale: Qt.vector3d(Math.min(graphView.width / 2.5, graphView.height / 2.5), Math.min(graphView.width / 2.5, graphView.height / 2.5), 200)
property vector3d scale: Qt.vector3d(Math.min(graphView.width / 2.5, graphView.height / 2.5), Math.min(graphView.width / 2.5, graphView.height / 2.5), Math.min(graphView.width / 2.5, graphView.height / 2.5))

height: 600
title: "Mildred QML Test"
Expand Down Expand Up @@ -53,7 +53,7 @@ ApplicationWindow {
axis: Axis {
id: xAxis

direction: true
direction: Axis.X
thickness: 0.01
}
}
Expand All @@ -64,12 +64,23 @@ ApplicationWindow {
axis: LogAxis {
id: yAxis

direction: false
direction: Axis.Y
maximum: 1.0
minimum: 0.01
thickness: 0.01
}
}
AxisModel {
color: "black"
scl: root.scale

axis: Axis {
id: zAxis

direction: Axis.Z
thickness: 0.01
}
}
}
View3D {
id: graphView
Expand All @@ -94,6 +105,11 @@ ApplicationWindow {
yAxis.nudge(-0.01 * event.pixelDelta.y);
}
}
OrbitCameraController {
anchors.fill: parent
camera: cameraOrthographicLeft
origin: standAloneScene
}
}
Pane {
id: settingsPane
Expand Down
12 changes: 6 additions & 6 deletions src/mainpage.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@ at least two axes to plot. The axis is declared via the AxisModel.
```qml
axis: Axis {
id: xAxis
direction: true
direction: Axis.X
thickness: 0.01
}
```

The axis requires a direction (which will eventually be an Enum, but
it currently just a boolean) and a thickness. To plot the axis in the
chart, wrap it within an AxisModel. It will need a `color` (probably
black) and a `scl`, which represents the size of the canvas. The
scale ensures that the graph can be safely resized.
The axis requires a direction (which can be X, Y, or Z) and a
thickness. To plot the axis in the chart, wrap it within an AxisModel.
It will need a `color` (probably black) and a `scl`, which represents
the size of the canvas. The scale ensures that the graph can be
safely resized.

```qml
AxisModel {
Expand Down
10 changes: 5 additions & 5 deletions src/plotGeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ void PlotGeometry::updateData()
auto xs = xAxis_->convert(xs_);
auto ys = yAxis_->convert(ys_);

std::vector<Point> ps(N);
std::vector<Vec3<float>> ps(N);
for (int i = 0; i < N; i++)
{
ps[i] = Point(xs[i], ys[i], 0.0);
ps[i] = Vec3<float>(xs[i], ys[i], 0.0);
}

auto ts = clip(faces_(ps));
Expand Down Expand Up @@ -59,9 +59,9 @@ void PlotGeometry::updateData()
update();
}

std::vector<Triangle> PlotGeometry::faces_([[maybe_unused]] std::vector<Point> ps) const { return {}; }
std::vector<Triangle> PlotGeometry::faces_([[maybe_unused]] std::vector<Vec3<float>> ps) const { return {}; }

bool outOfBounds(const Point &p) { return p.x < -1 || p.x > 1 || p.y < -1 || p.y > 1 || p.z < -1 || p.z > 1; }
bool outOfBounds(const Vec3<float> &p) { return p.x < -1 || p.x > 1 || p.y < -1 || p.y > 1 || p.z < -1 || p.z > 1; }

std::optional<Edge> clipEdge(const Edge &e)
{
Expand Down Expand Up @@ -180,7 +180,7 @@ std::vector<Triangle> PlotGeometry::clip(const std::vector<Triangle> &ts) const
for (const auto &t : ts)
{
std::vector<Edge> edges = {{t.a, t.b}, {t.b, t.c}, {t.c, t.a}};
std::vector<Point> vertices;
std::vector<Vec3<float>> vertices;
for (const auto &e : edges)
{
const auto clipped = clipEdge(e);
Expand Down
2 changes: 1 addition & 1 deletion src/plotGeometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class PlotGeometry : public QQuick3DGeometry
/** An array of polygon faces that would plot the given data
points. The points should be in chart space (not data
space).*/
virtual std::vector<Triangle> faces_(std::vector<Point> points) const;
virtual std::vector<Triangle> faces_(std::vector<Vec3<float>> points) const;
/** Take a list of polygon faces and crop them so that nothing
extends outside of the charting space. Triangles completely
outside the region are dropped while triangles partially
Expand Down
Loading

0 comments on commit 788b2df

Please sign in to comment.