rustgd / cgmath Goto Github PK
View Code? Open in Web Editor NEWA linear algebra and mathematics library for computer graphics.
Home Page: https://docs.rs/cgmath
License: Apache License 2.0
A linear algebra and mathematics library for computer graphics.
Home Page: https://docs.rs/cgmath
License: Apache License 2.0
For example, working on my current project, I was only able to use Vector3::new(...).normalize();
if I did use cgmath::*;
instead of a (I thought) cleaner use cgmath::{Vector3, Point3, etc.};
In addition, this requirement doesn't seem to be documented anywhere.
Instead of the ToX traits, did you consider implementing From ?
Hi there, I don't know if this is still going or not? but apparently let mat4 = rota.to_matrix4();
or something like that is now let mat4: Matrix4<_> = rota.into();
.
Have been trying to convert the step "A simple transformation" in https://open.gl/transformations to cgmath, will continue trying but if you could provide the "exact" same translation pointed there will love it.
Also... if this will be not more under development should I switch to nalgebra or some like that? (what about aabb and so on???
The README says that there are Vec2
, Vec3
, etc. types but the library appears to use Vector2
, Vector3
, etc. now.
extern crate cgmath;
use cgmath::*;
fn main() {
let axis = vec3::<f64>(1.0, 0.0, 1.0);
let a = Basis3::from_axis_angle(&axis, deg(75.0).to_rad());
let b = Basis3::from_axis_angle(&axis.normalize(), deg(75.0).to_rad());
println!("a = {:?}", a.as_matrix3());
println!("b = {:?}", b.as_matrix3());
println!("ฮ = {:?}", a.as_matrix3().sub_m(b.as_matrix3()));
assert!(a.approx_eq(&b));
}
I see different ways to fix this:
Basis3::from_axis_angle
and possibly Rotation3::from_axis_angle
. Assert that axis.length2()
is approximately 1.0 at entry.In modules that have
use cgmath::vector::Vector;
in them, you can no longer take slices from native rust vectors, eg.
let a = ~[1, 2, 3];
let b = a.as_slice();
"error: type ~[int]
does not implement any method in scope named as_slice
"
The method as_slice is supposed to come from module std::vec::Vector.
A workaround is to rename the cgmath import, eg.
use cgVector = cgmath::vector::Vector;
Possible quick fix: Rename cgmath::vector::Vector into Vec?
Currently, Transform
trait doesn't enforce the internal representation to be affine. It's fine for as long as you just transform stuff with it. Whenever you want to convert the transformation to, let's say, a GLSL friendly form, you need to constraint the internal representation more.
I propose the ToComponents
to provide an ability to extract translation, rotation and scale separately. The real question here is how to represent the rotation. When we work with a matrix, we can't just return a 3x3 portion of it, because it also includes the scale. Since we have to process the matrix in some way, we might as well demand a quaternion as an output. However, the user might also want Euler angles out of it. Hence the rotation has to support everything:
trait ToComponents<S> {
type Rotation: Rotation3<S>;
fn to_rotation(&self) -> Self::Rotation;
fn to_translation(&self) -> Vector3<S>;
fn to_scale(&self) -> Vector3<S>;
}
Alternative name: AffineTransform
.
To expand on my previous PR, do you think an additional method that added line to rectangle intersection would be useful?
If so, would an AABB be logical in using as the rectangle?
I noticed that inverse()
returns some strange results when I try and invert my view matrix. Not every matrix is correctly inverted, I captured a few that we can use to test.
view [[-0.131917, -0.76871, 0.625846, 0], [-0, 0.631364, 0.775487, 0], [-0.991261, 0.1023, -0.083287, 0], [0, -1.262728, -1.550973, 1]]
view^1 [[0, 0, -1.008816, 0], [-0.614136, 0.3556, 0.081729, 0], [0.5, 1, -0.06654, 0], [0, 2, 0, 1]]
view^1*view [[0.785015, 0.352493, 0.02861, 0], [0, 1, -0, 0], [-0.10447, -0.04691, 1.013903, 0], [0, 0, 0, 1]]
view [[0.065455, -0.720002, 0.690879, 0], [-0, 0.692364, 0.721549, 0], [-0.997856, -0.047229, 0.045318, 0], [0, -1.384727, -1.443098, 1]]
view^1 [[5.333333, -2.666667, -0.652307, 0], [-0.694769, 0.749559, -0.045574, 0], [0.666667, 0.666667, 0.04373, 0], [0, 2, 0, 1]]
view^1*view [[1.309913, -0.253644, 0.020329, 0], [0, 1, -0, 0], [-5.258871, 2.65576, 0.655042, 0], [0, 0, 0, 1]]
view [[0.409936, 0.683812, -0.603617, 0], [0, 0.661778, 0.7497, 0], [0.912114, -0.307329, 0.271286, 0], [-0, -1.323555, -1.499401, 1]]
view^1 [[0, 0, 1.096354, 0], [0.755239, 0.755843, -0.339431, 0], [-0.666667, 0.666667, 0.299623, 0], [0, 2, 0, 1]]
view^1*view [[0.918853, 0.114443, 0.03647, 0], [0, 1, 0, 0], [-0.412964, -0.051435, 1.185601, 0], [0, 0, 0, 1]]
view [[-0.160691, -0.772608, 0.614211, 0], [-0, 0.622298, 0.78278, 0], [-0.987005, 0.125786, -0.099998, 0], [0, -1.244597, -1.565561, 1]]
view^1 [[0, 2, -1.013166, 0], [-0.838591, 0.349061, 0.136529, 0], [0.666667, 1, -0.108538, 0], [0, 2, 0, 1]]
view^1*view [[1.057376, 0.023141, -0.009341, 0], [0, 1, 0, 0], [-0.172148, -2.030101, 1.028027, 0], [-0, 0, 0, 1]]
Normally it should look like this
view [[-0.681878, -0.403519, 0.610094, 0], [0, 0.83407, 0.551659, 0], [-0.731466, 0.376164, -0.568734, 0], [-0, -1.66814, -1.103317, 1]]
view^1 [[-0.681878, 0, -0.731466, 0], [-0.403519, 0.83407, 0.376164, 0], [0.610093, 0.551659, -0.568734, 0], [0, 2, 0, 1]]
view^1*view [[1, 0, 0, 0], [0, 1, 0, 0], [-0, 0, 1, 0], [-0, 0, 0, 1]]
Testing code with floating point numbers and cgmath data structures one can use assertions on ApproxEq types:
assert!(a.approx_eq(&b));
assert!(a.approx_eq_eps(&b, eps));
This does not yield readable error messages upon failure. Arguably it is also a bit ugly to read/write. I propose adding macros similar to assert_eq!
to alleviate this, e.g.:
assert_approx_eq!(a, b);
assert_approx_eq_eps!(a, b, eps);
I could go ahead and prepare a patch but I wanted to check first, if there is a reason why this has not been done yet or if anybody has objections to that.
For example,
let persp = cgmath::PerspectiveFov {
fovy: cgmath::Deg { s: 90.0f32 },
aspect: 1.0,
near: 0.1,
far: 1000.0
};
let frustum = Frustum::from_matrix4(persp.to_matrix4());
println!("{}", frustum.far);
println!("{}", persp.to_matrix4().mul_v(&Vector4::new(0.0, 0.0, 1.0, 1.0)));
println!("{}", persp.to_matrix4().mul_v(&Vector4::new(0.0, 0.0, -1.0, 1.0)));
println!("{}", persp.to_matrix4().mul_v(&Vector4::new(0.0, 0.0, -999.0, 1.0)));
println!("{}", persp.to_matrix4().mul_v(&Vector4::new(0.0, 0.0, -1001.0, 1.0)));
outputs 0x + 0y + 0.000999z - 0.999999 = 0
for the far plane, i.e. z=1000, when in fact the plane should be z=-1000.
I think this is because Plane::from_vector4 uses the vector's fourth component as D, but the way from_matrix4 uses it, it should be -D. For example, the left clipping plane should have the equation v . (row(3) + row(0)) = 0 (taking the rows from the projection matrix), but since planes are represented with equations of the form A_x + B_y + C*z - D = 0, the D is negated.
I'm not sure whether Plane::from_vector4 is doing what's intended, but either it needs to negate D, or Frustum::from_matrix4 needs to be fixed somehow.
fn transform_vec(&self, v: Vec3<S>) -> Vec3<S> {
self.mul_q(&Quat::from_sv(0., v)).mul_q(&self.conjugate()).v
}
Rotates a Vec3
by the quaternion, assuming it's of unit length. I would think this is one of the most common operations one would want to do on a quaternion, have I made a mistake in thinking it's not in the library already?
fn between_vecs(a: Vec3<S>, b: Vec3<S>) -> Quat<S>;
Would return the minimum-angle spatial rotation needed to rotate a
to b
(the axis of rotation would be a cross b). This can be implemented using from_axis_angle
but we can save a few trigonometric operations with a direct implementation. I needed this function at one point, but I'm not sure if it's common in other libraries.
fn to_mat4(&self) -> Mat4<S> {
self.to_mat3().to_mat4()
}
For the sake of convenience, implement the ToMat4
trait.
Vector/point types, quaternions, and various other types would possibly benefit from implementations of std::to_bytes::IterBytes
so they can be used as keys in std::hashmap::HashMap
s.
I admit to being a Rust newbie, and I don't have a good sense of the idioms yet; otherwise I would be happy to open a pull request :)
Hyeon: (what's the github name?)
Personally cgmath looks a bit needlessly complicated // ex: why
Vector3::new(x, y, z)
notvec3(x, y, z)
I was looking into having Cargo run the benchmarks instead of using a Makefile (see #135). Cargo uses full optimizations to build the benchmarks (which I think absolutely makes sense), while this project's custom Makefile does not. And thereby many benchmarks were completely optimized away by the compiler. This is probably due to the fact, that it knows too much at compile-time.
One can use random input data or use test::black_box
to alleviate this. In their current form most benchmarks are not really useful.
For reference, here is the output of running the benchmarks compiled with full optimizations:
test bench_matrix2_add_m ... bench: 0 ns/iter (+/- 0)
test bench_matrix2_add_self_m ... bench: 0 ns/iter (+/- 0)
test bench_matrix2_div_s ... bench: 0 ns/iter (+/- 0)
test bench_matrix2_div_self_s ... bench: 0 ns/iter (+/- 0)
test bench_matrix2_mul_m ... bench: 6 ns/iter (+/- 0)
test bench_matrix2_mul_s ... bench: 0 ns/iter (+/- 0)
test bench_matrix2_mul_self_m ... bench: 0 ns/iter (+/- 0)
test bench_matrix2_neg_self ... bench: 0 ns/iter (+/- 0)
test bench_matrix2_rem_s ... bench: 17 ns/iter (+/- 0)
test bench_matrix2_rem_self_s ... bench: 17 ns/iter (+/- 0)
test bench_matrix2_sub_m ... bench: 0 ns/iter (+/- 0)
test bench_matrix2_sub_self_m ... bench: 0 ns/iter (+/- 0)
test bench_matrix2_transpose ... bench: 2 ns/iter (+/- 0)
test bench_matrix2_transpose_self ... bench: 0 ns/iter (+/- 0)
test bench_matrix3_add_m ... bench: 2 ns/iter (+/- 0)
test bench_matrix3_add_self_m ... bench: 0 ns/iter (+/- 0)
test bench_matrix3_div_s ... bench: 0 ns/iter (+/- 0)
test bench_matrix3_div_self_s ... bench: 0 ns/iter (+/- 0)
test bench_matrix3_mul_m ... bench: 7 ns/iter (+/- 0)
test bench_matrix3_mul_s ... bench: 0 ns/iter (+/- 0)
test bench_matrix3_mul_self_m ... bench: 0 ns/iter (+/- 0)
test bench_matrix3_neg_self ... bench: 0 ns/iter (+/- 0)
test bench_matrix3_rem_s ... bench: 38 ns/iter (+/- 1)
test bench_matrix3_rem_self_s ... bench: 38 ns/iter (+/- 1)
test bench_matrix3_sub_m ... bench: 2 ns/iter (+/- 0)
test bench_matrix3_sub_self_m ... bench: 0 ns/iter (+/- 0)
test bench_matrix3_transpose ... bench: 3 ns/iter (+/- 0)
test bench_matrix3_transpose_self ... bench: 0 ns/iter (+/- 0)
test bench_matrix4_add_m ... bench: 2 ns/iter (+/- 0)
test bench_matrix4_add_self_m ... bench: 2 ns/iter (+/- 0)
test bench_matrix4_div_s ... bench: 0 ns/iter (+/- 0)
test bench_matrix4_div_self_s ... bench: 0 ns/iter (+/- 0)
test bench_matrix4_mul_m ... bench: 7 ns/iter (+/- 0)
test bench_matrix4_mul_s ... bench: 0 ns/iter (+/- 0)
test bench_matrix4_mul_self_m ... bench: 7 ns/iter (+/- 0)
test bench_matrix4_neg_self ... bench: 0 ns/iter (+/- 0)
test bench_matrix4_rem_s ... bench: 67 ns/iter (+/- 0)
test bench_matrix4_rem_self_s ... bench: 67 ns/iter (+/- 0)
test bench_matrix4_sub_m ... bench: 2 ns/iter (+/- 0)
test bench_matrix4_sub_self_m ... bench: 0 ns/iter (+/- 0)
test bench_matrix4_transpose ... bench: 5 ns/iter (+/- 0)
test bench_matrix4_transpose_self ... bench: 3 ns/iter (+/- 1)
cgmath-rs $ make
mkdir -p lib
rustc --out-dir=lib -O src/cgmath/lib.rs
src/cgmath/vector.rs:72:58: 72:61 error: failed to find an implementation of trait std::cmp::TotalOrd for S
src/cgmath/vector.rs:72 #[inline] fn comp_min(&self) -> S { self.fold(|a, b| min(a.clone(), b.clone())) }
(with bleeding edge rust off master)
Edit: didn't catch that breaking build icon from travis, so I reckon you're on top of this one ;)
As far as I can tell from the documentation, there are no such functions. I am aware that there are different techniques to go about this, but I still think the library could be improved by providing one implementation.
@ozkriff reports that #77 broke his project, https://github.com/ozkriff/marauder. I think it was something about no triangles being draw to the screen any more. This is serious, and indicates a gap in our test coverage.
The rand_macros
crate breaks all the time :(
/cc. #174
I currently am stretching myself quite thin when it comes to projects, and I feel like I am no longer able to adequately steer the development of cgmath going forwards. I am also considering moving to @sebcrozet's nalgebra library for my future projects. I can continue to merge PRs, but I can't see myself contributing much heading into the future. If somebody has the passion or energy to spare to keep things going, I am also happy to transfer ownership of the repository.
I have commented out the offending lines in my branch here just to get my project compiling again as I wasn't sure what to do about this. It might be the case that you need UBaseNum, or just say no unsigned geometries!
When inverting a matrix, we check that the determinant is non-zero using approx_eq
. If the determinant is approximately zero, the inversion fails.
But approx_eq
only goes to a precision of 10^-5.
That's problematic, because projection matrices often have very small determinants. This is especially true when the camera is zoomed out very far. In that case, we're transforming a large volume of world space to the clip space volume. Which means that the determinant tends to be very small. (This is because the determinant is the ratio of the two volumes.)
GLM is well known. It would be nice to have a compatible interface.
We don't need to change existing code, we can just add glm
module with some functions, so that glm::rotate
, for example, produces a matching Matrix4
.
Edit: I don't have much GLM experience, so maybe someone else wants to try this out?
Quaternion::mul_q
is correct, but mul_self_q
just multiplies the scalar part and vector part.
I'd like to use Aabb2 as a rectangle type in my code, and want the basic representation to match the range of points inside the box instead of the center: struct Aabb2 { top: Point2, size: Vec2 }. Rectangle code is mostly concerned with the edges instead of the center, so accessing those with simple arithmetic that doesn't involve dividing size components by two would be quite nice.
Code that needs the box center can use a method which derives the center point from the top and size data.
From user perspective writing cgmath::vector::Vector2
rather then cgmath::Vector2
adds nothing except verbosity. Everything is implemented as a methods, so name collisions are unlikely.
Vector +- Vector
Point +- Vector
Matrix * Vector
Quat * Vector
...
probably a lot more, but we need to keep the behavior strictly obvious (i.e. not overloading Vector*Vector as a dot product)
@kvark reports an error on the latest nightly:
src/cgmath/plane.rs:70:18: 70:27 error: cannot transmute from a type that contains type parameters
Once @nikomatsakis' trait reform lands, I would love to be able to do:
let vec4 = (vec2a, vec2b).to_vec4();
let vec3 = (1.3, vec2a).to_vec3();
let mat3 = (vec3, (vec2a, 3.0).to_vec3(), vec3).to_mat3();
I don't quite follow your logic of when to pass arguments by value and when to pass by reference. For example, on the one hand you have:
fn look_at(dir: &Vector3<S>, up: &Vector3<S>) -> Matrix3<S>
which seems reasonable enough, although passing two Vector3 by value shouldn't be too expensive. However, on the other hand you have:
fn new(left: Plane<S>, right: Plane<S>, bottom: Plane<S>, top: Plane<S>, near: Plane<S>, far: Plane<S>) -> Frustum<S>
which, as far as I understand, will imply the copy of 6 planes to construct a Frustum.
Could you shed some light into this?
Thanks.
@cmr has expressed concerns on #rust-gamedev that the API is confusing, especially in regards to transformations. He suggested an API closer to that of GLM. Of course that would be rather difficult seeing as Rust's overloading isn't nearly as expressive as C++'s. I am curious however as to what you guys think regarding the current API. What could be changed and improved?
cc. @ozkriff @csherratt
Now that breaking changes are mostly gone (I don't think you're using std::io, std::os, etc.), would it be possible to update the version of nalgebra on crates.io?
Right now, the Intersect
trait is implemented for tuples of values, like this:
(Sphere<S>, Ray3<S>)
The problem is that you have to copy the values if you want to use them after testing the intersection. For example:
let inter = (my_sphere.clone(), my_ray.clone().intersection();
some_other_function(&my_sphere, &my_ray);
To avoid that copying, could we implement Intersect
for tuples of references instead? Like this:
(&Sphere<S>, &Ray3<S>)
Or perhaps tuples of references and tuples of values could both be supported.
For a 2D AABB, 4 checks are being performed to determine if a point is inside.
This can be cut down to 2 checks, at the cost of the internals getting a little bit switched around.
Instead of storing AABBs as 2 points, they can be stored as a centre and extent:
pub struct Aabb2<S> {
centre: Point<S>,
extent: Vector2<S>,
}
(I don't know what the functional difference is between Points and Vectors, but I think it doesn't matter too much)
With that, the collision checking becomes a bit more efficient, as you can take the difference of 2 centres, and compare it to the sum of the extents, effectively halving the checks required. (I wrote a quick and dirty example here). The same idea can be applied to aabb-point collision by giving assuming points have an extent of zero.
The reason I haven't put this straight into a pull request is that it fundamentally changes the internals of aabbs in a way that may confuse people who aren't aware of the change. Also, the lack of an abs()
method for integer types may require some sort of workaround, which I am not sure of.
Most of the information is in the example. (http://is.gd/XNKOEn)
#[old_impl_check]
was recently removed:
src/line.rs:31:1: 31:18 error: The attribute `old_impl_check` is currently unknown to the the compiler and may have meaning added to it in the future
src/line.rs:31 #[old_impl_check]
^~~~~~~~~~~~~~~~~
src/line.rs:31:18: 31:18 help: add #![feature(custom_attribute)] to the crate attributes to enable
src/ray.rs:28:1: 28:18 error: The attribute `old_impl_check` is currently unknown to the the compiler and may have meaning added to it in the future
src/ray.rs:28 #[old_impl_check]
^~~~~~~~~~~~~~~~~
src/ray.rs:28:18: 28:18 help: add #![feature(custom_attribute)] to the crate attributes to enable
error: aborting due to 2 previous errors
Removing the attributes results in:
src/line.rs:31:6: 31:7 error: the type parameter `S` is not constrained by the impl trait, self type, or predicates [E0207]
src/line.rs:31 impl<S: BaseNum, V: Vector<S>, P: Point<S, V>> Line<P> {
^
src/line.rs:31:18: 31:19 error: the type parameter `V` is not constrained by the impl trait, self type, or predicates [E0207]
src/line.rs:31 impl<S: BaseNum, V: Vector<S>, P: Point<S, V>> Line<P> {
^
src/ray.rs:28:6: 28:7 error: the type parameter `S` is not constrained by the impl trait, self type, or predicates [E0207]
src/ray.rs:28 impl<S: BaseNum, V: Vector<S>, P: Point<S, V>> Ray<P, V> {
^
error: aborting due to 3 previous errors
Apparently cgmath needs associated types from the ground up to solve this problem.
It would be very useful (for me) if you could use standard operators with points,
that operated on each element piecewise (e.g. P1 {3, 1} + P2 {2, 2} = P3 {5, 3}).
To do this would require changing the point interface to include the function:
fn add_p(&self, p: &Self) -> Self;
as well as the optional functions:
fn add_self_p(&mut self, p: &Self);
fn sub_self_p(&mut self, p: &Self);
And to change the signature of sub_p
to:
fn sub_p(&self, p: &Self) -> Self;
The old behaviour of sub_p
could be achieved by chaining it with a to_vec()
call, or
(if it's a really common operation), a new method could be added to the interface.
gfx-rs library is math-independent and operates on fixed-size arrays. Thus, anything that is built using gfx-rs and cgmath-rs needs to convert from cgmath types into raw fixed-size arrays. See cube example code: https://github.com/gfx-rs/gfx-rs/blob/master/src/examples/cube/main.rs#L229
Currently it is difficult to correctly assemble a view matrix. Using Transform3D will end up with a matrix that is always originated towards or away from the origion.
Code example:
extern mod cgmath;
use cgmath::transform::Transform3D;
use cgmath::matrix::{Mat4, ToMat4, Matrix};
use cgmath::vector::{Vec3, Vec4};
use cgmath::projection::perspective;
use cgmath::quaternion::Quat;
use cgmath::angle::{deg, ToRad};
fn project(projection: &Mat4<f32>, view: &Mat4<f32>, model: &Mat4<f32>)
{
// this represents any vertex, we just use one at the origin because it is easy.
let vec = Vec4::new(0f32, 0f32, 0f32, 1f32);
// standard way to project the point
let projected_vec = projection.mul_m(view).mul_m(model).mul_v(&vec);
// OpenGL does this for you, This is only needed to compare viewports
let point = Vec3::new(projected_vec.x / projected_vec.w,
projected_vec.y / projected_vec.w,
projected_vec.z / projected_vec.w);
// x, y must be between -1 and 1. z Must be greater then 0 and less then 1 to be in the viewport.
println!("x: {} y: {}, z: {}", point.x, point.y, point.z);
}
fn main()
{
let projection = perspective(deg(45f32), 1f32, 0.1f32, 10f32);
let model = Transform3D::new(1f32,
Quat::from_axis_angle(&Vec3::new(0f32, 0f32, 0f32), deg(0f32).to_rad()),
Vec3::new(0f32, 0f32, 0f32));
// rotate the camera when keeping it a position 0, 0, -5.
// the model is always at the origin
for angle in std::iter::range_step(0, 360, 30) {
let view = Transform3D::new(1f32,
Quat::from_axis_angle(&Vec3::new(0f32, 1f32, 0f32), deg(angle as f32).to_rad()),
Vec3::new(0f32, 0f32, -5f32));
project(&projection, &view.get().to_mat4(), &model.get().to_mat4());
}
}
Output::
x: 0 y: 0, z: 0.979798
x: 0 y: 0, z: 0.979798
x: 0 y: 0, z: 0.979798
x: 0 y: 0, z: 0.979798
x: 0 y: 0, z: 0.979798
x: 0 y: 0, z: 0.979798
x: 0 y: 0, z: 0.979798
x: 0 y: 0, z: 0.979798
x: 0 y: 0, z: 0.979798
x: 0 y: 0, z: 0.979798
x: 0 y: 0, z: 0.979798
x: 0 y: 0, z: 0.979798
One way to create the correct matrix would be as follows
let translate = Mat4::new(1f32, 0f32, 0f32, 0f32,
0f32, 1f32, 0f32, 0f32,
0f32, 0f32, 1f32, 0f32,
0f32, 0f32, -5f32, 1f32);
let rotate = Quat::from_axis_angle(&Vec3::new(0f32, 1f32, 0f32), deg(angle as f32).to_rad()).to_mat3().to_mat4();
let view = rotate.mul_m(&translate);
project(&projection, &view, &model.get().to_mat4());
x: 0 y: 0, z: 0.979798
x: -1.393847 y: 0, z: 0.973547
x: -4.18154 y: 0, z: 0.939394
x: -40503776 y: 0, z: -677866.375
x: 4.181539 y: 0, z: 1.10101
x: 1.393847 y: 0, z: 1.066857
x: -0 y: 0, z: 1.060606
x: -1.393847 y: 0, z: 1.066857
x: -4.181541 y: 0, z: 1.10101
x: 40503776 y: 0, z: -677866.375
x: 4.181542 y: 0, z: 0.939394
x: 1.393847 y: 0, z: 0.973547
I think there should probably be a library function/object to help create this matrix.
unfortunately, cgmath is failing to build on rust-master right now. a verbose output
error: failed to find an implementation of trait std::ops::Add<vector::Vec2<S>,vector::Vec2<S>> for vector::Vec2<S>
in expansion of #[deriving(Zero)]
The branch rust-1.0 is what is on crates.io and is what people use I belive.
I would have thought that matrix_a * matrix_b
was just a convenient shorthand for matrix_a.mul_m(&matrix_b)
.
But apparently this is not the case:
extern crate cgmath;
use cgmath::matrix::Matrix3;
use cgmath::matrix::Matrix;
fn main() {
let m_a = Matrix3::new( 5.0, 4.0, 0.0,
-3.0, 1.0, -1.0,
3.0, 2.0, -2.0);
let m_b = Matrix3::new( 5.0, 6.0, 4.0,
7.0, 0.0, -1.0,
1.0, 2.0, -2.0);
println!("m_a.mul_m(m_b): {}", m_a.mul_m(&m_b));
println!("m_b.mul_m(m_a): {}", m_b.mul_m(&m_a));
println!("m_a * m_b: {}", m_a * m_b);
println!("m_b * m_a: {}", m_b * m_a);
}
Transcript of run:
% ./bug
m_a.mul_m(m_b): [[19, 34, -14], [32, 26, 2], [-7, 2, 2]]
m_b.mul_m(m_a): [[53, 30, 16], [-9, -20, -11], [27, 14, 14]]
m_a * m_b: [[25, 24, 0], [-21, 0, 1], [3, 4, 4]]
m_b * m_a: [[25, 24, 0], [-21, 0, 1], [3, 4, 4]]
I have not yet dived deeply into the code to attempt to explain this phenomenon. But I thought I would report it and see if someone else reported back with an explanation for the current behavior.
It would be nice to use quickcheck for some of the tests: https://github.com/BurntSushi/quickcheck
@mahkoh has requested some clarification about the ray-sphere intersection code (see PR #9). Namely if the origin of the ray is inside the sphere or the length isn't normed.
cc. @JeffBelgum
There are lots of conventions as to what constitutes Euler angles. I think it would be good to make the convention used in cgmath explicit in the documentation of the Rotation3 trait (maybe adding some neat diagrams with axes and angles to visually convey the sense of rotation?). Another idea that goes along these lines: the convention should be required by any Rotation3 implementation and asserting it sounds like a great property to test using quickcheck.
All this is probably low priority atm but I thought I'd open this issue after spending a bit of time empirically determining the convention.
This is a huge task, but I think the long term benefits are worth it. It would be helpful if we added some simd support for some operators.
We can split up BaseFloat
to ScalarFloat
and SIMDFloat
(Suggestions for better names?). SIMDFloat
is a subset of Float
of primitives that can map to a vector of elements. The idea is not that we try and use a f32x4
to represent a single Vector4
, but rather to create Vector4<f32x4>
. This would mean you are operating on four vector4's at a time.
Thoughts?
I'm beginning to feel like Array
is making our type signatures really ugly. It also makes the API more complex. The closures also make it harder for LLVM to perform optimizations. I would rather have abit of code duplication in exchange for simplicity.
I am planning to use Point3<i32>
, Point3<f32>
inside structs in my code that need to be hashable. For that, I understand they need to implement Hash + Eq
, but they only implement Hash + PartialEq
.
Is that just an oversight, or is there a reason?
Adding triangles to the library could be useful to then provide built-in functions such as plane-triangle and frustum-triangle intersections. However, the exact representation of a triangle is always application-dependent: it could be 3 vertices, 3 vertices and a normal, 3 indices into some array of vertices, etc. For this reason, in the application I am currently writing, I have written a Triangle
trait to abstract away particular triangle representations:
pub trait Triangle<S> {
fn p0 (&self) -> Point3<S>;
fn p1 (&self) -> Point3<S>;
fn p2 (&self) -> Point3<S>;
}
Once the trait is set up, you can provide a whole bunch of useful functions:
pub fn supporting_plane<S: BaseFloat> (t: &Triangle<S>) -> Option<Plane<S>>
pub enum PlaneIntersection {
Front,
Back,
Intersecting,
Containing
}
pub fn intersect<S: Num + BaseFloat> (p: &Plane<S>, t: &Triangle<S>) -> PlaneIntersection
When the client code wants to use these functions, they simply write a Triangle
implementation for their particular triangle representation:
struct SimpleTriangle {
_p0: Point3<f32>,
_p1: Point3<f32>,
_p2: Point3<f32>
}
impl Triangle<f32> for SimpleTriangle {
fn p0 (&self) -> Point3<f32> { self._p0 }
fn p1 (&self) -> Point3<f32> { self._p1 }
fn p2 (&self) -> Point3<f32> { self._p2 }
}
and then they are ready to roll.
What do you think about integrating something like this into cgmath?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.