Skip to content

Commit

Permalink
cxx-qt-lib: add support for QVector2D, QVector3D, QVector4D
Browse files Browse the repository at this point in the history
Related to KDAB#291
  • Loading branch information
ahayzen-kdab authored and przempore committed Mar 15, 2023
1 parent 45f0cf5 commit 91f1ec1
Show file tree
Hide file tree
Showing 23 changed files with 1,014 additions and 1 deletion.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Added

- Support for container types: `QSet<T>`, `QHash<K, V>`, `QList<T>`, `QMap<K, V>`, `QVector<T>`
- Support for further types: `QByteArray`, `QModelIndex`, `QPersistentModelIndex`, `QStringList`
- Support for further types: `QByteArray`, `QModelIndex`, `QPersistentModelIndex`, `QStringList`, `QVector2D`, `QVector3D`, `QVector4D`
- Support for nesting objects in properties, invokables, and signals with `*mut T`

### Changed
Expand Down
23 changes: 23 additions & 0 deletions crates/cxx-qt-lib-headers/include/qvector2d.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// clang-format off
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

#include <QtGui/QVector2D>

namespace rust {
namespace cxxqtlib1 {

// Qt 6 uses by-value, Qt 5 uses by-ref
float
qvector2DDistanceToLine(const QVector2D& vector,
QVector2D point,
QVector2D direction);
float
qvector2DDistanceToPoint(const QVector2D& vector, QVector2D point);

}
}
27 changes: 27 additions & 0 deletions crates/cxx-qt-lib-headers/include/qvector3d.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// clang-format off
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

#include <QtGui/QVector3D>

namespace rust {
namespace cxxqtlib1 {

// Qt 6 uses by-value, Qt 5 uses by-ref
float
qvector3DDistanceToLine(const QVector3D& vector,
QVector3D point,
QVector3D direction);
float
qvector3DDistanceToPlane(const QVector3D& vector,
QVector3D plane,
QVector3D normal);
float
qvector3DDistanceToPoint(const QVector3D& vector, QVector3D point);

}
}
9 changes: 9 additions & 0 deletions crates/cxx-qt-lib-headers/include/qvector4d.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// clang-format off
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

#include <QtGui/QVector4D>
3 changes: 3 additions & 0 deletions crates/cxx-qt-lib-headers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ pub fn write_headers(directory: impl AsRef<Path>) {
(include_str!("../include/qurl.h"), "qurl.h"),
(include_str!("../include/qvariant.h"), "qvariant.h"),
(include_str!("../include/qvector.h"), "qvector.h"),
(include_str!("../include/qvector2d.h"), "qvector2d.h"),
(include_str!("../include/qvector3d.h"), "qvector3d.h"),
(include_str!("../include/qvector4d.h"), "qvector4d.h"),
(include_str!("../include/std_types.h"), "std_types.h"),
] {
let h_path = format!("{}/{}", directory.display(), file_name);
Expand Down
6 changes: 6 additions & 0 deletions crates/cxx-qt-lib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ fn main() {
"qvector/qvector_u16",
"qvector/qvector_u32",
"qvector/qvector_u64",
"qvector2d",
"qvector3d",
"qvector4d",
];
for bridge in rust_bridges {
println!("cargo:rerun-if-changed=src/types/{bridge}.rs");
Expand Down Expand Up @@ -169,6 +172,9 @@ fn main() {
"qurl",
"qvariant/qvariant",
"qvector/qvector",
"qvector2d",
"qvector3d",
"qvector4d",
];
for cpp_file in cpp_files {
builder.file(format!("src/types/{}.cpp", cpp_file));
Expand Down
9 changes: 9 additions & 0 deletions crates/cxx-qt-lib/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,12 @@ pub use qvariant::{QVariant, QVariantValue};

mod qvector;
pub use qvector::{QVector, QVectorElement};

mod qvector2d;
pub use qvector2d::QVector2D;

mod qvector3d;
pub use qvector3d::QVector3D;

mod qvector4d;
pub use qvector4d::QVector4D;
39 changes: 39 additions & 0 deletions crates/cxx-qt-lib/src/types/qvector2d.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// clang-format off
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#include "cxx-qt-lib/qvector2d.h"

#include "assertion_utils.h"

// QVector2D has two float members - xp and yp
// https://code.qt.io/cgit/qt/qtbase.git/tree/src/gui/math3d/qvector2d.h?h=v5.15.6-lts-lgpl#n126
//
// https://code.qt.io/cgit/qt/qtbase.git/tree/src/gui/math3d/qvectornd.h?h=v6.2.4#n176
assert_alignment_and_size(QVector2D, alignof(float), sizeof(float[2]));

static_assert(::std::is_trivially_copyable<QVector2D>::value,
"QPointF should be trivially copyable");

namespace rust {
namespace cxxqtlib1 {

// Qt 6 uses by-value, Qt 5 uses by-ref
float
qvector2DDistanceToLine(const QVector2D& vector,
QVector2D point,
QVector2D direction)
{
return vector.distanceToLine(point, direction);
}

float
qvector2DDistanceToPoint(const QVector2D& vector, QVector2D point)
{
return vector.distanceToPoint(point);
}

}
}
195 changes: 195 additions & 0 deletions crates/cxx-qt-lib/src/types/qvector2d.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

use cxx::{type_id, ExternType};

#[cxx::bridge]
mod ffi {
unsafe extern "C++" {
include!("cxx-qt-lib/qpoint.h");
type QPoint = crate::QPoint;
include!("cxx-qt-lib/qpointf.h");
type QPointF = crate::QPointF;

include!("cxx-qt-lib/qvector2d.h");
type QVector2D = super::QVector2D;
include!("cxx-qt-lib/qvector3d.h");
type QVector3D = crate::QVector3D;
include!("cxx-qt-lib/qvector4d.h");
type QVector4D = crate::QVector4D;

/// Returns true if the x and y coordinates are set to 0.0, otherwise returns false.
#[rust_name = "is_null"]
fn isNull(self: &QVector2D) -> bool;

/// Returns the length of the vector from the origin.
fn length(self: &QVector2D) -> f32;

/// Returns the squared length of the vector from the origin.
/// This is equivalent to the dot product of the vector with itself.
#[rust_name = "length_squared"]
fn lengthSquared(self: &QVector2D) -> f32;

/// Normalizes the current vector in place. Nothing happens
/// if this vector is a null vector or the length of the vector is very close to 1.
fn normalize(self: &mut QVector2D);

/// Returns the normalized unit vector form of this vector.
///
/// If this vector is null, then a null vector is returned.
/// If the length of the vector is very close to 1, then the vector will be returned as-is.
/// Otherwise the normalized form of the vector of length 1 will be returned.
fn normalized(self: &QVector2D) -> QVector2D;

/// Sets the x coordinate of this point to the given finite x coordinate.
#[rust_name = "set_x"]
fn setX(self: &mut QVector2D, x: f32);
/// Sets the y coordinate of this point to the given finite y coordinate.
#[rust_name = "set_y"]
fn setY(self: &mut QVector2D, y: f32);

// From trait is more idiomatic to Rust and implemented in QPoint and QPointF
#[doc(hidden)]
#[rust_name = "to_point"]
fn toPoint(self: &QVector2D) -> QPoint;
#[doc(hidden)]
#[rust_name = "to_pointf"]
fn toPointF(self: &QVector2D) -> QPointF;

/// Returns the x coordinate of this point.
fn x(self: &QVector2D) -> f32;
/// Returns the y coordinate of this point.
fn y(self: &QVector2D) -> f32;

}

#[namespace = "rust::cxxqtlib1"]
unsafe extern "C++" {
include!("cxx-qt-lib/common.h");

#[doc(hidden)]
#[rust_name = "qvector2d_init_qvector4d"]
fn construct(vector: QVector4D) -> QVector2D;
#[doc(hidden)]
#[rust_name = "qvector2d_init_qvector3d"]
fn construct(vector: QVector3D) -> QVector2D;

#[doc(hidden)]
#[rust_name = "qvector2d_init_qpointf"]
fn construct(point: QPointF) -> QVector2D;
#[doc(hidden)]
#[rust_name = "qvector2d_init_qpoint"]
fn construct(point: QPoint) -> QVector2D;

#[doc(hidden)]
#[rust_name = "qvector2d_init"]
fn construct(x: f32, y: f32) -> QVector2D;

#[doc(hidden)]
#[rust_name = "qvector2d_init_default"]
fn construct() -> QVector2D;

// Note that Qt 5 takes const-ref and Qt 6 takes by-value
//
// We want by-value, as that is Rust-idiomatic, so for Qt 5 we create a proxy
#[doc(hidden)]
#[rust_name = "qvector2d_distance_to_line"]
fn qvector2DDistanceToLine(
vector: &QVector2D,
point: QVector2D,
direction: QVector2D,
) -> f32;
#[doc(hidden)]
#[rust_name = "qvector2d_distance_to_point"]
fn qvector2DDistanceToPoint(vector: &QVector2D, point: QVector2D) -> f32;
}
}

/// The QVector2D class represents a vector or vertex in 2D space.
#[derive(Debug, Clone)]
#[repr(C)]
pub struct QVector2D {
v: [f32; 2],
}

impl QVector2D {
/// Constructs a vector with coordinates (xpos, ypos). Both coordinates must be finite.
pub fn new(xpos: f32, ypos: f32) -> Self {
ffi::qvector2d_init(xpos, ypos)
}

/// Returns the distance that this vertex is from a line defined by point and the unit vector direction.
///
/// If direction is a null vector, then it does not define a line.
/// In that case, the distance from point to this vertex is returned.
pub fn distance_to_line(&self, point: QVector2D, direction: QVector2D) -> f32 {
ffi::qvector2d_distance_to_line(self, point, direction)
}

/// Returns the distance from this vertex to a point defined by the vertex point.
pub fn distance_to_point(&self, point: QVector2D) -> f32 {
ffi::qvector2d_distance_to_point(self, point)
}
}

impl Default for QVector2D {
/// Constructs a null vector, i.e. with coordinates (0, 0).
fn default() -> Self {
ffi::qvector2d_init_default()
}
}

impl From<crate::QVector4D> for QVector2D {
/// Constructs a vector with x and y coordinates from a 3D vector.
/// The z and w coordinates of vector are dropped.
fn from(value: crate::QVector4D) -> Self {
ffi::qvector2d_init_qvector4d(value)
}
}

impl From<crate::QVector3D> for QVector2D {
/// Constructs a vector with x and y coordinates from a 3D vector.
/// The z coordinate of vector is dropped.
fn from(value: crate::QVector3D) -> Self {
ffi::qvector2d_init_qvector3d(value)
}
}

impl From<crate::QPointF> for QVector2D {
/// Constructs a vector with x and y coordinates from a 2D point.
fn from(value: crate::QPointF) -> Self {
ffi::qvector2d_init_qpointf(value)
}
}

impl From<QVector2D> for crate::QPointF {
/// Returns the QPoint form of this 2D vector.
/// Each coordinate is rounded to the nearest integer.
fn from(value: QVector2D) -> Self {
value.to_pointf()
}
}

impl From<crate::QPoint> for QVector2D {
/// Constructs a vector with x and y coordinates from a 2D point.
fn from(value: crate::QPoint) -> Self {
ffi::qvector2d_init_qpoint(value)
}
}

impl From<QVector2D> for crate::QPoint {
/// Returns the QPointF form of this 2D vector.
fn from(value: QVector2D) -> Self {
value.to_point()
}
}

// Safety:
//
// Static checks on the C++ side ensure that QVector2D is trivial.
unsafe impl ExternType for QVector2D {
type Id = type_id!("QVector2D");
type Kind = cxx::kind::Trivial;
}
47 changes: 47 additions & 0 deletions crates/cxx-qt-lib/src/types/qvector3d.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// clang-format off
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#include "cxx-qt-lib/qvector3d.h"

#include "assertion_utils.h"

// QVector2D has two float members - xp and yp
// https://code.qt.io/cgit/qt/qtbase.git/tree/src/gui/math3d/qvector3d.h?h=v5.15.6-lts-lgpl#n141
//
// https://code.qt.io/cgit/qt/qtbase.git/tree/src/gui/math3d/qvectornd.h?h=v6.2.4#n334
assert_alignment_and_size(QVector3D, alignof(float), sizeof(float[3]));

static_assert(::std::is_trivially_copyable<QVector3D>::value,
"QPointF should be trivially copyable");

namespace rust {
namespace cxxqtlib1 {

// Qt 6 uses by-value, Qt 5 uses by-ref
float
qvector3DDistanceToLine(const QVector3D& vector,
QVector3D point,
QVector3D direction)
{
return vector.distanceToLine(point, direction);
}

float
qvector3DDistanceToPlane(const QVector3D& vector,
QVector3D plane,
QVector3D normal)
{
return vector.distanceToPlane(plane, normal);
}

float
qvector3DDistanceToPoint(const QVector3D& vector, QVector3D point)
{
return vector.distanceToPoint(point);
}

}
}
Loading

0 comments on commit 91f1ec1

Please sign in to comment.