new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"118514fd9c4958df0d25584cda4917186c46011569f55ef350530c1ad3fbdb48",".travis.yml":"13d3e5a7bf83b04c8e8cfa14f0297bd8366d68391d977dd547f64707dffc275a","COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"c91c98dc9510ef29a7ce0d7c78294f15cb139c9afecca38e5fda56b0a6984954","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/approxeq.rs":"6cf810ad389c73a27141a7a67454ed12d4b01c3c16605b9a7414b389bc0615dd","src/length.rs":"d7c6369f2fe2a17c845b57749bd48c471159f0571a7314d3bf90737d53f697d3","src/lib.rs":"e2e621f05304278d020429d0349acf7a4e7c7a9a72bd23fc0e55680267472ee9","src/macros.rs":"b63dabdb52df84ea170dc1dab5fe8d7a78c054562d1566bab416124708d2d7af","src/matrix2d.rs":"2361338f59813adf4eebaab76e4dd82be0fbfb9ff2461da8dd9ac9d43583b322","src/matrix4d.rs":"b8547bed6108b037192021c97169c00ad456120b849e9b7ac7bec40363edaec1","src/num.rs":"749b201289fc6663199160a2f9204e17925fd3053f8ab7779e7bfb377ad06227","src/point.rs":"dbf12a3ad35dc2502b7f2637856d8ee40f5a96e37ed00f3ee3272bf5752c060c","src/rect.rs":"0a255046dd11a6093d9a77e327e1df31802808536b4d87e4e3b80ff6b208de0f","src/scale_factor.rs":"df6dbd1f0f9f63210b92809f84a383dad982a74f09789cf22c7d8f9b62199d39","src/side_offsets.rs":"f85526a421ffda63ff01a3478d4162c8717eef68e942acfa2fd9a1adee02ebb2","src/size.rs":"ae1b647e300600b50a21dba8c1d915801782ebae82baeb5e49017e6d68a49b28","src/trig.rs":"ef290927af252ca90a29ba9f17158b591ed591604e66cb9df045dd47b9cfdca5"},"package":"6083f113c422ff9cd855a1cf6cc8ec0903606c0eb43a0c6a0ced3bdc9731e4c1"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/.gitignore
@@ -0,0 +1,2 @@
+Cargo.lock
+/target/
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/.travis.yml
@@ -0,0 +1,19 @@
+language: rust
+
+notifications:
+ webhooks: http://build.servo.org:54856/travis
+
+matrix:
+ include:
+ - rust: stable
+ env: FEATURES=""
+ - rust: beta
+ env: FEATURES=""
+ - rust: nightly
+ env: FEATURES=""
+ - rust: nightly
+ env: FEATURES="unstable"
+
+script:
+ - cargo build --verbose --features "$FEATURES"
+ - cargo test --verbose --features "$FEATURES"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/COPYRIGHT
@@ -0,0 +1,5 @@
+Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+<LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+option. All files in the project carrying such notice may not be
+copied, modified, or distributed except according to those terms.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "euclid"
+version = "0.13.0"
+authors = ["The Servo Project Developers"]
+description = "Geometry primitives"
+documentation = "https://docs.rs/euclid/"
+repository = "https://github.com/servo/euclid"
+keywords = ["matrix", "vector", "linear-algebra", "geometry"]
+categories = ["science"]
+license = "MIT / Apache-2.0"
+
+[features]
+unstable = []
+
+[dependencies]
+heapsize = "0.4"
+rustc-serialize = "0.3.2"
+num-traits = {version = "0.1.32", default-features = false}
+log = "0.3.1"
+serde = "0.9"
+
+[dev-dependencies]
+rand = "0.3.7"
+serde_test = "0.9"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2012-2013 Mozilla Foundation
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/README.md
@@ -0,0 +1,8 @@
+# euclid
+
+This is a small library for geometric types with a focus on 2d graphics and
+layout.
+
+* [Documentation](https://docs.rs/euclid/)
+* [Release notes](https://github.com/servo/euclid/releases)
+* [crates.io](https://crates.io/crates/euclid)
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/src/approxeq.rs
@@ -0,0 +1,36 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+/// Trait for testing approximate equality
+pub trait ApproxEq<Eps> {
+ fn approx_epsilon() -> Eps;
+ fn approx_eq(&self, other: &Self) -> bool;
+ fn approx_eq_eps(&self, other: &Self, approx_epsilon: &Eps) -> bool;
+}
+
+macro_rules! approx_eq {
+ ($ty:ty, $eps:expr) => (
+ impl ApproxEq<$ty> for $ty {
+ #[inline]
+ fn approx_epsilon() -> $ty { $eps }
+ #[inline]
+ fn approx_eq(&self, other: &$ty) -> bool {
+ self.approx_eq_eps(other, &$eps)
+ }
+ #[inline]
+ fn approx_eq_eps(&self, other: &$ty, approx_epsilon: &$ty) -> bool {
+ (*self - *other).abs() < *approx_epsilon
+ }
+ }
+ )
+}
+
+approx_eq!(f32, 1.0e-6);
+approx_eq!(f64, 1.0e-6);
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/src/length.rs
@@ -0,0 +1,449 @@
+// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//! A one-dimensional length, tagged with its units.
+
+use scale_factor::ScaleFactor;
+use num::Zero;
+
+use heapsize::HeapSizeOf;
+use num_traits::{NumCast, Saturating};
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
+use std::cmp::Ordering;
+use std::ops::{Add, Sub, Mul, Div, Neg};
+use std::ops::{AddAssign, SubAssign};
+use std::marker::PhantomData;
+use std::fmt;
+
+/// A one-dimensional distance, with value represented by `T` and unit of measurement `Unit`.
+///
+/// `T` can be any numeric type, for example a primitive type like `u64` or `f32`.
+///
+/// `Unit` is not used in the representation of a `Length` value. It is used only at compile time
+/// to ensure that a `Length` stored with one unit is converted explicitly before being used in an
+/// expression that requires a different unit. It may be a type without values, such as an empty
+/// enum.
+///
+/// You can multiply a `Length` by a `scale_factor::ScaleFactor` to convert it from one unit to
+/// another. See the `ScaleFactor` docs for an example.
+// Uncomment the derive, and remove the macro call, once heapsize gets
+// PhantomData<T> support.
+#[repr(C)]
+#[derive(RustcDecodable, RustcEncodable)]
+pub struct Length<T, Unit>(pub T, PhantomData<Unit>);
+
+impl<T: Clone, Unit> Clone for Length<T, Unit> {
+ fn clone(&self) -> Self {
+ Length(self.0.clone(), PhantomData)
+ }
+}
+
+impl<T: Copy, Unit> Copy for Length<T, Unit> {}
+
+impl<Unit, T: HeapSizeOf> HeapSizeOf for Length<T, Unit> {
+ fn heap_size_of_children(&self) -> usize {
+ self.0.heap_size_of_children()
+ }
+}
+
+impl<Unit, T> Deserialize for Length<T, Unit> where T: Deserialize {
+ fn deserialize<D>(deserializer: D) -> Result<Length<T, Unit>,D::Error>
+ where D: Deserializer {
+ Ok(Length(try!(Deserialize::deserialize(deserializer)), PhantomData))
+ }
+}
+
+impl<T, Unit> Serialize for Length<T, Unit> where T: Serialize {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
+ self.0.serialize(serializer)
+ }
+}
+
+impl<T, Unit> Length<T, Unit> {
+ pub fn new(x: T) -> Length<T, Unit> {
+ Length(x, PhantomData)
+ }
+}
+
+impl<Unit, T: Clone> Length<T, Unit> {
+ pub fn get(&self) -> T {
+ self.0.clone()
+ }
+}
+
+impl<T: fmt::Debug + Clone, U> fmt::Debug for Length<T, U> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.get().fmt(f)
+ }
+}
+
+impl<T: fmt::Display + Clone, U> fmt::Display for Length<T, U> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.get().fmt(f)
+ }
+}
+
+// length + length
+impl<U, T: Clone + Add<T, Output=T>> Add for Length<T, U> {
+ type Output = Length<T, U>;
+ fn add(self, other: Length<T, U>) -> Length<T, U> {
+ Length::new(self.get() + other.get())
+ }
+}
+
+// length += length
+impl<U, T: Clone + AddAssign<T>> AddAssign for Length<T, U> {
+ fn add_assign(&mut self, other: Length<T, U>) {
+ self.0 += other.get();
+ }
+}
+
+// length - length
+impl<U, T: Clone + Sub<T, Output=T>> Sub<Length<T, U>> for Length<T, U> {
+ type Output = Length<T, U>;
+ fn sub(self, other: Length<T, U>) -> <Self as Sub>::Output {
+ Length::new(self.get() - other.get())
+ }
+}
+
+// length -= length
+impl<U, T: Clone + SubAssign<T>> SubAssign for Length<T, U> {
+ fn sub_assign(&mut self, other: Length<T, U>) {
+ self.0 -= other.get();
+ }
+}
+
+// Saturating length + length and length - length.
+impl<U, T: Clone + Saturating> Saturating for Length<T, U> {
+ fn saturating_add(self, other: Length<T, U>) -> Length<T, U> {
+ Length::new(self.get().saturating_add(other.get()))
+ }
+
+ fn saturating_sub(self, other: Length<T, U>) -> Length<T, U> {
+ Length::new(self.get().saturating_sub(other.get()))
+ }
+}
+
+// length / length
+impl<Src, Dst, T: Clone + Div<T, Output=T>> Div<Length<T, Src>> for Length<T, Dst> {
+ type Output = ScaleFactor<T, Src, Dst>;
+ #[inline]
+ fn div(self, other: Length<T, Src>) -> ScaleFactor<T, Src, Dst> {
+ ScaleFactor::new(self.get() / other.get())
+ }
+}
+
+// length * scaleFactor
+impl<Src, Dst, T: Clone + Mul<T, Output=T>> Mul<ScaleFactor<T, Src, Dst>> for Length<T, Src> {
+ type Output = Length<T, Dst>;
+ #[inline]
+ fn mul(self, scale: ScaleFactor<T, Src, Dst>) -> Length<T, Dst> {
+ Length::new(self.get() * scale.get())
+ }
+}
+
+// length / scaleFactor
+impl<Src, Dst, T: Clone + Div<T, Output=T>> Div<ScaleFactor<T, Src, Dst>> for Length<T, Dst> {
+ type Output = Length<T, Src>;
+ #[inline]
+ fn div(self, scale: ScaleFactor<T, Src, Dst>) -> Length<T, Src> {
+ Length::new(self.get() / scale.get())
+ }
+}
+
+// -length
+impl <U, T:Clone + Neg<Output=T>> Neg for Length<T, U> {
+ type Output = Length<T, U>;
+ #[inline]
+ fn neg(self) -> Length<T, U> {
+ Length::new(-self.get())
+ }
+}
+
+impl<Unit, T0: NumCast + Clone> Length<T0, Unit> {
+ /// Cast from one numeric representation to another, preserving the units.
+ pub fn cast<T1: NumCast + Clone>(&self) -> Option<Length<T1, Unit>> {
+ NumCast::from(self.get()).map(Length::new)
+ }
+}
+
+impl<Unit, T: Clone + PartialEq> PartialEq for Length<T, Unit> {
+ fn eq(&self, other: &Length<T, Unit>) -> bool { self.get().eq(&other.get()) }
+}
+
+impl<Unit, T: Clone + PartialOrd> PartialOrd for Length<T, Unit> {
+ fn partial_cmp(&self, other: &Length<T, Unit>) -> Option<Ordering> {
+ self.get().partial_cmp(&other.get())
+ }
+}
+
+impl<Unit, T: Clone + Eq> Eq for Length<T, Unit> {}
+
+impl<Unit, T: Clone + Ord> Ord for Length<T, Unit> {
+ fn cmp(&self, other: &Length<T, Unit>) -> Ordering { self.get().cmp(&other.get()) }
+}
+
+impl<Unit, T: Zero> Zero for Length<T, Unit> {
+ fn zero() -> Length<T, Unit> {
+ Length::new(Zero::zero())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::Length;
+ use num::Zero;
+
+ use heapsize::HeapSizeOf;
+ use num_traits::Saturating;
+ use scale_factor::ScaleFactor;
+ use std::f32::INFINITY;
+
+ extern crate serde_test;
+ use self::serde_test::Token;
+ use self::serde_test::assert_tokens;
+
+ enum Inch {}
+ enum Mm {}
+ enum Cm {}
+ enum Second {}
+
+ #[test]
+ fn test_clone() {
+ // A cloned Length is a separate length with the state matching the
+ // original Length at the point it was cloned.
+ let mut variable_length: Length<f32, Inch> = Length::new(12.0);
+
+ let one_foot = variable_length.clone();
+ variable_length.0 = 24.0;
+
+ assert_eq!(one_foot.get(), 12.0);
+ assert_eq!(variable_length.get(), 24.0);
+ }
+
+ #[test]
+ fn test_heapsizeof_builtins() {
+ // Heap size of built-ins is zero by default.
+ let one_foot: Length<f32, Inch> = Length::new(12.0);
+
+ let heap_size_length_f32 = one_foot.heap_size_of_children();
+
+ assert_eq!(heap_size_length_f32, 0);
+ }
+
+ #[test]
+ fn test_heapsizeof_length_vector() {
+ // Heap size of any Length is just the heap size of the length value.
+ for n in 0..5 {
+ let length: Length<Vec<f32>, Inch> = Length::new(Vec::with_capacity(n));
+
+ assert_eq!(length.heap_size_of_children(), length.0.heap_size_of_children());
+ }
+ }
+
+ #[test]
+ fn test_length_serde() {
+ let one_cm: Length<f32, Mm> = Length::new(10.0);
+
+ assert_tokens(&one_cm, &[Token::F32(10.0)]);
+ }
+
+ #[test]
+ fn test_get_clones_length_value() {
+ // Calling get returns a clone of the Length's value.
+ // To test this, we need something clone-able - hence a vector.
+ let mut length: Length<Vec<i32>, Inch> = Length::new(vec![1, 2, 3]);
+
+ let value = length.get();
+ length.0.push(4);
+
+ assert_eq!(value, vec![1, 2, 3]);
+ assert_eq!(length.get(), vec![1, 2, 3, 4]);
+ }
+
+ #[test]
+ fn test_fmt_debug() {
+ // Debug and display format the value only.
+ let one_cm: Length<f32, Mm> = Length::new(10.0);
+
+ let result = format!("{:?}", one_cm);
+
+ assert_eq!(result, "10");
+ }
+
+ #[test]
+ fn test_fmt_display() {
+ // Debug and display format the value only.
+ let one_cm: Length<f32, Mm> = Length::new(10.0);
+
+ let result = format!("{}", one_cm);
+
+ assert_eq!(result, "10");
+ }
+
+ #[test]
+ fn test_add() {
+ let length1: Length<u8, Mm> = Length::new(250);
+ let length2: Length<u8, Mm> = Length::new(5);
+
+ let result = length1 + length2;
+
+ assert_eq!(result.get(), 255);
+ }
+
+ #[test]
+ fn test_addassign() {
+ let one_cm: Length<f32, Mm> = Length::new(10.0);
+ let mut measurement: Length<f32, Mm> = Length::new(5.0);
+
+ measurement += one_cm;
+
+ assert_eq!(measurement.get(), 15.0);
+ }
+
+ #[test]
+ fn test_sub() {
+ let length1: Length<u8, Mm> = Length::new(250);
+ let length2: Length<u8, Mm> = Length::new(5);
+
+ let result = length1 - length2;
+
+ assert_eq!(result.get(), 245);
+ }
+
+ #[test]
+ fn test_subassign() {
+ let one_cm: Length<f32, Mm> = Length::new(10.0);
+ let mut measurement: Length<f32, Mm> = Length::new(5.0);
+
+ measurement -= one_cm;
+
+ assert_eq!(measurement.get(), -5.0);
+ }
+
+ #[test]
+ fn test_saturating_add() {
+ let length1: Length<u8, Mm> = Length::new(250);
+ let length2: Length<u8, Mm> = Length::new(6);
+
+ let result = length1.saturating_add(length2);
+
+ assert_eq!(result.get(), 255);
+ }
+
+ #[test]
+ fn test_saturating_sub() {
+ let length1: Length<u8, Mm> = Length::new(5);
+ let length2: Length<u8, Mm> = Length::new(10);
+
+ let result = length1.saturating_sub(length2);
+
+ assert_eq!(result.get(), 0);
+ }
+
+ #[test]
+ fn test_division_by_length() {
+ // Division results in a ScaleFactor from denominator units
+ // to numerator units.
+ let length: Length<f32, Cm> = Length::new(5.0);
+ let duration: Length<f32, Second> = Length::new(10.0);
+
+ let result = length / duration;
+
+ let expected: ScaleFactor<f32, Second, Cm> = ScaleFactor::new(0.5);
+ assert_eq!(result, expected);
+ }
+
+ #[test]
+ fn test_multiplication() {
+ let length_mm: Length<f32, Mm> = Length::new(10.0);
+ let cm_per_mm: ScaleFactor<f32, Mm, Cm> = ScaleFactor::new(0.1);
+
+ let result = length_mm * cm_per_mm;
+
+ let expected: Length<f32, Cm> = Length::new(1.0);
+ assert_eq!(result, expected);
+ }
+
+ #[test]
+ fn test_division_by_scalefactor() {
+ let length: Length<f32, Cm> = Length::new(5.0);
+ let cm_per_second: ScaleFactor<f32, Second, Cm> = ScaleFactor::new(10.0);
+
+ let result = length / cm_per_second;
+
+ let expected: Length<f32, Second> = Length::new(0.5);
+ assert_eq!(result, expected);
+ }
+
+ #[test]
+ fn test_negation() {
+ let length: Length<f32, Cm> = Length::new(5.0);
+
+ let result = -length;
+
+ let expected: Length<f32, Cm> = Length::new(-5.0);
+ assert_eq!(result, expected);
+ }
+
+ #[test]
+ fn test_cast() {
+ let length_as_i32: Length<i32, Cm> = Length::new(5);
+
+ let result: Length<f32, Cm> = length_as_i32.cast().unwrap();
+
+ let length_as_f32: Length<f32, Cm> = Length::new(5.0);
+ assert_eq!(result, length_as_f32);
+ }
+
+ #[test]
+ fn test_equality() {
+ let length_5_point_0: Length<f32, Cm> = Length::new(5.0);
+ let length_5_point_1: Length<f32, Cm> = Length::new(5.1);
+ let length_0_point_1: Length<f32, Cm> = Length::new(0.1);
+
+ assert!(length_5_point_0 == length_5_point_1 - length_0_point_1);
+ assert!(length_5_point_0 != length_5_point_1);
+ }
+
+ #[test]
+ fn test_order() {
+ let length_5_point_0: Length<f32, Cm> = Length::new(5.0);
+ let length_5_point_1: Length<f32, Cm> = Length::new(5.1);
+ let length_0_point_1: Length<f32, Cm> = Length::new(0.1);
+
+ assert!(length_5_point_0 < length_5_point_1);
+ assert!(length_5_point_0 <= length_5_point_1);
+ assert!(length_5_point_0 <= length_5_point_1 - length_0_point_1);
+ assert!(length_5_point_1 > length_5_point_0);
+ assert!(length_5_point_1 >= length_5_point_0);
+ assert!(length_5_point_0 >= length_5_point_1 - length_0_point_1);
+ }
+
+ #[test]
+ fn test_zero_add() {
+ type LengthCm = Length<f32, Cm>;
+ let length: LengthCm = Length::new(5.0);
+
+ let result = length - LengthCm::zero();
+
+ assert_eq!(result, length);
+ }
+
+ #[test]
+ fn test_zero_division() {
+ type LengthCm = Length<f32, Cm>;
+ let length: LengthCm = Length::new(5.0);
+ let length_zero: LengthCm = Length::zero();
+
+ let result = length / length_zero;
+
+ let expected: ScaleFactor<f32, Cm, Cm> = ScaleFactor::new(INFINITY);
+ assert_eq!(result, expected);
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/src/lib.rs
@@ -0,0 +1,113 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![cfg_attr(feature = "unstable", feature(asm, repr_simd, test))]
+
+//! A collection of strongly typed math tools for computer graphics with an inclination
+//! towards 2d graphics and layout.
+//!
+//! All types are generic over the scalar type of their component (`f32`, `i32`, etc.),
+//! and tagged with a generic Unit parameter which is useful to prevent mixing
+//! values from different spaces. For example it should not be legal to translate
+//! a screen-space position by a world-space vector and this can be expressed using
+//! the generic Unit parameter.
+//!
+//! This unit system is not mandatory and all Typed* structures have an alias
+//! with the default unit: `UnknownUnit`.
+//! for example ```Point2D<T>``` is equivalent to ```TypedPoint2D<T, UnknownUnit>```.
+//! Client code typically creates a set of aliases for each type and doesn't need
+//! to deal with the specifics of typed units further. For example:
+//!
+//! All euclid types are marked `#[repr(C)]` in order to facilitate exposing them to
+//! foreign function interfaces (provided the underlying scalar type is also `repr(C)`).
+//!
+//! ```rust
+//! use euclid::*;
+//! pub struct ScreenSpace;
+//! pub type ScreenPoint = TypedPoint2D<f32, ScreenSpace>;
+//! pub type ScreenSize = TypedSize2D<f32, ScreenSpace>;
+//! pub struct WorldSpace;
+//! pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
+//! pub type ProjectionMatrix = TypedMatrix4D<f32, WorldSpace, ScreenSpace>;
+//! // etc...
+//! ```
+//!
+//! Components are accessed in their scalar form by default for convenience, and most
+//! types additionally implement strongly typed accessors which return typed ```Length``` wrappers.
+//! For example:
+//!
+//! ```rust
+//! # use euclid::*;
+//! # pub struct WorldSpace;
+//! # pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
+//! let p = WorldPoint::new(0.0, 1.0, 1.0);
+//! // p.x is an f32.
+//! println!("p.x = {:?} ", p.x);
+//! // p.x is a Length<f32, WorldSpace>.
+//! println!("p.x_typed() = {:?} ", p.x_typed());
+//! // Length::get returns the scalar value (f32).
+//! assert_eq!(p.x, p.x_typed().get());
+//! ```
+
+extern crate heapsize;
+
+#[cfg_attr(test, macro_use)]
+extern crate log;
+extern crate rustc_serialize;
+extern crate serde;
+
+#[cfg(test)]
+extern crate rand;
+#[cfg(feature = "unstable")]
+extern crate test;
+extern crate num_traits;
+
+pub use length::Length;
+pub use scale_factor::ScaleFactor;
+pub use matrix2d::{Matrix2D, TypedMatrix2D};
+pub use matrix4d::{Matrix4D, TypedMatrix4D};
+pub use point::{
+ Point2D, TypedPoint2D,
+ Point3D, TypedPoint3D,
+ Point4D, TypedPoint4D,
+};
+pub use rect::{Rect, TypedRect};
+pub use side_offsets::{SideOffsets2D, TypedSideOffsets2D};
+#[cfg(feature = "unstable")] pub use side_offsets::SideOffsets2DSimdI32;
+pub use size::{Size2D, TypedSize2D};
+
+pub mod approxeq;
+pub mod length;
+#[macro_use]
+mod macros;
+pub mod matrix2d;
+pub mod matrix4d;
+pub mod num;
+pub mod point;
+pub mod rect;
+pub mod scale_factor;
+pub mod side_offsets;
+pub mod size;
+pub mod trig;
+
+/// The default unit.
+#[derive(Clone, Copy, RustcDecodable, RustcEncodable)]
+pub struct UnknownUnit;
+
+/// Unit for angles in radians.
+pub struct Rad;
+
+/// Unit for angles in degrees.
+pub struct Deg;
+
+/// A value in radians.
+pub type Radians<T> = Length<T, Rad>;
+
+/// A value in Degrees.
+pub type Degrees<T> = Length<T, Deg>;
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/src/macros.rs
@@ -0,0 +1,87 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+macro_rules! define_matrix {
+ (
+ $(#[$attr:meta])*
+ pub struct $name:ident<T, $($phantom:ident),+> {
+ $(pub $field:ident: T,)+
+ }
+ ) => (
+ #[repr(C)]
+ $(#[$attr])*
+ pub struct $name<T, $($phantom),+> {
+ $(pub $field: T,)+
+ _unit: PhantomData<($($phantom),+)>
+ }
+
+ impl<T: Clone, $($phantom),+> Clone for $name<T, $($phantom),+> {
+ fn clone(&self) -> Self {
+ $name {
+ $($field: self.$field.clone(),)+
+ _unit: PhantomData,
+ }
+ }
+ }
+
+ impl<T: Copy, $($phantom),+> Copy for $name<T, $($phantom),+> {}
+
+ impl<T, $($phantom),+> ::heapsize::HeapSizeOf for $name<T, $($phantom),+>
+ where T: ::heapsize::HeapSizeOf
+ {
+ fn heap_size_of_children(&self) -> usize {
+ $(self.$field.heap_size_of_children() +)+ 0
+ }
+ }
+
+ impl<T, $($phantom),+> ::serde::Deserialize for $name<T, $($phantom),+>
+ where T: ::serde::Deserialize
+ {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where D: ::serde::Deserializer
+ {
+ let ($($field,)+) =
+ try!(::serde::Deserialize::deserialize(deserializer));
+ Ok($name {
+ $($field: $field,)+
+ _unit: PhantomData,
+ })
+ }
+ }
+
+ impl<T, $($phantom),+> ::serde::Serialize for $name<T, $($phantom),+>
+ where T: ::serde::Serialize
+ {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where S: ::serde::Serializer
+ {
+ ($(&self.$field,)+).serialize(serializer)
+ }
+ }
+
+ impl<T, $($phantom),+> ::std::cmp::Eq for $name<T, $($phantom),+>
+ where T: ::std::cmp::Eq {}
+
+ impl<T, $($phantom),+> ::std::cmp::PartialEq for $name<T, $($phantom),+>
+ where T: ::std::cmp::PartialEq
+ {
+ fn eq(&self, other: &Self) -> bool {
+ true $(&& self.$field == other.$field)+
+ }
+ }
+
+ impl<T, $($phantom),+> ::std::hash::Hash for $name<T, $($phantom),+>
+ where T: ::std::hash::Hash
+ {
+ fn hash<H: ::std::hash::Hasher>(&self, h: &mut H) {
+ $(self.$field.hash(h);)+
+ }
+ }
+ )
+}
rename from third_party/rust/euclid/src/matrix2d.rs
rename to third_party/rust/euclid-0.13.0/src/matrix2d.rs
rename from third_party/rust/euclid/src/matrix4d.rs
rename to third_party/rust/euclid-0.13.0/src/matrix4d.rs
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/src/num.rs
@@ -0,0 +1,77 @@
+// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//! A one-dimensional length, tagged with its units.
+
+use num_traits;
+
+
+pub trait Zero {
+ fn zero() -> Self;
+}
+
+impl<T: num_traits::Zero> Zero for T {
+ fn zero() -> T { num_traits::Zero::zero() }
+}
+
+pub trait One {
+ fn one() -> Self;
+}
+
+impl<T: num_traits::One> One for T {
+ fn one() -> T { num_traits::One::one() }
+}
+
+
+pub trait Round : Copy { fn round(self) -> Self; }
+pub trait Floor : Copy { fn floor(self) -> Self; }
+pub trait Ceil : Copy { fn ceil(self) -> Self; }
+
+macro_rules! num_int {
+ ($ty:ty) => (
+ impl Round for $ty {
+ #[inline]
+ fn round(self) -> $ty { self }
+ }
+ impl Floor for $ty {
+ #[inline]
+ fn floor(self) -> $ty { self }
+ }
+ impl Ceil for $ty {
+ #[inline]
+ fn ceil(self) -> $ty { self }
+ }
+ )
+}
+macro_rules! num_float {
+ ($ty:ty) => (
+ impl Round for $ty {
+ #[inline]
+ fn round(self) -> $ty { self.round() }
+ }
+ impl Floor for $ty {
+ #[inline]
+ fn floor(self) -> $ty { self.floor() }
+ }
+ impl Ceil for $ty {
+ #[inline]
+ fn ceil(self) -> $ty { self.ceil() }
+ }
+ )
+}
+
+num_int!(i16);
+num_int!(u16);
+num_int!(i32);
+num_int!(u32);
+num_int!(i64);
+num_int!(u64);
+num_int!(isize);
+num_int!(usize);
+num_float!(f32);
+num_float!(f64);
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/src/point.rs
@@ -0,0 +1,995 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::UnknownUnit;
+use approxeq::ApproxEq;
+use length::Length;
+use scale_factor::ScaleFactor;
+use size::TypedSize2D;
+use num::*;
+use num_traits::{Float, NumCast};
+use std::fmt;
+use std::ops::{Add, Neg, Mul, Sub, Div};
+use std::marker::PhantomData;
+
+define_matrix! {
+ /// A 2d Point tagged with a unit.
+ #[derive(RustcDecodable, RustcEncodable)]
+ pub struct TypedPoint2D<T, U> {
+ pub x: T,
+ pub y: T,
+ }
+}
+
+/// Default 2d point type with no unit.
+///
+/// `Point2D` provides the same methods as `TypedPoint2D`.
+pub type Point2D<T> = TypedPoint2D<T, UnknownUnit>;
+
+impl<T: Copy + Zero, U> TypedPoint2D<T, U> {
+ /// Constructor, setting all components to zero.
+ #[inline]
+ pub fn zero() -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(Zero::zero(), Zero::zero())
+ }
+
+ /// Convert into a 3d point.
+ #[inline]
+ pub fn to_3d(&self) -> TypedPoint3D<T, U> {
+ TypedPoint3D::new(self.x, self.y, Zero::zero())
+ }
+}
+
+impl<T: fmt::Debug, U> fmt::Debug for TypedPoint2D<T, U> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "({:?},{:?})", self.x, self.y)
+ }
+}
+
+impl<T: fmt::Display, U> fmt::Display for TypedPoint2D<T, U> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "({},{})", self.x, self.y)
+ }
+}
+
+impl<T: Copy, U> TypedPoint2D<T, U> {
+ /// Constructor taking scalar values directly.
+ #[inline]
+ pub fn new(x: T, y: T) -> TypedPoint2D<T, U> {
+ TypedPoint2D { x: x, y: y, _unit: PhantomData }
+ }
+
+ /// Constructor taking properly typed Lengths instead of scalar values.
+ #[inline]
+ pub fn from_lengths(x: Length<T, U>, y: Length<T, U>) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(x.0, y.0)
+ }
+
+ /// Returns self.x as a Length carrying the unit.
+ #[inline]
+ pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
+
+ /// Returns self.y as a Length carrying the unit.
+ #[inline]
+ pub fn y_typed(&self) -> Length<T, U> { Length::new(self.y) }
+
+ /// Drop the units, preserving only the numeric value.
+ #[inline]
+ pub fn to_untyped(&self) -> Point2D<T> {
+ TypedPoint2D::new(self.x, self.y)
+ }
+
+ /// Tag a unitless value with units.
+ #[inline]
+ pub fn from_untyped(p: &Point2D<T>) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(p.x, p.y)
+ }
+
+ #[inline]
+ pub fn to_array(&self) -> [T; 2] {
+ [self.x, self.y]
+ }
+}
+
+impl<T, U> TypedPoint2D<T, U>
+where T: Copy + Mul<T, Output=T> + Add<T, Output=T> + Sub<T, Output=T> {
+ /// Dot product.
+ #[inline]
+ pub fn dot(self, other: TypedPoint2D<T, U>) -> T {
+ self.x * other.x + self.y * other.y
+ }
+
+ /// Returns the norm of the cross product [self.x, self.y, 0] x [other.x, other.y, 0]..
+ #[inline]
+ pub fn cross(self, other: TypedPoint2D<T, U>) -> T {
+ self.x * other.y - self.y * other.x
+ }
+
+ #[inline]
+ pub fn normalize(self) -> Self where T: Float + ApproxEq<T> {
+ let dot = self.dot(self);
+ if dot.approx_eq(&T::zero()) {
+ self
+ } else {
+ self / dot.sqrt()
+ }
+ }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> Add for TypedPoint2D<T, U> {
+ type Output = TypedPoint2D<T, U>;
+ fn add(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(self.x + other.x, self.y + other.y)
+ }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> Add<TypedSize2D<T, U>> for TypedPoint2D<T, U> {
+ type Output = TypedPoint2D<T, U>;
+ fn add(self, other: TypedSize2D<T, U>) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(self.x + other.width, self.y + other.height)
+ }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> TypedPoint2D<T, U> {
+ pub fn add_size(&self, other: &TypedSize2D<T, U>) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(self.x + other.width, self.y + other.height)
+ }
+}
+
+impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedPoint2D<T, U> {
+ type Output = TypedPoint2D<T, U>;
+ fn sub(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(self.x - other.x, self.y - other.y)
+ }
+}
+
+impl <T: Copy + Neg<Output=T>, U> Neg for TypedPoint2D<T, U> {
+ type Output = TypedPoint2D<T, U>;
+ #[inline]
+ fn neg(self) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(-self.x, -self.y)
+ }
+}
+
+impl<T: Float, U> TypedPoint2D<T, U> {
+ pub fn min(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(self.x.min(other.x), self.y.min(other.y))
+ }
+
+ pub fn max(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(self.x.max(other.x), self.y.max(other.y))
+ }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedPoint2D<T, U> {
+ type Output = TypedPoint2D<T, U>;
+ #[inline]
+ fn mul(self, scale: T) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(self.x * scale, self.y * scale)
+ }
+}
+
+impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedPoint2D<T, U> {
+ type Output = TypedPoint2D<T, U>;
+ #[inline]
+ fn div(self, scale: T) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(self.x / scale, self.y / scale)
+ }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedPoint2D<T, U1> {
+ type Output = TypedPoint2D<T, U2>;
+ #[inline]
+ fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedPoint2D<T, U2> {
+ TypedPoint2D::new(self.x * scale.get(), self.y * scale.get())
+ }
+}
+
+impl<T: Copy + Div<T, Output=T>, U1, U2> Div<ScaleFactor<T, U1, U2>> for TypedPoint2D<T, U2> {
+ type Output = TypedPoint2D<T, U1>;
+ #[inline]
+ fn div(self, scale: ScaleFactor<T, U1, U2>) -> TypedPoint2D<T, U1> {
+ TypedPoint2D::new(self.x / scale.get(), self.y / scale.get())
+ }
+}
+
+impl<T: Round, U> TypedPoint2D<T, U> {
+ /// Rounds each component to the nearest integer value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ /// For example `{ -0.1, -0.8 }.round() == { 0.0, -1.0 }`.
+ pub fn round(&self) -> Self {
+ TypedPoint2D::new(self.x.round(), self.y.round())
+ }
+}
+
+impl<T: Ceil, U> TypedPoint2D<T, U> {
+ /// Rounds each component to the smallest integer equal or greater than the original value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ /// For example `{ -0.1, -0.8 }.ceil() == { 0.0, 0.0 }`.
+ pub fn ceil(&self) -> Self {
+ TypedPoint2D::new(self.x.ceil(), self.y.ceil())
+ }
+}
+
+impl<T: Floor, U> TypedPoint2D<T, U> {
+ /// Rounds each component to the biggest integer equal or lower than the original value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ /// For example `{ -0.1, -0.8 }.floor() == { -1.0, -1.0 }`.
+ pub fn floor(&self) -> Self {
+ TypedPoint2D::new(self.x.floor(), self.y.floor())
+ }
+}
+
+impl<T: NumCast + Copy, U> TypedPoint2D<T, U> {
+ /// Cast from one numeric representation to another, preserving the units.
+ ///
+ /// When casting from floating point to integer coordinates, the decimals are truncated
+ /// as one would expect from a simple cast, but this behavior does not always make sense
+ /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
+ pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedPoint2D<NewT, U>> {
+ match (NumCast::from(self.x), NumCast::from(self.y)) {
+ (Some(x), Some(y)) => Some(TypedPoint2D::new(x, y)),
+ _ => None
+ }
+ }
+
+ // Convenience functions for common casts
+
+ /// Cast into an `f32` point.
+ pub fn to_f32(&self) -> TypedPoint2D<f32, U> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `usize` point, truncating decimals if any.
+ ///
+ /// When casting from floating point points, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ pub fn to_usize(&self) -> TypedPoint2D<usize, U> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an i32 point, truncating decimals if any.
+ ///
+ /// When casting from floating point points, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ pub fn to_i32(&self) -> TypedPoint2D<i32, U> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an i64 point, truncating decimals if any.
+ ///
+ /// When casting from floating point points, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ pub fn to_i64(&self) -> TypedPoint2D<i64, U> {
+ self.cast().unwrap()
+ }
+}
+
+impl<T: Copy+ApproxEq<T>, U> ApproxEq<TypedPoint2D<T, U>> for TypedPoint2D<T, U> {
+ #[inline]
+ fn approx_epsilon() -> Self {
+ TypedPoint2D::new(T::approx_epsilon(), T::approx_epsilon())
+ }
+
+ #[inline]
+ fn approx_eq(&self, other: &Self) -> bool {
+ self.x.approx_eq(&other.x) && self.y.approx_eq(&other.y)
+ }
+
+ #[inline]
+ fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {
+ self.x.approx_eq_eps(&other.x, &eps.x) && self.y.approx_eq_eps(&other.y, &eps.y)
+ }
+}
+
+define_matrix! {
+ /// A 3d Point tagged with a unit.
+ #[derive(RustcDecodable, RustcEncodable)]
+ pub struct TypedPoint3D<T, U> {
+ pub x: T,
+ pub y: T,
+ pub z: T,
+ }
+}
+
+/// Default 3d point type with no unit.
+///
+/// `Point3D` provides the same methods as `TypedPoint3D`.
+pub type Point3D<T> = TypedPoint3D<T, UnknownUnit>;
+
+impl<T: Copy + Zero, U> TypedPoint3D<T, U> {
+ /// Constructor, setting all copmonents to zero.
+ #[inline]
+ pub fn zero() -> TypedPoint3D<T, U> {
+ TypedPoint3D::new(Zero::zero(), Zero::zero(), Zero::zero())
+ }
+}
+
+impl<T: fmt::Debug, U> fmt::Debug for TypedPoint3D<T, U> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "({:?},{:?},{:?})", self.x, self.y, self.z)
+ }
+}
+
+impl<T: fmt::Display, U> fmt::Display for TypedPoint3D<T, U> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "({},{},{})", self.x, self.y, self.z)
+ }
+}
+
+impl<T: Copy, U> TypedPoint3D<T, U> {
+ /// Constructor taking scalar values directly.
+ #[inline]
+ pub fn new(x: T, y: T, z: T) -> TypedPoint3D<T, U> {
+ TypedPoint3D { x: x, y: y, z: z, _unit: PhantomData }
+ }
+
+ /// Constructor taking properly typed Lengths instead of scalar values.
+ #[inline]
+ pub fn from_lengths(x: Length<T, U>, y: Length<T, U>, z: Length<T, U>) -> TypedPoint3D<T, U> {
+ TypedPoint3D::new(x.0, y.0, z.0)
+ }
+
+ /// Returns self.x as a Length carrying the unit.
+ #[inline]
+ pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
+
+ /// Returns self.y as a Length carrying the unit.
+ #[inline]
+ pub fn y_typed(&self) -> Length<T, U> { Length::new(self.y) }
+
+ /// Returns self.z as a Length carrying the unit.
+ #[inline]
+ pub fn z_typed(&self) -> Length<T, U> { Length::new(self.z) }
+
+ #[inline]
+ pub fn to_array(&self) -> [T; 3] { [self.x, self.y, self.z] }
+
+ /// Drop the units, preserving only the numeric value.
+ #[inline]
+ pub fn to_untyped(&self) -> Point3D<T> {
+ TypedPoint3D::new(self.x, self.y, self.z)
+ }
+
+ /// Tag a unitless value with units.
+ #[inline]
+ pub fn from_untyped(p: &Point3D<T>) -> TypedPoint3D<T, U> {
+ TypedPoint3D::new(p.x, p.y, p.z)
+ }
+
+ /// Convert into a 2d point.
+ #[inline]
+ pub fn to_2d(&self) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(self.x, self.y)
+ }
+}
+
+impl<T: Mul<T, Output=T> +
+ Add<T, Output=T> +
+ Sub<T, Output=T> +
+ Copy, U> TypedPoint3D<T, U> {
+
+ // Dot product.
+ #[inline]
+ pub fn dot(self, other: TypedPoint3D<T, U>) -> T {
+ self.x * other.x +
+ self.y * other.y +
+ self.z * other.z
+ }
+
+ // Cross product.
+ #[inline]
+ pub fn cross(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
+ TypedPoint3D::new(self.y * other.z - self.z * other.y,
+ self.z * other.x - self.x * other.z,
+ self.x * other.y - self.y * other.x)
+ }
+
+ #[inline]
+ pub fn normalize(self) -> Self where T: Float + ApproxEq<T> {
+ let dot = self.dot(self);
+ if dot.approx_eq(&T::zero()) {
+ self
+ } else {
+ self / dot.sqrt()
+ }
+ }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> Add for TypedPoint3D<T, U> {
+ type Output = TypedPoint3D<T, U>;
+ fn add(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
+ TypedPoint3D::new(self.x + other.x,
+ self.y + other.y,
+ self.z + other.z)
+ }
+}
+
+impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedPoint3D<T, U> {
+ type Output = TypedPoint3D<T, U>;
+ fn sub(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
+ TypedPoint3D::new(self.x - other.x,
+ self.y - other.y,
+ self.z - other.z)
+ }
+}
+
+impl <T: Copy + Neg<Output=T>, U> Neg for TypedPoint3D<T, U> {
+ type Output = TypedPoint3D<T, U>;
+ #[inline]
+ fn neg(self) -> TypedPoint3D<T, U> {
+ TypedPoint3D::new(-self.x, -self.y, -self.z)
+ }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedPoint3D<T, U> {
+ type Output = Self;
+ #[inline]
+ fn mul(self, scale: T) -> Self {
+ Self::new(self.x * scale, self.y * scale, self.z * scale)
+ }
+}
+
+impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedPoint3D<T, U> {
+ type Output = Self;
+ #[inline]
+ fn div(self, scale: T) -> Self {
+ Self::new(self.x / scale, self.y / scale, self.z / scale)
+ }
+}
+
+impl<T: Float, U> TypedPoint3D<T, U> {
+ pub fn min(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
+ TypedPoint3D::new(self.x.min(other.x),
+ self.y.min(other.y),
+ self.z.min(other.z))
+ }
+
+ pub fn max(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
+ TypedPoint3D::new(self.x.max(other.x), self.y.max(other.y),
+ self.z.max(other.z))
+ }
+}
+
+impl<T: Round, U> TypedPoint3D<T, U> {
+ /// Rounds each component to the nearest integer value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ pub fn round(&self) -> Self {
+ TypedPoint3D::new(self.x.round(), self.y.round(), self.z.round())
+ }
+}
+
+impl<T: Ceil, U> TypedPoint3D<T, U> {
+ /// Rounds each component to the smallest integer equal or greater than the original value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ pub fn ceil(&self) -> Self {
+ TypedPoint3D::new(self.x.ceil(), self.y.ceil(), self.z.ceil())
+ }
+}
+
+impl<T: Floor, U> TypedPoint3D<T, U> {
+ /// Rounds each component to the biggest integer equal or lower than the original value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ pub fn floor(&self) -> Self {
+ TypedPoint3D::new(self.x.floor(), self.y.floor(), self.z.floor())
+ }
+}
+
+impl<T: NumCast + Copy, U> TypedPoint3D<T, U> {
+ /// Cast from one numeric representation to another, preserving the units.
+ ///
+ /// When casting from floating point to integer coordinates, the decimals are truncated
+ /// as one would expect from a simple cast, but this behavior does not always make sense
+ /// geometrically. Consider using round(), ceil or floor() before casting.
+ pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedPoint3D<NewT, U>> {
+ match (NumCast::from(self.x),
+ NumCast::from(self.y),
+ NumCast::from(self.z)) {
+ (Some(x), Some(y), Some(z)) => Some(TypedPoint3D::new(x, y, z)),
+ _ => None
+ }
+ }
+
+ // Convenience functions for common casts
+
+ /// Cast into an `f32` point.
+ pub fn to_f32(&self) -> TypedPoint3D<f32, U> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `usize` point, truncating decimals if any.
+ ///
+ /// When casting from floating point points, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ pub fn to_usize(&self) -> TypedPoint3D<usize, U> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `i32` point, truncating decimals if any.
+ ///
+ /// When casting from floating point points, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ pub fn to_i32(&self) -> TypedPoint3D<i32, U> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `i64` point, truncating decimals if any.
+ ///
+ /// When casting from floating point points, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ pub fn to_i64(&self) -> TypedPoint3D<i64, U> {
+ self.cast().unwrap()
+ }
+}
+
+impl<T: Copy+ApproxEq<T>, U> ApproxEq<TypedPoint3D<T, U>> for TypedPoint3D<T, U> {
+ #[inline]
+ fn approx_epsilon() -> Self {
+ TypedPoint3D::new(T::approx_epsilon(), T::approx_epsilon(), T::approx_epsilon())
+ }
+
+ #[inline]
+ fn approx_eq(&self, other: &Self) -> bool {
+ self.x.approx_eq(&other.x)
+ && self.y.approx_eq(&other.y)
+ && self.z.approx_eq(&other.z)
+ }
+
+ #[inline]
+ fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {
+ self.x.approx_eq_eps(&other.x, &eps.x)
+ && self.y.approx_eq_eps(&other.y, &eps.y)
+ && self.z.approx_eq_eps(&other.z, &eps.z)
+ }
+}
+
+define_matrix! {
+ /// A 4d Point tagged with a unit.
+ #[derive(RustcDecodable, RustcEncodable)]
+ pub struct TypedPoint4D<T, U> {
+ pub x: T,
+ pub y: T,
+ pub z: T,
+ pub w: T,
+ }
+}
+
+/// Default 4d point with no unit.
+///
+/// `Point4D` provides the same methods as `TypedPoint4D`.
+pub type Point4D<T> = TypedPoint4D<T, UnknownUnit>;
+
+impl<T: Copy + Zero, U> TypedPoint4D<T, U> {
+ /// Constructor, setting all copmonents to zero.
+ #[inline]
+ pub fn zero() -> TypedPoint4D<T, U> {
+ TypedPoint4D::new(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero())
+ }
+}
+
+impl<T: fmt::Debug, U> fmt::Debug for TypedPoint4D<T, U> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "({:?},{:?},{:?},{:?})", self.x, self.y, self.z, self.w)
+ }
+}
+
+impl<T: fmt::Display, U> fmt::Display for TypedPoint4D<T, U> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "({},{},{},{})", self.x, self.y, self.z, self.w)
+ }
+}
+
+impl<T: Copy, U> TypedPoint4D<T, U> {
+ /// Constructor taking scalar values directly.
+ #[inline]
+ pub fn new(x: T, y: T, z: T, w: T) -> TypedPoint4D<T, U> {
+ TypedPoint4D { x: x, y: y, z: z, w: w, _unit: PhantomData }
+ }
+
+ /// Constructor taking properly typed Lengths instead of scalar values.
+ #[inline]
+ pub fn from_lengths(x: Length<T, U>,
+ y: Length<T, U>,
+ z: Length<T, U>,
+ w: Length<T, U>) -> TypedPoint4D<T, U> {
+ TypedPoint4D::new(x.0, y.0, z.0, w.0)
+ }
+
+ /// Returns self.x as a Length carrying the unit.
+ #[inline]
+ pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
+
+ /// Returns self.y as a Length carrying the unit.
+ #[inline]
+ pub fn y_typed(&self) -> Length<T, U> { Length::new(self.y) }
+
+ /// Returns self.z as a Length carrying the unit.
+ #[inline]
+ pub fn z_typed(&self) -> Length<T, U> { Length::new(self.z) }
+
+ /// Returns self.w as a Length carrying the unit.
+ #[inline]
+ pub fn w_typed(&self) -> Length<T, U> { Length::new(self.w) }
+
+ /// Drop the units, preserving only the numeric value.
+ #[inline]
+ pub fn to_untyped(&self) -> Point4D<T> {
+ TypedPoint4D::new(self.x, self.y, self.z, self.w)
+ }
+
+ /// Tag a unitless value with units.
+ #[inline]
+ pub fn from_untyped(p: &Point4D<T>) -> TypedPoint4D<T, U> {
+ TypedPoint4D::new(p.x, p.y, p.z, p.w)
+ }
+
+ #[inline]
+ pub fn to_array(&self) -> [T; 4] {
+ [self.x, self.y, self.z, self.w]
+ }
+}
+
+impl<T: Copy + Div<T, Output=T>, U> TypedPoint4D<T, U> {
+ /// Convert into a 2d point.
+ #[inline]
+ pub fn to_2d(self) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(self.x / self.w, self.y / self.w)
+ }
+
+ /// Convert into a 3d point.
+ #[inline]
+ pub fn to_3d(self) -> TypedPoint3D<T, U> {
+ TypedPoint3D::new(self.x / self.w, self.y / self.w, self.z / self.w)
+ }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> Add for TypedPoint4D<T, U> {
+ type Output = TypedPoint4D<T, U>;
+ fn add(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
+ TypedPoint4D::new(self.x + other.x,
+ self.y + other.y,
+ self.z + other.z,
+ self.w + other.w)
+ }
+}
+
+impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedPoint4D<T, U> {
+ type Output = TypedPoint4D<T, U>;
+ fn sub(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
+ TypedPoint4D::new(self.x - other.x,
+ self.y - other.y,
+ self.z - other.z,
+ self.w - other.w)
+ }
+}
+
+impl <T: Copy + Neg<Output=T>, U> Neg for TypedPoint4D<T, U> {
+ type Output = TypedPoint4D<T, U>;
+ #[inline]
+ fn neg(self) -> TypedPoint4D<T, U> {
+ TypedPoint4D::new(-self.x, -self.y, -self.z, -self.w)
+ }
+}
+
+impl<T: Float, U> TypedPoint4D<T, U> {
+ pub fn min(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
+ TypedPoint4D::new(self.x.min(other.x), self.y.min(other.y),
+ self.z.min(other.z), self.w.min(other.w))
+ }
+
+ pub fn max(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
+ TypedPoint4D::new(self.x.max(other.x), self.y.max(other.y),
+ self.z.max(other.z), self.w.max(other.w))
+ }
+}
+
+impl<T: Round, U> TypedPoint4D<T, U> {
+ /// Rounds each component to the nearest integer value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ pub fn round(&self) -> Self {
+ TypedPoint4D::new(self.x.round(), self.y.round(), self.z.round(), self.w.round())
+ }
+}
+
+impl<T: Ceil, U> TypedPoint4D<T, U> {
+ /// Rounds each component to the smallest integer equal or greater than the original value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ pub fn ceil(&self) -> Self {
+ TypedPoint4D::new(self.x.ceil(), self.y.ceil(), self.z.ceil(), self.w.ceil())
+ }
+}
+
+impl<T: Floor, U> TypedPoint4D<T, U> {
+ /// Rounds each component to the biggest integer equal or lower than the original value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ pub fn floor(&self) -> Self {
+ TypedPoint4D::new(self.x.floor(), self.y.floor(), self.z.floor(), self.w.floor())
+ }
+}
+
+impl<T: NumCast + Copy, U> TypedPoint4D<T, U> {
+ /// Cast from one numeric representation to another, preserving the units.
+ ///
+ /// When casting from floating point to integer coordinates, the decimals are truncated
+ /// as one would expect from a simple cast, but this behavior does not always make sense
+ /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
+ pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedPoint4D<NewT, U>> {
+ match (NumCast::from(self.x),
+ NumCast::from(self.y),
+ NumCast::from(self.z),
+ NumCast::from(self.w)) {
+ (Some(x), Some(y), Some(z), Some(w)) => Some(TypedPoint4D::new(x, y, z, w)),
+ _ => None
+ }
+ }
+
+ // Convenience functions for common casts
+
+ /// Cast into an `f32` point.
+ pub fn to_f32(&self) -> TypedPoint4D<f32, U> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `usize` point, truncating decimals if any.
+ ///
+ /// When casting from floating point points, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ pub fn to_usize(&self) -> TypedPoint4D<usize, U> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `i32` point, truncating decimals if any.
+ ///
+ /// When casting from floating point points, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ pub fn to_i32(&self) -> TypedPoint4D<i32, U> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `i64` point, truncating decimals if any.
+ ///
+ /// When casting from floating point points, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ pub fn to_i64(&self) -> TypedPoint4D<i64, U> {
+ self.cast().unwrap()
+ }
+}
+
+impl<T: ApproxEq<T>, U> ApproxEq<T> for TypedPoint4D<T, U> {
+ fn approx_epsilon() -> T {
+ T::approx_epsilon()
+ }
+
+ fn approx_eq_eps(&self, other: &Self, approx_epsilon: &T) -> bool {
+ self.x.approx_eq_eps(&other.x, approx_epsilon)
+ && self.y.approx_eq_eps(&other.y, approx_epsilon)
+ && self.z.approx_eq_eps(&other.z, approx_epsilon)
+ && self.w.approx_eq_eps(&other.w, approx_epsilon)
+ }
+
+ fn approx_eq(&self, other: &Self) -> bool {
+ self.approx_eq_eps(&other, &Self::approx_epsilon())
+ }
+}
+
+pub fn point2<T: Copy, U>(x: T, y: T) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(x, y)
+}
+
+pub fn point3<T: Copy, U>(x: T, y: T, z: T) -> TypedPoint3D<T, U> {
+ TypedPoint3D::new(x, y, z)
+}
+
+pub fn point4<T: Copy, U>(x: T, y: T, z: T, w: T) -> TypedPoint4D<T, U> {
+ TypedPoint4D::new(x, y, z, w)
+}
+
+#[cfg(test)]
+mod point2d {
+ use super::Point2D;
+
+ #[test]
+ pub fn test_scalar_mul() {
+ let p1: Point2D<f32> = Point2D::new(3.0, 5.0);
+
+ let result = p1 * 5.0;
+
+ assert_eq!(result, Point2D::new(15.0, 25.0));
+ }
+
+ #[test]
+ pub fn test_dot() {
+ let p1: Point2D<f32> = Point2D::new(2.0, 7.0);
+ let p2: Point2D<f32> = Point2D::new(13.0, 11.0);
+ assert_eq!(p1.dot(p2), 103.0);
+ }
+
+ #[test]
+ pub fn test_cross() {
+ let p1: Point2D<f32> = Point2D::new(4.0, 7.0);
+ let p2: Point2D<f32> = Point2D::new(13.0, 8.0);
+ let r = p1.cross(p2);
+ assert_eq!(r, -59.0);
+ }
+
+ #[test]
+ pub fn test_normalize() {
+ let p0: Point2D<f32> = Point2D::zero();
+ let p1: Point2D<f32> = Point2D::new(4.0, 0.0);
+ let p2: Point2D<f32> = Point2D::new(3.0, -4.0);
+ assert_eq!(p0.normalize(), p0);
+ assert_eq!(p1.normalize(), Point2D::new(1.0, 0.0));
+ assert_eq!(p2.normalize(), Point2D::new(0.6, -0.8));
+ }
+
+ #[test]
+ pub fn test_min() {
+ let p1 = Point2D::new(1.0, 3.0);
+ let p2 = Point2D::new(2.0, 2.0);
+
+ let result = p1.min(p2);
+
+ assert_eq!(result, Point2D::new(1.0, 2.0));
+ }
+
+ #[test]
+ pub fn test_max() {
+ let p1 = Point2D::new(1.0, 3.0);
+ let p2 = Point2D::new(2.0, 2.0);
+
+ let result = p1.max(p2);
+
+ assert_eq!(result, Point2D::new(2.0, 3.0));
+ }
+}
+
+#[cfg(test)]
+mod typedpoint2d {
+ use super::TypedPoint2D;
+ use scale_factor::ScaleFactor;
+
+ pub enum Mm {}
+ pub enum Cm {}
+
+ pub type Point2DMm<T> = TypedPoint2D<T, Mm>;
+ pub type Point2DCm<T> = TypedPoint2D<T, Cm>;
+
+ #[test]
+ pub fn test_add() {
+ let p1 = Point2DMm::new(1.0, 2.0);
+ let p2 = Point2DMm::new(3.0, 4.0);
+
+ let result = p1 + p2;
+
+ assert_eq!(result, Point2DMm::new(4.0, 6.0));
+ }
+
+ #[test]
+ pub fn test_scalar_mul() {
+ let p1 = Point2DMm::new(1.0, 2.0);
+ let cm_per_mm: ScaleFactor<f32, Mm, Cm> = ScaleFactor::new(0.1);
+
+ let result = p1 * cm_per_mm;
+
+ assert_eq!(result, Point2DCm::new(0.1, 0.2));
+ }
+}
+
+#[cfg(test)]
+mod point3d {
+ use super::Point3D;
+
+ #[test]
+ pub fn test_dot() {
+ let p1 = Point3D::new(7.0, 21.0, 32.0);
+ let p2 = Point3D::new(43.0, 5.0, 16.0);
+ assert_eq!(p1.dot(p2), 918.0);
+ }
+
+ #[test]
+ pub fn test_cross() {
+ let p1 = Point3D::new(4.0, 7.0, 9.0);
+ let p2 = Point3D::new(13.0, 8.0, 3.0);
+ let p3 = p1.cross(p2);
+ assert_eq!(p3, Point3D::new(-51.0, 105.0, -59.0));
+ }
+
+ #[test]
+ pub fn test_normalize() {
+ let p0: Point3D<f32> = Point3D::zero();
+ let p1: Point3D<f32> = Point3D::new(0.0, -6.0, 0.0);
+ let p2: Point3D<f32> = Point3D::new(1.0, 2.0, -2.0);
+ assert_eq!(p0.normalize(), p0);
+ assert_eq!(p1.normalize(), Point3D::new(0.0, -1.0, 0.0));
+ assert_eq!(p2.normalize(), Point3D::new(1.0/3.0, 2.0/3.0, -2.0/3.0));
+ }
+
+ #[test]
+ pub fn test_min() {
+ let p1 = Point3D::new(1.0, 3.0, 5.0);
+ let p2 = Point3D::new(2.0, 2.0, -1.0);
+
+ let result = p1.min(p2);
+
+ assert_eq!(result, Point3D::new(1.0, 2.0, -1.0));
+ }
+
+ #[test]
+ pub fn test_max() {
+ let p1 = Point3D::new(1.0, 3.0, 5.0);
+ let p2 = Point3D::new(2.0, 2.0, -1.0);
+
+ let result = p1.max(p2);
+
+ assert_eq!(result, Point3D::new(2.0, 3.0, 5.0));
+ }
+}
+
+#[cfg(test)]
+mod point4d {
+ use super::Point4D;
+
+ #[test]
+ pub fn test_add() {
+ let p1 = Point4D::new(7.0, 21.0, 32.0, 1.0);
+ let p2 = Point4D::new(43.0, 5.0, 16.0, 2.0);
+
+ let result = p1 + p2;
+
+ assert_eq!(result, Point4D::new(50.0, 26.0, 48.0, 3.0));
+ }
+
+ #[test]
+ pub fn test_sub() {
+ let p1 = Point4D::new(7.0, 21.0, 32.0, 1.0);
+ let p2 = Point4D::new(43.0, 5.0, 16.0, 2.0);
+
+ let result = p1 - p2;
+
+ assert_eq!(result, Point4D::new(-36.0, 16.0, 16.0, -1.0));
+ }
+
+ #[test]
+ pub fn test_min() {
+ let p1 = Point4D::new(1.0, 3.0, 5.0, 7.0);
+ let p2 = Point4D::new(2.0, 2.0, -1.0, 10.0);
+
+ let result = p1.min(p2);
+
+ assert_eq!(result, Point4D::new(1.0, 2.0, -1.0, 7.0));
+ }
+
+ #[test]
+ pub fn test_max() {
+ let p1 = Point4D::new(1.0, 3.0, 5.0, 7.0);
+ let p2 = Point4D::new(2.0, 2.0, -1.0, 10.0);
+
+ let result = p1.max(p2);
+
+ assert_eq!(result, Point4D::new(2.0, 3.0, 5.0, 10.0));
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/src/rect.rs
@@ -0,0 +1,671 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::UnknownUnit;
+use length::Length;
+use scale_factor::ScaleFactor;
+use num::*;
+use point::TypedPoint2D;
+use size::TypedSize2D;
+
+use heapsize::HeapSizeOf;
+use num_traits::NumCast;
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
+use std::cmp::PartialOrd;
+use std::fmt;
+use std::ops::{Add, Sub, Mul, Div};
+
+/// A 2d Rectangle optionally tagged with a unit.
+#[derive(RustcDecodable, RustcEncodable)]
+pub struct TypedRect<T, U = UnknownUnit> {
+ pub origin: TypedPoint2D<T, U>,
+ pub size: TypedSize2D<T, U>,
+}
+
+/// The default rectangle type with no unit.
+pub type Rect<T> = TypedRect<T, UnknownUnit>;
+
+impl<T: HeapSizeOf, U> HeapSizeOf for TypedRect<T, U> {
+ fn heap_size_of_children(&self) -> usize {
+ self.origin.heap_size_of_children() + self.size.heap_size_of_children()
+ }
+}
+
+impl<T: Copy + Deserialize, U> Deserialize for TypedRect<T, U> {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where D: Deserializer
+ {
+ let (origin, size) = try!(Deserialize::deserialize(deserializer));
+ Ok(TypedRect::new(origin, size))
+ }
+}
+
+impl<T: Serialize, U> Serialize for TypedRect<T, U> {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where S: Serializer
+ {
+ (&self.origin, &self.size).serialize(serializer)
+ }
+}
+
+impl<T: Copy, U> Copy for TypedRect<T, U> {}
+
+impl<T: Copy, U> Clone for TypedRect<T, U> {
+ fn clone(&self) -> TypedRect<T, U> { *self }
+}
+
+impl<T: PartialEq, U> PartialEq<TypedRect<T, U>> for TypedRect<T, U> {
+ fn eq(&self, other: &TypedRect<T, U>) -> bool {
+ self.origin.eq(&other.origin) && self.size.eq(&other.size)
+ }
+}
+
+impl<T: Eq, U> Eq for TypedRect<T, U> {}
+
+impl<T: fmt::Debug, U> fmt::Debug for TypedRect<T, U> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "TypedRect({:?} at {:?})", self.size, self.origin)
+ }
+}
+
+impl<T: fmt::Display, U> fmt::Display for TypedRect<T, U> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "Rect({} at {})", self.size, self.origin)
+ }
+}
+
+impl<T, U> TypedRect<T, U> {
+ /// Constructor.
+ pub fn new(origin: TypedPoint2D<T, U>, size: TypedSize2D<T, U>) -> TypedRect<T, U> {
+ TypedRect {
+ origin: origin,
+ size: size,
+ }
+ }
+}
+
+impl<T, U> TypedRect<T, U>
+where T: Copy + Clone + Zero + PartialOrd + PartialEq + Add<T, Output=T> + Sub<T, Output=T> {
+ #[inline]
+ pub fn intersects(&self, other: &TypedRect<T, U>) -> bool {
+ self.origin.x < other.origin.x + other.size.width &&
+ other.origin.x < self.origin.x + self.size.width &&
+ self.origin.y < other.origin.y + other.size.height &&
+ other.origin.y < self.origin.y + self.size.height
+ }
+
+ #[inline]
+ pub fn max_x(&self) -> T {
+ self.origin.x + self.size.width
+ }
+
+ #[inline]
+ pub fn min_x(&self) -> T {
+ self.origin.x
+ }
+
+ #[inline]
+ pub fn max_y(&self) -> T {
+ self.origin.y + self.size.height
+ }
+
+ #[inline]
+ pub fn min_y(&self) -> T {
+ self.origin.y
+ }
+
+ #[inline]
+ pub fn max_x_typed(&self) -> Length<T, U> {
+ Length::new(self.max_x())
+ }
+
+ #[inline]
+ pub fn min_x_typed(&self) -> Length<T, U> {
+ Length::new(self.min_x())
+ }
+
+ #[inline]
+ pub fn max_y_typed(&self) -> Length<T, U> {
+ Length::new(self.max_y())
+ }
+
+ #[inline]
+ pub fn min_y_typed(&self) -> Length<T, U> {
+ Length::new(self.min_y())
+ }
+
+ #[inline]
+ pub fn intersection(&self, other: &TypedRect<T, U>) -> Option<TypedRect<T, U>> {
+ if !self.intersects(other) {
+ return None;
+ }
+
+ let upper_left = TypedPoint2D::new(max(self.min_x(), other.min_x()),
+ max(self.min_y(), other.min_y()));
+ let lower_right_x = min(self.max_x(), other.max_x());
+ let lower_right_y = min(self.max_y(), other.max_y());
+
+ Some(TypedRect::new(upper_left, TypedSize2D::new(lower_right_x - upper_left.x,
+ lower_right_y - upper_left.y)))
+ }
+
+ /// Translates the rect by a vector.
+ #[inline]
+ pub fn translate(&self, other: &TypedPoint2D<T, U>) -> TypedRect<T, U> {
+ TypedRect::new(
+ TypedPoint2D::new(self.origin.x + other.x, self.origin.y + other.y),
+ self.size
+ )
+ }
+
+ /// Returns true if this rectangle contains the point. Points are considered
+ /// in the rectangle if they are on the left or top edge, but outside if they
+ /// are on the right or bottom edge.
+ #[inline]
+ pub fn contains(&self, other: &TypedPoint2D<T, U>) -> bool {
+ self.origin.x <= other.x && other.x < self.origin.x + self.size.width &&
+ self.origin.y <= other.y && other.y < self.origin.y + self.size.height
+ }
+
+ /// Returns true if this rectangle contains the interior of rect. Always
+ /// returns true if rect is empty, and always returns false if rect is
+ /// nonempty but this rectangle is empty.
+ #[inline]
+ pub fn contains_rect(&self, rect: &TypedRect<T, U>) -> bool {
+ rect.is_empty() ||
+ (self.min_x() <= rect.min_x() && rect.max_x() <= self.max_x() &&
+ self.min_y() <= rect.min_y() && rect.max_y() <= self.max_y())
+ }
+
+ #[inline]
+ pub fn inflate(&self, width: T, height: T) -> TypedRect<T, U> {
+ TypedRect::new(
+ TypedPoint2D::new(self.origin.x - width, self.origin.y - height),
+ TypedSize2D::new(self.size.width + width + width, self.size.height + height + height),
+ )
+ }
+
+ #[inline]
+ pub fn inflate_typed(&self, width: Length<T, U>, height: Length<T, U>) -> TypedRect<T, U> {
+ self.inflate(width.get(), height.get())
+ }
+
+ #[inline]
+ pub fn top_right(&self) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(self.max_x(), self.origin.y)
+ }
+
+ #[inline]
+ pub fn bottom_left(&self) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(self.origin.x, self.max_y())
+ }
+
+ #[inline]
+ pub fn bottom_right(&self) -> TypedPoint2D<T, U> {
+ TypedPoint2D::new(self.max_x(), self.max_y())
+ }
+
+ #[inline]
+ pub fn translate_by_size(&self, size: &TypedSize2D<T, U>) -> TypedRect<T, U> {
+ self.translate(&TypedPoint2D::new(size.width, size.height))
+ }
+
+ /// Returns the smallest rectangle containing the four points.
+ pub fn from_points(points: &[TypedPoint2D<T, U>]) -> Self {
+ if points.len() == 0 {
+ return TypedRect::zero();
+ }
+ let (mut min_x, mut min_y) = (points[0].x, points[0].y);
+ let (mut max_x, mut max_y) = (min_x, min_y);
+ for point in &points[1..] {
+ if point.x < min_x {
+ min_x = point.x
+ }
+ if point.x > max_x {
+ max_x = point.x
+ }
+ if point.y < min_y {
+ min_y = point.y
+ }
+ if point.y > max_y {
+ max_y = point.y
+ }
+ }
+ TypedRect::new(TypedPoint2D::new(min_x, min_y),
+ TypedSize2D::new(max_x - min_x, max_y - min_y))
+ }
+}
+
+impl<T, U> TypedRect<T, U>
+where T: Copy + Clone + PartialOrd + Add<T, Output=T> + Sub<T, Output=T> + Zero {
+ #[inline]
+ pub fn union(&self, other: &TypedRect<T, U>) -> TypedRect<T, U> {
+ if self.size == Zero::zero() {
+ return *other;
+ }
+ if other.size == Zero::zero() {
+ return *self;
+ }
+
+ let upper_left = TypedPoint2D::new(min(self.min_x(), other.min_x()),
+ min(self.min_y(), other.min_y()));
+
+ let lower_right_x = max(self.max_x(), other.max_x());
+ let lower_right_y = max(self.max_y(), other.max_y());
+
+ TypedRect::new(
+ upper_left,
+ TypedSize2D::new(lower_right_x - upper_left.x, lower_right_y - upper_left.y)
+ )
+ }
+}
+
+impl<T, U> TypedRect<T, U> {
+ #[inline]
+ pub fn scale<Scale: Copy>(&self, x: Scale, y: Scale) -> TypedRect<T, U>
+ where T: Copy + Clone + Mul<Scale, Output=T> {
+ TypedRect::new(
+ TypedPoint2D::new(self.origin.x * x, self.origin.y * y),
+ TypedSize2D::new(self.size.width * x, self.size.height * y)
+ )
+ }
+}
+
+impl<T: Copy + PartialEq + Zero, U> TypedRect<T, U> {
+ /// Constructor, setting all sides to zero.
+ pub fn zero() -> TypedRect<T, U> {
+ TypedRect::new(
+ TypedPoint2D::zero(),
+ TypedSize2D::zero(),
+ )
+ }
+
+ /// Returns true if the size is zero, regardless of the origin's value.
+ pub fn is_empty(&self) -> bool {
+ self.size.width == Zero::zero() || self.size.height == Zero::zero()
+ }
+}
+
+
+pub fn min<T: Clone + PartialOrd>(x: T, y: T) -> T {
+ if x <= y { x } else { y }
+}
+
+pub fn max<T: Clone + PartialOrd>(x: T, y: T) -> T {
+ if x >= y { x } else { y }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedRect<T, U> {
+ type Output = TypedRect<T, U>;
+ #[inline]
+ fn mul(self, scale: T) -> TypedRect<T, U> {
+ TypedRect::new(self.origin * scale, self.size * scale)
+ }
+}
+
+impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedRect<T, U> {
+ type Output = TypedRect<T, U>;
+ #[inline]
+ fn div(self, scale: T) -> TypedRect<T, U> {
+ TypedRect::new(self.origin / scale, self.size / scale)
+ }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedRect<T, U1> {
+ type Output = TypedRect<T, U2>;
+ #[inline]
+ fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedRect<T, U2> {
+ TypedRect::new(self.origin * scale, self.size * scale)
+ }
+}
+
+impl<T: Copy + Div<T, Output=T>, U1, U2> Div<ScaleFactor<T, U1, U2>> for TypedRect<T, U2> {
+ type Output = TypedRect<T, U1>;
+ #[inline]
+ fn div(self, scale: ScaleFactor<T, U1, U2>) -> TypedRect<T, U1> {
+ TypedRect::new(self.origin / scale, self.size / scale)
+ }
+}
+
+impl<T: Copy, Unit> TypedRect<T, Unit> {
+ /// Drop the units, preserving only the numeric value.
+ pub fn to_untyped(&self) -> Rect<T> {
+ TypedRect::new(self.origin.to_untyped(), self.size.to_untyped())
+ }
+
+ /// Tag a unitless value with units.
+ pub fn from_untyped(r: &Rect<T>) -> TypedRect<T, Unit> {
+ TypedRect::new(TypedPoint2D::from_untyped(&r.origin), TypedSize2D::from_untyped(&r.size))
+ }
+}
+
+impl<T0: NumCast + Copy, Unit> TypedRect<T0, Unit> {
+ /// Cast from one numeric representation to another, preserving the units.
+ ///
+ /// When casting from floating point to integer coordinates, the decimals are truncated
+ /// as one would expect from a simple cast, but this behavior does not always make sense
+ /// geometrically. Consider using round(), round_in or round_out() before casting.
+ pub fn cast<T1: NumCast + Copy>(&self) -> Option<TypedRect<T1, Unit>> {
+ match (self.origin.cast(), self.size.cast()) {
+ (Some(origin), Some(size)) => Some(TypedRect::new(origin, size)),
+ _ => None
+ }
+ }
+}
+
+impl<T: Floor + Ceil + Round + Add<T, Output=T> + Sub<T, Output=T>, U> TypedRect<T, U> {
+ /// Return a rectangle with edges rounded to integer coordinates, such that
+ /// the returned rectangle has the same set of pixel centers as the original
+ /// one.
+ /// Edges at offset 0.5 round up.
+ /// Suitable for most places where integral device coordinates
+ /// are needed, but note that any translation should be applied first to
+ /// avoid pixel rounding errors.
+ /// Note that this is *not* rounding to nearest integer if the values are negative.
+ /// They are always rounding as floor(n + 0.5).
+ pub fn round(&self) -> Self {
+ let origin = self.origin.round();
+ let size = self.origin.add_size(&self.size).round() - origin;
+ TypedRect::new(origin, TypedSize2D::new(size.x, size.y))
+ }
+
+ /// Return a rectangle with edges rounded to integer coordinates, such that
+ /// the original rectangle contains the resulting rectangle.
+ pub fn round_in(&self) -> Self {
+ let origin = self.origin.ceil();
+ let size = self.origin.add_size(&self.size).floor() - origin;
+ TypedRect::new(origin, TypedSize2D::new(size.x, size.y))
+ }
+
+ /// Return a rectangle with edges rounded to integer coordinates, such that
+ /// the original rectangle is contained in the resulting rectangle.
+ pub fn round_out(&self) -> Self {
+ let origin = self.origin.floor();
+ let size = self.origin.add_size(&self.size).ceil() - origin;
+ TypedRect::new(origin, TypedSize2D::new(size.x, size.y))
+ }
+}
+
+// Convenience functions for common casts
+impl<T: NumCast + Copy, Unit> TypedRect<T, Unit> {
+ /// Cast into an `f32` rectangle.
+ pub fn to_f32(&self) -> TypedRect<f32, Unit> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `usize` rectangle, truncating decimals if any.
+ ///
+ /// When casting from floating point rectangles, it is worth considering whether
+ /// to `round()`, `round_in()` or `round_out()` before the cast in order to
+ /// obtain the desired conversion behavior.
+ pub fn to_usize(&self) -> TypedRect<usize, Unit> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `i32` rectangle, truncating decimals if any.
+ ///
+ /// When casting from floating point rectangles, it is worth considering whether
+ /// to `round()`, `round_in()` or `round_out()` before the cast in order to
+ /// obtain the desired conversion behavior.
+ pub fn to_i32(&self) -> TypedRect<i32, Unit> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `i64` rectangle, truncating decimals if any.
+ ///
+ /// When casting from floating point rectangles, it is worth considering whether
+ /// to `round()`, `round_in()` or `round_out()` before the cast in order to
+ /// obtain the desired conversion behavior.
+ pub fn to_i64(&self) -> TypedRect<i64, Unit> {
+ self.cast().unwrap()
+ }
+}
+
+/// Shorthand for `TypedRect::new(TypedPoint2D::new(x, y), TypedSize2D::new(w, h))`.
+pub fn rect<T: Copy, U>(x: T, y: T, w: T, h: T) -> TypedRect<T, U> {
+ TypedRect::new(TypedPoint2D::new(x, y), TypedSize2D::new(w, h))
+}
+
+#[cfg(test)]
+mod tests {
+ use point::Point2D;
+ use size::Size2D;
+ use super::*;
+
+ #[test]
+ fn test_min_max() {
+ assert!(min(0u32, 1u32) == 0u32);
+ assert!(min(-1.0f32, 0.0f32) == -1.0f32);
+
+ assert!(max(0u32, 1u32) == 1u32);
+ assert!(max(-1.0f32, 0.0f32) == 0.0f32);
+ }
+
+ #[test]
+ fn test_translate() {
+ let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
+ let pp = p.translate(&Point2D::new(10,15));
+
+ assert!(pp.size.width == 50);
+ assert!(pp.size.height == 40);
+ assert!(pp.origin.x == 10);
+ assert!(pp.origin.y == 15);
+
+
+ let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
+ let rr = r.translate(&Point2D::new(0,-10));
+
+ assert!(rr.size.width == 50);
+ assert!(rr.size.height == 40);
+ assert!(rr.origin.x == -10);
+ assert!(rr.origin.y == -15);
+ }
+
+ #[test]
+ fn test_translate_by_size() {
+ let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
+ let pp = p.translate_by_size(&Size2D::new(10,15));
+
+ assert!(pp.size.width == 50);
+ assert!(pp.size.height == 40);
+ assert!(pp.origin.x == 10);
+ assert!(pp.origin.y == 15);
+
+
+ let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
+ let rr = r.translate_by_size(&Size2D::new(0,-10));
+
+ assert!(rr.size.width == 50);
+ assert!(rr.size.height == 40);
+ assert!(rr.origin.x == -10);
+ assert!(rr.origin.y == -15);
+ }
+
+ #[test]
+ fn test_union() {
+ let p = Rect::new(Point2D::new(0, 0), Size2D::new(50, 40));
+ let q = Rect::new(Point2D::new(20,20), Size2D::new(5, 5));
+ let r = Rect::new(Point2D::new(-15, -30), Size2D::new(200, 15));
+ let s = Rect::new(Point2D::new(20, -15), Size2D::new(250, 200));
+
+ let pq = p.union(&q);
+ assert!(pq.origin == Point2D::new(0, 0));
+ assert!(pq.size == Size2D::new(50, 40));
+
+ let pr = p.union(&r);
+ assert!(pr.origin == Point2D::new(-15, -30));
+ assert!(pr.size == Size2D::new(200, 70));
+
+ let ps = p.union(&s);
+ assert!(ps.origin == Point2D::new(0, -15));
+ assert!(ps.size == Size2D::new(270, 200));
+
+ }
+
+ #[test]
+ fn test_intersection() {
+ let p = Rect::new(Point2D::new(0, 0), Size2D::new(10, 20));
+ let q = Rect::new(Point2D::new(5, 15), Size2D::new(10, 10));
+ let r = Rect::new(Point2D::new(-5, -5), Size2D::new(8, 8));
+
+ let pq = p.intersection(&q);
+ assert!(pq.is_some());
+ let pq = pq.unwrap();
+ assert!(pq.origin == Point2D::new(5, 15));
+ assert!(pq.size == Size2D::new(5, 5));
+
+ let pr = p.intersection(&r);
+ assert!(pr.is_some());
+ let pr = pr.unwrap();
+ assert!(pr.origin == Point2D::new(0, 0));
+ assert!(pr.size == Size2D::new(3, 3));
+
+ let qr = q.intersection(&r);
+ assert!(qr.is_none());
+ }
+
+ #[test]
+ fn test_contains() {
+ let r = Rect::new(Point2D::new(-20, 15), Size2D::new(100, 200));
+
+ assert!(r.contains(&Point2D::new(0, 50)));
+ assert!(r.contains(&Point2D::new(-10, 200)));
+
+ // The `contains` method is inclusive of the top/left edges, but not the
+ // bottom/right edges.
+ assert!(r.contains(&Point2D::new(-20, 15)));
+ assert!(!r.contains(&Point2D::new(80, 15)));
+ assert!(!r.contains(&Point2D::new(80, 215)));
+ assert!(!r.contains(&Point2D::new(-20, 215)));
+
+ // Points beyond the top-left corner.
+ assert!(!r.contains(&Point2D::new(-25, 15)));
+ assert!(!r.contains(&Point2D::new(-15, 10)));
+
+ // Points beyond the top-right corner.
+ assert!(!r.contains(&Point2D::new(85, 20)));
+ assert!(!r.contains(&Point2D::new(75, 10)));
+
+ // Points beyond the bottom-right corner.
+ assert!(!r.contains(&Point2D::new(85, 210)));
+ assert!(!r.contains(&Point2D::new(75, 220)));
+
+ // Points beyond the bottom-left corner.
+ assert!(!r.contains(&Point2D::new(-25, 210)));
+ assert!(!r.contains(&Point2D::new(-15, 220)));
+
+ let r = Rect::new(Point2D::new(-20.0, 15.0), Size2D::new(100.0, 200.0));
+ assert!(r.contains_rect(&r));
+ assert!(!r.contains_rect(&r.translate(&Point2D::new( 0.1, 0.0))));
+ assert!(!r.contains_rect(&r.translate(&Point2D::new(-0.1, 0.0))));
+ assert!(!r.contains_rect(&r.translate(&Point2D::new( 0.0, 0.1))));
+ assert!(!r.contains_rect(&r.translate(&Point2D::new( 0.0, -0.1))));
+ // Empty rectangles are always considered as contained in other rectangles,
+ // even if their origin is not.
+ let p = Point2D::new(1.0, 1.0);
+ assert!(!r.contains(&p));
+ assert!(r.contains_rect(&Rect::new(p, Size2D::zero())));
+ }
+
+ #[test]
+ fn test_scale() {
+ let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
+ let pp = p.scale(10, 15);
+
+ assert!(pp.size.width == 500);
+ assert!(pp.size.height == 600);
+ assert!(pp.origin.x == 0);
+ assert!(pp.origin.y == 0);
+
+ let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
+ let rr = r.scale(1, 20);
+
+ assert!(rr.size.width == 50);
+ assert!(rr.size.height == 800);
+ assert!(rr.origin.x == -10);
+ assert!(rr.origin.y == -100);
+ }
+
+ #[test]
+ fn test_inflate() {
+ let p = Rect::new(Point2D::new(0, 0), Size2D::new(10, 10));
+ let pp = p.inflate(10, 20);
+
+ assert!(pp.size.width == 30);
+ assert!(pp.size.height == 50);
+ assert!(pp.origin.x == -10);
+ assert!(pp.origin.y == -20);
+
+ let r = Rect::new(Point2D::new(0, 0), Size2D::new(10, 20));
+ let rr = r.inflate(-2, -5);
+
+ assert!(rr.size.width == 6);
+ assert!(rr.size.height == 10);
+ assert!(rr.origin.x == 2);
+ assert!(rr.origin.y == 5);
+ }
+
+ #[test]
+ fn test_min_max_x_y() {
+ let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
+ assert!(p.max_y() == 40);
+ assert!(p.min_y() == 0);
+ assert!(p.max_x() == 50);
+ assert!(p.min_x() == 0);
+
+ let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
+ assert!(r.max_y() == 35);
+ assert!(r.min_y() == -5);
+ assert!(r.max_x() == 40);
+ assert!(r.min_x() == -10);
+ }
+
+ #[test]
+ fn test_is_empty() {
+ assert!(Rect::new(Point2D::new(0u32, 0u32), Size2D::new(0u32, 0u32)).is_empty());
+ assert!(Rect::new(Point2D::new(0u32, 0u32), Size2D::new(10u32, 0u32)).is_empty());
+ assert!(Rect::new(Point2D::new(0u32, 0u32), Size2D::new(0u32, 10u32)).is_empty());
+ assert!(!Rect::new(Point2D::new(0u32, 0u32), Size2D::new(1u32, 1u32)).is_empty());
+ assert!(Rect::new(Point2D::new(10u32, 10u32), Size2D::new(0u32, 0u32)).is_empty());
+ assert!(Rect::new(Point2D::new(10u32, 10u32), Size2D::new(10u32, 0u32)).is_empty());
+ assert!(Rect::new(Point2D::new(10u32, 10u32), Size2D::new(0u32, 10u32)).is_empty());
+ assert!(!Rect::new(Point2D::new(10u32, 10u32), Size2D::new(1u32, 1u32)).is_empty());
+ }
+
+ #[test]
+ fn test_round() {
+ let mut x = -2.0;
+ let mut y = -2.0;
+ let mut w = -2.0;
+ let mut h = -2.0;
+ while x < 2.0 {
+ while y < 2.0 {
+ while w < 2.0 {
+ while h < 2.0 {
+ let rect = Rect::new(Point2D::new(x, y), Size2D::new(w, h));
+
+ assert!(rect.contains_rect(&rect.round_in()));
+ assert!(rect.round_in().inflate(1.0, 1.0).contains_rect(&rect));
+
+ assert!(rect.round_out().contains_rect(&rect));
+ assert!(rect.inflate(1.0, 1.0).contains_rect(&rect.round_out()));
+
+ assert!(rect.inflate(1.0, 1.0).contains_rect(&rect.round()));
+ assert!(rect.round().inflate(1.0, 1.0).contains_rect(&rect));
+
+ h += 0.1;
+ }
+ w += 0.1;
+ }
+ y += 0.1;
+ }
+ x += 0.1
+ }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/src/scale_factor.rs
@@ -0,0 +1,172 @@
+// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//! A type-checked scaling factor between units.
+
+use num::One;
+
+use heapsize::HeapSizeOf;
+use num_traits::NumCast;
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
+use std::fmt;
+use std::ops::{Add, Mul, Sub, Div};
+use std::marker::PhantomData;
+
+/// A scaling factor between two different units of measurement.
+///
+/// This is effectively a type-safe float, intended to be used in combination with other types like
+/// `length::Length` to enforce conversion between systems of measurement at compile time.
+///
+/// `Src` and `Dst` represent the units before and after multiplying a value by a `ScaleFactor`. They
+/// may be types without values, such as empty enums. For example:
+///
+/// ```rust
+/// use euclid::scale_factor::ScaleFactor;
+/// use euclid::length::Length;
+/// enum Mm {};
+/// enum Inch {};
+///
+/// let mm_per_inch: ScaleFactor<f32, Inch, Mm> = ScaleFactor::new(25.4);
+///
+/// let one_foot: Length<f32, Inch> = Length::new(12.0);
+/// let one_foot_in_mm: Length<f32, Mm> = one_foot * mm_per_inch;
+/// ```
+#[repr(C)]
+#[derive(RustcDecodable, RustcEncodable)]
+pub struct ScaleFactor<T, Src, Dst>(pub T, PhantomData<(Src, Dst)>);
+
+impl<T: HeapSizeOf, Src, Dst> HeapSizeOf for ScaleFactor<T, Src, Dst> {
+ fn heap_size_of_children(&self) -> usize {
+ self.0.heap_size_of_children()
+ }
+}
+
+impl<T, Src, Dst> Deserialize for ScaleFactor<T, Src, Dst> where T: Deserialize {
+ fn deserialize<D>(deserializer: D) -> Result<ScaleFactor<T, Src, Dst>, D::Error>
+ where D: Deserializer {
+ Ok(ScaleFactor(try!(Deserialize::deserialize(deserializer)), PhantomData))
+ }
+}
+
+impl<T, Src, Dst> Serialize for ScaleFactor<T, Src, Dst> where T: Serialize {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
+ self.0.serialize(serializer)
+ }
+}
+
+impl<T, Src, Dst> ScaleFactor<T, Src, Dst> {
+ pub fn new(x: T) -> ScaleFactor<T, Src, Dst> {
+ ScaleFactor(x, PhantomData)
+ }
+}
+
+impl<T: Clone, Src, Dst> ScaleFactor<T, Src, Dst> {
+ pub fn get(&self) -> T {
+ self.0.clone()
+ }
+}
+
+impl<T: Clone + One + Div<T, Output=T>, Src, Dst> ScaleFactor<T, Src, Dst> {
+ /// The inverse ScaleFactor (1.0 / self).
+ pub fn inv(&self) -> ScaleFactor<T, Dst, Src> {
+ let one: T = One::one();
+ ScaleFactor::new(one / self.get())
+ }
+}
+
+// scale0 * scale1
+impl<T: Clone + Mul<T, Output=T>, A, B, C>
+Mul<ScaleFactor<T, B, C>> for ScaleFactor<T, A, B> {
+ type Output = ScaleFactor<T, A, C>;
+ #[inline]
+ fn mul(self, other: ScaleFactor<T, B, C>) -> ScaleFactor<T, A, C> {
+ ScaleFactor::new(self.get() * other.get())
+ }
+}
+
+// scale0 + scale1
+impl<T: Clone + Add<T, Output=T>, Src, Dst> Add for ScaleFactor<T, Src, Dst> {
+ type Output = ScaleFactor<T, Src, Dst>;
+ #[inline]
+ fn add(self, other: ScaleFactor<T, Src, Dst>) -> ScaleFactor<T, Src, Dst> {
+ ScaleFactor::new(self.get() + other.get())
+ }
+}
+
+// scale0 - scale1
+impl<T: Clone + Sub<T, Output=T>, Src, Dst> Sub for ScaleFactor<T, Src, Dst> {
+ type Output = ScaleFactor<T, Src, Dst>;
+ #[inline]
+ fn sub(self, other: ScaleFactor<T, Src, Dst>) -> ScaleFactor<T, Src, Dst> {
+ ScaleFactor::new(self.get() - other.get())
+ }
+}
+
+impl<T: NumCast + Clone, Src, Dst0> ScaleFactor<T, Src, Dst0> {
+ /// Cast from one numeric representation to another, preserving the units.
+ pub fn cast<T1: NumCast + Clone>(&self) -> Option<ScaleFactor<T1, Src, Dst0>> {
+ NumCast::from(self.get()).map(ScaleFactor::new)
+ }
+}
+
+// FIXME: Switch to `derive(PartialEq, Clone)` after this Rust issue is fixed:
+// https://github.com/mozilla/rust/issues/7671
+
+impl<T: PartialEq, Src, Dst> PartialEq for ScaleFactor<T, Src, Dst> {
+ fn eq(&self, other: &ScaleFactor<T, Src, Dst>) -> bool {
+ self.0 == other.0
+ }
+}
+
+impl<T: Clone, Src, Dst> Clone for ScaleFactor<T, Src, Dst> {
+ fn clone(&self) -> ScaleFactor<T, Src, Dst> {
+ ScaleFactor::new(self.get())
+ }
+}
+
+impl<T: Copy, Src, Dst> Copy for ScaleFactor<T, Src, Dst> {}
+
+impl<T: fmt::Debug, Src, Dst> fmt::Debug for ScaleFactor<T, Src, Dst> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl<T: fmt::Display, Src, Dst> fmt::Display for ScaleFactor<T, Src, Dst> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::ScaleFactor;
+
+ enum Inch {}
+ enum Cm {}
+ enum Mm {}
+
+ #[test]
+ fn test_scale_factor() {
+ let mm_per_inch: ScaleFactor<f32, Inch, Mm> = ScaleFactor::new(25.4);
+ let cm_per_mm: ScaleFactor<f32, Mm, Cm> = ScaleFactor::new(0.1);
+
+ let mm_per_cm: ScaleFactor<f32, Cm, Mm> = cm_per_mm.inv();
+ assert_eq!(mm_per_cm.get(), 10.0);
+
+ let cm_per_inch: ScaleFactor<f32, Inch, Cm> = mm_per_inch * cm_per_mm;
+ assert_eq!(cm_per_inch, ScaleFactor::new(2.54));
+
+ let a: ScaleFactor<isize, Inch, Inch> = ScaleFactor::new(2);
+ let b: ScaleFactor<isize, Inch, Inch> = ScaleFactor::new(3);
+ assert!(a != b);
+ assert_eq!(a, a.clone());
+ assert_eq!(a.clone() + b.clone(), ScaleFactor::new(5));
+ assert_eq!(a - b, ScaleFactor::new(-1));
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/src/side_offsets.rs
@@ -0,0 +1,283 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
+//! and margins in CSS.
+
+use super::UnknownUnit;
+use length::Length;
+use num::Zero;
+use std::fmt;
+use std::ops::Add;
+use std::marker::PhantomData;
+
+#[cfg(feature = "unstable")]
+use heapsize::HeapSizeOf;
+
+/// A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
+/// and margins in CSS, optionally tagged with a unit.
+define_matrix! {
+ pub struct TypedSideOffsets2D<T, U> {
+ pub top: T,
+ pub right: T,
+ pub bottom: T,
+ pub left: T,
+ }
+}
+
+impl<T: fmt::Debug, U> fmt::Debug for TypedSideOffsets2D<T, U> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "({:?},{:?},{:?},{:?})",
+ self.top, self.right, self.bottom, self.left)
+ }
+}
+
+/// The default side offset type with no unit.
+pub type SideOffsets2D<T> = TypedSideOffsets2D<T, UnknownUnit>;
+
+impl<T: Copy, U> TypedSideOffsets2D<T, U> {
+ /// Constructor taking a scalar for each side.
+ pub fn new(top: T, right: T, bottom: T, left: T) -> TypedSideOffsets2D<T, U> {
+ TypedSideOffsets2D {
+ top: top,
+ right: right,
+ bottom: bottom,
+ left: left,
+ _unit: PhantomData,
+ }
+ }
+
+ /// Constructor taking a typed Length for each side.
+ pub fn from_lengths(top: Length<T, U>,
+ right: Length<T, U>,
+ bottom: Length<T, U>,
+ left: Length<T, U>) -> TypedSideOffsets2D<T, U> {
+ TypedSideOffsets2D::new(top.0, right.0, bottom.0, left.0)
+ }
+
+ /// Access self.top as a typed Length instead of a scalar value.
+ pub fn top_typed(&self) -> Length<T, U> { Length::new(self.top) }
+
+ /// Access self.right as a typed Length instead of a scalar value.
+ pub fn right_typed(&self) -> Length<T, U> { Length::new(self.right) }
+
+ /// Access self.bottom as a typed Length instead of a scalar value.
+ pub fn bottom_typed(&self) -> Length<T, U> { Length::new(self.bottom) }
+
+ /// Access self.left as a typed Length instead of a scalar value.
+ pub fn left_typed(&self) -> Length<T, U> { Length::new(self.left) }
+
+ /// Constructor setting the same value to all sides, taking a scalar value directly.
+ pub fn new_all_same(all: T) -> TypedSideOffsets2D<T, U> {
+ TypedSideOffsets2D::new(all, all, all, all)
+ }
+
+ /// Constructor setting the same value to all sides, taking a typed Length.
+ pub fn from_length_all_same(all: Length<T, U>) -> TypedSideOffsets2D<T, U> {
+ TypedSideOffsets2D::new_all_same(all.0)
+ }
+}
+
+impl<T, U> TypedSideOffsets2D<T, U> where T: Add<T, Output=T> + Copy {
+ pub fn horizontal(&self) -> T {
+ self.left + self.right
+ }
+
+ pub fn vertical(&self) -> T {
+ self.top + self.bottom
+ }
+
+ pub fn horizontal_typed(&self) -> Length<T, U> {
+ Length::new(self.horizontal())
+ }
+
+ pub fn vertical_typed(&self) -> Length<T, U> {
+ Length::new(self.vertical())
+ }
+}
+
+impl<T, U> Add for TypedSideOffsets2D<T, U> where T : Copy + Add<T, Output=T> {
+ type Output = TypedSideOffsets2D<T, U>;
+ fn add(self, other: TypedSideOffsets2D<T, U>) -> TypedSideOffsets2D<T, U> {
+ TypedSideOffsets2D::new(
+ self.top + other.top,
+ self.right + other.right,
+ self.bottom + other.bottom,
+ self.left + other.left,
+ )
+ }
+}
+
+impl<T: Copy + Zero, U> TypedSideOffsets2D<T, U> {
+ /// Constructor, setting all sides to zero.
+ pub fn zero() -> TypedSideOffsets2D<T, U> {
+ TypedSideOffsets2D::new(
+ Zero::zero(),
+ Zero::zero(),
+ Zero::zero(),
+ Zero::zero(),
+ )
+ }
+}
+
+/// A SIMD enabled version of TypedSideOffsets2D specialized for i32.
+#[cfg(feature = "unstable")]
+#[derive(Clone, Copy, PartialEq)]
+#[repr(simd)]
+pub struct SideOffsets2DSimdI32 {
+ pub top: i32,
+ pub bottom: i32,
+ pub right: i32,
+ pub left: i32,
+}
+
+#[cfg(feature = "unstable")]
+impl HeapSizeOf for SideOffsets2DSimdI32 {
+ fn heap_size_of_children(&self) -> usize { 0 }
+}
+
+#[cfg(feature = "unstable")]
+impl SideOffsets2DSimdI32 {
+ #[inline]
+ pub fn new(top: i32, right: i32, bottom: i32, left: i32) -> SideOffsets2DSimdI32 {
+ SideOffsets2DSimdI32 {
+ top: top,
+ bottom: bottom,
+ right: right,
+ left: left,
+ }
+ }
+}
+
+#[cfg(feature = "unstable")]
+impl SideOffsets2DSimdI32 {
+ #[inline]
+ pub fn new_all_same(all: i32) -> SideOffsets2DSimdI32 {
+ SideOffsets2DSimdI32::new(all.clone(), all.clone(), all.clone(), all.clone())
+ }
+}
+
+#[cfg(feature = "unstable")]
+impl SideOffsets2DSimdI32 {
+ #[inline]
+ pub fn horizontal(&self) -> i32 {
+ self.left + self.right
+ }
+
+ #[inline]
+ pub fn vertical(&self) -> i32 {
+ self.top + self.bottom
+ }
+}
+
+/*impl Add for SideOffsets2DSimdI32 {
+ type Output = SideOffsets2DSimdI32;
+ #[inline]
+ fn add(self, other: SideOffsets2DSimdI32) -> SideOffsets2DSimdI32 {
+ self + other // Use SIMD addition
+ }
+}*/
+
+#[cfg(feature = "unstable")]
+impl SideOffsets2DSimdI32 {
+ #[inline]
+ pub fn zero() -> SideOffsets2DSimdI32 {
+ SideOffsets2DSimdI32 {
+ top: 0,
+ bottom: 0,
+ right: 0,
+ left: 0,
+ }
+ }
+
+ #[cfg(not(target_arch = "x86_64"))]
+ #[inline]
+ pub fn is_zero(&self) -> bool {
+ self.top == 0 && self.right == 0 && self.bottom == 0 && self.left == 0
+ }
+
+ #[cfg(target_arch = "x86_64")]
+ #[inline]
+ pub fn is_zero(&self) -> bool {
+ let is_zero: bool;
+ unsafe {
+ asm! {
+ "ptest $1, $1
+ setz $0"
+ : "=r"(is_zero)
+ : "x"(*self)
+ :
+ : "intel"
+ };
+ }
+ is_zero
+ }
+}
+
+#[cfg(feature = "unstable")]
+#[cfg(test)]
+mod tests {
+ use super::SideOffsets2DSimdI32;
+
+ #[test]
+ fn test_is_zero() {
+ assert!(SideOffsets2DSimdI32::new_all_same(0).is_zero());
+ assert!(!SideOffsets2DSimdI32::new_all_same(1).is_zero());
+ assert!(!SideOffsets2DSimdI32::new(1, 0, 0, 0).is_zero());
+ assert!(!SideOffsets2DSimdI32::new(0, 1, 0, 0).is_zero());
+ assert!(!SideOffsets2DSimdI32::new(0, 0, 1, 0).is_zero());
+ assert!(!SideOffsets2DSimdI32::new(0, 0, 0, 1).is_zero());
+ }
+}
+
+#[cfg(feature = "unstable")]
+#[cfg(bench)]
+mod bench {
+ use test::BenchHarness;
+ use std::num::Zero;
+ use rand::{XorShiftRng, Rng};
+ use super::SideOffsets2DSimdI32;
+
+ #[cfg(target_arch = "x86")]
+ #[cfg(target_arch = "x86_64")]
+ #[bench]
+ fn bench_naive_is_zero(bh: &mut BenchHarness) {
+ fn is_zero(x: &SideOffsets2DSimdI32) -> bool {
+ x.top.is_zero() && x.right.is_zero() && x.bottom.is_zero() && x.left.is_zero()
+ }
+ let mut rng = XorShiftRng::new().unwrap();
+ bh.iter(|| is_zero(&rng.gen::<SideOffsets2DSimdI32>()))
+ }
+
+ #[bench]
+ fn bench_is_zero(bh: &mut BenchHarness) {
+ let mut rng = XorShiftRng::new().unwrap();
+ bh.iter(|| rng.gen::<SideOffsets2DSimdI32>().is_zero())
+ }
+
+ #[bench]
+ fn bench_naive_add(bh: &mut BenchHarness) {
+ fn add(x: &SideOffsets2DSimdI32, y: &SideOffsets2DSimdI32) -> SideOffsets2DSimdI32 {
+ SideOffsets2DSimdI32 {
+ top: x.top + y.top,
+ right: x.right + y.right,
+ bottom: x.bottom + y.bottom,
+ left: x.left + y.left,
+ }
+ }
+ let mut rng = XorShiftRng::new().unwrap();
+ bh.iter(|| add(&rng.gen::<SideOffsets2DSimdI32>(), &rng.gen::<SideOffsets2DSimdI32>()))
+ }
+
+ #[bench]
+ fn bench_add(bh: &mut BenchHarness) {
+ let mut rng = XorShiftRng::new().unwrap();
+ bh.iter(|| rng.gen::<SideOffsets2DSimdI32>() + rng.gen::<SideOffsets2DSimdI32>())
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/src/size.rs
@@ -0,0 +1,276 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::UnknownUnit;
+use length::Length;
+use scale_factor::ScaleFactor;
+use num::*;
+
+use num_traits::NumCast;
+use std::fmt;
+use std::ops::{Add, Div, Mul, Sub};
+use std::marker::PhantomData;
+
+/// A 2d size tagged with a unit.
+define_matrix! {
+ #[derive(RustcDecodable, RustcEncodable)]
+ pub struct TypedSize2D<T, U> {
+ pub width: T,
+ pub height: T,
+ }
+}
+
+/// Default 2d size type with no unit.
+///
+/// `Size2D` provides the same methods as `TypedSize2D`.
+pub type Size2D<T> = TypedSize2D<T, UnknownUnit>;
+
+impl<T: fmt::Debug, U> fmt::Debug for TypedSize2D<T, U> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}×{:?}", self.width, self.height)
+ }
+}
+
+impl<T: fmt::Display, U> fmt::Display for TypedSize2D<T, U> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "({}x{})", self.width, self.height)
+ }
+}
+
+impl<T, U> TypedSize2D<T, U> {
+ /// Constructor taking scalar values.
+ pub fn new(width: T, height: T) -> TypedSize2D<T, U> {
+ TypedSize2D {
+ width: width,
+ height: height,
+ _unit: PhantomData,
+ }
+ }
+}
+
+impl<T: Clone, U> TypedSize2D<T, U> {
+ /// Constructor taking scalar strongly typed lengths.
+ pub fn from_lengths(width: Length<T, U>, height: Length<T, U>) -> TypedSize2D<T, U> {
+ TypedSize2D::new(width.get(), height.get())
+ }
+}
+
+impl<T: Round, U> TypedSize2D<T, U> {
+ /// Rounds each component to the nearest integer value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ pub fn round(&self) -> Self {
+ TypedSize2D::new(self.width.round(), self.height.round())
+ }
+}
+
+impl<T: Ceil, U> TypedSize2D<T, U> {
+ /// Rounds each component to the smallest integer equal or greater than the original value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ pub fn ceil(&self) -> Self {
+ TypedSize2D::new(self.width.ceil(), self.height.ceil())
+ }
+}
+
+impl<T: Floor, U> TypedSize2D<T, U> {
+ /// Rounds each component to the biggest integer equal or lower than the original value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ pub fn floor(&self) -> Self {
+ TypedSize2D::new(self.width.floor(), self.height.floor())
+ }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> Add for TypedSize2D<T, U> {
+ type Output = TypedSize2D<T, U>;
+ fn add(self, other: TypedSize2D<T, U>) -> TypedSize2D<T, U> {
+ TypedSize2D::new(self.width + other.width, self.height + other.height)
+ }
+}
+
+impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedSize2D<T, U> {
+ type Output = TypedSize2D<T, U>;
+ fn sub(self, other: TypedSize2D<T, U>) -> TypedSize2D<T, U> {
+ TypedSize2D::new(self.width - other.width, self.height - other.height)
+ }
+}
+
+impl<T: Copy + Clone + Mul<T, Output=U>, U> TypedSize2D<T, U> {
+ pub fn area(&self) -> U { self.width * self.height }
+}
+
+impl<T: Zero, U> TypedSize2D<T, U> {
+ pub fn zero() -> TypedSize2D<T, U> {
+ TypedSize2D::new(
+ Zero::zero(),
+ Zero::zero(),
+ )
+ }
+}
+
+impl<T: Zero, U> Zero for TypedSize2D<T, U> {
+ fn zero() -> TypedSize2D<T, U> {
+ TypedSize2D::new(
+ Zero::zero(),
+ Zero::zero(),
+ )
+ }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedSize2D<T, U> {
+ type Output = TypedSize2D<T, U>;
+ #[inline]
+ fn mul(self, scale: T) -> TypedSize2D<T, U> {
+ TypedSize2D::new(self.width * scale, self.height * scale)
+ }
+}
+
+impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedSize2D<T, U> {
+ type Output = TypedSize2D<T, U>;
+ #[inline]
+ fn div(self, scale: T) -> TypedSize2D<T, U> {
+ TypedSize2D::new(self.width / scale, self.height / scale)
+ }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedSize2D<T, U1> {
+ type Output = TypedSize2D<T, U2>;
+ #[inline]
+ fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedSize2D<T, U2> {
+ TypedSize2D::new(self.width * scale.get(), self.height * scale.get())
+ }
+}
+
+impl<T: Copy + Div<T, Output=T>, U1, U2> Div<ScaleFactor<T, U1, U2>> for TypedSize2D<T, U2> {
+ type Output = TypedSize2D<T, U1>;
+ #[inline]
+ fn div(self, scale: ScaleFactor<T, U1, U2>) -> TypedSize2D<T, U1> {
+ TypedSize2D::new(self.width / scale.get(), self.height / scale.get())
+ }
+}
+
+impl<T: Copy, U> TypedSize2D<T, U> {
+ /// Returns self.width as a Length carrying the unit.
+ #[inline]
+ pub fn width_typed(&self) -> Length<T, U> { Length::new(self.width) }
+
+ /// Returns self.height as a Length carrying the unit.
+ #[inline]
+ pub fn height_typed(&self) -> Length<T, U> { Length::new(self.height) }
+
+ #[inline]
+ pub fn to_array(&self) -> [T; 2] { [self.width, self.height] }
+
+ /// Drop the units, preserving only the numeric value.
+ pub fn to_untyped(&self) -> Size2D<T> {
+ TypedSize2D::new(self.width, self.height)
+ }
+
+ /// Tag a unitless value with units.
+ pub fn from_untyped(p: &Size2D<T>) -> TypedSize2D<T, U> {
+ TypedSize2D::new(p.width, p.height)
+ }
+}
+
+impl<T: NumCast + Copy, Unit> TypedSize2D<T, Unit> {
+ /// Cast from one numeric representation to another, preserving the units.
+ ///
+ /// When casting from floating point to integer coordinates, the decimals are truncated
+ /// as one would expect from a simple cast, but this behavior does not always make sense
+ /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
+ pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedSize2D<NewT, Unit>> {
+ match (NumCast::from(self.width), NumCast::from(self.height)) {
+ (Some(w), Some(h)) => Some(TypedSize2D::new(w, h)),
+ _ => None
+ }
+ }
+
+ // Convenience functions for common casts
+
+ /// Cast into an `f32` size.
+ pub fn to_f32(&self) -> TypedSize2D<f32, Unit> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `uint` size, truncating decimals if any.
+ ///
+ /// When casting from floating point sizes, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ pub fn to_usize(&self) -> TypedSize2D<usize, Unit> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `i32` size, truncating decimals if any.
+ ///
+ /// When casting from floating point sizes, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ pub fn to_i32(&self) -> TypedSize2D<i32, Unit> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `i64` size, truncating decimals if any.
+ ///
+ /// When casting from floating point sizes, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ pub fn to_i64(&self) -> TypedSize2D<i64, Unit> {
+ self.cast().unwrap()
+ }
+}
+
+/// Shorthand for `TypedSize2D::new(w, h)`.
+pub fn size2<T, U>(w: T, h: T) -> TypedSize2D<T, U> {
+ TypedSize2D::new(w, h)
+}
+
+#[cfg(test)]
+mod size2d {
+ use super::Size2D;
+
+ #[test]
+ pub fn test_add() {
+ let p1 = Size2D::new(1.0, 2.0);
+ let p2 = Size2D::new(3.0, 4.0);
+ assert_eq!(p1 + p2, Size2D::new(4.0, 6.0));
+
+ let p1 = Size2D::new(1.0, 2.0);
+ let p2 = Size2D::new(0.0, 0.0);
+ assert_eq!(p1 + p2, Size2D::new(1.0, 2.0));
+
+ let p1 = Size2D::new(1.0, 2.0);
+ let p2 = Size2D::new(-3.0, -4.0);
+ assert_eq!(p1 + p2, Size2D::new(-2.0, -2.0));
+
+ let p1 = Size2D::new(0.0, 0.0);
+ let p2 = Size2D::new(0.0, 0.0);
+ assert_eq!(p1 + p2, Size2D::new(0.0, 0.0));
+ }
+
+ #[test]
+ pub fn test_sub() {
+ let p1 = Size2D::new(1.0, 2.0);
+ let p2 = Size2D::new(3.0, 4.0);
+ assert_eq!(p1 - p2, Size2D::new(-2.0, -2.0));
+
+ let p1 = Size2D::new(1.0, 2.0);
+ let p2 = Size2D::new(0.0, 0.0);
+ assert_eq!(p1 - p2, Size2D::new(1.0, 2.0));
+
+ let p1 = Size2D::new(1.0, 2.0);
+ let p2 = Size2D::new(-3.0, -4.0);
+ assert_eq!(p1 - p2, Size2D::new(4.0, 6.0));
+
+ let p1 = Size2D::new(0.0, 0.0);
+ let p2 = Size2D::new(0.0, 0.0);
+ assert_eq!(p1 - p2, Size2D::new(0.0, 0.0));
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.13.0/src/trig.rs
@@ -0,0 +1,32 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+/// Trait for basic trigonometry functions, so they can be used on generic numeric types
+pub trait Trig {
+ fn sin(self) -> Self;
+ fn cos(self) -> Self;
+ fn tan(self) -> Self;
+}
+
+macro_rules! trig {
+ ($ty:ty) => (
+ impl Trig for $ty {
+ #[inline]
+ fn sin(self) -> $ty { self.sin() }
+ #[inline]
+ fn cos(self) -> $ty { self.cos() }
+ #[inline]
+ fn tan(self) -> $ty { self.tan() }
+ }
+ )
+}
+
+trig!(f32);
+trig!(f64);
--- a/third_party/rust/euclid/.cargo-checksum.json
+++ b/third_party/rust/euclid/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"118514fd9c4958df0d25584cda4917186c46011569f55ef350530c1ad3fbdb48",".travis.yml":"13d3e5a7bf83b04c8e8cfa14f0297bd8366d68391d977dd547f64707dffc275a","COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"c91c98dc9510ef29a7ce0d7c78294f15cb139c9afecca38e5fda56b0a6984954","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/approxeq.rs":"6cf810ad389c73a27141a7a67454ed12d4b01c3c16605b9a7414b389bc0615dd","src/length.rs":"d7c6369f2fe2a17c845b57749bd48c471159f0571a7314d3bf90737d53f697d3","src/lib.rs":"e2e621f05304278d020429d0349acf7a4e7c7a9a72bd23fc0e55680267472ee9","src/macros.rs":"b63dabdb52df84ea170dc1dab5fe8d7a78c054562d1566bab416124708d2d7af","src/matrix2d.rs":"2361338f59813adf4eebaab76e4dd82be0fbfb9ff2461da8dd9ac9d43583b322","src/matrix4d.rs":"b8547bed6108b037192021c97169c00ad456120b849e9b7ac7bec40363edaec1","src/num.rs":"749b201289fc6663199160a2f9204e17925fd3053f8ab7779e7bfb377ad06227","src/point.rs":"dbf12a3ad35dc2502b7f2637856d8ee40f5a96e37ed00f3ee3272bf5752c060c","src/rect.rs":"0a255046dd11a6093d9a77e327e1df31802808536b4d87e4e3b80ff6b208de0f","src/scale_factor.rs":"df6dbd1f0f9f63210b92809f84a383dad982a74f09789cf22c7d8f9b62199d39","src/side_offsets.rs":"f85526a421ffda63ff01a3478d4162c8717eef68e942acfa2fd9a1adee02ebb2","src/size.rs":"ae1b647e300600b50a21dba8c1d915801782ebae82baeb5e49017e6d68a49b28","src/trig.rs":"ef290927af252ca90a29ba9f17158b591ed591604e66cb9df045dd47b9cfdca5"},"package":"6083f113c422ff9cd855a1cf6cc8ec0903606c0eb43a0c6a0ced3bdc9731e4c1"}
\ No newline at end of file
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"118514fd9c4958df0d25584cda4917186c46011569f55ef350530c1ad3fbdb48",".travis.yml":"56843ecfd2b71797b648b8e537623e84af3c638ea4b8472ed27c55f097bce3dc","COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"596d3bcfc1684713b5c557e84b35b98250bebb3d4715e44741d227ab246a16ab","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/approxeq.rs":"6cf810ad389c73a27141a7a67454ed12d4b01c3c16605b9a7414b389bc0615dd","src/length.rs":"d7877ebc7ee2e85df2a1f5b9376011bdeeaa5cd7fa2fbdba0934df7456c0821e","src/lib.rs":"77b97c1d7889f037180b68344471ecf7c46b5412fe7c92504debc422c8739b61","src/macros.rs":"b63dabdb52df84ea170dc1dab5fe8d7a78c054562d1566bab416124708d2d7af","src/num.rs":"749b201289fc6663199160a2f9204e17925fd3053f8ab7779e7bfb377ad06227","src/point.rs":"42c1ee0997598d3482ac4c58f255e31b56a97a3a0aa1871b61f55074eecf1ae2","src/rect.rs":"e18811e3be9dba41976b611d52dbe13c5a27dc7db3e3e779daabeed7670b658f","src/scale_factor.rs":"61f979384316ae8a70e836b0d4b016ec5c26a952776037a65801152af4a247cb","src/side_offsets.rs":"fd95ffc9a74e9e84314875c388e763d0780486eb7f9034423e3a22048361e379","src/size.rs":"d9a6fb1f080a06e1332b2e804f8334e086e6d6f17a4288f35133d80b2e2da765","src/transform2d.rs":"4fe4fef7266b06b7790cd400d990ad02e6e605499a1a33c8e39b5e00364389ba","src/transform3d.rs":"cd8a08dd341fcea4c5b10e00d029424e382f3b0002dd8341f302be7f1c12c4fc","src/trig.rs":"ef290927af252ca90a29ba9f17158b591ed591604e66cb9df045dd47b9cfdca5","src/vector.rs":"c087700ad35c3e18e0f5722573f6a24ed2b0452e044c1f0bbb6466c993c560f1"},"package":"995b21c36b37e0f18ed9ba1714378a337e3ff19a6e5e952ea94b0f3dd4e12fbc"}
\ No newline at end of file
--- a/third_party/rust/euclid/.travis.yml
+++ b/third_party/rust/euclid/.travis.yml
@@ -1,9 +1,14 @@
language: rust
+rust:
+ - 1.15.1
+ - stable
+ - beta
+ - nightly
notifications:
webhooks: http://build.servo.org:54856/travis
matrix:
include:
- rust: stable
env: FEATURES=""
--- a/third_party/rust/euclid/Cargo.toml
+++ b/third_party/rust/euclid/Cargo.toml
@@ -1,24 +1,23 @@
[package]
name = "euclid"
-version = "0.13.0"
+version = "0.14.4"
authors = ["The Servo Project Developers"]
description = "Geometry primitives"
documentation = "https://docs.rs/euclid/"
repository = "https://github.com/servo/euclid"
keywords = ["matrix", "vector", "linear-algebra", "geometry"]
categories = ["science"]
license = "MIT / Apache-2.0"
[features]
unstable = []
[dependencies]
heapsize = "0.4"
-rustc-serialize = "0.3.2"
num-traits = {version = "0.1.32", default-features = false}
log = "0.3.1"
serde = "0.9"
[dev-dependencies]
rand = "0.3.7"
serde_test = "0.9"
--- a/third_party/rust/euclid/src/length.rs
+++ b/third_party/rust/euclid/src/length.rs
@@ -8,16 +8,17 @@
// except according to those terms.
//! A one-dimensional length, tagged with its units.
use scale_factor::ScaleFactor;
use num::Zero;
use heapsize::HeapSizeOf;
use num_traits::{NumCast, Saturating};
+use num::One;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cmp::Ordering;
use std::ops::{Add, Sub, Mul, Div, Neg};
use std::ops::{AddAssign, SubAssign};
use std::marker::PhantomData;
use std::fmt;
/// A one-dimensional distance, with value represented by `T` and unit of measurement `Unit`.
@@ -29,17 +30,16 @@ use std::fmt;
/// expression that requires a different unit. It may be a type without values, such as an empty
/// enum.
///
/// You can multiply a `Length` by a `scale_factor::ScaleFactor` to convert it from one unit to
/// another. See the `ScaleFactor` docs for an example.
// Uncomment the derive, and remove the macro call, once heapsize gets
// PhantomData<T> support.
#[repr(C)]
-#[derive(RustcDecodable, RustcEncodable)]
pub struct Length<T, Unit>(pub T, PhantomData<Unit>);
impl<T: Clone, Unit> Clone for Length<T, Unit> {
fn clone(&self) -> Self {
Length(self.0.clone(), PhantomData)
}
}
@@ -47,30 +47,30 @@ impl<T: Copy, Unit> Copy for Length<T, U
impl<Unit, T: HeapSizeOf> HeapSizeOf for Length<T, Unit> {
fn heap_size_of_children(&self) -> usize {
self.0.heap_size_of_children()
}
}
impl<Unit, T> Deserialize for Length<T, Unit> where T: Deserialize {
- fn deserialize<D>(deserializer: D) -> Result<Length<T, Unit>,D::Error>
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer {
Ok(Length(try!(Deserialize::deserialize(deserializer)), PhantomData))
}
}
impl<T, Unit> Serialize for Length<T, Unit> where T: Serialize {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
self.0.serialize(serializer)
}
}
impl<T, Unit> Length<T, Unit> {
- pub fn new(x: T) -> Length<T, Unit> {
+ pub fn new(x: T) -> Self {
Length(x, PhantomData)
}
}
impl<Unit, T: Clone> Length<T, Unit> {
pub fn get(&self) -> T {
self.0.clone()
}
@@ -168,37 +168,49 @@ impl <U, T:Clone + Neg<Output=T>> Neg fo
impl<Unit, T0: NumCast + Clone> Length<T0, Unit> {
/// Cast from one numeric representation to another, preserving the units.
pub fn cast<T1: NumCast + Clone>(&self) -> Option<Length<T1, Unit>> {
NumCast::from(self.get()).map(Length::new)
}
}
impl<Unit, T: Clone + PartialEq> PartialEq for Length<T, Unit> {
- fn eq(&self, other: &Length<T, Unit>) -> bool { self.get().eq(&other.get()) }
+ fn eq(&self, other: &Self) -> bool { self.get().eq(&other.get()) }
}
impl<Unit, T: Clone + PartialOrd> PartialOrd for Length<T, Unit> {
- fn partial_cmp(&self, other: &Length<T, Unit>) -> Option<Ordering> {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.get().partial_cmp(&other.get())
}
}
impl<Unit, T: Clone + Eq> Eq for Length<T, Unit> {}
impl<Unit, T: Clone + Ord> Ord for Length<T, Unit> {
- fn cmp(&self, other: &Length<T, Unit>) -> Ordering { self.get().cmp(&other.get()) }
+ fn cmp(&self, other: &Self) -> Ordering { self.get().cmp(&other.get()) }
}
impl<Unit, T: Zero> Zero for Length<T, Unit> {
- fn zero() -> Length<T, Unit> {
+ fn zero() -> Self {
Length::new(Zero::zero())
}
}
+impl<T, U> Length<T, U>
+where T: Copy + One + Add<Output=T> + Sub<Output=T> + Mul<Output=T> {
+ /// Linearly interpolate between this length and another length.
+ ///
+ /// `t` is expected to be between zero and one.
+ #[inline]
+ pub fn lerp(&self, other: Self, t: T) -> Self {
+ let one_t = T::one() - t;
+ Length::new(one_t * self.get() + t * other.get())
+ }
+}
+
#[cfg(test)]
mod tests {
use super::Length;
use num::Zero;
use heapsize::HeapSizeOf;
use num_traits::Saturating;
use scale_factor::ScaleFactor;
--- a/third_party/rust/euclid/src/lib.rs
+++ b/third_party/rust/euclid/src/lib.rs
@@ -54,60 +54,82 @@
//! // Length::get returns the scalar value (f32).
//! assert_eq!(p.x, p.x_typed().get());
//! ```
extern crate heapsize;
#[cfg_attr(test, macro_use)]
extern crate log;
-extern crate rustc_serialize;
extern crate serde;
#[cfg(test)]
extern crate rand;
#[cfg(feature = "unstable")]
extern crate test;
extern crate num_traits;
pub use length::Length;
pub use scale_factor::ScaleFactor;
-pub use matrix2d::{Matrix2D, TypedMatrix2D};
-pub use matrix4d::{Matrix4D, TypedMatrix4D};
+pub use transform2d::{Transform2D, TypedTransform2D};
+pub use transform3d::{Transform3D, TypedTransform3D};
pub use point::{
- Point2D, TypedPoint2D,
- Point3D, TypedPoint3D,
- Point4D, TypedPoint4D,
+ Point2D, TypedPoint2D, point2,
+ Point3D, TypedPoint3D, point3,
};
-pub use rect::{Rect, TypedRect};
+pub use vector::{
+ Vector2D, TypedVector2D, vec2,
+ Vector3D, TypedVector3D, vec3,
+};
+
+pub use rect::{Rect, TypedRect, rect};
pub use side_offsets::{SideOffsets2D, TypedSideOffsets2D};
#[cfg(feature = "unstable")] pub use side_offsets::SideOffsets2DSimdI32;
-pub use size::{Size2D, TypedSize2D};
+pub use size::{Size2D, TypedSize2D, size2};
+pub use trig::Trig;
pub mod approxeq;
-pub mod length;
+pub mod num;
+mod length;
#[macro_use]
mod macros;
-pub mod matrix2d;
-pub mod matrix4d;
-pub mod num;
-pub mod point;
-pub mod rect;
-pub mod scale_factor;
-pub mod side_offsets;
-pub mod size;
-pub mod trig;
+mod transform2d;
+mod transform3d;
+mod point;
+mod rect;
+mod scale_factor;
+mod side_offsets;
+mod size;
+mod trig;
+mod vector;
/// The default unit.
-#[derive(Clone, Copy, RustcDecodable, RustcEncodable)]
+#[derive(Clone, Copy)]
pub struct UnknownUnit;
/// Unit for angles in radians.
pub struct Rad;
/// Unit for angles in degrees.
pub struct Deg;
/// A value in radians.
pub type Radians<T> = Length<T, Rad>;
/// A value in Degrees.
pub type Degrees<T> = Length<T, Deg>;
+
+/// Temporary alias to facilitate the transition to the new naming scheme
+#[deprecated]
+pub type Matrix2D<T> = Transform2D<T>;
+
+/// Temporary alias to facilitate the transition to the new naming scheme
+#[deprecated]
+pub type TypedMatrix2D<T, Src, Dst> = TypedTransform2D<T, Src, Dst>;
+
+/// Temporary alias to facilitate the transition to the new naming scheme
+#[deprecated]
+pub type Matrix4D<T> = Transform3D<T>;
+
+/// Temporary alias to facilitate the transition to the new naming scheme
+#[deprecated]
+pub type TypedMatrix4D<T, Src, Dst> = TypedTransform3D<T, Src, Dst>;
+
--- a/third_party/rust/euclid/src/point.rs
+++ b/third_party/rust/euclid/src/point.rs
@@ -9,45 +9,50 @@
use super::UnknownUnit;
use approxeq::ApproxEq;
use length::Length;
use scale_factor::ScaleFactor;
use size::TypedSize2D;
use num::*;
use num_traits::{Float, NumCast};
+use vector::{TypedVector2D, TypedVector3D, vec2, vec3};
use std::fmt;
-use std::ops::{Add, Neg, Mul, Sub, Div};
+use std::ops::{Add, Mul, Sub, Div, AddAssign, SubAssign, MulAssign, DivAssign};
use std::marker::PhantomData;
define_matrix! {
/// A 2d Point tagged with a unit.
- #[derive(RustcDecodable, RustcEncodable)]
pub struct TypedPoint2D<T, U> {
pub x: T,
pub y: T,
}
}
/// Default 2d point type with no unit.
///
/// `Point2D` provides the same methods as `TypedPoint2D`.
pub type Point2D<T> = TypedPoint2D<T, UnknownUnit>;
impl<T: Copy + Zero, U> TypedPoint2D<T, U> {
/// Constructor, setting all components to zero.
#[inline]
- pub fn zero() -> TypedPoint2D<T, U> {
- TypedPoint2D::new(Zero::zero(), Zero::zero())
+ pub fn origin() -> Self {
+ point2(Zero::zero(), Zero::zero())
+ }
+
+ #[inline]
+ pub fn zero() -> Self {
+ Self::origin()
}
/// Convert into a 3d point.
#[inline]
pub fn to_3d(&self) -> TypedPoint3D<T, U> {
- TypedPoint3D::new(self.x, self.y, Zero::zero())
+ point3(self.x, self.y, Zero::zero())
}
}
impl<T: fmt::Debug, U> fmt::Debug for TypedPoint2D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:?},{:?})", self.x, self.y)
}
}
@@ -56,269 +61,353 @@ impl<T: fmt::Display, U> fmt::Display fo
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "({},{})", self.x, self.y)
}
}
impl<T: Copy, U> TypedPoint2D<T, U> {
/// Constructor taking scalar values directly.
#[inline]
- pub fn new(x: T, y: T) -> TypedPoint2D<T, U> {
+ pub fn new(x: T, y: T) -> Self {
TypedPoint2D { x: x, y: y, _unit: PhantomData }
}
/// Constructor taking properly typed Lengths instead of scalar values.
#[inline]
- pub fn from_lengths(x: Length<T, U>, y: Length<T, U>) -> TypedPoint2D<T, U> {
- TypedPoint2D::new(x.0, y.0)
+ pub fn from_lengths(x: Length<T, U>, y: Length<T, U>) -> Self {
+ point2(x.0, y.0)
+ }
+
+ /// Create a 3d point from this one, using the specified z value.
+ #[inline]
+ pub fn extend(&self, z: T) -> TypedPoint3D<T, U> {
+ point3(self.x, self.y, z)
+ }
+
+ /// Cast this point into a vector.
+ ///
+ /// Equivalent to substracting the origin to this point.
+ #[inline]
+ pub fn to_vector(&self) -> TypedVector2D<T, U> {
+ vec2(self.x, self.y)
}
/// Returns self.x as a Length carrying the unit.
#[inline]
pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
/// Returns self.y as a Length carrying the unit.
#[inline]
pub fn y_typed(&self) -> Length<T, U> { Length::new(self.y) }
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> Point2D<T> {
- TypedPoint2D::new(self.x, self.y)
+ point2(self.x, self.y)
}
/// Tag a unitless value with units.
#[inline]
- pub fn from_untyped(p: &Point2D<T>) -> TypedPoint2D<T, U> {
- TypedPoint2D::new(p.x, p.y)
+ pub fn from_untyped(p: &Point2D<T>) -> Self {
+ point2(p.x, p.y)
}
#[inline]
pub fn to_array(&self) -> [T; 2] {
[self.x, self.y]
}
}
-impl<T, U> TypedPoint2D<T, U>
-where T: Copy + Mul<T, Output=T> + Add<T, Output=T> + Sub<T, Output=T> {
- /// Dot product.
- #[inline]
- pub fn dot(self, other: TypedPoint2D<T, U>) -> T {
- self.x * other.x + self.y * other.y
- }
-
- /// Returns the norm of the cross product [self.x, self.y, 0] x [other.x, other.y, 0]..
- #[inline]
- pub fn cross(self, other: TypedPoint2D<T, U>) -> T {
- self.x * other.y - self.y * other.x
- }
-
+impl<T: Copy + Add<T, Output=T>, U> TypedPoint2D<T, U> {
#[inline]
- pub fn normalize(self) -> Self where T: Float + ApproxEq<T> {
- let dot = self.dot(self);
- if dot.approx_eq(&T::zero()) {
- self
- } else {
- self / dot.sqrt()
- }
- }
-}
-
-impl<T: Copy + Add<T, Output=T>, U> Add for TypedPoint2D<T, U> {
- type Output = TypedPoint2D<T, U>;
- fn add(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
- TypedPoint2D::new(self.x + other.x, self.y + other.y)
+ pub fn add_size(&self, other: &TypedSize2D<T, U>) -> Self {
+ point2(self.x + other.width, self.y + other.height)
}
}
impl<T: Copy + Add<T, Output=T>, U> Add<TypedSize2D<T, U>> for TypedPoint2D<T, U> {
- type Output = TypedPoint2D<T, U>;
- fn add(self, other: TypedSize2D<T, U>) -> TypedPoint2D<T, U> {
- TypedPoint2D::new(self.x + other.width, self.y + other.height)
+ type Output = Self;
+ #[inline]
+ fn add(self, other: TypedSize2D<T, U>) -> Self {
+ point2(self.x + other.width, self.y + other.height)
}
}
-impl<T: Copy + Add<T, Output=T>, U> TypedPoint2D<T, U> {
- pub fn add_size(&self, other: &TypedSize2D<T, U>) -> TypedPoint2D<T, U> {
- TypedPoint2D::new(self.x + other.width, self.y + other.height)
+impl<T: Copy + Add<T, Output=T>, U> AddAssign<TypedVector2D<T, U>> for TypedPoint2D<T, U> {
+ #[inline]
+ fn add_assign(&mut self, other: TypedVector2D<T, U>) {
+ *self = *self + other
+ }
+}
+
+impl<T: Copy + Sub<T, Output=T>, U> SubAssign<TypedVector2D<T, U>> for TypedPoint2D<T, U> {
+ #[inline]
+ fn sub_assign(&mut self, other: TypedVector2D<T, U>) {
+ *self = *self - other
+ }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> Add<TypedVector2D<T, U>> for TypedPoint2D<T, U> {
+ type Output = Self;
+ #[inline]
+ fn add(self, other: TypedVector2D<T, U>) -> Self {
+ point2(self.x + other.x, self.y + other.y)
}
}
impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedPoint2D<T, U> {
- type Output = TypedPoint2D<T, U>;
- fn sub(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
- TypedPoint2D::new(self.x - other.x, self.y - other.y)
+ type Output = TypedVector2D<T, U>;
+ #[inline]
+ fn sub(self, other: Self) -> TypedVector2D<T, U> {
+ vec2(self.x - other.x, self.y - other.y)
}
}
-impl <T: Copy + Neg<Output=T>, U> Neg for TypedPoint2D<T, U> {
- type Output = TypedPoint2D<T, U>;
+impl<T: Copy + Sub<T, Output=T>, U> Sub<TypedVector2D<T, U>> for TypedPoint2D<T, U> {
+ type Output = Self;
#[inline]
- fn neg(self) -> TypedPoint2D<T, U> {
- TypedPoint2D::new(-self.x, -self.y)
+ fn sub(self, other: TypedVector2D<T, U>) -> Self {
+ point2(self.x - other.x, self.y - other.y)
}
}
impl<T: Float, U> TypedPoint2D<T, U> {
- pub fn min(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
- TypedPoint2D::new(self.x.min(other.x), self.y.min(other.y))
+ #[inline]
+ pub fn min(self, other: Self) -> Self {
+ point2(self.x.min(other.x), self.y.min(other.y))
}
- pub fn max(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
- TypedPoint2D::new(self.x.max(other.x), self.y.max(other.y))
+ #[inline]
+ pub fn max(self, other: Self) -> Self {
+ point2(self.x.max(other.x), self.y.max(other.y))
}
}
impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedPoint2D<T, U> {
- type Output = TypedPoint2D<T, U>;
+ type Output = Self;
#[inline]
- fn mul(self, scale: T) -> TypedPoint2D<T, U> {
- TypedPoint2D::new(self.x * scale, self.y * scale)
+ fn mul(self, scale: T) -> Self {
+ point2(self.x * scale, self.y * scale)
+ }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U> MulAssign<T> for TypedPoint2D<T, U> {
+ #[inline]
+ fn mul_assign(&mut self, scale: T) {
+ *self = *self * scale
}
}
impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedPoint2D<T, U> {
- type Output = TypedPoint2D<T, U>;
+ type Output = Self;
#[inline]
- fn div(self, scale: T) -> TypedPoint2D<T, U> {
- TypedPoint2D::new(self.x / scale, self.y / scale)
+ fn div(self, scale: T) -> Self {
+ point2(self.x / scale, self.y / scale)
+ }
+}
+
+impl<T: Copy + Div<T, Output=T>, U> DivAssign<T> for TypedPoint2D<T, U> {
+ #[inline]
+ fn div_assign(&mut self, scale: T) {
+ *self = *self / scale
}
}
impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedPoint2D<T, U1> {
type Output = TypedPoint2D<T, U2>;
#[inline]
fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedPoint2D<T, U2> {
- TypedPoint2D::new(self.x * scale.get(), self.y * scale.get())
+ point2(self.x * scale.get(), self.y * scale.get())
}
}
impl<T: Copy + Div<T, Output=T>, U1, U2> Div<ScaleFactor<T, U1, U2>> for TypedPoint2D<T, U2> {
type Output = TypedPoint2D<T, U1>;
#[inline]
fn div(self, scale: ScaleFactor<T, U1, U2>) -> TypedPoint2D<T, U1> {
- TypedPoint2D::new(self.x / scale.get(), self.y / scale.get())
+ point2(self.x / scale.get(), self.y / scale.get())
}
}
impl<T: Round, U> TypedPoint2D<T, U> {
/// Rounds each component to the nearest integer value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
/// For example `{ -0.1, -0.8 }.round() == { 0.0, -1.0 }`.
+ #[inline]
+ #[must_use]
pub fn round(&self) -> Self {
- TypedPoint2D::new(self.x.round(), self.y.round())
+ point2(self.x.round(), self.y.round())
}
}
impl<T: Ceil, U> TypedPoint2D<T, U> {
/// Rounds each component to the smallest integer equal or greater than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
/// For example `{ -0.1, -0.8 }.ceil() == { 0.0, 0.0 }`.
+ #[inline]
+ #[must_use]
pub fn ceil(&self) -> Self {
- TypedPoint2D::new(self.x.ceil(), self.y.ceil())
+ point2(self.x.ceil(), self.y.ceil())
}
}
impl<T: Floor, U> TypedPoint2D<T, U> {
/// Rounds each component to the biggest integer equal or lower than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
/// For example `{ -0.1, -0.8 }.floor() == { -1.0, -1.0 }`.
+ #[inline]
+ #[must_use]
pub fn floor(&self) -> Self {
- TypedPoint2D::new(self.x.floor(), self.y.floor())
+ point2(self.x.floor(), self.y.floor())
}
}
impl<T: NumCast + Copy, U> TypedPoint2D<T, U> {
/// Cast from one numeric representation to another, preserving the units.
///
/// When casting from floating point to integer coordinates, the decimals are truncated
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
+ #[inline]
pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedPoint2D<NewT, U>> {
match (NumCast::from(self.x), NumCast::from(self.y)) {
- (Some(x), Some(y)) => Some(TypedPoint2D::new(x, y)),
+ (Some(x), Some(y)) => Some(point2(x, y)),
_ => None
}
}
// Convenience functions for common casts
/// Cast into an `f32` point.
+ #[inline]
pub fn to_f32(&self) -> TypedPoint2D<f32, U> {
self.cast().unwrap()
}
/// Cast into an `usize` point, truncating decimals if any.
///
/// When casting from floating point points, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
+ #[inline]
pub fn to_usize(&self) -> TypedPoint2D<usize, U> {
self.cast().unwrap()
}
/// Cast into an i32 point, truncating decimals if any.
///
/// When casting from floating point points, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
+ #[inline]
pub fn to_i32(&self) -> TypedPoint2D<i32, U> {
self.cast().unwrap()
}
/// Cast into an i64 point, truncating decimals if any.
///
/// When casting from floating point points, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
+ #[inline]
pub fn to_i64(&self) -> TypedPoint2D<i64, U> {
self.cast().unwrap()
}
}
+impl<T, U> TypedPoint2D<T, U>
+where T: Copy + One + Add<Output=T> + Sub<Output=T> + Mul<Output=T> {
+ /// Linearly interpolate between this point and another point.
+ ///
+ /// `t` is expected to be between zero and one.
+ #[inline]
+ pub fn lerp(&self, other: Self, t: T) -> Self {
+ let one_t = T::one() - t;
+ point2(
+ one_t * self.x + t * other.x,
+ one_t * self.y + t * other.y,
+ )
+ }
+}
+
impl<T: Copy+ApproxEq<T>, U> ApproxEq<TypedPoint2D<T, U>> for TypedPoint2D<T, U> {
#[inline]
fn approx_epsilon() -> Self {
- TypedPoint2D::new(T::approx_epsilon(), T::approx_epsilon())
+ point2(T::approx_epsilon(), T::approx_epsilon())
}
#[inline]
fn approx_eq(&self, other: &Self) -> bool {
self.x.approx_eq(&other.x) && self.y.approx_eq(&other.y)
}
#[inline]
fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {
self.x.approx_eq_eps(&other.x, &eps.x) && self.y.approx_eq_eps(&other.y, &eps.y)
}
}
+impl<T: Copy, U> Into<[T; 2]> for TypedPoint2D<T, U> {
+ fn into(self) -> [T; 2] {
+ self.to_array()
+ }
+}
+
+impl<T: Copy, U> From<[T; 2]> for TypedPoint2D<T, U> {
+ fn from(array: [T; 2]) -> Self {
+ point2(array[0], array[1])
+ }
+}
+
+
define_matrix! {
/// A 3d Point tagged with a unit.
- #[derive(RustcDecodable, RustcEncodable)]
pub struct TypedPoint3D<T, U> {
pub x: T,
pub y: T,
pub z: T,
}
}
/// Default 3d point type with no unit.
///
/// `Point3D` provides the same methods as `TypedPoint3D`.
pub type Point3D<T> = TypedPoint3D<T, UnknownUnit>;
impl<T: Copy + Zero, U> TypedPoint3D<T, U> {
/// Constructor, setting all copmonents to zero.
#[inline]
- pub fn zero() -> TypedPoint3D<T, U> {
- TypedPoint3D::new(Zero::zero(), Zero::zero(), Zero::zero())
+ pub fn origin() -> Self {
+ point3(Zero::zero(), Zero::zero(), Zero::zero())
+ }
+}
+
+impl<T: Copy + One, U> TypedPoint3D<T, U> {
+ #[inline]
+ pub fn to_array_4d(&self) -> [T; 4] {
+ [self.x, self.y, self.z, One::one()]
+ }
+}
+
+impl<T, U> TypedPoint3D<T, U>
+where T: Copy + One + Add<Output=T> + Sub<Output=T> + Mul<Output=T> {
+ /// Linearly interpolate between this point and another point.
+ ///
+ /// `t` is expected to be between zero and one.
+ #[inline]
+ pub fn lerp(&self, other: Self, t: T) -> Self {
+ let one_t = T::one() - t;
+ point3(
+ one_t * self.x + t * other.x,
+ one_t * self.y + t * other.y,
+ one_t * self.z + t * other.z,
+ )
}
}
impl<T: fmt::Debug, U> fmt::Debug for TypedPoint3D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:?},{:?},{:?})", self.x, self.y, self.z)
}
}
@@ -327,24 +416,32 @@ impl<T: fmt::Display, U> fmt::Display fo
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({},{},{})", self.x, self.y, self.z)
}
}
impl<T: Copy, U> TypedPoint3D<T, U> {
/// Constructor taking scalar values directly.
#[inline]
- pub fn new(x: T, y: T, z: T) -> TypedPoint3D<T, U> {
+ pub fn new(x: T, y: T, z: T) -> Self {
TypedPoint3D { x: x, y: y, z: z, _unit: PhantomData }
}
/// Constructor taking properly typed Lengths instead of scalar values.
#[inline]
- pub fn from_lengths(x: Length<T, U>, y: Length<T, U>, z: Length<T, U>) -> TypedPoint3D<T, U> {
- TypedPoint3D::new(x.0, y.0, z.0)
+ pub fn from_lengths(x: Length<T, U>, y: Length<T, U>, z: Length<T, U>) -> Self {
+ point3(x.0, y.0, z.0)
+ }
+
+ /// Cast this point into a vector.
+ ///
+ /// Equivalent to substracting the origin to this point.
+ #[inline]
+ pub fn to_vector(&self) -> TypedVector3D<T, U> {
+ vec3(self.x, self.y, self.z)
}
/// Returns self.x as a Length carrying the unit.
#[inline]
pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
/// Returns self.y as a Length carrying the unit.
#[inline]
@@ -355,200 +452,190 @@ impl<T: Copy, U> TypedPoint3D<T, U> {
pub fn z_typed(&self) -> Length<T, U> { Length::new(self.z) }
#[inline]
pub fn to_array(&self) -> [T; 3] { [self.x, self.y, self.z] }
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> Point3D<T> {
- TypedPoint3D::new(self.x, self.y, self.z)
+ point3(self.x, self.y, self.z)
}
/// Tag a unitless value with units.
#[inline]
- pub fn from_untyped(p: &Point3D<T>) -> TypedPoint3D<T, U> {
- TypedPoint3D::new(p.x, p.y, p.z)
+ pub fn from_untyped(p: &Point3D<T>) -> Self {
+ point3(p.x, p.y, p.z)
}
/// Convert into a 2d point.
#[inline]
pub fn to_2d(&self) -> TypedPoint2D<T, U> {
- TypedPoint2D::new(self.x, self.y)
+ point2(self.x, self.y)
+ }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> AddAssign<TypedVector3D<T, U>> for TypedPoint3D<T, U> {
+ #[inline]
+ fn add_assign(&mut self, other: TypedVector3D<T, U>) {
+ *self = *self + other
}
}
-impl<T: Mul<T, Output=T> +
- Add<T, Output=T> +
- Sub<T, Output=T> +
- Copy, U> TypedPoint3D<T, U> {
-
- // Dot product.
- #[inline]
- pub fn dot(self, other: TypedPoint3D<T, U>) -> T {
- self.x * other.x +
- self.y * other.y +
- self.z * other.z
- }
-
- // Cross product.
+impl<T: Copy + Sub<T, Output=T>, U> SubAssign<TypedVector3D<T, U>> for TypedPoint3D<T, U> {
#[inline]
- pub fn cross(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
- TypedPoint3D::new(self.y * other.z - self.z * other.y,
- self.z * other.x - self.x * other.z,
- self.x * other.y - self.y * other.x)
- }
-
- #[inline]
- pub fn normalize(self) -> Self where T: Float + ApproxEq<T> {
- let dot = self.dot(self);
- if dot.approx_eq(&T::zero()) {
- self
- } else {
- self / dot.sqrt()
- }
+ fn sub_assign(&mut self, other: TypedVector3D<T, U>) {
+ *self = *self - other
}
}
-impl<T: Copy + Add<T, Output=T>, U> Add for TypedPoint3D<T, U> {
- type Output = TypedPoint3D<T, U>;
- fn add(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
- TypedPoint3D::new(self.x + other.x,
- self.y + other.y,
- self.z + other.z)
+impl<T: Copy + Add<T, Output=T>, U> Add<TypedVector3D<T, U>> for TypedPoint3D<T, U> {
+ type Output = Self;
+ #[inline]
+ fn add(self, other: TypedVector3D<T, U>) -> Self {
+ point3(self.x + other.x, self.y + other.y, self.z + other.z)
}
}
impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedPoint3D<T, U> {
- type Output = TypedPoint3D<T, U>;
- fn sub(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
- TypedPoint3D::new(self.x - other.x,
- self.y - other.y,
- self.z - other.z)
+ type Output = TypedVector3D<T, U>;
+ #[inline]
+ fn sub(self, other: Self) -> TypedVector3D<T, U> {
+ vec3(self.x - other.x, self.y - other.y, self.z - other.z)
}
}
-impl <T: Copy + Neg<Output=T>, U> Neg for TypedPoint3D<T, U> {
- type Output = TypedPoint3D<T, U>;
+impl<T: Copy + Sub<T, Output=T>, U> Sub<TypedVector3D<T, U>> for TypedPoint3D<T, U> {
+ type Output = Self;
#[inline]
- fn neg(self) -> TypedPoint3D<T, U> {
- TypedPoint3D::new(-self.x, -self.y, -self.z)
+ fn sub(self, other: TypedVector3D<T, U>) -> Self {
+ point3(self.x - other.x, self.y - other.y, self.z - other.z)
}
}
impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedPoint3D<T, U> {
type Output = Self;
#[inline]
fn mul(self, scale: T) -> Self {
- Self::new(self.x * scale, self.y * scale, self.z * scale)
+ point3(self.x * scale, self.y * scale, self.z * scale)
}
}
impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedPoint3D<T, U> {
type Output = Self;
#[inline]
fn div(self, scale: T) -> Self {
- Self::new(self.x / scale, self.y / scale, self.z / scale)
+ point3(self.x / scale, self.y / scale, self.z / scale)
}
}
impl<T: Float, U> TypedPoint3D<T, U> {
- pub fn min(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
- TypedPoint3D::new(self.x.min(other.x),
- self.y.min(other.y),
- self.z.min(other.z))
+ #[inline]
+ pub fn min(self, other: Self) -> Self {
+ point3(self.x.min(other.x), self.y.min(other.y), self.z.min(other.z))
}
- pub fn max(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
- TypedPoint3D::new(self.x.max(other.x), self.y.max(other.y),
- self.z.max(other.z))
+ #[inline]
+ pub fn max(self, other: Self) -> Self {
+ point3(self.x.max(other.x), self.y.max(other.y), self.z.max(other.z))
}
}
impl<T: Round, U> TypedPoint3D<T, U> {
/// Rounds each component to the nearest integer value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
+ #[inline]
+ #[must_use]
pub fn round(&self) -> Self {
- TypedPoint3D::new(self.x.round(), self.y.round(), self.z.round())
+ point3(self.x.round(), self.y.round(), self.z.round())
}
}
impl<T: Ceil, U> TypedPoint3D<T, U> {
/// Rounds each component to the smallest integer equal or greater than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
+ #[inline]
+ #[must_use]
pub fn ceil(&self) -> Self {
- TypedPoint3D::new(self.x.ceil(), self.y.ceil(), self.z.ceil())
+ point3(self.x.ceil(), self.y.ceil(), self.z.ceil())
}
}
impl<T: Floor, U> TypedPoint3D<T, U> {
/// Rounds each component to the biggest integer equal or lower than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
+ #[inline]
+ #[must_use]
pub fn floor(&self) -> Self {
- TypedPoint3D::new(self.x.floor(), self.y.floor(), self.z.floor())
+ point3(self.x.floor(), self.y.floor(), self.z.floor())
}
}
impl<T: NumCast + Copy, U> TypedPoint3D<T, U> {
/// Cast from one numeric representation to another, preserving the units.
///
/// When casting from floating point to integer coordinates, the decimals are truncated
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using round(), ceil or floor() before casting.
+ #[inline]
pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedPoint3D<NewT, U>> {
match (NumCast::from(self.x),
NumCast::from(self.y),
NumCast::from(self.z)) {
- (Some(x), Some(y), Some(z)) => Some(TypedPoint3D::new(x, y, z)),
+ (Some(x), Some(y), Some(z)) => Some(point3(x, y, z)),
_ => None
}
}
// Convenience functions for common casts
/// Cast into an `f32` point.
+ #[inline]
pub fn to_f32(&self) -> TypedPoint3D<f32, U> {
self.cast().unwrap()
}
/// Cast into an `usize` point, truncating decimals if any.
///
/// When casting from floating point points, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
+ #[inline]
pub fn to_usize(&self) -> TypedPoint3D<usize, U> {
self.cast().unwrap()
}
/// Cast into an `i32` point, truncating decimals if any.
///
/// When casting from floating point points, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
+ #[inline]
pub fn to_i32(&self) -> TypedPoint3D<i32, U> {
self.cast().unwrap()
}
/// Cast into an `i64` point, truncating decimals if any.
///
/// When casting from floating point points, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
+ #[inline]
pub fn to_i64(&self) -> TypedPoint3D<i64, U> {
self.cast().unwrap()
}
}
impl<T: Copy+ApproxEq<T>, U> ApproxEq<TypedPoint3D<T, U>> for TypedPoint3D<T, U> {
#[inline]
fn approx_epsilon() -> Self {
- TypedPoint3D::new(T::approx_epsilon(), T::approx_epsilon(), T::approx_epsilon())
+ point3(T::approx_epsilon(), T::approx_epsilon(), T::approx_epsilon())
}
#[inline]
fn approx_eq(&self, other: &Self) -> bool {
self.x.approx_eq(&other.x)
&& self.y.approx_eq(&other.y)
&& self.z.approx_eq(&other.z)
}
@@ -556,302 +643,51 @@ impl<T: Copy+ApproxEq<T>, U> ApproxEq<Ty
#[inline]
fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {
self.x.approx_eq_eps(&other.x, &eps.x)
&& self.y.approx_eq_eps(&other.y, &eps.y)
&& self.z.approx_eq_eps(&other.z, &eps.z)
}
}
-define_matrix! {
- /// A 4d Point tagged with a unit.
- #[derive(RustcDecodable, RustcEncodable)]
- pub struct TypedPoint4D<T, U> {
- pub x: T,
- pub y: T,
- pub z: T,
- pub w: T,
- }
-}
-
-/// Default 4d point with no unit.
-///
-/// `Point4D` provides the same methods as `TypedPoint4D`.
-pub type Point4D<T> = TypedPoint4D<T, UnknownUnit>;
-
-impl<T: Copy + Zero, U> TypedPoint4D<T, U> {
- /// Constructor, setting all copmonents to zero.
- #[inline]
- pub fn zero() -> TypedPoint4D<T, U> {
- TypedPoint4D::new(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero())
- }
-}
-
-impl<T: fmt::Debug, U> fmt::Debug for TypedPoint4D<T, U> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "({:?},{:?},{:?},{:?})", self.x, self.y, self.z, self.w)
- }
-}
-
-impl<T: fmt::Display, U> fmt::Display for TypedPoint4D<T, U> {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- write!(formatter, "({},{},{},{})", self.x, self.y, self.z, self.w)
- }
-}
-
-impl<T: Copy, U> TypedPoint4D<T, U> {
- /// Constructor taking scalar values directly.
- #[inline]
- pub fn new(x: T, y: T, z: T, w: T) -> TypedPoint4D<T, U> {
- TypedPoint4D { x: x, y: y, z: z, w: w, _unit: PhantomData }
- }
-
- /// Constructor taking properly typed Lengths instead of scalar values.
- #[inline]
- pub fn from_lengths(x: Length<T, U>,
- y: Length<T, U>,
- z: Length<T, U>,
- w: Length<T, U>) -> TypedPoint4D<T, U> {
- TypedPoint4D::new(x.0, y.0, z.0, w.0)
- }
-
- /// Returns self.x as a Length carrying the unit.
- #[inline]
- pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
-
- /// Returns self.y as a Length carrying the unit.
- #[inline]
- pub fn y_typed(&self) -> Length<T, U> { Length::new(self.y) }
-
- /// Returns self.z as a Length carrying the unit.
- #[inline]
- pub fn z_typed(&self) -> Length<T, U> { Length::new(self.z) }
-
- /// Returns self.w as a Length carrying the unit.
- #[inline]
- pub fn w_typed(&self) -> Length<T, U> { Length::new(self.w) }
-
- /// Drop the units, preserving only the numeric value.
- #[inline]
- pub fn to_untyped(&self) -> Point4D<T> {
- TypedPoint4D::new(self.x, self.y, self.z, self.w)
- }
-
- /// Tag a unitless value with units.
- #[inline]
- pub fn from_untyped(p: &Point4D<T>) -> TypedPoint4D<T, U> {
- TypedPoint4D::new(p.x, p.y, p.z, p.w)
- }
-
- #[inline]
- pub fn to_array(&self) -> [T; 4] {
- [self.x, self.y, self.z, self.w]
- }
-}
-
-impl<T: Copy + Div<T, Output=T>, U> TypedPoint4D<T, U> {
- /// Convert into a 2d point.
- #[inline]
- pub fn to_2d(self) -> TypedPoint2D<T, U> {
- TypedPoint2D::new(self.x / self.w, self.y / self.w)
- }
-
- /// Convert into a 3d point.
- #[inline]
- pub fn to_3d(self) -> TypedPoint3D<T, U> {
- TypedPoint3D::new(self.x / self.w, self.y / self.w, self.z / self.w)
- }
-}
-
-impl<T: Copy + Add<T, Output=T>, U> Add for TypedPoint4D<T, U> {
- type Output = TypedPoint4D<T, U>;
- fn add(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
- TypedPoint4D::new(self.x + other.x,
- self.y + other.y,
- self.z + other.z,
- self.w + other.w)
+impl<T: Copy, U> Into<[T; 3]> for TypedPoint3D<T, U> {
+ fn into(self) -> [T; 3] {
+ self.to_array()
}
}
-impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedPoint4D<T, U> {
- type Output = TypedPoint4D<T, U>;
- fn sub(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
- TypedPoint4D::new(self.x - other.x,
- self.y - other.y,
- self.z - other.z,
- self.w - other.w)
- }
-}
-
-impl <T: Copy + Neg<Output=T>, U> Neg for TypedPoint4D<T, U> {
- type Output = TypedPoint4D<T, U>;
- #[inline]
- fn neg(self) -> TypedPoint4D<T, U> {
- TypedPoint4D::new(-self.x, -self.y, -self.z, -self.w)
- }
-}
-
-impl<T: Float, U> TypedPoint4D<T, U> {
- pub fn min(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
- TypedPoint4D::new(self.x.min(other.x), self.y.min(other.y),
- self.z.min(other.z), self.w.min(other.w))
- }
-
- pub fn max(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
- TypedPoint4D::new(self.x.max(other.x), self.y.max(other.y),
- self.z.max(other.z), self.w.max(other.w))
- }
-}
-
-impl<T: Round, U> TypedPoint4D<T, U> {
- /// Rounds each component to the nearest integer value.
- ///
- /// This behavior is preserved for negative values (unlike the basic cast).
- pub fn round(&self) -> Self {
- TypedPoint4D::new(self.x.round(), self.y.round(), self.z.round(), self.w.round())
- }
-}
-
-impl<T: Ceil, U> TypedPoint4D<T, U> {
- /// Rounds each component to the smallest integer equal or greater than the original value.
- ///
- /// This behavior is preserved for negative values (unlike the basic cast).
- pub fn ceil(&self) -> Self {
- TypedPoint4D::new(self.x.ceil(), self.y.ceil(), self.z.ceil(), self.w.ceil())
- }
-}
-
-impl<T: Floor, U> TypedPoint4D<T, U> {
- /// Rounds each component to the biggest integer equal or lower than the original value.
- ///
- /// This behavior is preserved for negative values (unlike the basic cast).
- pub fn floor(&self) -> Self {
- TypedPoint4D::new(self.x.floor(), self.y.floor(), self.z.floor(), self.w.floor())
+impl<T: Copy, U> From<[T; 3]> for TypedPoint3D<T, U> {
+ fn from(array: [T; 3]) -> Self {
+ point3(array[0], array[1], array[2])
}
}
-impl<T: NumCast + Copy, U> TypedPoint4D<T, U> {
- /// Cast from one numeric representation to another, preserving the units.
- ///
- /// When casting from floating point to integer coordinates, the decimals are truncated
- /// as one would expect from a simple cast, but this behavior does not always make sense
- /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
- pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedPoint4D<NewT, U>> {
- match (NumCast::from(self.x),
- NumCast::from(self.y),
- NumCast::from(self.z),
- NumCast::from(self.w)) {
- (Some(x), Some(y), Some(z), Some(w)) => Some(TypedPoint4D::new(x, y, z, w)),
- _ => None
- }
- }
-
- // Convenience functions for common casts
-
- /// Cast into an `f32` point.
- pub fn to_f32(&self) -> TypedPoint4D<f32, U> {
- self.cast().unwrap()
- }
-
- /// Cast into an `usize` point, truncating decimals if any.
- ///
- /// When casting from floating point points, it is worth considering whether
- /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
- /// the desired conversion behavior.
- pub fn to_usize(&self) -> TypedPoint4D<usize, U> {
- self.cast().unwrap()
- }
-
- /// Cast into an `i32` point, truncating decimals if any.
- ///
- /// When casting from floating point points, it is worth considering whether
- /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
- /// the desired conversion behavior.
- pub fn to_i32(&self) -> TypedPoint4D<i32, U> {
- self.cast().unwrap()
- }
-
- /// Cast into an `i64` point, truncating decimals if any.
- ///
- /// When casting from floating point points, it is worth considering whether
- /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
- /// the desired conversion behavior.
- pub fn to_i64(&self) -> TypedPoint4D<i64, U> {
- self.cast().unwrap()
- }
-}
-
-impl<T: ApproxEq<T>, U> ApproxEq<T> for TypedPoint4D<T, U> {
- fn approx_epsilon() -> T {
- T::approx_epsilon()
- }
-
- fn approx_eq_eps(&self, other: &Self, approx_epsilon: &T) -> bool {
- self.x.approx_eq_eps(&other.x, approx_epsilon)
- && self.y.approx_eq_eps(&other.y, approx_epsilon)
- && self.z.approx_eq_eps(&other.z, approx_epsilon)
- && self.w.approx_eq_eps(&other.w, approx_epsilon)
- }
-
- fn approx_eq(&self, other: &Self) -> bool {
- self.approx_eq_eps(&other, &Self::approx_epsilon())
- }
-}
pub fn point2<T: Copy, U>(x: T, y: T) -> TypedPoint2D<T, U> {
TypedPoint2D::new(x, y)
}
pub fn point3<T: Copy, U>(x: T, y: T, z: T) -> TypedPoint3D<T, U> {
TypedPoint3D::new(x, y, z)
}
-pub fn point4<T: Copy, U>(x: T, y: T, z: T, w: T) -> TypedPoint4D<T, U> {
- TypedPoint4D::new(x, y, z, w)
-}
-
#[cfg(test)]
mod point2d {
use super::Point2D;
#[test]
pub fn test_scalar_mul() {
let p1: Point2D<f32> = Point2D::new(3.0, 5.0);
let result = p1 * 5.0;
assert_eq!(result, Point2D::new(15.0, 25.0));
}
#[test]
- pub fn test_dot() {
- let p1: Point2D<f32> = Point2D::new(2.0, 7.0);
- let p2: Point2D<f32> = Point2D::new(13.0, 11.0);
- assert_eq!(p1.dot(p2), 103.0);
- }
-
- #[test]
- pub fn test_cross() {
- let p1: Point2D<f32> = Point2D::new(4.0, 7.0);
- let p2: Point2D<f32> = Point2D::new(13.0, 8.0);
- let r = p1.cross(p2);
- assert_eq!(r, -59.0);
- }
-
- #[test]
- pub fn test_normalize() {
- let p0: Point2D<f32> = Point2D::zero();
- let p1: Point2D<f32> = Point2D::new(4.0, 0.0);
- let p2: Point2D<f32> = Point2D::new(3.0, -4.0);
- assert_eq!(p0.normalize(), p0);
- assert_eq!(p1.normalize(), Point2D::new(1.0, 0.0));
- assert_eq!(p2.normalize(), Point2D::new(0.6, -0.8));
- }
-
- #[test]
pub fn test_min() {
let p1 = Point2D::new(1.0, 3.0);
let p2 = Point2D::new(2.0, 2.0);
let result = p1.min(p2);
assert_eq!(result, Point2D::new(1.0, 2.0));
}
@@ -866,74 +702,71 @@ mod point2d {
assert_eq!(result, Point2D::new(2.0, 3.0));
}
}
#[cfg(test)]
mod typedpoint2d {
use super::TypedPoint2D;
use scale_factor::ScaleFactor;
+ use vector::vec2;
pub enum Mm {}
pub enum Cm {}
pub type Point2DMm<T> = TypedPoint2D<T, Mm>;
pub type Point2DCm<T> = TypedPoint2D<T, Cm>;
#[test]
pub fn test_add() {
let p1 = Point2DMm::new(1.0, 2.0);
- let p2 = Point2DMm::new(3.0, 4.0);
+ let p2 = vec2(3.0, 4.0);
let result = p1 + p2;
assert_eq!(result, Point2DMm::new(4.0, 6.0));
}
#[test]
+ pub fn test_add_assign() {
+ let mut p1 = Point2DMm::new(1.0, 2.0);
+ p1 += vec2(3.0, 4.0);
+
+ assert_eq!(p1, Point2DMm::new(4.0, 6.0));
+ }
+
+ #[test]
pub fn test_scalar_mul() {
let p1 = Point2DMm::new(1.0, 2.0);
let cm_per_mm: ScaleFactor<f32, Mm, Cm> = ScaleFactor::new(0.1);
let result = p1 * cm_per_mm;
assert_eq!(result, Point2DCm::new(0.1, 0.2));
}
+
+ #[test]
+ pub fn test_conv_vector() {
+ use {Point2D, point2};
+
+ for i in 0..100 {
+ // We don't care about these values as long as they are not the same.
+ let x = i as f32 *0.012345;
+ let y = i as f32 *0.987654;
+ let p: Point2D<f32> = point2(x, y);
+ assert_eq!(p.to_vector().to_point(), p);
+ }
+ }
}
#[cfg(test)]
mod point3d {
use super::Point3D;
#[test]
- pub fn test_dot() {
- let p1 = Point3D::new(7.0, 21.0, 32.0);
- let p2 = Point3D::new(43.0, 5.0, 16.0);
- assert_eq!(p1.dot(p2), 918.0);
- }
-
- #[test]
- pub fn test_cross() {
- let p1 = Point3D::new(4.0, 7.0, 9.0);
- let p2 = Point3D::new(13.0, 8.0, 3.0);
- let p3 = p1.cross(p2);
- assert_eq!(p3, Point3D::new(-51.0, 105.0, -59.0));
- }
-
- #[test]
- pub fn test_normalize() {
- let p0: Point3D<f32> = Point3D::zero();
- let p1: Point3D<f32> = Point3D::new(0.0, -6.0, 0.0);
- let p2: Point3D<f32> = Point3D::new(1.0, 2.0, -2.0);
- assert_eq!(p0.normalize(), p0);
- assert_eq!(p1.normalize(), Point3D::new(0.0, -1.0, 0.0));
- assert_eq!(p2.normalize(), Point3D::new(1.0/3.0, 2.0/3.0, -2.0/3.0));
- }
-
- #[test]
pub fn test_min() {
let p1 = Point3D::new(1.0, 3.0, 5.0);
let p2 = Point3D::new(2.0, 2.0, -1.0);
let result = p1.min(p2);
assert_eq!(result, Point3D::new(1.0, 2.0, -1.0));
}
@@ -942,54 +775,22 @@ mod point3d {
pub fn test_max() {
let p1 = Point3D::new(1.0, 3.0, 5.0);
let p2 = Point3D::new(2.0, 2.0, -1.0);
let result = p1.max(p2);
assert_eq!(result, Point3D::new(2.0, 3.0, 5.0));
}
-}
-
-#[cfg(test)]
-mod point4d {
- use super::Point4D;
-
- #[test]
- pub fn test_add() {
- let p1 = Point4D::new(7.0, 21.0, 32.0, 1.0);
- let p2 = Point4D::new(43.0, 5.0, 16.0, 2.0);
-
- let result = p1 + p2;
-
- assert_eq!(result, Point4D::new(50.0, 26.0, 48.0, 3.0));
- }
#[test]
- pub fn test_sub() {
- let p1 = Point4D::new(7.0, 21.0, 32.0, 1.0);
- let p2 = Point4D::new(43.0, 5.0, 16.0, 2.0);
-
- let result = p1 - p2;
-
- assert_eq!(result, Point4D::new(-36.0, 16.0, 16.0, -1.0));
- }
-
- #[test]
- pub fn test_min() {
- let p1 = Point4D::new(1.0, 3.0, 5.0, 7.0);
- let p2 = Point4D::new(2.0, 2.0, -1.0, 10.0);
-
- let result = p1.min(p2);
-
- assert_eq!(result, Point4D::new(1.0, 2.0, -1.0, 7.0));
- }
-
- #[test]
- pub fn test_max() {
- let p1 = Point4D::new(1.0, 3.0, 5.0, 7.0);
- let p2 = Point4D::new(2.0, 2.0, -1.0, 10.0);
-
- let result = p1.max(p2);
-
- assert_eq!(result, Point4D::new(2.0, 3.0, 5.0, 10.0));
+ pub fn test_conv_vector() {
+ use point3;
+ for i in 0..100 {
+ // We don't care about these values as long as they are not the same.
+ let x = i as f32 *0.012345;
+ let y = i as f32 *0.987654;
+ let z = x * y;
+ let p: Point3D<f32> = point3(x, y, z);
+ assert_eq!(p.to_vector().to_point(), p);
+ }
}
}
--- a/third_party/rust/euclid/src/rect.rs
+++ b/third_party/rust/euclid/src/rect.rs
@@ -7,27 +7,28 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::UnknownUnit;
use length::Length;
use scale_factor::ScaleFactor;
use num::*;
use point::TypedPoint2D;
+use vector::TypedVector2D;
use size::TypedSize2D;
use heapsize::HeapSizeOf;
use num_traits::NumCast;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cmp::PartialOrd;
use std::fmt;
+use std::hash::{Hash, Hasher};
use std::ops::{Add, Sub, Mul, Div};
/// A 2d Rectangle optionally tagged with a unit.
-#[derive(RustcDecodable, RustcEncodable)]
pub struct TypedRect<T, U = UnknownUnit> {
pub origin: TypedPoint2D<T, U>,
pub size: TypedSize2D<T, U>,
}
/// The default rectangle type with no unit.
pub type Rect<T> = TypedRect<T, UnknownUnit>;
@@ -49,24 +50,32 @@ impl<T: Copy + Deserialize, U> Deseriali
impl<T: Serialize, U> Serialize for TypedRect<T, U> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
(&self.origin, &self.size).serialize(serializer)
}
}
+impl<T: Hash, U> Hash for TypedRect<T, U>
+{
+ fn hash<H: Hasher>(&self, h: &mut H) {
+ self.origin.hash(h);
+ self.size.hash(h);
+ }
+}
+
impl<T: Copy, U> Copy for TypedRect<T, U> {}
impl<T: Copy, U> Clone for TypedRect<T, U> {
- fn clone(&self) -> TypedRect<T, U> { *self }
+ fn clone(&self) -> Self { *self }
}
impl<T: PartialEq, U> PartialEq<TypedRect<T, U>> for TypedRect<T, U> {
- fn eq(&self, other: &TypedRect<T, U>) -> bool {
+ fn eq(&self, other: &Self) -> bool {
self.origin.eq(&other.origin) && self.size.eq(&other.size)
}
}
impl<T: Eq, U> Eq for TypedRect<T, U> {}
impl<T: fmt::Debug, U> fmt::Debug for TypedRect<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -77,28 +86,28 @@ impl<T: fmt::Debug, U> fmt::Debug for Ty
impl<T: fmt::Display, U> fmt::Display for TypedRect<T, U> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "Rect({} at {})", self.size, self.origin)
}
}
impl<T, U> TypedRect<T, U> {
/// Constructor.
- pub fn new(origin: TypedPoint2D<T, U>, size: TypedSize2D<T, U>) -> TypedRect<T, U> {
+ pub fn new(origin: TypedPoint2D<T, U>, size: TypedSize2D<T, U>) -> Self {
TypedRect {
origin: origin,
size: size,
}
}
}
impl<T, U> TypedRect<T, U>
where T: Copy + Clone + Zero + PartialOrd + PartialEq + Add<T, Output=T> + Sub<T, Output=T> {
#[inline]
- pub fn intersects(&self, other: &TypedRect<T, U>) -> bool {
+ pub fn intersects(&self, other: &Self) -> bool {
self.origin.x < other.origin.x + other.size.width &&
other.origin.x < self.origin.x + self.size.width &&
self.origin.y < other.origin.y + other.size.height &&
other.origin.y < self.origin.y + self.size.height
}
#[inline]
pub fn max_x(&self) -> T {
@@ -136,68 +145,68 @@ where T: Copy + Clone + Zero + PartialOr
}
#[inline]
pub fn min_y_typed(&self) -> Length<T, U> {
Length::new(self.min_y())
}
#[inline]
- pub fn intersection(&self, other: &TypedRect<T, U>) -> Option<TypedRect<T, U>> {
+ pub fn intersection(&self, other: &Self) -> Option<Self> {
if !self.intersects(other) {
return None;
}
let upper_left = TypedPoint2D::new(max(self.min_x(), other.min_x()),
max(self.min_y(), other.min_y()));
let lower_right_x = min(self.max_x(), other.max_x());
let lower_right_y = min(self.max_y(), other.max_y());
Some(TypedRect::new(upper_left, TypedSize2D::new(lower_right_x - upper_left.x,
lower_right_y - upper_left.y)))
}
- /// Translates the rect by a vector.
+ /// Returns the same rectangle, translated by a vector.
#[inline]
- pub fn translate(&self, other: &TypedPoint2D<T, U>) -> TypedRect<T, U> {
- TypedRect::new(
- TypedPoint2D::new(self.origin.x + other.x, self.origin.y + other.y),
- self.size
- )
+ #[must_use]
+ pub fn translate(&self, by: &TypedVector2D<T, U>) -> Self {
+ Self::new(self.origin + *by, self.size)
}
/// Returns true if this rectangle contains the point. Points are considered
/// in the rectangle if they are on the left or top edge, but outside if they
/// are on the right or bottom edge.
#[inline]
pub fn contains(&self, other: &TypedPoint2D<T, U>) -> bool {
self.origin.x <= other.x && other.x < self.origin.x + self.size.width &&
self.origin.y <= other.y && other.y < self.origin.y + self.size.height
}
/// Returns true if this rectangle contains the interior of rect. Always
/// returns true if rect is empty, and always returns false if rect is
/// nonempty but this rectangle is empty.
#[inline]
- pub fn contains_rect(&self, rect: &TypedRect<T, U>) -> bool {
+ pub fn contains_rect(&self, rect: &Self) -> bool {
rect.is_empty() ||
(self.min_x() <= rect.min_x() && rect.max_x() <= self.max_x() &&
self.min_y() <= rect.min_y() && rect.max_y() <= self.max_y())
}
#[inline]
- pub fn inflate(&self, width: T, height: T) -> TypedRect<T, U> {
+ #[must_use]
+ pub fn inflate(&self, width: T, height: T) -> Self {
TypedRect::new(
TypedPoint2D::new(self.origin.x - width, self.origin.y - height),
TypedSize2D::new(self.size.width + width + width, self.size.height + height + height),
)
}
#[inline]
- pub fn inflate_typed(&self, width: Length<T, U>, height: Length<T, U>) -> TypedRect<T, U> {
+ #[must_use]
+ pub fn inflate_typed(&self, width: Length<T, U>, height: Length<T, U>) -> Self {
self.inflate(width.get(), height.get())
}
#[inline]
pub fn top_right(&self) -> TypedPoint2D<T, U> {
TypedPoint2D::new(self.max_x(), self.origin.y)
}
@@ -207,18 +216,19 @@ where T: Copy + Clone + Zero + PartialOr
}
#[inline]
pub fn bottom_right(&self) -> TypedPoint2D<T, U> {
TypedPoint2D::new(self.max_x(), self.max_y())
}
#[inline]
- pub fn translate_by_size(&self, size: &TypedSize2D<T, U>) -> TypedRect<T, U> {
- self.translate(&TypedPoint2D::new(size.width, size.height))
+ #[must_use]
+ pub fn translate_by_size(&self, size: &TypedSize2D<T, U>) -> Self {
+ self.translate(&size.to_vector())
}
/// Returns the smallest rectangle containing the four points.
pub fn from_points(points: &[TypedPoint2D<T, U>]) -> Self {
if points.len() == 0 {
return TypedRect::zero();
}
let (mut min_x, mut min_y) = (points[0].x, points[0].y);
@@ -238,19 +248,33 @@ where T: Copy + Clone + Zero + PartialOr
}
}
TypedRect::new(TypedPoint2D::new(min_x, min_y),
TypedSize2D::new(max_x - min_x, max_y - min_y))
}
}
impl<T, U> TypedRect<T, U>
+where T: Copy + One + Add<Output=T> + Sub<Output=T> + Mul<Output=T> {
+ /// Linearly interpolate between this rectangle and another rectange.
+ ///
+ /// `t` is expected to be between zero and one.
+ #[inline]
+ pub fn lerp(&self, other: Self, t: T) -> Self {
+ Self::new(
+ self.origin.lerp(other.origin, t),
+ self.size.lerp(other.size, t),
+ )
+ }
+}
+
+impl<T, U> TypedRect<T, U>
where T: Copy + Clone + PartialOrd + Add<T, Output=T> + Sub<T, Output=T> + Zero {
#[inline]
- pub fn union(&self, other: &TypedRect<T, U>) -> TypedRect<T, U> {
+ pub fn union(&self, other: &Self) -> Self {
if self.size == Zero::zero() {
return *other;
}
if other.size == Zero::zero() {
return *self;
}
let upper_left = TypedPoint2D::new(min(self.min_x(), other.min_x()),
@@ -263,30 +287,30 @@ where T: Copy + Clone + PartialOrd + Add
upper_left,
TypedSize2D::new(lower_right_x - upper_left.x, lower_right_y - upper_left.y)
)
}
}
impl<T, U> TypedRect<T, U> {
#[inline]
- pub fn scale<Scale: Copy>(&self, x: Scale, y: Scale) -> TypedRect<T, U>
+ pub fn scale<Scale: Copy>(&self, x: Scale, y: Scale) -> Self
where T: Copy + Clone + Mul<Scale, Output=T> {
TypedRect::new(
TypedPoint2D::new(self.origin.x * x, self.origin.y * y),
TypedSize2D::new(self.size.width * x, self.size.height * y)
)
}
}
impl<T: Copy + PartialEq + Zero, U> TypedRect<T, U> {
/// Constructor, setting all sides to zero.
- pub fn zero() -> TypedRect<T, U> {
+ pub fn zero() -> Self {
TypedRect::new(
- TypedPoint2D::zero(),
+ TypedPoint2D::origin(),
TypedSize2D::zero(),
)
}
/// Returns true if the size is zero, regardless of the origin's value.
pub fn is_empty(&self) -> bool {
self.size.width == Zero::zero() || self.size.height == Zero::zero()
}
@@ -297,27 +321,27 @@ pub fn min<T: Clone + PartialOrd>(x: T,
if x <= y { x } else { y }
}
pub fn max<T: Clone + PartialOrd>(x: T, y: T) -> T {
if x >= y { x } else { y }
}
impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedRect<T, U> {
- type Output = TypedRect<T, U>;
+ type Output = Self;
#[inline]
- fn mul(self, scale: T) -> TypedRect<T, U> {
+ fn mul(self, scale: T) -> Self {
TypedRect::new(self.origin * scale, self.size * scale)
}
}
impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedRect<T, U> {
- type Output = TypedRect<T, U>;
+ type Output = Self;
#[inline]
- fn div(self, scale: T) -> TypedRect<T, U> {
+ fn div(self, scale: T) -> Self {
TypedRect::new(self.origin / scale, self.size / scale)
}
}
impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedRect<T, U1> {
type Output = TypedRect<T, U2>;
#[inline]
fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedRect<T, U2> {
@@ -364,32 +388,35 @@ impl<T: Floor + Ceil + Round + Add<T, Ou
/// the returned rectangle has the same set of pixel centers as the original
/// one.
/// Edges at offset 0.5 round up.
/// Suitable for most places where integral device coordinates
/// are needed, but note that any translation should be applied first to
/// avoid pixel rounding errors.
/// Note that this is *not* rounding to nearest integer if the values are negative.
/// They are always rounding as floor(n + 0.5).
+ #[must_use]
pub fn round(&self) -> Self {
let origin = self.origin.round();
let size = self.origin.add_size(&self.size).round() - origin;
TypedRect::new(origin, TypedSize2D::new(size.x, size.y))
}
/// Return a rectangle with edges rounded to integer coordinates, such that
/// the original rectangle contains the resulting rectangle.
+ #[must_use]
pub fn round_in(&self) -> Self {
let origin = self.origin.ceil();
let size = self.origin.add_size(&self.size).floor() - origin;
TypedRect::new(origin, TypedSize2D::new(size.x, size.y))
}
/// Return a rectangle with edges rounded to integer coordinates, such that
/// the original rectangle is contained in the resulting rectangle.
+ #[must_use]
pub fn round_out(&self) -> Self {
let origin = self.origin.floor();
let size = self.origin.add_size(&self.size).ceil() - origin;
TypedRect::new(origin, TypedSize2D::new(size.x, size.y))
}
}
// Convenience functions for common casts
@@ -430,41 +457,42 @@ impl<T: NumCast + Copy, Unit> TypedRect<
/// Shorthand for `TypedRect::new(TypedPoint2D::new(x, y), TypedSize2D::new(w, h))`.
pub fn rect<T: Copy, U>(x: T, y: T, w: T, h: T) -> TypedRect<T, U> {
TypedRect::new(TypedPoint2D::new(x, y), TypedSize2D::new(w, h))
}
#[cfg(test)]
mod tests {
use point::Point2D;
+ use vector::vec2;
use size::Size2D;
use super::*;
#[test]
fn test_min_max() {
assert!(min(0u32, 1u32) == 0u32);
assert!(min(-1.0f32, 0.0f32) == -1.0f32);
assert!(max(0u32, 1u32) == 1u32);
assert!(max(-1.0f32, 0.0f32) == 0.0f32);
}
#[test]
fn test_translate() {
let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
- let pp = p.translate(&Point2D::new(10,15));
+ let pp = p.translate(&vec2(10,15));
assert!(pp.size.width == 50);
assert!(pp.size.height == 40);
assert!(pp.origin.x == 10);
assert!(pp.origin.y == 15);
let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
- let rr = r.translate(&Point2D::new(0,-10));
+ let rr = r.translate(&vec2(0,-10));
assert!(rr.size.width == 50);
assert!(rr.size.height == 40);
assert!(rr.origin.x == -10);
assert!(rr.origin.y == -15);
}
#[test]
@@ -557,20 +585,20 @@ mod tests {
assert!(!r.contains(&Point2D::new(75, 220)));
// Points beyond the bottom-left corner.
assert!(!r.contains(&Point2D::new(-25, 210)));
assert!(!r.contains(&Point2D::new(-15, 220)));
let r = Rect::new(Point2D::new(-20.0, 15.0), Size2D::new(100.0, 200.0));
assert!(r.contains_rect(&r));
- assert!(!r.contains_rect(&r.translate(&Point2D::new( 0.1, 0.0))));
- assert!(!r.contains_rect(&r.translate(&Point2D::new(-0.1, 0.0))));
- assert!(!r.contains_rect(&r.translate(&Point2D::new( 0.0, 0.1))));
- assert!(!r.contains_rect(&r.translate(&Point2D::new( 0.0, -0.1))));
+ assert!(!r.contains_rect(&r.translate(&vec2( 0.1, 0.0))));
+ assert!(!r.contains_rect(&r.translate(&vec2(-0.1, 0.0))));
+ assert!(!r.contains_rect(&r.translate(&vec2( 0.0, 0.1))));
+ assert!(!r.contains_rect(&r.translate(&vec2( 0.0, -0.1))));
// Empty rectangles are always considered as contained in other rectangles,
// even if their origin is not.
let p = Point2D::new(1.0, 1.0);
assert!(!r.contains(&p));
assert!(r.contains_rect(&Rect::new(p, Size2D::zero())));
}
#[test]
--- a/third_party/rust/euclid/src/scale_factor.rs
+++ b/third_party/rust/euclid/src/scale_factor.rs
@@ -21,28 +21,27 @@ use std::marker::PhantomData;
///
/// This is effectively a type-safe float, intended to be used in combination with other types like
/// `length::Length` to enforce conversion between systems of measurement at compile time.
///
/// `Src` and `Dst` represent the units before and after multiplying a value by a `ScaleFactor`. They
/// may be types without values, such as empty enums. For example:
///
/// ```rust
-/// use euclid::scale_factor::ScaleFactor;
-/// use euclid::length::Length;
+/// use euclid::ScaleFactor;
+/// use euclid::Length;
/// enum Mm {};
/// enum Inch {};
///
/// let mm_per_inch: ScaleFactor<f32, Inch, Mm> = ScaleFactor::new(25.4);
///
/// let one_foot: Length<f32, Inch> = Length::new(12.0);
/// let one_foot_in_mm: Length<f32, Mm> = one_foot * mm_per_inch;
/// ```
#[repr(C)]
-#[derive(RustcDecodable, RustcEncodable)]
pub struct ScaleFactor<T, Src, Dst>(pub T, PhantomData<(Src, Dst)>);
impl<T: HeapSizeOf, Src, Dst> HeapSizeOf for ScaleFactor<T, Src, Dst> {
fn heap_size_of_children(&self) -> usize {
self.0.heap_size_of_children()
}
}
--- a/third_party/rust/euclid/src/side_offsets.rs
+++ b/third_party/rust/euclid/src/side_offsets.rs
@@ -38,53 +38,53 @@ impl<T: fmt::Debug, U> fmt::Debug for Ty
}
}
/// The default side offset type with no unit.
pub type SideOffsets2D<T> = TypedSideOffsets2D<T, UnknownUnit>;
impl<T: Copy, U> TypedSideOffsets2D<T, U> {
/// Constructor taking a scalar for each side.
- pub fn new(top: T, right: T, bottom: T, left: T) -> TypedSideOffsets2D<T, U> {
+ pub fn new(top: T, right: T, bottom: T, left: T) -> Self {
TypedSideOffsets2D {
top: top,
right: right,
bottom: bottom,
left: left,
_unit: PhantomData,
}
}
/// Constructor taking a typed Length for each side.
pub fn from_lengths(top: Length<T, U>,
right: Length<T, U>,
bottom: Length<T, U>,
- left: Length<T, U>) -> TypedSideOffsets2D<T, U> {
+ left: Length<T, U>) -> Self {
TypedSideOffsets2D::new(top.0, right.0, bottom.0, left.0)
}
/// Access self.top as a typed Length instead of a scalar value.
pub fn top_typed(&self) -> Length<T, U> { Length::new(self.top) }
/// Access self.right as a typed Length instead of a scalar value.
pub fn right_typed(&self) -> Length<T, U> { Length::new(self.right) }
/// Access self.bottom as a typed Length instead of a scalar value.
pub fn bottom_typed(&self) -> Length<T, U> { Length::new(self.bottom) }
/// Access self.left as a typed Length instead of a scalar value.
pub fn left_typed(&self) -> Length<T, U> { Length::new(self.left) }
/// Constructor setting the same value to all sides, taking a scalar value directly.
- pub fn new_all_same(all: T) -> TypedSideOffsets2D<T, U> {
+ pub fn new_all_same(all: T) -> Self {
TypedSideOffsets2D::new(all, all, all, all)
}
/// Constructor setting the same value to all sides, taking a typed Length.
- pub fn from_length_all_same(all: Length<T, U>) -> TypedSideOffsets2D<T, U> {
+ pub fn from_length_all_same(all: Length<T, U>) -> Self {
TypedSideOffsets2D::new_all_same(all.0)
}
}
impl<T, U> TypedSideOffsets2D<T, U> where T: Add<T, Output=T> + Copy {
pub fn horizontal(&self) -> T {
self.left + self.right
}
@@ -98,30 +98,30 @@ impl<T, U> TypedSideOffsets2D<T, U> wher
}
pub fn vertical_typed(&self) -> Length<T, U> {
Length::new(self.vertical())
}
}
impl<T, U> Add for TypedSideOffsets2D<T, U> where T : Copy + Add<T, Output=T> {
- type Output = TypedSideOffsets2D<T, U>;
- fn add(self, other: TypedSideOffsets2D<T, U>) -> TypedSideOffsets2D<T, U> {
+ type Output = Self;
+ fn add(self, other: Self) -> Self {
TypedSideOffsets2D::new(
self.top + other.top,
self.right + other.right,
self.bottom + other.bottom,
self.left + other.left,
)
}
}
impl<T: Copy + Zero, U> TypedSideOffsets2D<T, U> {
/// Constructor, setting all sides to zero.
- pub fn zero() -> TypedSideOffsets2D<T, U> {
+ pub fn zero() -> Self {
TypedSideOffsets2D::new(
Zero::zero(),
Zero::zero(),
Zero::zero(),
Zero::zero(),
)
}
}
--- a/third_party/rust/euclid/src/size.rs
+++ b/third_party/rust/euclid/src/size.rs
@@ -5,26 +5,26 @@
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::UnknownUnit;
use length::Length;
use scale_factor::ScaleFactor;
+use vector::{TypedVector2D, vec2};
use num::*;
use num_traits::NumCast;
use std::fmt;
use std::ops::{Add, Div, Mul, Sub};
use std::marker::PhantomData;
/// A 2d size tagged with a unit.
define_matrix! {
- #[derive(RustcDecodable, RustcEncodable)]
pub struct TypedSize2D<T, U> {
pub width: T,
pub height: T,
}
}
/// Default 2d size type with no unit.
///
@@ -40,28 +40,28 @@ impl<T: fmt::Debug, U> fmt::Debug for Ty
impl<T: fmt::Display, U> fmt::Display for TypedSize2D<T, U> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "({}x{})", self.width, self.height)
}
}
impl<T, U> TypedSize2D<T, U> {
/// Constructor taking scalar values.
- pub fn new(width: T, height: T) -> TypedSize2D<T, U> {
+ pub fn new(width: T, height: T) -> Self {
TypedSize2D {
width: width,
height: height,
_unit: PhantomData,
}
}
}
impl<T: Clone, U> TypedSize2D<T, U> {
/// Constructor taking scalar strongly typed lengths.
- pub fn from_lengths(width: Length<T, U>, height: Length<T, U>) -> TypedSize2D<T, U> {
+ pub fn from_lengths(width: Length<T, U>, height: Length<T, U>) -> Self {
TypedSize2D::new(width.get(), height.get())
}
}
impl<T: Round, U> TypedSize2D<T, U> {
/// Rounds each component to the nearest integer value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
@@ -84,63 +84,78 @@ impl<T: Floor, U> TypedSize2D<T, U> {
///
/// This behavior is preserved for negative values (unlike the basic cast).
pub fn floor(&self) -> Self {
TypedSize2D::new(self.width.floor(), self.height.floor())
}
}
impl<T: Copy + Add<T, Output=T>, U> Add for TypedSize2D<T, U> {
- type Output = TypedSize2D<T, U>;
- fn add(self, other: TypedSize2D<T, U>) -> TypedSize2D<T, U> {
+ type Output = Self;
+ fn add(self, other: Self) -> Self {
TypedSize2D::new(self.width + other.width, self.height + other.height)
}
}
impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedSize2D<T, U> {
- type Output = TypedSize2D<T, U>;
- fn sub(self, other: TypedSize2D<T, U>) -> TypedSize2D<T, U> {
+ type Output = Self;
+ fn sub(self, other: Self) -> Self {
TypedSize2D::new(self.width - other.width, self.height - other.height)
}
}
impl<T: Copy + Clone + Mul<T, Output=U>, U> TypedSize2D<T, U> {
pub fn area(&self) -> U { self.width * self.height }
}
+impl<T, U> TypedSize2D<T, U>
+where T: Copy + One + Add<Output=T> + Sub<Output=T> + Mul<Output=T> {
+ /// Linearly interpolate between this size and another size.
+ ///
+ /// `t` is expected to be between zero and one.
+ #[inline]
+ pub fn lerp(&self, other: Self, t: T) -> Self {
+ let one_t = T::one() - t;
+ size2(
+ one_t * self.width + t * other.width,
+ one_t * self.height + t * other.height,
+ )
+ }
+}
+
impl<T: Zero, U> TypedSize2D<T, U> {
- pub fn zero() -> TypedSize2D<T, U> {
+ pub fn zero() -> Self {
TypedSize2D::new(
Zero::zero(),
Zero::zero(),
)
}
}
impl<T: Zero, U> Zero for TypedSize2D<T, U> {
- fn zero() -> TypedSize2D<T, U> {
+ fn zero() -> Self {
TypedSize2D::new(
Zero::zero(),
Zero::zero(),
)
}
}
impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedSize2D<T, U> {
- type Output = TypedSize2D<T, U>;
+ type Output = Self;
#[inline]
- fn mul(self, scale: T) -> TypedSize2D<T, U> {
+ fn mul(self, scale: T) -> Self {
TypedSize2D::new(self.width * scale, self.height * scale)
}
}
impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedSize2D<T, U> {
- type Output = TypedSize2D<T, U>;
+ type Output = Self;
#[inline]
- fn div(self, scale: T) -> TypedSize2D<T, U> {
+ fn div(self, scale: T) -> Self {
TypedSize2D::new(self.width / scale, self.height / scale)
}
}
impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedSize2D<T, U1> {
type Output = TypedSize2D<T, U2>;
#[inline]
fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedSize2D<T, U2> {
@@ -163,23 +178,26 @@ impl<T: Copy, U> TypedSize2D<T, U> {
/// Returns self.height as a Length carrying the unit.
#[inline]
pub fn height_typed(&self) -> Length<T, U> { Length::new(self.height) }
#[inline]
pub fn to_array(&self) -> [T; 2] { [self.width, self.height] }
+ #[inline]
+ pub fn to_vector(&self) -> TypedVector2D<T, U> { vec2(self.width, self.height) }
+
/// Drop the units, preserving only the numeric value.
pub fn to_untyped(&self) -> Size2D<T> {
TypedSize2D::new(self.width, self.height)
}
/// Tag a unitless value with units.
- pub fn from_untyped(p: &Size2D<T>) -> TypedSize2D<T, U> {
+ pub fn from_untyped(p: &Size2D<T>) -> Self {
TypedSize2D::new(p.width, p.height)
}
}
impl<T: NumCast + Copy, Unit> TypedSize2D<T, Unit> {
/// Cast from one numeric representation to another, preserving the units.
///
/// When casting from floating point to integer coordinates, the decimals are truncated
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid/src/transform2d.rs
@@ -0,0 +1,488 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::{UnknownUnit, Radians};
+use num::{One, Zero};
+use point::TypedPoint2D;
+use vector::{TypedVector2D, vec2};
+use rect::TypedRect;
+use std::ops::{Add, Mul, Div, Sub};
+use std::marker::PhantomData;
+use approxeq::ApproxEq;
+use trig::Trig;
+use std::fmt;
+
+define_matrix! {
+ /// A 2d transform stored as a 2 by 3 matrix in row-major order in memory.
+ ///
+ /// Transforms can be parametrized over the source and destination units, to describe a
+ /// transformation from a space to another.
+ /// For example, `TypedTransform2D<f32, WordSpace, ScreenSpace>::transform_point4d`
+ /// takes a `TypedPoint2D<f32, WordSpace>` and returns a `TypedPoint2D<f32, ScreenSpace>`.
+ ///
+ /// Transforms expose a set of convenience methods for pre- and post-transformations.
+ /// A pre-transformation corresponds to adding an operation that is applied before
+ /// the rest of the transformation, while a post-transformation adds an operation
+ /// that is applied after.
+ pub struct TypedTransform2D<T, Src, Dst> {
+ pub m11: T, pub m12: T,
+ pub m21: T, pub m22: T,
+ pub m31: T, pub m32: T,
+ }
+}
+
+/// The default 2d transform type with no units.
+pub type Transform2D<T> = TypedTransform2D<T, UnknownUnit, UnknownUnit>;
+
+impl<T: Copy, Src, Dst> TypedTransform2D<T, Src, Dst> {
+ /// Create a transform specifying its matrix elements in row-major order.
+ pub fn row_major(m11: T, m12: T, m21: T, m22: T, m31: T, m32: T) -> Self {
+ TypedTransform2D {
+ m11: m11, m12: m12,
+ m21: m21, m22: m22,
+ m31: m31, m32: m32,
+ _unit: PhantomData,
+ }
+ }
+
+ /// Create a transform specifying its matrix elements in column-major order.
+ pub fn column_major(m11: T, m21: T, m31: T, m12: T, m22: T, m32: T) -> Self {
+ TypedTransform2D {
+ m11: m11, m12: m12,
+ m21: m21, m22: m22,
+ m31: m31, m32: m32,
+ _unit: PhantomData,
+ }
+ }
+
+ /// Returns an array containing this transform's terms in row-major order (the order
+ /// in which the transform is actually laid out in memory).
+ pub fn to_row_major_array(&self) -> [T; 6] {
+ [
+ self.m11, self.m12,
+ self.m21, self.m22,
+ self.m31, self.m32
+ ]
+ }
+
+ /// Returns an array containing this transform's terms in column-major order.
+ pub fn to_column_major_array(&self) -> [T; 6] {
+ [
+ self.m11, self.m21, self.m31,
+ self.m12, self.m22, self.m32
+ ]
+ }
+
+ /// Returns an array containing this transform's 3 rows in (in row-major order)
+ /// as arrays.
+ ///
+ /// This is a convenience method to interface with other libraries like glium.
+ pub fn to_row_arrays(&self) -> [[T; 2]; 3] {
+ [
+ [self.m11, self.m12],
+ [self.m21, self.m22],
+ [self.m31, self.m32],
+ ]
+ }
+
+ /// Creates a transform from an array of 6 elements in row-major order.
+ pub fn from_row_major_array(array: [T; 6]) -> Self {
+ Self::row_major(
+ array[0], array[1],
+ array[2], array[3],
+ array[4], array[5],
+ )
+ }
+
+ /// Creates a transform from 3 rows of 2 elements (row-major order).
+ pub fn from_row_arrays(array: [[T; 2]; 3]) -> Self {
+ Self::row_major(
+ array[0][0], array[0][1],
+ array[1][0], array[1][1],
+ array[2][0], array[2][1],
+ )
+ }
+
+ /// Drop the units, preserving only the numeric value.
+ pub fn to_untyped(&self) -> Transform2D<T> {
+ Transform2D::row_major(
+ self.m11, self.m12,
+ self.m21, self.m22,
+ self.m31, self.m32
+ )
+ }
+
+ /// Tag a unitless value with units.
+ pub fn from_untyped(p: &Transform2D<T>) -> Self {
+ TypedTransform2D::row_major(
+ p.m11, p.m12,
+ p.m21, p.m22,
+ p.m31, p.m32
+ )
+ }
+}
+
+impl<T, Src, Dst> TypedTransform2D<T, Src, Dst>
+where T: Copy +
+ PartialEq +
+ One + Zero {
+ pub fn identity() -> Self {
+ let (_0, _1) = (Zero::zero(), One::one());
+ TypedTransform2D::row_major(
+ _1, _0,
+ _0, _1,
+ _0, _0
+ )
+ }
+
+ // Intentional not public, because it checks for exact equivalence
+ // while most consumers will probably want some sort of approximate
+ // equivalence to deal with floating-point errors.
+ fn is_identity(&self) -> bool {
+ *self == TypedTransform2D::identity()
+ }
+}
+
+impl<T, Src, Dst> TypedTransform2D<T, Src, Dst>
+where T: Copy + Clone +
+ Add<T, Output=T> +
+ Mul<T, Output=T> +
+ Div<T, Output=T> +
+ Sub<T, Output=T> +
+ Trig +
+ PartialOrd +
+ One + Zero {
+
+ /// Returns the multiplication of the two matrices such that mat's transformation
+ /// applies after self's transformation.
+ #[must_use]
+ pub fn post_mul<NewDst>(&self, mat: &TypedTransform2D<T, Dst, NewDst>) -> TypedTransform2D<T, Src, NewDst> {
+ TypedTransform2D::row_major(
+ self.m11 * mat.m11 + self.m12 * mat.m21,
+ self.m11 * mat.m12 + self.m12 * mat.m22,
+ self.m21 * mat.m11 + self.m22 * mat.m21,
+ self.m21 * mat.m12 + self.m22 * mat.m22,
+ self.m31 * mat.m11 + self.m32 * mat.m21 + mat.m31,
+ self.m31 * mat.m12 + self.m32 * mat.m22 + mat.m32,
+ )
+ }
+
+ /// Returns the multiplication of the two matrices such that mat's transformation
+ /// applies before self's transformation.
+ #[must_use]
+ pub fn pre_mul<NewSrc>(&self, mat: &TypedTransform2D<T, NewSrc, Src>) -> TypedTransform2D<T, NewSrc, Dst> {
+ mat.post_mul(self)
+ }
+
+ /// Returns a translation transform.
+ pub fn create_translation(x: T, y: T) -> Self {
+ let (_0, _1): (T, T) = (Zero::zero(), One::one());
+ TypedTransform2D::row_major(
+ _1, _0,
+ _0, _1,
+ x, y
+ )
+ }
+
+ /// Applies a translation after self's transformation and returns the resulting transform.
+ #[must_use]
+ pub fn post_translate(&self, v: TypedVector2D<T, Dst>) -> Self {
+ self.post_mul(&TypedTransform2D::create_translation(v.x, v.y))
+ }
+
+ /// Applies a translation before self's transformation and returns the resulting transform.
+ #[must_use]
+ pub fn pre_translate(&self, v: TypedVector2D<T, Src>) -> Self {
+ self.pre_mul(&TypedTransform2D::create_translation(v.x, v.y))
+ }
+
+ /// Returns a scale transform.
+ pub fn create_scale(x: T, y: T) -> Self {
+ let _0 = Zero::zero();
+ TypedTransform2D::row_major(
+ x, _0,
+ _0, y,
+ _0, _0
+ )
+ }
+
+ /// Applies a scale after self's transformation and returns the resulting transform.
+ #[must_use]
+ pub fn post_scale(&self, x: T, y: T) -> Self {
+ self.post_mul(&TypedTransform2D::create_scale(x, y))
+ }
+
+ /// Applies a scale before self's transformation and returns the resulting transform.
+ #[must_use]
+ pub fn pre_scale(&self, x: T, y: T) -> Self {
+ TypedTransform2D::row_major(
+ self.m11 * x, self.m12,
+ self.m21, self.m22 * y,
+ self.m31, self.m32
+ )
+ }
+
+ /// Returns a rotation transform.
+ pub fn create_rotation(theta: Radians<T>) -> Self {
+ let _0 = Zero::zero();
+ let cos = theta.get().cos();
+ let sin = theta.get().sin();
+ TypedTransform2D::row_major(
+ cos, _0 - sin,
+ sin, cos,
+ _0, _0
+ )
+ }
+
+ /// Applies a rotation after self's transformation and returns the resulting transform.
+ #[must_use]
+ pub fn post_rotate(&self, theta: Radians<T>) -> Self {
+ self.post_mul(&TypedTransform2D::create_rotation(theta))
+ }
+
+ /// Applies a rotation after self's transformation and returns the resulting transform.
+ #[must_use]
+ pub fn pre_rotate(&self, theta: Radians<T>) -> Self {
+ self.pre_mul(&TypedTransform2D::create_rotation(theta))
+ }
+
+ /// Returns the given point transformed by this transform.
+ #[inline]
+ #[must_use]
+ pub fn transform_point(&self, point: &TypedPoint2D<T, Src>) -> TypedPoint2D<T, Dst> {
+ TypedPoint2D::new(point.x * self.m11 + point.y * self.m21 + self.m31,
+ point.x * self.m12 + point.y * self.m22 + self.m32)
+ }
+
+ /// Returns the given vector transformed by this matrix.
+ #[inline]
+ #[must_use]
+ pub fn transform_vector(&self, vec: &TypedVector2D<T, Src>) -> TypedVector2D<T, Dst> {
+ vec2(vec.x * self.m11 + vec.y * self.m21,
+ vec.x * self.m12 + vec.y * self.m22)
+ }
+
+ /// Returns a rectangle that encompasses the result of transforming the given rectangle by this
+ /// transform.
+ #[inline]
+ #[must_use]
+ pub fn transform_rect(&self, rect: &TypedRect<T, Src>) -> TypedRect<T, Dst> {
+ TypedRect::from_points(&[
+ self.transform_point(&rect.origin),
+ self.transform_point(&rect.top_right()),
+ self.transform_point(&rect.bottom_left()),
+ self.transform_point(&rect.bottom_right()),
+ ])
+ }
+
+ /// Computes and returns the determinant of this transform.
+ pub fn determinant(&self) -> T {
+ self.m11 * self.m22 - self.m12 * self.m21
+ }
+
+ /// Returns the inverse transform if possible.
+ #[must_use]
+ pub fn inverse(&self) -> Option<TypedTransform2D<T, Dst, Src>> {
+ let det = self.determinant();
+
+ let _0: T = Zero::zero();
+ let _1: T = One::one();
+
+ if det == _0 {
+ return None;
+ }
+
+ let inv_det = _1 / det;
+ Some(TypedTransform2D::row_major(
+ inv_det * self.m22,
+ inv_det * (_0 - self.m12),
+ inv_det * (_0 - self.m21),
+ inv_det * self.m11,
+ inv_det * (self.m21 * self.m32 - self.m22 * self.m31),
+ inv_det * (self.m31 * self.m12 - self.m11 * self.m32),
+ ))
+ }
+
+ /// Returns the same transform with a different destination unit.
+ #[inline]
+ pub fn with_destination<NewDst>(&self) -> TypedTransform2D<T, Src, NewDst> {
+ TypedTransform2D::row_major(
+ self.m11, self.m12,
+ self.m21, self.m22,
+ self.m31, self.m32,
+ )
+ }
+
+ /// Returns the same transform with a different source unit.
+ #[inline]
+ pub fn with_source<NewSrc>(&self) -> TypedTransform2D<T, NewSrc, Dst> {
+ TypedTransform2D::row_major(
+ self.m11, self.m12,
+ self.m21, self.m22,
+ self.m31, self.m32,
+ )
+ }
+}
+
+impl<T: ApproxEq<T>, Src, Dst> TypedTransform2D<T, Src, Dst> {
+ pub fn approx_eq(&self, other: &Self) -> bool {
+ self.m11.approx_eq(&other.m11) && self.m12.approx_eq(&other.m12) &&
+ self.m21.approx_eq(&other.m21) && self.m22.approx_eq(&other.m22) &&
+ self.m31.approx_eq(&other.m31) && self.m32.approx_eq(&other.m32)
+ }
+}
+
+impl<T: Copy + fmt::Debug, Src, Dst> fmt::Debug for TypedTransform2D<T, Src, Dst>
+where T: Copy + fmt::Debug +
+ PartialEq +
+ One + Zero {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self.is_identity() {
+ write!(f, "[I]")
+ } else {
+ self.to_row_major_array().fmt(f)
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use approxeq::ApproxEq;
+ use point::Point2D;
+ use Radians;
+
+ use std::f32::consts::FRAC_PI_2;
+
+ type Mat = Transform2D<f32>;
+
+ fn rad(v: f32) -> Radians<f32> { Radians::new(v) }
+
+ #[test]
+ pub fn test_translation() {
+ let t1 = Mat::create_translation(1.0, 2.0);
+ let t2 = Mat::identity().pre_translate(vec2(1.0, 2.0));
+ let t3 = Mat::identity().post_translate(vec2(1.0, 2.0));
+ assert_eq!(t1, t2);
+ assert_eq!(t1, t3);
+
+ assert_eq!(t1.transform_point(&Point2D::new(1.0, 1.0)), Point2D::new(2.0, 3.0));
+
+ assert_eq!(t1.post_mul(&t1), Mat::create_translation(2.0, 4.0));
+ }
+
+ #[test]
+ pub fn test_rotation() {
+ let r1 = Mat::create_rotation(rad(FRAC_PI_2));
+ let r2 = Mat::identity().pre_rotate(rad(FRAC_PI_2));
+ let r3 = Mat::identity().post_rotate(rad(FRAC_PI_2));
+ assert_eq!(r1, r2);
+ assert_eq!(r1, r3);
+
+ assert!(r1.transform_point(&Point2D::new(1.0, 2.0)).approx_eq(&Point2D::new(2.0, -1.0)));
+
+ assert!(r1.post_mul(&r1).approx_eq(&Mat::create_rotation(rad(FRAC_PI_2*2.0))));
+ }
+
+ #[test]
+ pub fn test_scale() {
+ let s1 = Mat::create_scale(2.0, 3.0);
+ let s2 = Mat::identity().pre_scale(2.0, 3.0);
+ let s3 = Mat::identity().post_scale(2.0, 3.0);
+ assert_eq!(s1, s2);
+ assert_eq!(s1, s3);
+
+ assert!(s1.transform_point(&Point2D::new(2.0, 2.0)).approx_eq(&Point2D::new(4.0, 6.0)));
+ }
+
+ #[test]
+ fn test_column_major() {
+ assert_eq!(
+ Mat::row_major(
+ 1.0, 2.0,
+ 3.0, 4.0,
+ 5.0, 6.0
+ ),
+ Mat::column_major(
+ 1.0, 3.0, 5.0,
+ 2.0, 4.0, 6.0,
+ )
+ );
+ }
+
+ #[test]
+ pub fn test_inverse_simple() {
+ let m1 = Mat::identity();
+ let m2 = m1.inverse().unwrap();
+ assert!(m1.approx_eq(&m2));
+ }
+
+ #[test]
+ pub fn test_inverse_scale() {
+ let m1 = Mat::create_scale(1.5, 0.3);
+ let m2 = m1.inverse().unwrap();
+ assert!(m1.pre_mul(&m2).approx_eq(&Mat::identity()));
+ }
+
+ #[test]
+ pub fn test_inverse_translate() {
+ let m1 = Mat::create_translation(-132.0, 0.3);
+ let m2 = m1.inverse().unwrap();
+ assert!(m1.pre_mul(&m2).approx_eq(&Mat::identity()));
+ }
+
+ #[test]
+ fn test_inverse_none() {
+ assert!(Mat::create_scale(2.0, 0.0).inverse().is_none());
+ assert!(Mat::create_scale(2.0, 2.0).inverse().is_some());
+ }
+
+ #[test]
+ pub fn test_pre_post() {
+ let m1 = Transform2D::identity().post_scale(1.0, 2.0).post_translate(vec2(1.0, 2.0));
+ let m2 = Transform2D::identity().pre_translate(vec2(1.0, 2.0)).pre_scale(1.0, 2.0);
+ assert!(m1.approx_eq(&m2));
+
+ let r = Mat::create_rotation(rad(FRAC_PI_2));
+ let t = Mat::create_translation(2.0, 3.0);
+
+ let a = Point2D::new(1.0, 1.0);
+
+ assert!(r.post_mul(&t).transform_point(&a).approx_eq(&Point2D::new(3.0, 2.0)));
+ assert!(t.post_mul(&r).transform_point(&a).approx_eq(&Point2D::new(4.0, -3.0)));
+ assert!(t.post_mul(&r).transform_point(&a).approx_eq(&r.transform_point(&t.transform_point(&a))));
+
+ assert!(r.pre_mul(&t).transform_point(&a).approx_eq(&Point2D::new(4.0, -3.0)));
+ assert!(t.pre_mul(&r).transform_point(&a).approx_eq(&Point2D::new(3.0, 2.0)));
+ assert!(t.pre_mul(&r).transform_point(&a).approx_eq(&t.transform_point(&r.transform_point(&a))));
+ }
+
+ #[test]
+ fn test_size_of() {
+ use std::mem::size_of;
+ assert_eq!(size_of::<Transform2D<f32>>(), 6*size_of::<f32>());
+ assert_eq!(size_of::<Transform2D<f64>>(), 6*size_of::<f64>());
+ }
+
+ #[test]
+ pub fn test_is_identity() {
+ let m1 = Transform2D::identity();
+ assert!(m1.is_identity());
+ let m2 = m1.post_translate(vec2(0.1, 0.0));
+ assert!(!m2.is_identity());
+ }
+
+ #[test]
+ pub fn test_transform_vector() {
+ // Translation does not apply to vectors.
+ let m1 = Mat::create_translation(1.0, 1.0);
+ let v1 = vec2(10.0, -10.0);
+ assert_eq!(v1, m1.transform_vector(&v1));
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid/src/transform3d.rs
@@ -0,0 +1,888 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::{UnknownUnit, Radians};
+use approxeq::ApproxEq;
+use trig::Trig;
+use point::{TypedPoint2D, TypedPoint3D, point2, point3};
+use vector::{TypedVector2D, TypedVector3D, vec2, vec3};
+use rect::TypedRect;
+use transform2d::TypedTransform2D;
+use scale_factor::ScaleFactor;
+use num::{One, Zero};
+use std::ops::{Add, Mul, Sub, Div, Neg};
+use std::marker::PhantomData;
+use std::fmt;
+
+define_matrix! {
+ /// A 3d transform stored as a 4 by 4 matrix in row-major order in memory.
+ ///
+ /// Transforms can be parametrized over the source and destination units, to describe a
+ /// transformation from a space to another.
+ /// For example, `TypedTransform3D<f32, WordSpace, ScreenSpace>::transform_point3d`
+ /// takes a `TypedPoint3D<f32, WordSpace>` and returns a `TypedPoint3D<f32, ScreenSpace>`.
+ ///
+ /// Transforms expose a set of convenience methods for pre- and post-transformations.
+ /// A pre-transformation corresponds to adding an operation that is applied before
+ /// the rest of the transformation, while a post-transformation adds an operation
+ /// that is applied after.
+ pub struct TypedTransform3D<T, Src, Dst> {
+ pub m11: T, pub m12: T, pub m13: T, pub m14: T,
+ pub m21: T, pub m22: T, pub m23: T, pub m24: T,
+ pub m31: T, pub m32: T, pub m33: T, pub m34: T,
+ pub m41: T, pub m42: T, pub m43: T, pub m44: T,
+ }
+}
+
+/// The default 4d transform type with no units.
+pub type Transform3D<T> = TypedTransform3D<T, UnknownUnit, UnknownUnit>;
+
+impl<T, Src, Dst> TypedTransform3D<T, Src, Dst> {
+ /// Create a transform specifying its components in row-major order.
+ ///
+ /// For example, the translation terms m41, m42, m43 on the last row with the
+ /// row-major convention) are the 13rd, 14th and 15th parameters.
+ #[inline]
+ pub fn row_major(
+ m11: T, m12: T, m13: T, m14: T,
+ m21: T, m22: T, m23: T, m24: T,
+ m31: T, m32: T, m33: T, m34: T,
+ m41: T, m42: T, m43: T, m44: T)
+ -> Self {
+ TypedTransform3D {
+ m11: m11, m12: m12, m13: m13, m14: m14,
+ m21: m21, m22: m22, m23: m23, m24: m24,
+ m31: m31, m32: m32, m33: m33, m34: m34,
+ m41: m41, m42: m42, m43: m43, m44: m44,
+ _unit: PhantomData,
+ }
+ }
+
+ /// Create a transform specifying its components in column-major order.
+ ///
+ /// For example, the translation terms m41, m42, m43 on the last column with the
+ /// column-major convention) are the 4th, 8th and 12nd parameters.
+ #[inline]
+ pub fn column_major(
+ m11: T, m21: T, m31: T, m41: T,
+ m12: T, m22: T, m32: T, m42: T,
+ m13: T, m23: T, m33: T, m43: T,
+ m14: T, m24: T, m34: T, m44: T)
+ -> Self {
+ TypedTransform3D {
+ m11: m11, m12: m12, m13: m13, m14: m14,
+ m21: m21, m22: m22, m23: m23, m24: m24,
+ m31: m31, m32: m32, m33: m33, m34: m34,
+ m41: m41, m42: m42, m43: m43, m44: m44,
+ _unit: PhantomData,
+ }
+ }
+}
+
+impl <T, Src, Dst> TypedTransform3D<T, Src, Dst>
+where T: Copy + Clone +
+ PartialEq +
+ One + Zero {
+ #[inline]
+ pub fn identity() -> Self {
+ let (_0, _1): (T, T) = (Zero::zero(), One::one());
+ TypedTransform3D::row_major(
+ _1, _0, _0, _0,
+ _0, _1, _0, _0,
+ _0, _0, _1, _0,
+ _0, _0, _0, _1
+ )
+ }
+
+ // Intentional not public, because it checks for exact equivalence
+ // while most consumers will probably want some sort of approximate
+ // equivalence to deal with floating-point errors.
+ #[inline]
+ fn is_identity(&self) -> bool {
+ *self == TypedTransform3D::identity()
+ }
+}
+
+impl <T, Src, Dst> TypedTransform3D<T, Src, Dst>
+where T: Copy + Clone +
+ Add<T, Output=T> +
+ Sub<T, Output=T> +
+ Mul<T, Output=T> +
+ Div<T, Output=T> +
+ Neg<Output=T> +
+ ApproxEq<T> +
+ PartialOrd +
+ Trig +
+ One + Zero {
+
+ /// Create a 4 by 4 transform representing a 2d transformation, specifying its components
+ /// in row-major order.
+ #[inline]
+ pub fn row_major_2d(m11: T, m12: T, m21: T, m22: T, m41: T, m42: T) -> Self {
+ let (_0, _1): (T, T) = (Zero::zero(), One::one());
+ TypedTransform3D::row_major(
+ m11, m12, _0, _0,
+ m21, m22, _0, _0,
+ _0, _0, _1, _0,
+ m41, m42, _0, _1
+ )
+ }
+
+ /// Create an orthogonal projection transform.
+ pub fn ortho(left: T, right: T,
+ bottom: T, top: T,
+ near: T, far: T) -> Self {
+ let tx = -((right + left) / (right - left));
+ let ty = -((top + bottom) / (top - bottom));
+ let tz = -((far + near) / (far - near));
+
+ let (_0, _1): (T, T) = (Zero::zero(), One::one());
+ let _2 = _1 + _1;
+ TypedTransform3D::row_major(
+ _2 / (right - left), _0 , _0 , _0,
+ _0 , _2 / (top - bottom), _0 , _0,
+ _0 , _0 , -_2 / (far - near), _0,
+ tx , ty , tz , _1
+ )
+ }
+
+ /// Returns true if this transform can be represented with a TypedTransform2D.
+ ///
+ /// See https://drafts.csswg.org/css-transforms/#2d-transform
+ #[inline]
+ pub fn is_2d(&self) -> bool {
+ let (_0, _1): (T, T) = (Zero::zero(), One::one());
+ self.m31 == _0 && self.m32 == _0 &&
+ self.m13 == _0 && self.m23 == _0 &&
+ self.m43 == _0 && self.m14 == _0 &&
+ self.m24 == _0 && self.m34 == _0 &&
+ self.m33 == _1 && self.m44 == _1
+ }
+
+ /// Create a 2D transform picking the relevent terms from this transform.
+ ///
+ /// This method assumes that self represents a 2d transformation, callers
+ /// should check that self.is_2d() returns true beforehand.
+ pub fn to_2d(&self) -> TypedTransform2D<T, Src, Dst> {
+ TypedTransform2D::row_major(
+ self.m11, self.m12,
+ self.m21, self.m22,
+ self.m41, self.m42
+ )
+ }
+
+ pub fn approx_eq(&self, other: &Self) -> bool {
+ self.m11.approx_eq(&other.m11) && self.m12.approx_eq(&other.m12) &&
+ self.m13.approx_eq(&other.m13) && self.m14.approx_eq(&other.m14) &&
+ self.m21.approx_eq(&other.m21) && self.m22.approx_eq(&other.m22) &&
+ self.m23.approx_eq(&other.m23) && self.m24.approx_eq(&other.m24) &&
+ self.m31.approx_eq(&other.m31) && self.m32.approx_eq(&other.m32) &&
+ self.m33.approx_eq(&other.m33) && self.m34.approx_eq(&other.m34) &&
+ self.m41.approx_eq(&other.m41) && self.m42.approx_eq(&other.m42) &&
+ self.m43.approx_eq(&other.m43) && self.m44.approx_eq(&other.m44)
+ }
+
+ /// Returns the same transform with a different destination unit.
+ #[inline]
+ pub fn with_destination<NewDst>(&self) -> TypedTransform3D<T, Src, NewDst> {
+ TypedTransform3D::row_major(
+ self.m11, self.m12, self.m13, self.m14,
+ self.m21, self.m22, self.m23, self.m24,
+ self.m31, self.m32, self.m33, self.m34,
+ self.m41, self.m42, self.m43, self.m44,
+ )
+ }
+
+ /// Returns the same transform with a different source unit.
+ #[inline]
+ pub fn with_source<NewSrc>(&self) -> TypedTransform3D<T, NewSrc, Dst> {
+ TypedTransform3D::row_major(
+ self.m11, self.m12, self.m13, self.m14,
+ self.m21, self.m22, self.m23, self.m24,
+ self.m31, self.m32, self.m33, self.m34,
+ self.m41, self.m42, self.m43, self.m44,
+ )
+ }
+
+ /// Drop the units, preserving only the numeric value.
+ #[inline]
+ pub fn to_untyped(&self) -> Transform3D<T> {
+ Transform3D::row_major(
+ self.m11, self.m12, self.m13, self.m14,
+ self.m21, self.m22, self.m23, self.m24,
+ self.m31, self.m32, self.m33, self.m34,
+ self.m41, self.m42, self.m43, self.m44,
+ )
+ }
+
+ /// Tag a unitless value with units.
+ #[inline]
+ pub fn from_untyped(m: &Transform3D<T>) -> Self {
+ TypedTransform3D::row_major(
+ m.m11, m.m12, m.m13, m.m14,
+ m.m21, m.m22, m.m23, m.m24,
+ m.m31, m.m32, m.m33, m.m34,
+ m.m41, m.m42, m.m43, m.m44,
+ )
+ }
+
+ /// Returns the multiplication of the two matrices such that mat's transformation
+ /// applies after self's transformation.
+ pub fn post_mul<NewDst>(&self, mat: &TypedTransform3D<T, Dst, NewDst>) -> TypedTransform3D<T, Src, NewDst> {
+ TypedTransform3D::row_major(
+ self.m11 * mat.m11 + self.m12 * mat.m21 + self.m13 * mat.m31 + self.m14 * mat.m41,
+ self.m11 * mat.m12 + self.m12 * mat.m22 + self.m13 * mat.m32 + self.m14 * mat.m42,
+ self.m11 * mat.m13 + self.m12 * mat.m23 + self.m13 * mat.m33 + self.m14 * mat.m43,
+ self.m11 * mat.m14 + self.m12 * mat.m24 + self.m13 * mat.m34 + self.m14 * mat.m44,
+ self.m21 * mat.m11 + self.m22 * mat.m21 + self.m23 * mat.m31 + self.m24 * mat.m41,
+ self.m21 * mat.m12 + self.m22 * mat.m22 + self.m23 * mat.m32 + self.m24 * mat.m42,
+ self.m21 * mat.m13 + self.m22 * mat.m23 + self.m23 * mat.m33 + self.m24 * mat.m43,
+ self.m21 * mat.m14 + self.m22 * mat.m24 + self.m23 * mat.m34 + self.m24 * mat.m44,
+ self.m31 * mat.m11 + self.m32 * mat.m21 + self.m33 * mat.m31 + self.m34 * mat.m41,
+ self.m31 * mat.m12 + self.m32 * mat.m22 + self.m33 * mat.m32 + self.m34 * mat.m42,
+ self.m31 * mat.m13 + self.m32 * mat.m23 + self.m33 * mat.m33 + self.m34 * mat.m43,
+ self.m31 * mat.m14 + self.m32 * mat.m24 + self.m33 * mat.m34 + self.m34 * mat.m44,
+ self.m41 * mat.m11 + self.m42 * mat.m21 + self.m43 * mat.m31 + self.m44 * mat.m41,
+ self.m41 * mat.m12 + self.m42 * mat.m22 + self.m43 * mat.m32 + self.m44 * mat.m42,
+ self.m41 * mat.m13 + self.m42 * mat.m23 + self.m43 * mat.m33 + self.m44 * mat.m43,
+ self.m41 * mat.m14 + self.m42 * mat.m24 + self.m43 * mat.m34 + self.m44 * mat.m44,
+ )
+ }
+
+ /// Returns the multiplication of the two matrices such that mat's transformation
+ /// applies before self's transformation.
+ pub fn pre_mul<NewSrc>(&self, mat: &TypedTransform3D<T, NewSrc, Src>) -> TypedTransform3D<T, NewSrc, Dst> {
+ mat.post_mul(self)
+ }
+
+ /// Returns the inverse transform if possible.
+ pub fn inverse(&self) -> Option<TypedTransform3D<T, Dst, Src>> {
+ let det = self.determinant();
+
+ if det == Zero::zero() {
+ return None;
+ }
+
+ // todo(gw): this could be made faster by special casing
+ // for simpler transform types.
+ let m = TypedTransform3D::row_major(
+ self.m23*self.m34*self.m42 - self.m24*self.m33*self.m42 +
+ self.m24*self.m32*self.m43 - self.m22*self.m34*self.m43 -
+ self.m23*self.m32*self.m44 + self.m22*self.m33*self.m44,
+
+ self.m14*self.m33*self.m42 - self.m13*self.m34*self.m42 -
+ self.m14*self.m32*self.m43 + self.m12*self.m34*self.m43 +
+ self.m13*self.m32*self.m44 - self.m12*self.m33*self.m44,
+
+ self.m13*self.m24*self.m42 - self.m14*self.m23*self.m42 +
+ self.m14*self.m22*self.m43 - self.m12*self.m24*self.m43 -
+ self.m13*self.m22*self.m44 + self.m12*self.m23*self.m44,
+
+ self.m14*self.m23*self.m32 - self.m13*self.m24*self.m32 -
+ self.m14*self.m22*self.m33 + self.m12*self.m24*self.m33 +
+ self.m13*self.m22*self.m34 - self.m12*self.m23*self.m34,
+
+ self.m24*self.m33*self.m41 - self.m23*self.m34*self.m41 -
+ self.m24*self.m31*self.m43 + self.m21*self.m34*self.m43 +
+ self.m23*self.m31*self.m44 - self.m21*self.m33*self.m44,
+
+ self.m13*self.m34*self.m41 - self.m14*self.m33*self.m41 +
+ self.m14*self.m31*self.m43 - self.m11*self.m34*self.m43 -
+ self.m13*self.m31*self.m44 + self.m11*self.m33*self.m44,
+
+ self.m14*self.m23*self.m41 - self.m13*self.m24*self.m41 -
+ self.m14*self.m21*self.m43 + self.m11*self.m24*self.m43 +
+ self.m13*self.m21*self.m44 - self.m11*self.m23*self.m44,
+
+ self.m13*self.m24*self.m31 - self.m14*self.m23*self.m31 +
+ self.m14*self.m21*self.m33 - self.m11*self.m24*self.m33 -
+ self.m13*self.m21*self.m34 + self.m11*self.m23*self.m34,
+
+ self.m22*self.m34*self.m41 - self.m24*self.m32*self.m41 +
+ self.m24*self.m31*self.m42 - self.m21*self.m34*self.m42 -
+ self.m22*self.m31*self.m44 + self.m21*self.m32*self.m44,
+
+ self.m14*self.m32*self.m41 - self.m12*self.m34*self.m41 -
+ self.m14*self.m31*self.m42 + self.m11*self.m34*self.m42 +
+ self.m12*self.m31*self.m44 - self.m11*self.m32*self.m44,
+
+ self.m12*self.m24*self.m41 - self.m14*self.m22*self.m41 +
+ self.m14*self.m21*self.m42 - self.m11*self.m24*self.m42 -
+ self.m12*self.m21*self.m44 + self.m11*self.m22*self.m44,
+
+ self.m14*self.m22*self.m31 - self.m12*self.m24*self.m31 -
+ self.m14*self.m21*self.m32 + self.m11*self.m24*self.m32 +
+ self.m12*self.m21*self.m34 - self.m11*self.m22*self.m34,
+
+ self.m23*self.m32*self.m41 - self.m22*self.m33*self.m41 -
+ self.m23*self.m31*self.m42 + self.m21*self.m33*self.m42 +
+ self.m22*self.m31*self.m43 - self.m21*self.m32*self.m43,
+
+ self.m12*self.m33*self.m41 - self.m13*self.m32*self.m41 +
+ self.m13*self.m31*self.m42 - self.m11*self.m33*self.m42 -
+ self.m12*self.m31*self.m43 + self.m11*self.m32*self.m43,
+
+ self.m13*self.m22*self.m41 - self.m12*self.m23*self.m41 -
+ self.m13*self.m21*self.m42 + self.m11*self.m23*self.m42 +
+ self.m12*self.m21*self.m43 - self.m11*self.m22*self.m43,
+
+ self.m12*self.m23*self.m31 - self.m13*self.m22*self.m31 +
+ self.m13*self.m21*self.m32 - self.m11*self.m23*self.m32 -
+ self.m12*self.m21*self.m33 + self.m11*self.m22*self.m33
+ );
+
+ let _1: T = One::one();
+ Some(m.mul_s(_1 / det))
+ }
+
+ /// Compute the determinant of the transform.
+ pub fn determinant(&self) -> T {
+ self.m14 * self.m23 * self.m32 * self.m41 -
+ self.m13 * self.m24 * self.m32 * self.m41 -
+ self.m14 * self.m22 * self.m33 * self.m41 +
+ self.m12 * self.m24 * self.m33 * self.m41 +
+ self.m13 * self.m22 * self.m34 * self.m41 -
+ self.m12 * self.m23 * self.m34 * self.m41 -
+ self.m14 * self.m23 * self.m31 * self.m42 +
+ self.m13 * self.m24 * self.m31 * self.m42 +
+ self.m14 * self.m21 * self.m33 * self.m42 -
+ self.m11 * self.m24 * self.m33 * self.m42 -
+ self.m13 * self.m21 * self.m34 * self.m42 +
+ self.m11 * self.m23 * self.m34 * self.m42 +
+ self.m14 * self.m22 * self.m31 * self.m43 -
+ self.m12 * self.m24 * self.m31 * self.m43 -
+ self.m14 * self.m21 * self.m32 * self.m43 +
+ self.m11 * self.m24 * self.m32 * self.m43 +
+ self.m12 * self.m21 * self.m34 * self.m43 -
+ self.m11 * self.m22 * self.m34 * self.m43 -
+ self.m13 * self.m22 * self.m31 * self.m44 +
+ self.m12 * self.m23 * self.m31 * self.m44 +
+ self.m13 * self.m21 * self.m32 * self.m44 -
+ self.m11 * self.m23 * self.m32 * self.m44 -
+ self.m12 * self.m21 * self.m33 * self.m44 +
+ self.m11 * self.m22 * self.m33 * self.m44
+ }
+
+ /// Multiplies all of the transform's component by a scalar and returns the result.
+ #[must_use]
+ pub fn mul_s(&self, x: T) -> Self {
+ TypedTransform3D::row_major(
+ self.m11 * x, self.m12 * x, self.m13 * x, self.m14 * x,
+ self.m21 * x, self.m22 * x, self.m23 * x, self.m24 * x,
+ self.m31 * x, self.m32 * x, self.m33 * x, self.m34 * x,
+ self.m41 * x, self.m42 * x, self.m43 * x, self.m44 * x
+ )
+ }
+
+ /// Convenience function to create a scale transform from a ScaleFactor.
+ pub fn from_scale_factor(scale: ScaleFactor<T, Src, Dst>) -> Self {
+ TypedTransform3D::create_scale(scale.get(), scale.get(), scale.get())
+ }
+
+ /// Returns the given 2d point transformed by this transform.
+ ///
+ /// The input point must be use the unit Src, and the returned point has the unit Dst.
+ #[inline]
+ pub fn transform_point2d(&self, p: &TypedPoint2D<T, Src>) -> TypedPoint2D<T, Dst> {
+ let x = p.x * self.m11 + p.y * self.m21 + self.m41;
+ let y = p.x * self.m12 + p.y * self.m22 + self.m42;
+
+ let w = p.x * self.m14 + p.y * self.m24 + self.m44;
+
+ point2(x/w, y/w)
+ }
+
+ /// Returns the given 2d vector transformed by this matrix.
+ ///
+ /// The input point must be use the unit Src, and the returned point has the unit Dst.
+ #[inline]
+ pub fn transform_vector2d(&self, v: &TypedVector2D<T, Src>) -> TypedVector2D<T, Dst> {
+ vec2(
+ v.x * self.m11 + v.y * self.m21,
+ v.x * self.m12 + v.y * self.m22,
+ )
+ }
+
+ /// Returns the given 3d point transformed by this transform.
+ ///
+ /// The input point must be use the unit Src, and the returned point has the unit Dst.
+ #[inline]
+ pub fn transform_point3d(&self, p: &TypedPoint3D<T, Src>) -> TypedPoint3D<T, Dst> {
+ let x = p.x * self.m11 + p.y * self.m21 + p.z * self.m31 + self.m41;
+ let y = p.x * self.m12 + p.y * self.m22 + p.z * self.m32 + self.m42;
+ let z = p.x * self.m13 + p.y * self.m23 + p.z * self.m33 + self.m43;
+ let w = p.x * self.m14 + p.y * self.m24 + p.z * self.m34 + self.m44;
+
+ point3(x/w, y/w, z/w)
+ }
+
+ /// Returns the given 3d vector transformed by this matrix.
+ ///
+ /// The input point must be use the unit Src, and the returned point has the unit Dst.
+ #[inline]
+ pub fn transform_vector3d(&self, v: &TypedVector3D<T, Src>) -> TypedVector3D<T, Dst> {
+ vec3(
+ v.x * self.m11 + v.y * self.m21 + v.z * self.m31,
+ v.x * self.m12 + v.y * self.m22 + v.z * self.m32,
+ v.x * self.m13 + v.y * self.m23 + v.z * self.m33,
+ )
+ }
+
+ /// Returns a rectangle that encompasses the result of transforming the given rectangle by this
+ /// transform.
+ pub fn transform_rect(&self, rect: &TypedRect<T, Src>) -> TypedRect<T, Dst> {
+ TypedRect::from_points(&[
+ self.transform_point2d(&rect.origin),
+ self.transform_point2d(&rect.top_right()),
+ self.transform_point2d(&rect.bottom_left()),
+ self.transform_point2d(&rect.bottom_right()),
+ ])
+ }
+
+ /// Create a 3d translation transform
+ pub fn create_translation(x: T, y: T, z: T) -> Self {
+ let (_0, _1): (T, T) = (Zero::zero(), One::one());
+ TypedTransform3D::row_major(
+ _1, _0, _0, _0,
+ _0, _1, _0, _0,
+ _0, _0, _1, _0,
+ x, y, z, _1
+ )
+ }
+
+ /// Returns a transform with a translation applied before self's transformation.
+ #[must_use]
+ pub fn pre_translate(&self, v: TypedVector3D<T, Src>) -> Self {
+ self.pre_mul(&TypedTransform3D::create_translation(v.x, v.y, v.z))
+ }
+
+ /// Returns a transform with a translation applied after self's transformation.
+ #[must_use]
+ pub fn post_translate(&self, v: TypedVector3D<T, Dst>) -> Self {
+ self.post_mul(&TypedTransform3D::create_translation(v.x, v.y, v.z))
+ }
+
+ /// Create a 3d scale transform
+ pub fn create_scale(x: T, y: T, z: T) -> Self {
+ let (_0, _1): (T, T) = (Zero::zero(), One::one());
+ TypedTransform3D::row_major(
+ x, _0, _0, _0,
+ _0, y, _0, _0,
+ _0, _0, z, _0,
+ _0, _0, _0, _1
+ )
+ }
+
+ /// Returns a transform with a scale applied before self's transformation.
+ #[must_use]
+ pub fn pre_scale(&self, x: T, y: T, z: T) -> Self {
+ TypedTransform3D::row_major(
+ self.m11 * x, self.m12, self.m13, self.m14,
+ self.m21 , self.m22 * y, self.m23, self.m24,
+ self.m31 , self.m32, self.m33 * z, self.m34,
+ self.m41 , self.m42, self.m43, self.m44
+ )
+ }
+
+ /// Returns a transform with a scale applied after self's transformation.
+ #[must_use]
+ pub fn post_scale(&self, x: T, y: T, z: T) -> Self {
+ self.post_mul(&TypedTransform3D::create_scale(x, y, z))
+ }
+
+ /// Create a 3d rotation transform from an angle / axis.
+ /// The supplied axis must be normalized.
+ pub fn create_rotation(x: T, y: T, z: T, theta: Radians<T>) -> Self {
+ let (_0, _1): (T, T) = (Zero::zero(), One::one());
+ let _2 = _1 + _1;
+
+ let xx = x * x;
+ let yy = y * y;
+ let zz = z * z;
+
+ let half_theta = theta.get() / _2;
+ let sc = half_theta.sin() * half_theta.cos();
+ let sq = half_theta.sin() * half_theta.sin();
+
+ TypedTransform3D::row_major(
+ _1 - _2 * (yy + zz) * sq,
+ _2 * (x * y * sq - z * sc),
+ _2 * (x * z * sq + y * sc),
+ _0,
+
+ _2 * (x * y * sq + z * sc),
+ _1 - _2 * (xx + zz) * sq,
+ _2 * (y * z * sq - x * sc),
+ _0,
+
+ _2 * (x * z * sq - y * sc),
+ _2 * (y * z * sq + x * sc),
+ _1 - _2 * (xx + yy) * sq,
+ _0,
+
+ _0,
+ _0,
+ _0,
+ _1
+ )
+ }
+
+ /// Returns a transform with a rotation applied after self's transformation.
+ #[must_use]
+ pub fn post_rotate(&self, x: T, y: T, z: T, theta: Radians<T>) -> Self {
+ self.post_mul(&TypedTransform3D::create_rotation(x, y, z, theta))
+ }
+
+ /// Returns a transform with a rotation applied before self's transformation.
+ #[must_use]
+ pub fn pre_rotate(&self, x: T, y: T, z: T, theta: Radians<T>) -> Self {
+ self.pre_mul(&TypedTransform3D::create_rotation(x, y, z, theta))
+ }
+
+ /// Create a 2d skew transform.
+ ///
+ /// See https://drafts.csswg.org/css-transforms/#funcdef-skew
+ pub fn create_skew(alpha: Radians<T>, beta: Radians<T>) -> Self {
+ let (_0, _1): (T, T) = (Zero::zero(), One::one());
+ let (sx, sy) = (beta.get().tan(), alpha.get().tan());
+ TypedTransform3D::row_major(
+ _1, sx, _0, _0,
+ sy, _1, _0, _0,
+ _0, _0, _1, _0,
+ _0, _0, _0, _1
+ )
+ }
+
+ /// Create a simple perspective projection transform
+ pub fn create_perspective(d: T) -> Self {
+ let (_0, _1): (T, T) = (Zero::zero(), One::one());
+ TypedTransform3D::row_major(
+ _1, _0, _0, _0,
+ _0, _1, _0, _0,
+ _0, _0, _1, -_1 / d,
+ _0, _0, _0, _1
+ )
+ }
+}
+
+impl<T: Copy, Src, Dst> TypedTransform3D<T, Src, Dst> {
+ /// Returns an array containing this transform's terms in row-major order (the order
+ /// in which the transform is actually laid out in memory).
+ pub fn to_row_major_array(&self) -> [T; 16] {
+ [
+ self.m11, self.m12, self.m13, self.m14,
+ self.m21, self.m22, self.m23, self.m24,
+ self.m31, self.m32, self.m33, self.m34,
+ self.m41, self.m42, self.m43, self.m44
+ ]
+ }
+
+ /// Returns an array containing this transform's terms in column-major order.
+ pub fn to_column_major_array(&self) -> [T; 16] {
+ [
+ self.m11, self.m21, self.m31, self.m41,
+ self.m12, self.m22, self.m32, self.m42,
+ self.m13, self.m23, self.m33, self.m43,
+ self.m14, self.m24, self.m34, self.m44
+ ]
+ }
+
+ /// Returns an array containing this transform's 4 rows in (in row-major order)
+ /// as arrays.
+ ///
+ /// This is a convenience method to interface with other libraries like glium.
+ pub fn to_row_arrays(&self) -> [[T; 4]; 4] {
+ [
+ [self.m11, self.m12, self.m13, self.m14],
+ [self.m21, self.m22, self.m23, self.m24],
+ [self.m31, self.m32, self.m33, self.m34],
+ [self.m41, self.m42, self.m43, self.m44]
+ ]
+ }
+
+ /// Returns an array containing this transform's 4 columns in (in row-major order,
+ /// or 4 rows in column-major order) as arrays.
+ ///
+ /// This is a convenience method to interface with other libraries like glium.
+ pub fn to_column_arrays(&self) -> [[T; 4]; 4] {
+ [
+ [self.m11, self.m21, self.m31, self.m41],
+ [self.m12, self.m22, self.m32, self.m42],
+ [self.m13, self.m23, self.m33, self.m43],
+ [self.m14, self.m24, self.m34, self.m44]
+ ]
+ }
+
+ /// Creates a transform from an array of 16 elements in row-major order.
+ pub fn from_array(array: [T; 16]) -> Self {
+ Self::row_major(
+ array[0], array[1], array[2], array[3],
+ array[4], array[5], array[6], array[7],
+ array[8], array[9], array[10], array[11],
+ array[12], array[13], array[14], array[15],
+ )
+ }
+
+ /// Creates a transform from 4 rows of 4 elements (row-major order).
+ pub fn from_row_arrays(array: [[T; 4]; 4]) -> Self {
+ Self::row_major(
+ array[0][0], array[0][1], array[0][2], array[0][3],
+ array[1][0], array[1][1], array[1][2], array[1][3],
+ array[2][0], array[2][1], array[2][2], array[2][3],
+ array[3][0], array[3][1], array[3][2], array[3][3],
+ )
+ }
+}
+
+impl<T, Src, Dst> fmt::Debug for TypedTransform3D<T, Src, Dst>
+where T: Copy + fmt::Debug +
+ PartialEq +
+ One + Zero {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self.is_identity() {
+ write!(f, "[I]")
+ } else {
+ self.to_row_major_array().fmt(f)
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use approxeq::ApproxEq;
+ use transform2d::Transform2D;
+ use point::{Point2D, Point3D};
+ use Radians;
+ use super::*;
+
+ use std::f32::consts::FRAC_PI_2;
+
+ type Mf32 = Transform3D<f32>;
+
+ // For convenience.
+ fn rad(v: f32) -> Radians<f32> { Radians::new(v) }
+
+ #[test]
+ pub fn test_translation() {
+ let t1 = Mf32::create_translation(1.0, 2.0, 3.0);
+ let t2 = Mf32::identity().pre_translate(vec3(1.0, 2.0, 3.0));
+ let t3 = Mf32::identity().post_translate(vec3(1.0, 2.0, 3.0));
+ assert_eq!(t1, t2);
+ assert_eq!(t1, t3);
+
+ assert_eq!(t1.transform_point3d(&Point3D::new(1.0, 1.0, 1.0)), Point3D::new(2.0, 3.0, 4.0));
+ assert_eq!(t1.transform_point2d(&Point2D::new(1.0, 1.0)), Point2D::new(2.0, 3.0));
+
+ assert_eq!(t1.post_mul(&t1), Mf32::create_translation(2.0, 4.0, 6.0));
+
+ assert!(!t1.is_2d());
+ assert_eq!(Mf32::create_translation(1.0, 2.0, 3.0).to_2d(), Transform2D::create_translation(1.0, 2.0));
+ }
+
+ #[test]
+ pub fn test_rotation() {
+ let r1 = Mf32::create_rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2));
+ let r2 = Mf32::identity().pre_rotate(0.0, 0.0, 1.0, rad(FRAC_PI_2));
+ let r3 = Mf32::identity().post_rotate(0.0, 0.0, 1.0, rad(FRAC_PI_2));
+ assert_eq!(r1, r2);
+ assert_eq!(r1, r3);
+
+ assert!(r1.transform_point3d(&Point3D::new(1.0, 2.0, 3.0)).approx_eq(&Point3D::new(2.0, -1.0, 3.0)));
+ assert!(r1.transform_point2d(&Point2D::new(1.0, 2.0)).approx_eq(&Point2D::new(2.0, -1.0)));
+
+ assert!(r1.post_mul(&r1).approx_eq(&Mf32::create_rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2*2.0))));
+
+ assert!(r1.is_2d());
+ assert!(r1.to_2d().approx_eq(&Transform2D::create_rotation(rad(FRAC_PI_2))));
+ }
+
+ #[test]
+ pub fn test_scale() {
+ let s1 = Mf32::create_scale(2.0, 3.0, 4.0);
+ let s2 = Mf32::identity().pre_scale(2.0, 3.0, 4.0);
+ let s3 = Mf32::identity().post_scale(2.0, 3.0, 4.0);
+ assert_eq!(s1, s2);
+ assert_eq!(s1, s3);
+
+ assert!(s1.transform_point3d(&Point3D::new(2.0, 2.0, 2.0)).approx_eq(&Point3D::new(4.0, 6.0, 8.0)));
+ assert!(s1.transform_point2d(&Point2D::new(2.0, 2.0)).approx_eq(&Point2D::new(4.0, 6.0)));
+
+ assert_eq!(s1.post_mul(&s1), Mf32::create_scale(4.0, 9.0, 16.0));
+
+ assert!(!s1.is_2d());
+ assert_eq!(Mf32::create_scale(2.0, 3.0, 0.0).to_2d(), Transform2D::create_scale(2.0, 3.0));
+ }
+
+ #[test]
+ pub fn test_ortho() {
+ let (left, right, bottom, top) = (0.0f32, 1.0f32, 0.1f32, 1.0f32);
+ let (near, far) = (-1.0f32, 1.0f32);
+ let result = Mf32::ortho(left, right, bottom, top, near, far);
+ let expected = Mf32::row_major(
+ 2.0, 0.0, 0.0, 0.0,
+ 0.0, 2.22222222, 0.0, 0.0,
+ 0.0, 0.0, -1.0, 0.0,
+ -1.0, -1.22222222, -0.0, 1.0
+ );
+ debug!("result={:?} expected={:?}", result, expected);
+ assert!(result.approx_eq(&expected));
+ }
+
+ #[test]
+ pub fn test_is_2d() {
+ assert!(Mf32::identity().is_2d());
+ assert!(Mf32::create_rotation(0.0, 0.0, 1.0, rad(0.7854)).is_2d());
+ assert!(!Mf32::create_rotation(0.0, 1.0, 0.0, rad(0.7854)).is_2d());
+ }
+
+ #[test]
+ pub fn test_row_major_2d() {
+ let m1 = Mf32::row_major_2d(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
+ let m2 = Mf32::row_major(
+ 1.0, 2.0, 0.0, 0.0,
+ 3.0, 4.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 5.0, 6.0, 0.0, 1.0
+ );
+ assert_eq!(m1, m2);
+ }
+
+ #[test]
+ fn test_column_major() {
+ assert_eq!(
+ Mf32::row_major(
+ 1.0, 2.0, 3.0, 4.0,
+ 5.0, 6.0, 7.0, 8.0,
+ 9.0, 10.0, 11.0, 12.0,
+ 13.0, 14.0, 15.0, 16.0,
+ ),
+ Mf32::column_major(
+ 1.0, 5.0, 9.0, 13.0,
+ 2.0, 6.0, 10.0, 14.0,
+ 3.0, 7.0, 11.0, 15.0,
+ 4.0, 8.0, 12.0, 16.0,
+ )
+ );
+ }
+
+ #[test]
+ pub fn test_inverse_simple() {
+ let m1 = Mf32::identity();
+ let m2 = m1.inverse().unwrap();
+ assert!(m1.approx_eq(&m2));
+ }
+
+ #[test]
+ pub fn test_inverse_scale() {
+ let m1 = Mf32::create_scale(1.5, 0.3, 2.1);
+ let m2 = m1.inverse().unwrap();
+ assert!(m1.pre_mul(&m2).approx_eq(&Mf32::identity()));
+ }
+
+ #[test]
+ pub fn test_inverse_translate() {
+ let m1 = Mf32::create_translation(-132.0, 0.3, 493.0);
+ let m2 = m1.inverse().unwrap();
+ assert!(m1.pre_mul(&m2).approx_eq(&Mf32::identity()));
+ }
+
+ #[test]
+ pub fn test_inverse_rotate() {
+ let m1 = Mf32::create_rotation(0.0, 1.0, 0.0, rad(1.57));
+ let m2 = m1.inverse().unwrap();
+ assert!(m1.pre_mul(&m2).approx_eq(&Mf32::identity()));
+ }
+
+ #[test]
+ pub fn test_inverse_transform_point_2d() {
+ let m1 = Mf32::create_translation(100.0, 200.0, 0.0);
+ let m2 = m1.inverse().unwrap();
+ assert!(m1.pre_mul(&m2).approx_eq(&Mf32::identity()));
+
+ let p1 = Point2D::new(1000.0, 2000.0);
+ let p2 = m1.transform_point2d(&p1);
+ assert!(p2.eq(&Point2D::new(1100.0, 2200.0)));
+
+ let p3 = m2.transform_point2d(&p2);
+ assert!(p3.eq(&p1));
+ }
+
+ #[test]
+ fn test_inverse_none() {
+ assert!(Mf32::create_scale(2.0, 0.0, 2.0).inverse().is_none());
+ assert!(Mf32::create_scale(2.0, 2.0, 2.0).inverse().is_some());
+ }
+
+ #[test]
+ pub fn test_pre_post() {
+ let m1 = Transform3D::identity().post_scale(1.0, 2.0, 3.0).post_translate(vec3(1.0, 2.0, 3.0));
+ let m2 = Transform3D::identity().pre_translate(vec3(1.0, 2.0, 3.0)).pre_scale(1.0, 2.0, 3.0);
+ assert!(m1.approx_eq(&m2));
+
+ let r = Mf32::create_rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2));
+ let t = Mf32::create_translation(2.0, 3.0, 0.0);
+
+ let a = Point3D::new(1.0, 1.0, 1.0);
+
+ assert!(r.post_mul(&t).transform_point3d(&a).approx_eq(&Point3D::new(3.0, 2.0, 1.0)));
+ assert!(t.post_mul(&r).transform_point3d(&a).approx_eq(&Point3D::new(4.0, -3.0, 1.0)));
+ assert!(t.post_mul(&r).transform_point3d(&a).approx_eq(&r.transform_point3d(&t.transform_point3d(&a))));
+
+ assert!(r.pre_mul(&t).transform_point3d(&a).approx_eq(&Point3D::new(4.0, -3.0, 1.0)));
+ assert!(t.pre_mul(&r).transform_point3d(&a).approx_eq(&Point3D::new(3.0, 2.0, 1.0)));
+ assert!(t.pre_mul(&r).transform_point3d(&a).approx_eq(&t.transform_point3d(&r.transform_point3d(&a))));
+ }
+
+ #[test]
+ fn test_size_of() {
+ use std::mem::size_of;
+ assert_eq!(size_of::<Transform3D<f32>>(), 16*size_of::<f32>());
+ assert_eq!(size_of::<Transform3D<f64>>(), 16*size_of::<f64>());
+ }
+
+ #[test]
+ pub fn test_transform_associativity() {
+ let m1 = Mf32::row_major(3.0, 2.0, 1.5, 1.0,
+ 0.0, 4.5, -1.0, -4.0,
+ 0.0, 3.5, 2.5, 40.0,
+ 0.0, 3.0, 0.0, 1.0);
+ let m2 = Mf32::row_major(1.0, -1.0, 3.0, 0.0,
+ -1.0, 0.5, 0.0, 2.0,
+ 1.5, -2.0, 6.0, 0.0,
+ -2.5, 6.0, 1.0, 1.0);
+
+ let p = Point3D::new(1.0, 3.0, 5.0);
+ let p1 = m2.pre_mul(&m1).transform_point3d(&p);
+ let p2 = m2.transform_point3d(&m1.transform_point3d(&p));
+ assert!(p1.approx_eq(&p2));
+ }
+
+ #[test]
+ pub fn test_is_identity() {
+ let m1 = Transform3D::identity();
+ assert!(m1.is_identity());
+ let m2 = m1.post_translate(vec3(0.1, 0.0, 0.0));
+ assert!(!m2.is_identity());
+ }
+
+ #[test]
+ pub fn test_transform_vector() {
+ // Translation does not apply to vectors.
+ let m = Mf32::create_translation(1.0, 2.0, 3.0);
+ let v1 = vec3(10.0, -10.0, 3.0);
+ assert_eq!(v1, m.transform_vector3d(&v1));
+ // While it does apply to points.
+ assert!(v1.to_point() != m.transform_point3d(&v1.to_point()));
+
+ // same thing with 2d vectors/points
+ let v2 = vec2(10.0, -5.0);
+ assert_eq!(v2, m.transform_vector2d(&v2));
+ assert!(v2.to_point() != m.transform_point2d(&v2.to_point()));
+ }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid/src/vector.rs
@@ -0,0 +1,894 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::UnknownUnit;
+use approxeq::ApproxEq;
+use length::Length;
+use point::{TypedPoint2D, TypedPoint3D, point2, point3};
+use size::{TypedSize2D, size2};
+use scale_factor::ScaleFactor;
+use num::*;
+use num_traits::{Float, NumCast};
+use std::fmt;
+use std::ops::{Add, Neg, Mul, Sub, Div, AddAssign, SubAssign, MulAssign, DivAssign};
+use std::marker::PhantomData;
+
+define_matrix! {
+ /// A 2d Vector tagged with a unit.
+ pub struct TypedVector2D<T, U> {
+ pub x: T,
+ pub y: T,
+ }
+}
+
+/// Default 2d vector type with no unit.
+///
+/// `Vector2D` provides the same methods as `TypedVector2D`.
+pub type Vector2D<T> = TypedVector2D<T, UnknownUnit>;
+
+impl<T: Copy + Zero, U> TypedVector2D<T, U> {
+ /// Constructor, setting all components to zero.
+ #[inline]
+ pub fn zero() -> Self {
+ TypedVector2D::new(Zero::zero(), Zero::zero())
+ }
+
+ /// Convert into a 3d vector.
+ #[inline]
+ pub fn to_3d(&self) -> TypedVector3D<T, U> {
+ vec3(self.x, self.y, Zero::zero())
+ }
+}
+
+impl<T: fmt::Debug, U> fmt::Debug for TypedVector2D<T, U> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "({:?},{:?})", self.x, self.y)
+ }
+}
+
+impl<T: fmt::Display, U> fmt::Display for TypedVector2D<T, U> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "({},{})", self.x, self.y)
+ }
+}
+
+impl<T: Copy, U> TypedVector2D<T, U> {
+ /// Constructor taking scalar values directly.
+ #[inline]
+ pub fn new(x: T, y: T) -> Self {
+ TypedVector2D { x: x, y: y, _unit: PhantomData }
+ }
+
+ /// Constructor taking properly typed Lengths instead of scalar values.
+ #[inline]
+ pub fn from_lengths(x: Length<T, U>, y: Length<T, U>) -> Self {
+ vec2(x.0, y.0)
+ }
+
+ /// Create a 3d vector from this one, using the specified z value.
+ #[inline]
+ pub fn extend(&self, z: T) -> TypedVector3D<T, U> {
+ vec3(self.x, self.y, z)
+ }
+
+ /// Cast this vector into a point.
+ ///
+ /// Equivalent to adding this vector to the origin.
+ #[inline]
+ pub fn to_point(&self) -> TypedPoint2D<T, U> {
+ point2(self.x, self.y)
+ }
+
+ /// Cast this vector into a size.
+ #[inline]
+ pub fn to_size(&self) -> TypedSize2D<T, U> {
+ size2(self.x, self.y)
+ }
+
+
+ /// Returns self.x as a Length carrying the unit.
+ #[inline]
+ pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
+
+ /// Returns self.y as a Length carrying the unit.
+ #[inline]
+ pub fn y_typed(&self) -> Length<T, U> { Length::new(self.y) }
+
+ /// Drop the units, preserving only the numeric value.
+ #[inline]
+ pub fn to_untyped(&self) -> Vector2D<T> {
+ vec2(self.x, self.y)
+ }
+
+ /// Tag a unitless value with units.
+ #[inline]
+ pub fn from_untyped(p: &Vector2D<T>) -> Self {
+ vec2(p.x, p.y)
+ }
+
+ #[inline]
+ pub fn to_array(&self) -> [T; 2] {
+ [self.x, self.y]
+ }
+}
+
+impl<T, U> TypedVector2D<T, U>
+where T: Copy + Mul<T, Output=T> + Add<T, Output=T> + Sub<T, Output=T> {
+ /// Dot product.
+ #[inline]
+ pub fn dot(self, other: Self) -> T {
+ self.x * other.x + self.y * other.y
+ }
+
+ /// Returns the norm of the cross product [self.x, self.y, 0] x [other.x, other.y, 0]..
+ #[inline]
+ pub fn cross(self, other: Self) -> T {
+ self.x * other.y - self.y * other.x
+ }
+
+ #[inline]
+ pub fn normalize(self) -> Self where T: Float + ApproxEq<T> {
+ let dot = self.dot(self);
+ if dot.approx_eq(&T::zero()) {
+ self
+ } else {
+ self / dot.sqrt()
+ }
+ }
+
+ #[inline]
+ pub fn square_length(&self) -> T {
+ self.x * self.x + self.y * self.y
+ }
+
+ #[inline]
+ pub fn length(&self) -> T where T: Float + ApproxEq<T> {
+ self.square_length().sqrt()
+ }
+}
+
+impl<T, U> TypedVector2D<T, U>
+where T: Copy + One + Add<Output=T> + Sub<Output=T> + Mul<Output=T> {
+ /// Linearly interpolate between this vector and another vector.
+ ///
+ /// `t` is expected to be between zero and one.
+ #[inline]
+ pub fn lerp(&self, other: Self, t: T) -> Self {
+ let one_t = T::one() - t;
+ (*self) * one_t + other * t
+ }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> Add for TypedVector2D<T, U> {
+ type Output = Self;
+ fn add(self, other: Self) -> Self {
+ TypedVector2D::new(self.x + other.x, self.y + other.y)
+ }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> AddAssign for TypedVector2D<T, U> {
+ #[inline]
+ fn add_assign(&mut self, other: Self) {
+ *self = *self + other
+ }
+}
+
+impl<T: Copy + Sub<T, Output=T>, U> SubAssign<TypedVector2D<T, U>> for TypedVector2D<T, U> {
+ #[inline]
+ fn sub_assign(&mut self, other: Self) {
+ *self = *self - other
+ }
+}
+
+impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedVector2D<T, U> {
+ type Output = Self;
+ #[inline]
+ fn sub(self, other: Self) -> Self {
+ vec2(self.x - other.x, self.y - other.y)
+ }
+}
+
+impl <T: Copy + Neg<Output=T>, U> Neg for TypedVector2D<T, U> {
+ type Output = Self;
+ #[inline]
+ fn neg(self) -> Self {
+ vec2(-self.x, -self.y)
+ }
+}
+
+impl<T: Float, U> TypedVector2D<T, U> {
+ #[inline]
+ pub fn min(self, other: Self) -> Self {
+ vec2(self.x.min(other.x), self.y.min(other.y))
+ }
+
+ #[inline]
+ pub fn max(self, other: Self) -> Self {
+ vec2(self.x.max(other.x), self.y.max(other.y))
+ }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedVector2D<T, U> {
+ type Output = Self;
+ #[inline]
+ fn mul(self, scale: T) -> Self {
+ vec2(self.x * scale, self.y * scale)
+ }
+}
+
+impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedVector2D<T, U> {
+ type Output = Self;
+ #[inline]
+ fn div(self, scale: T) -> Self {
+ vec2(self.x / scale, self.y / scale)
+ }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U> MulAssign<T> for TypedVector2D<T, U> {
+ #[inline]
+ fn mul_assign(&mut self, scale: T) {
+ *self = *self * scale
+ }
+}
+
+impl<T: Copy + Div<T, Output=T>, U> DivAssign<T> for TypedVector2D<T, U> {
+ #[inline]
+ fn div_assign(&mut self, scale: T) {
+ *self = *self / scale
+ }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedVector2D<T, U1> {
+ type Output = TypedVector2D<T, U2>;
+ #[inline]
+ fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedVector2D<T, U2> {
+ vec2(self.x * scale.get(), self.y * scale.get())
+ }
+}
+
+impl<T: Copy + Div<T, Output=T>, U1, U2> Div<ScaleFactor<T, U1, U2>> for TypedVector2D<T, U2> {
+ type Output = TypedVector2D<T, U1>;
+ #[inline]
+ fn div(self, scale: ScaleFactor<T, U1, U2>) -> TypedVector2D<T, U1> {
+ vec2(self.x / scale.get(), self.y / scale.get())
+ }
+}
+
+impl<T: Round, U> TypedVector2D<T, U> {
+ /// Rounds each component to the nearest integer value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ /// For example `{ -0.1, -0.8 }.round() == { 0.0, -1.0 }`.
+ #[inline]
+ #[must_use]
+ pub fn round(&self) -> Self {
+ vec2(self.x.round(), self.y.round())
+ }
+}
+
+impl<T: Ceil, U> TypedVector2D<T, U> {
+ /// Rounds each component to the smallest integer equal or greater than the original value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ /// For example `{ -0.1, -0.8 }.ceil() == { 0.0, 0.0 }`.
+ #[inline]
+ #[must_use]
+ pub fn ceil(&self) -> Self {
+ vec2(self.x.ceil(), self.y.ceil())
+ }
+}
+
+impl<T: Floor, U> TypedVector2D<T, U> {
+ /// Rounds each component to the biggest integer equal or lower than the original value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ /// For example `{ -0.1, -0.8 }.floor() == { -1.0, -1.0 }`.
+ #[inline]
+ #[must_use]
+ pub fn floor(&self) -> Self {
+ vec2(self.x.floor(), self.y.floor())
+ }
+}
+
+impl<T: NumCast + Copy, U> TypedVector2D<T, U> {
+ /// Cast from one numeric representation to another, preserving the units.
+ ///
+ /// When casting from floating vector to integer coordinates, the decimals are truncated
+ /// as one would expect from a simple cast, but this behavior does not always make sense
+ /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
+ #[inline]
+ pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedVector2D<NewT, U>> {
+ match (NumCast::from(self.x), NumCast::from(self.y)) {
+ (Some(x), Some(y)) => Some(TypedVector2D::new(x, y)),
+ _ => None
+ }
+ }
+
+ // Convenience functions for common casts
+
+ /// Cast into an `f32` vector.
+ #[inline]
+ pub fn to_f32(&self) -> TypedVector2D<f32, U> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `usize` vector, truncating decimals if any.
+ ///
+ /// When casting from floating vector vectors, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ #[inline]
+ pub fn to_usize(&self) -> TypedVector2D<usize, U> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an i32 vector, truncating decimals if any.
+ ///
+ /// When casting from floating vector vectors, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ #[inline]
+ pub fn to_i32(&self) -> TypedVector2D<i32, U> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an i64 vector, truncating decimals if any.
+ ///
+ /// When casting from floating vector vectors, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ #[inline]
+ pub fn to_i64(&self) -> TypedVector2D<i64, U> {
+ self.cast().unwrap()
+ }
+}
+
+impl<T: Copy+ApproxEq<T>, U> ApproxEq<TypedVector2D<T, U>> for TypedVector2D<T, U> {
+ #[inline]
+ fn approx_epsilon() -> Self {
+ vec2(T::approx_epsilon(), T::approx_epsilon())
+ }
+
+ #[inline]
+ fn approx_eq(&self, other: &Self) -> bool {
+ self.x.approx_eq(&other.x) && self.y.approx_eq(&other.y)
+ }
+
+ #[inline]
+ fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {
+ self.x.approx_eq_eps(&other.x, &eps.x) && self.y.approx_eq_eps(&other.y, &eps.y)
+ }
+}
+
+impl<T: Copy, U> Into<[T; 2]> for TypedVector2D<T, U> {
+ fn into(self) -> [T; 2] {
+ self.to_array()
+ }
+}
+
+impl<T: Copy, U> From<[T; 2]> for TypedVector2D<T, U> {
+ fn from(array: [T; 2]) -> Self {
+ vec2(array[0], array[1])
+ }
+}
+
+define_matrix! {
+ /// A 3d Vector tagged with a unit.
+ pub struct TypedVector3D<T, U> {
+ pub x: T,
+ pub y: T,
+ pub z: T,
+ }
+}
+
+/// Default 3d vector type with no unit.
+///
+/// `Vector3D` provides the same methods as `TypedVector3D`.
+pub type Vector3D<T> = TypedVector3D<T, UnknownUnit>;
+
+impl<T: Copy + Zero, U> TypedVector3D<T, U> {
+ /// Constructor, setting all copmonents to zero.
+ #[inline]
+ pub fn zero() -> Self {
+ vec3(Zero::zero(), Zero::zero(), Zero::zero())
+ }
+
+ #[inline]
+ pub fn to_array_4d(&self) -> [T; 4] {
+ [self.x, self.y, self.z, Zero::zero()]
+ }
+}
+
+impl<T: fmt::Debug, U> fmt::Debug for TypedVector3D<T, U> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "({:?},{:?},{:?})", self.x, self.y, self.z)
+ }
+}
+
+impl<T: fmt::Display, U> fmt::Display for TypedVector3D<T, U> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "({},{},{})", self.x, self.y, self.z)
+ }
+}
+
+impl<T: Copy, U> TypedVector3D<T, U> {
+ /// Constructor taking scalar values directly.
+ #[inline]
+ pub fn new(x: T, y: T, z: T) -> Self {
+ TypedVector3D { x: x, y: y, z: z, _unit: PhantomData }
+ }
+
+ /// Constructor taking properly typed Lengths instead of scalar values.
+ #[inline]
+ pub fn from_lengths(x: Length<T, U>, y: Length<T, U>, z: Length<T, U>) -> TypedVector3D<T, U> {
+ vec3(x.0, y.0, z.0)
+ }
+
+ /// Cast this vector into a point.
+ ///
+ /// Equivalent to adding this vector to the origin.
+ #[inline]
+ pub fn to_point(&self) -> TypedPoint3D<T, U> {
+ point3(self.x, self.y, self.z)
+ }
+
+ /// Returns self.x as a Length carrying the unit.
+ #[inline]
+ pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
+
+ /// Returns self.y as a Length carrying the unit.
+ #[inline]
+ pub fn y_typed(&self) -> Length<T, U> { Length::new(self.y) }
+
+ /// Returns self.z as a Length carrying the unit.
+ #[inline]
+ pub fn z_typed(&self) -> Length<T, U> { Length::new(self.z) }
+
+ #[inline]
+ pub fn to_array(&self) -> [T; 3] { [self.x, self.y, self.z] }
+
+ /// Drop the units, preserving only the numeric value.
+ #[inline]
+ pub fn to_untyped(&self) -> Vector3D<T> {
+ vec3(self.x, self.y, self.z)
+ }
+
+ /// Tag a unitless value with units.
+ #[inline]
+ pub fn from_untyped(p: &Vector3D<T>) -> Self {
+ vec3(p.x, p.y, p.z)
+ }
+
+ /// Convert into a 2d vector.
+ #[inline]
+ pub fn to_2d(&self) -> TypedVector2D<T, U> {
+ vec2(self.x, self.y)
+ }
+}
+
+impl<T: Mul<T, Output=T> +
+ Add<T, Output=T> +
+ Sub<T, Output=T> +
+ Copy, U> TypedVector3D<T, U> {
+
+ // Dot product.
+ #[inline]
+ pub fn dot(self, other: Self) -> T {
+ self.x * other.x +
+ self.y * other.y +
+ self.z * other.z
+ }
+
+ // Cross product.
+ #[inline]
+ pub fn cross(self, other: Self) -> Self {
+ vec3(
+ self.y * other.z - self.z * other.y,
+ self.z * other.x - self.x * other.z,
+ self.x * other.y - self.y * other.x
+ )
+ }
+
+ #[inline]
+ pub fn normalize(self) -> Self where T: Float + ApproxEq<T> {
+ let dot = self.dot(self);
+ if dot.approx_eq(&T::zero()) {
+ self
+ } else {
+ self / dot.sqrt()
+ }
+ }
+
+ #[inline]
+ pub fn square_length(&self) -> T {
+ self.x * self.x + self.y * self.y + self.z * self.z
+ }
+
+ #[inline]
+ pub fn length(&self) -> T where T: Float + ApproxEq<T> {
+ self.square_length().sqrt()
+ }
+}
+
+impl<T, U> TypedVector3D<T, U>
+where T: Copy + One + Add<Output=T> + Sub<Output=T> + Mul<Output=T> {
+ /// Linearly interpolate between this vector and another vector.
+ ///
+ /// `t` is expected to be between zero and one.
+ #[inline]
+ pub fn lerp(&self, other: Self, t: T) -> Self {
+ let one_t = T::one() - t;
+ (*self) * one_t + other * t
+ }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> Add for TypedVector3D<T, U> {
+ type Output = Self;
+ #[inline]
+ fn add(self, other: Self) -> Self {
+ vec3(self.x + other.x, self.y + other.y, self.z + other.z)
+ }
+}
+
+impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedVector3D<T, U> {
+ type Output = Self;
+ #[inline]
+ fn sub(self, other: Self) -> Self {
+ vec3(self.x - other.x, self.y - other.y, self.z - other.z)
+ }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> AddAssign for TypedVector3D<T, U> {
+ #[inline]
+ fn add_assign(&mut self, other: Self) {
+ *self = *self + other
+ }
+}
+
+impl<T: Copy + Sub<T, Output=T>, U> SubAssign<TypedVector3D<T, U>> for TypedVector3D<T, U> {
+ #[inline]
+ fn sub_assign(&mut self, other: Self) {
+ *self = *self - other
+ }
+}
+
+impl <T: Copy + Neg<Output=T>, U> Neg for TypedVector3D<T, U> {
+ type Output = Self;
+ #[inline]
+ fn neg(self) -> Self {
+ vec3(-self.x, -self.y, -self.z)
+ }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedVector3D<T, U> {
+ type Output = Self;
+ #[inline]
+ fn mul(self, scale: T) -> Self {
+ Self::new(self.x * scale, self.y * scale, self.z * scale)
+ }
+}
+
+impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedVector3D<T, U> {
+ type Output = Self;
+ #[inline]
+ fn div(self, scale: T) -> Self {
+ Self::new(self.x / scale, self.y / scale, self.z / scale)
+ }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U> MulAssign<T> for TypedVector3D<T, U> {
+ #[inline]
+ fn mul_assign(&mut self, scale: T) {
+ *self = *self * scale
+ }
+}
+
+impl<T: Copy + Div<T, Output=T>, U> DivAssign<T> for TypedVector3D<T, U> {
+ #[inline]
+ fn div_assign(&mut self, scale: T) {
+ *self = *self / scale
+ }
+}
+
+impl<T: Float, U> TypedVector3D<T, U> {
+ #[inline]
+ pub fn min(self, other: Self) -> Self {
+ vec3(self.x.min(other.x), self.y.min(other.y), self.z.min(other.z))
+ }
+
+ #[inline]
+ pub fn max(self, other: Self) -> Self {
+ vec3(self.x.max(other.x), self.y.max(other.y), self.z.max(other.z))
+ }
+}
+
+impl<T: Round, U> TypedVector3D<T, U> {
+ /// Rounds each component to the nearest integer value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ #[inline]
+ #[must_use]
+ pub fn round(&self) -> Self {
+ vec3(self.x.round(), self.y.round(), self.z.round())
+ }
+}
+
+impl<T: Ceil, U> TypedVector3D<T, U> {
+ /// Rounds each component to the smallest integer equal or greater than the original value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ #[inline]
+ #[must_use]
+ pub fn ceil(&self) -> Self {
+ vec3(self.x.ceil(), self.y.ceil(), self.z.ceil())
+ }
+}
+
+impl<T: Floor, U> TypedVector3D<T, U> {
+ /// Rounds each component to the biggest integer equal or lower than the original value.
+ ///
+ /// This behavior is preserved for negative values (unlike the basic cast).
+ #[inline]
+ #[must_use]
+ pub fn floor(&self) -> Self {
+ vec3(self.x.floor(), self.y.floor(), self.z.floor())
+ }
+}
+
+impl<T: NumCast + Copy, U> TypedVector3D<T, U> {
+ /// Cast from one numeric representation to another, preserving the units.
+ ///
+ /// When casting from floating vector to integer coordinates, the decimals are truncated
+ /// as one would expect from a simple cast, but this behavior does not always make sense
+ /// geometrically. Consider using round(), ceil or floor() before casting.
+ #[inline]
+ pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedVector3D<NewT, U>> {
+ match (NumCast::from(self.x),
+ NumCast::from(self.y),
+ NumCast::from(self.z)) {
+ (Some(x), Some(y), Some(z)) => Some(vec3(x, y, z)),
+ _ => None
+ }
+ }
+
+ // Convenience functions for common casts
+
+ /// Cast into an `f32` vector.
+ #[inline]
+ pub fn to_f32(&self) -> TypedVector3D<f32, U> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `usize` vector, truncating decimals if any.
+ ///
+ /// When casting from floating vector vectors, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ #[inline]
+ pub fn to_usize(&self) -> TypedVector3D<usize, U> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `i32` vector, truncating decimals if any.
+ ///
+ /// When casting from floating vector vectors, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ #[inline]
+ pub fn to_i32(&self) -> TypedVector3D<i32, U> {
+ self.cast().unwrap()
+ }
+
+ /// Cast into an `i64` vector, truncating decimals if any.
+ ///
+ /// When casting from floating vector vectors, it is worth considering whether
+ /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+ /// the desired conversion behavior.
+ #[inline]
+ pub fn to_i64(&self) -> TypedVector3D<i64, U> {
+ self.cast().unwrap()
+ }
+}
+
+impl<T: Copy+ApproxEq<T>, U> ApproxEq<TypedVector3D<T, U>> for TypedVector3D<T, U> {
+ #[inline]
+ fn approx_epsilon() -> Self {
+ vec3(T::approx_epsilon(), T::approx_epsilon(), T::approx_epsilon())
+ }
+
+ #[inline]
+ fn approx_eq(&self, other: &Self) -> bool {
+ self.x.approx_eq(&other.x)
+ && self.y.approx_eq(&other.y)
+ && self.z.approx_eq(&other.z)
+ }
+
+ #[inline]
+ fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {
+ self.x.approx_eq_eps(&other.x, &eps.x)
+ && self.y.approx_eq_eps(&other.y, &eps.y)
+ && self.z.approx_eq_eps(&other.z, &eps.z)
+ }
+}
+
+impl<T: Copy, U> Into<[T; 3]> for TypedVector3D<T, U> {
+ fn into(self) -> [T; 3] {
+ self.to_array()
+ }
+}
+
+impl<T: Copy, U> From<[T; 3]> for TypedVector3D<T, U> {
+ fn from(array: [T; 3]) -> Self {
+ vec3(array[0], array[1], array[2])
+ }
+}
+
+
+/// Convenience constructor.
+#[inline]
+pub fn vec2<T: Copy, U>(x: T, y: T) -> TypedVector2D<T, U> {
+ TypedVector2D::new(x, y)
+}
+
+/// Convenience constructor.
+#[inline]
+pub fn vec3<T: Copy, U>(x: T, y: T, z: T) -> TypedVector3D<T, U> {
+ TypedVector3D::new(x, y, z)
+}
+
+#[cfg(test)]
+mod vector2d {
+ use super::{Vector2D, vec2};
+ type Vec2 = Vector2D<f32>;
+
+ #[test]
+ pub fn test_scalar_mul() {
+ let p1: Vec2 = vec2(3.0, 5.0);
+
+ let result = p1 * 5.0;
+
+ assert_eq!(result, Vector2D::new(15.0, 25.0));
+ }
+
+ #[test]
+ pub fn test_dot() {
+ let p1: Vec2 = vec2(2.0, 7.0);
+ let p2: Vec2 = vec2(13.0, 11.0);
+ assert_eq!(p1.dot(p2), 103.0);
+ }
+
+ #[test]
+ pub fn test_cross() {
+ let p1: Vec2 = vec2(4.0, 7.0);
+ let p2: Vec2 = vec2(13.0, 8.0);
+ let r = p1.cross(p2);
+ assert_eq!(r, -59.0);
+ }
+
+ #[test]
+ pub fn test_normalize() {
+ let p0: Vec2 = Vec2::zero();
+ let p1: Vec2 = vec2(4.0, 0.0);
+ let p2: Vec2 = vec2(3.0, -4.0);
+ assert_eq!(p0.normalize(), p0);
+ assert_eq!(p1.normalize(), vec2(1.0, 0.0));
+ assert_eq!(p2.normalize(), vec2(0.6, -0.8));
+ }
+
+ #[test]
+ pub fn test_min() {
+ let p1: Vec2 = vec2(1.0, 3.0);
+ let p2: Vec2 = vec2(2.0, 2.0);
+
+ let result = p1.min(p2);
+
+ assert_eq!(result, vec2(1.0, 2.0));
+ }
+
+ #[test]
+ pub fn test_max() {
+ let p1: Vec2 = vec2(1.0, 3.0);
+ let p2: Vec2 = vec2(2.0, 2.0);
+
+ let result = p1.max(p2);
+
+ assert_eq!(result, vec2(2.0, 3.0));
+ }
+}
+
+#[cfg(test)]
+mod typedvector2d {
+ use super::{TypedVector2D, vec2};
+ use scale_factor::ScaleFactor;
+
+ pub enum Mm {}
+ pub enum Cm {}
+
+ pub type Vector2DMm<T> = TypedVector2D<T, Mm>;
+ pub type Vector2DCm<T> = TypedVector2D<T, Cm>;
+
+ #[test]
+ pub fn test_add() {
+ let p1 = Vector2DMm::new(1.0, 2.0);
+ let p2 = Vector2DMm::new(3.0, 4.0);
+
+ let result = p1 + p2;
+
+ assert_eq!(result, vec2(4.0, 6.0));
+ }
+
+ #[test]
+ pub fn test_add_assign() {
+ let mut p1 = Vector2DMm::new(1.0, 2.0);
+ p1 += vec2(3.0, 4.0);
+
+ assert_eq!(p1, vec2(4.0, 6.0));
+ }
+
+ #[test]
+ pub fn test_scalar_mul() {
+ let p1 = Vector2DMm::new(1.0, 2.0);
+ let cm_per_mm: ScaleFactor<f32, Mm, Cm> = ScaleFactor::new(0.1);
+
+ let result: Vector2DCm<f32> = p1 * cm_per_mm;
+
+ assert_eq!(result, vec2(0.1, 0.2));
+ }
+}
+
+#[cfg(test)]
+mod vector3d {
+ use super::{Vector3D, vec3};
+ type Vec3 = Vector3D<f32>;
+
+ #[test]
+ pub fn test_dot() {
+ let p1: Vec3 = vec3(7.0, 21.0, 32.0);
+ let p2: Vec3 = vec3(43.0, 5.0, 16.0);
+ assert_eq!(p1.dot(p2), 918.0);
+ }
+
+ #[test]
+ pub fn test_cross() {
+ let p1: Vec3 = vec3(4.0, 7.0, 9.0);
+ let p2: Vec3 = vec3(13.0, 8.0, 3.0);
+ let p3 = p1.cross(p2);
+ assert_eq!(p3, vec3(-51.0, 105.0, -59.0));
+ }
+
+ #[test]
+ pub fn test_normalize() {
+ let p0: Vec3 = Vec3::zero();
+ let p1: Vec3 = vec3(0.0, -6.0, 0.0);
+ let p2: Vec3 = vec3(1.0, 2.0, -2.0);
+ assert_eq!(p0.normalize(), p0);
+ assert_eq!(p1.normalize(), vec3(0.0, -1.0, 0.0));
+ assert_eq!(p2.normalize(), vec3(1.0/3.0, 2.0/3.0, -2.0/3.0));
+ }
+
+ #[test]
+ pub fn test_min() {
+ let p1: Vec3 = vec3(1.0, 3.0, 5.0);
+ let p2: Vec3 = vec3(2.0, 2.0, -1.0);
+
+ let result = p1.min(p2);
+
+ assert_eq!(result, vec3(1.0, 2.0, -1.0));
+ }
+
+ #[test]
+ pub fn test_max() {
+ let p1: Vec3 = vec3(1.0, 3.0, 5.0);
+ let p2: Vec3 = vec3(2.0, 2.0, -1.0);
+
+ let result = p1.max(p2);
+
+ assert_eq!(result, vec3(2.0, 3.0, 5.0));
+ }
+}
--- a/third_party/rust/plane-split/.cargo-checksum.json
+++ b/third_party/rust/plane-split/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"f9b1ca6ae27d1c18215265024629a8960c31379f206d9ed20f64e0b2dcf79805",".travis.yml":"b76d49f66f842c652d40825c67791352364a6b6bbb7d8d1009f2ac79eb413e66","Cargo.toml":"6a8c18281f4854b2f184e335d2efb7702ed920f3e66adbe84ce2013215215068","LICENSE":"b946744aeda89b467929585fe8eeb5461847695220c1b168fb375d8abd4ea3d0","README.md":"62f99334c17b451342fcea70eb1cc27b26612616b7c1a58fab50dd493f766f32","benches/split.rs":"49befe22321f34280106fdea53d93644b7757873407376247f86f9d55d09b4ab","src/bsp.rs":"1bc961e97b47f6d918384858310c60a20f9490e11404a89f379a2ad6c5705071","src/lib.rs":"c7f52a46d9ebdb9c1346b39312110aaba75821297e5f446c81a8a25706d850f5","src/naive.rs":"c7e50de094d24b609f03e3dc9599bb040a6baef84bce93ffab7af7f049fb805b","tests/main.rs":"915d915c5ca82befef82f1604cc974b072238a8d69043341589d8dd569d412d3","tests/split.rs":"a4681a788f9a9a515d4084d97ba33406a54bc0725711ade9fc955348d1703368"},"package":"f00d5b0bef85e7e218329cde2f9b75784967c62c0cc9b7faa491d81c2d35eb2a"}
\ No newline at end of file
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"f9b1ca6ae27d1c18215265024629a8960c31379f206d9ed20f64e0b2dcf79805",".travis.yml":"b76d49f66f842c652d40825c67791352364a6b6bbb7d8d1009f2ac79eb413e66","Cargo.toml":"42a432c2bd866b37698e064e7f72b6cf96d7aa57dcc5ae32c9474bd6eef745a2","LICENSE":"b946744aeda89b467929585fe8eeb5461847695220c1b168fb375d8abd4ea3d0","README.md":"62f99334c17b451342fcea70eb1cc27b26612616b7c1a58fab50dd493f766f32","benches/split.rs":"dfe01759652e2098f20547e0ddcc1b2937e88c6d6ddb025353c037a46b7ef85d","src/bsp.rs":"66e1690aa8540f744ee013ac0e550ecdee84633727cb3a2d8239db3597ad25d6","src/lib.rs":"21d6135c10dd820c2b9ac484cc018e1149f2bf44c315d27134edd3ecb8a7f3d2","src/naive.rs":"444d3298224009209ae329458fe8df953193b15a04da29cdd6f498572a6471bf","tests/main.rs":"d65d7fe01ff3091a9b470a2f26b28108968ca5d32a5a14defba4336df31c7d7f","tests/split.rs":"19d5bfaaf93115ddecdac0f720893c61b2ed73a0bcb4711534ac7e4500cc06ae"},"package":"da4c13e9ba1388fd628ec2bcd69f3346dec64357e9b552601b244f92189d4610"}
\ No newline at end of file
--- a/third_party/rust/plane-split/Cargo.toml
+++ b/third_party/rust/plane-split/Cargo.toml
@@ -1,15 +1,15 @@
[package]
name = "plane-split"
-version = "0.4.1"
+version = "0.5.0"
description = "Plane splitting"
authors = ["Dzmitry Malyshau <kvark@mozilla.com>"]
license = "MPL-2.0"
repository = "https://github.com/kvark/plane-split"
keywords = ["geometry", "math"]
documentation = "https://docs.rs/plane-split"
[dependencies]
binary-space-partition = "0.1.2"
-euclid = "0.13"
+euclid = "0.14.2"
log = "0.3"
num-traits = {version = "0.1.37", default-features = false}
--- a/third_party/rust/plane-split/benches/split.rs
+++ b/third_party/rust/plane-split/benches/split.rs
@@ -1,31 +1,31 @@
#![feature(test)]
extern crate euclid;
extern crate plane_split;
extern crate test;
use std::sync::Arc;
-use euclid::TypedPoint3D;
+use euclid::vec3;
use plane_split::{BspSplitter, NaiveSplitter, Splitter, _make_grid};
#[bench]
fn bench_naive(b: &mut test::Bencher) {
let polys = Arc::new(_make_grid(5));
let mut splitter = NaiveSplitter::new();
- let view = TypedPoint3D::new(0.0, 0.0, 1.0);
+ let view = vec3(0.0, 0.0, 1.0);
b.iter(|| {
let p = polys.clone();
splitter.solve(&p, view);
});
}
#[bench]
fn bench_bsp(b: &mut test::Bencher) {
let polys = Arc::new(_make_grid(5));
let mut splitter = BspSplitter::new();
- let view = TypedPoint3D::new(0.0, 0.0, 1.0);
+ let view = vec3(0.0, 0.0, 1.0);
b.iter(|| {
let p = polys.clone();
splitter.solve(&p, view);
});
}
--- a/third_party/rust/plane-split/src/bsp.rs
+++ b/third_party/rust/plane-split/src/bsp.rs
@@ -1,10 +1,10 @@
use binary_space_partition::{BspNode, Plane, PlaneCut};
-use euclid::TypedPoint3D;
+use euclid::{TypedPoint3D, TypedVector3D};
use euclid::approxeq::ApproxEq;
use num_traits::{Float, One, Zero};
use std::{fmt, ops};
use {Intersection, Polygon, Splitter};
impl<T, U> Plane for Polygon<T, U> where
T: Copy + fmt::Debug + ApproxEq<T> +
@@ -91,20 +91,20 @@ impl<T, U> Splitter<T, U> for BspSplitte
fn reset(&mut self) {
self.tree = BspNode::new();
}
fn add(&mut self, poly: Polygon<T, U>) {
self.tree.insert(poly);
}
- fn sort(&mut self, view: TypedPoint3D<T, U>) -> &[Polygon<T, U>] {
+ fn sort(&mut self, view: TypedVector3D<T, U>) -> &[Polygon<T, U>] {
//debug!("\t\ttree before sorting {:?}", self.tree);
let poly = Polygon {
- points: [TypedPoint3D::zero(); 4],
+ points: [TypedPoint3D::origin(); 4],
normal: -view, //Note: BSP `order()` is back to front
offset: T::zero(),
anchor: 0,
};
self.result.clear();
self.tree.order(&poly, &mut self.result);
&self.result
}
--- a/third_party/rust/plane-split/src/lib.rs
+++ b/third_party/rust/plane-split/src/lib.rs
@@ -15,44 +15,44 @@ extern crate euclid;
#[macro_use]
extern crate log;
extern crate num_traits;
mod bsp;
mod naive;
use std::{fmt, mem, ops};
-use euclid::{Point2D, TypedMatrix4D, TypedPoint3D, TypedRect};
+use euclid::{Point2D, TypedTransform3D, TypedPoint3D, TypedVector3D, TypedRect};
use euclid::approxeq::ApproxEq;
-use euclid::trig::Trig;
+use euclid::Trig;
use num_traits::{Float, One, Zero};
pub use self::bsp::BspSplitter;
pub use self::naive::NaiveSplitter;
fn is_zero<T>(value: T) -> bool where
T: Copy + Zero + ApproxEq<T> + ops::Mul<T, Output=T> {
//HACK: this is rough, but the original Epsilon is too strict
(value * value).approx_eq(&T::zero())
}
-fn is_zero_vec<T, U>(vec: TypedPoint3D<T, U>) -> bool where
+fn is_zero_vec<T, U>(vec: TypedVector3D<T, U>) -> bool where
T: Copy + Zero + ApproxEq<T> +
ops::Add<T, Output=T> + ops::Sub<T, Output=T> + ops::Mul<T, Output=T> {
vec.dot(vec).approx_eq(&T::zero())
}
/// A generic line.
#[derive(Debug)]
pub struct Line<T, U> {
/// Arbitrary point on the line.
pub origin: TypedPoint3D<T, U>,
/// Normalized direction of the line.
- pub dir: TypedPoint3D<T, U>,
+ pub dir: TypedVector3D<T, U>,
}
impl<T, U> Line<T, U> where
T: Copy + One + Zero + ApproxEq<T> +
ops::Add<T, Output=T> + ops::Sub<T, Output=T> + ops::Mul<T, Output=T>
{
/// Check if the line has consistent parameters.
pub fn is_valid(&self) -> bool {
@@ -68,17 +68,17 @@ impl<T, U> Line<T, U> where
/// A convex flat polygon with 4 points, defined by equation:
/// dot(v, normal) + offset = 0
#[derive(Debug, PartialEq)]
pub struct Polygon<T, U> {
/// Points making the polygon.
pub points: [TypedPoint3D<T, U>; 4],
/// Normalized vector perpendicular to the polygon plane.
- pub normal: TypedPoint3D<T, U>,
+ pub normal: TypedVector3D<T, U>,
/// Constant offset from the normal plane, specified in the
/// direction opposite to the normal.
pub offset: T,
/// A simple anchoring index to allow association of the
/// produced split polygons with the original one.
pub anchor: usize,
}
@@ -174,34 +174,34 @@ impl<T, U> Polygon<T, U> where
T: Copy + fmt::Debug + ApproxEq<T> +
ops::Sub<T, Output=T> + ops::Add<T, Output=T> +
ops::Mul<T, Output=T> + ops::Div<T, Output=T> +
Zero + One + Float,
U: fmt::Debug,
{
/// Construct a polygon from a transformed rectangle.
pub fn from_transformed_rect<V>(rect: TypedRect<T, V>,
- transform: TypedMatrix4D<T, V, U>,
+ transform: TypedTransform3D<T, V, U>,
anchor: usize)
-> Polygon<T, U>
where T: Trig + ops::Neg<Output=T> {
let points = [
transform.transform_point3d(&rect.origin.to_3d()),
transform.transform_point3d(&rect.top_right().to_3d()),
transform.transform_point3d(&rect.bottom_right().to_3d()),
transform.transform_point3d(&rect.bottom_left().to_3d()),
];
//Note: this code path could be more efficient if we had inverse-transpose
//let n4 = transform.transform_point4d(&TypedPoint4D::new(T::zero(), T::zero(), T::one(), T::zero()));
//let normal = TypedPoint3D::new(n4.x, n4.y, n4.z);
let normal = (points[1] - points[0]).cross(points[2] - points[0])
.normalize();
- let offset = -TypedPoint3D::new(transform.m41, transform.m42, transform.m43).dot(normal);
+ let offset = -TypedVector3D::new(transform.m41, transform.m42, transform.m43).dot(normal);
Polygon {
points: points,
normal: normal,
offset: offset,
anchor: anchor,
}
}
@@ -226,17 +226,17 @@ impl<T, U> Polygon<T, U> where
let y = ab * ca - a2 * cb;
Point2D::new(x, y) / denom
}
/// Return the signed distance from this polygon to a point.
/// The distance is negative if the point is on the other side of the polygon
/// from the direction of the normal.
pub fn signed_distance_to(&self, point: &TypedPoint3D<T, U>) -> T {
- point.dot(self.normal) + self.offset
+ point.to_vector().dot(self.normal) + self.offset
}
/// Compute the distance across the line to the polygon plane,
/// starting from the line origin.
pub fn distance_to_line(&self, line: &Line<T, U>) -> T
where T: ops::Neg<Output=T> {
self.signed_distance_to(&line.origin) / -self.normal.dot(line.dir)
}
@@ -278,23 +278,23 @@ impl<T, U> Polygon<T, U> where
/// Check if this polygon contains another one.
pub fn contains(&self, other: &Self) -> bool {
//TODO: actually check for inside/outside
self.normal == other.normal && self.offset == other.offset
}
/// Project this polygon onto a 3D vector, returning a line projection.
/// Note: we can think of it as a projection to a ray placed at the origin.
- pub fn project_on(&self, vector: &TypedPoint3D<T, U>) -> LineProjection<T> {
+ pub fn project_on(&self, vector: &TypedVector3D<T, U>) -> LineProjection<T> {
LineProjection {
markers: [
- vector.dot(self.points[0]),
- vector.dot(self.points[1]),
- vector.dot(self.points[2]),
- vector.dot(self.points[3]),
+ vector.dot(self.points[0].to_vector()),
+ vector.dot(self.points[1].to_vector()),
+ vector.dot(self.points[2].to_vector()),
+ vector.dot(self.points[3].to_vector()),
],
}
}
/// Compute the line of intersection with another polygon.
pub fn intersect(&self, other: &Self) -> Intersection<Line<T, U>> {
if self.are_outside(&other.points) || other.are_outside(&self.points) {
// one is completely outside the other
@@ -316,17 +316,18 @@ impl<T, U> Polygon<T, U> where
}
// compute any point on the intersection between planes
// (n1, v) + d1 = 0
// (n2, v) + d2 = 0
// v = a*n1/w + b*n2/w; w = (n1, n2)
// v = (d2*w - d1) / (1 - w*w) * n1 - (d2 - d1*w) / (1 - w*w) * n2
let w = self.normal.dot(other.normal);
let factor = T::one() / (T::one() - w * w);
- let center = self.normal * ((other.offset * w - self.offset) * factor) -
+ let center = TypedPoint3D::origin() +
+ self.normal * ((other.offset * w - self.offset) * factor) -
other.normal* ((other.offset - self.offset * w) * factor);
Intersection::Inside(Line {
origin: center,
dir: cross_dir.normalize(),
})
}
/// Split the polygon along the specified `Line`. Will do nothing if the line
@@ -438,20 +439,20 @@ pub trait Splitter<T, U> {
fn reset(&mut self);
/// Add a new polygon and return a slice of the subdivisions
/// that avoid collision with any of the previously added polygons.
fn add(&mut self, Polygon<T, U>);
/// Sort the produced polygon set by the ascending distance across
/// the specified view vector. Return the sorted slice.
- fn sort(&mut self, TypedPoint3D<T, U>) -> &[Polygon<T, U>];
+ fn sort(&mut self, TypedVector3D<T, U>) -> &[Polygon<T, U>];
/// Process a set of polygons at once.
- fn solve(&mut self, input: &[Polygon<T, U>], view: TypedPoint3D<T, U>)
+ fn solve(&mut self, input: &[Polygon<T, U>], view: TypedVector3D<T, U>)
-> &[Polygon<T, U>]
where T: Clone, U: Clone {
self.reset();
for p in input.iter() {
self.add(p.clone());
}
self.sort(view)
}
@@ -465,36 +466,36 @@ pub fn _make_grid(count: usize) -> Vec<P
let len = count as f32;
polys.extend((0 .. count).map(|i| Polygon {
points: [
TypedPoint3D::new(0.0, i as f32, 0.0),
TypedPoint3D::new(len, i as f32, 0.0),
TypedPoint3D::new(len, i as f32, len),
TypedPoint3D::new(0.0, i as f32, len),
],
- normal: TypedPoint3D::new(0.0, 1.0, 0.0),
+ normal: TypedVector3D::new(0.0, 1.0, 0.0),
offset: -(i as f32),
anchor: 0,
}));
polys.extend((0 .. count).map(|i| Polygon {
points: [
TypedPoint3D::new(i as f32, 0.0, 0.0),
TypedPoint3D::new(i as f32, len, 0.0),
TypedPoint3D::new(i as f32, len, len),
TypedPoint3D::new(i as f32, 0.0, len),
],
- normal: TypedPoint3D::new(1.0, 0.0, 0.0),
+ normal: TypedVector3D::new(1.0, 0.0, 0.0),
offset: -(i as f32),
anchor: 0,
}));
polys.extend((0 .. count).map(|i| Polygon {
points: [
TypedPoint3D::new(0.0, 0.0, i as f32),
TypedPoint3D::new(len, 0.0, i as f32),
TypedPoint3D::new(len, len, i as f32),
TypedPoint3D::new(0.0, len, i as f32),
],
- normal: TypedPoint3D::new(0.0, 0.0, 1.0),
+ normal: TypedVector3D::new(0.0, 0.0, 1.0),
offset: -(i as f32),
anchor: 0,
}));
polys
}
--- a/third_party/rust/plane-split/src/naive.rs
+++ b/third_party/rust/plane-split/src/naive.rs
@@ -1,12 +1,12 @@
use std::{fmt, ops};
use std::cmp::Ordering;
use {Intersection, Line, Polygon, Splitter};
-use euclid::TypedPoint3D;
+use euclid::TypedVector3D;
use euclid::approxeq::ApproxEq;
use num_traits::{Float, One, Zero};
/// Naive plane splitter, has at least O(n^2) complexity.
pub struct NaiveSplitter<T, U> {
result: Vec<Polygon<T, U>>,
current: Vec<Polygon<T, U>>,
@@ -22,18 +22,18 @@ impl<T, U> NaiveSplitter<T, U> {
temp: Vec::new(),
}
}
}
/// Find a closest intersection point between two polygons,
/// across the specified direction.
fn intersect_across<T, U>(a: &Polygon<T, U>, b: &Polygon<T, U>,
- dir: TypedPoint3D<T, U>)
- -> TypedPoint3D<T, U>
+ dir: TypedVector3D<T, U>)
+ -> TypedVector3D<T, U>
where
T: Copy + fmt::Debug + PartialOrd + ApproxEq<T> +
ops::Sub<T, Output=T> + ops::Add<T, Output=T> +
ops::Mul<T, Output=T> + ops::Div<T, Output=T> +
Zero + One + Float,
U: fmt::Debug,
{
let pa = a.project_on(&dir).get_bounds();
@@ -131,21 +131,21 @@ impl<
self.current.extend(self.temp.drain(..));
}
let index = self.result.len();
self.result.extend(self.current.drain(..));
debug!("Split result: {:?}", &self.result[index..]);
}
//TODO: verify/prove that the sorting approach is consistent
- fn sort(&mut self, view: TypedPoint3D<T, U>) -> &[Polygon<T, U>] {
+ fn sort(&mut self, view: TypedVector3D<T, U>) -> &[Polygon<T, U>] {
// choose the most perpendicular axis among these two
let axis_pre = {
- let axis_pre0 = TypedPoint3D::new(T::one(), T::zero(), T::zero());
- let axis_pre1 = TypedPoint3D::new(T::zero(), T::one(), T::zero());
+ let axis_pre0 = TypedVector3D::new(T::one(), T::zero(), T::zero());
+ let axis_pre1 = TypedVector3D::new(T::zero(), T::one(), T::zero());
if view.dot(axis_pre0).abs() < view.dot(axis_pre1).abs() {
axis_pre0
} else {
axis_pre1
}
};
// do the orthogonalization
let axis_x = view.cross(axis_pre);
@@ -155,17 +155,17 @@ impl<
partial_sort_by(&mut self.result, |a, b| {
debug!("\t\t{:?}\n\t\t{:?}", a, b);
//TODO: proper intersection
// compute the origin
let comp_x = intersect_across(a, b, axis_x);
let comp_y = intersect_across(a, b, axis_y);
// line that tries to intersect both
let line = Line {
- origin: comp_x + comp_y,
+ origin: (comp_x + comp_y).to_point(),
dir: view,
};
debug!("\t\tGot {:?}", line);
// distances across the line
let da = a.distance_to_line(&line);
let db = b.distance_to_line(&line);
debug!("\t\tDistances {:?} {:?}", da, db);
// final compare
--- a/third_party/rust/plane-split/tests/main.rs
+++ b/third_party/rust/plane-split/tests/main.rs
@@ -1,140 +1,140 @@
extern crate euclid;
extern crate plane_split;
-use euclid::{Point2D, Radians, TypedPoint2D, TypedPoint3D, TypedRect, TypedSize2D, TypedMatrix4D};
+use euclid::{Radians, TypedRect, TypedSize2D, TypedTransform3D, point2, point3, vec3};
use euclid::approxeq::ApproxEq;
use plane_split::{Intersection, Line, LineProjection, Polygon};
#[test]
fn line_proj_bounds() {
assert_eq!((-5i8, 4), LineProjection { markers: [-5i8, 1, 4, 2] }.get_bounds());
assert_eq!((1f32, 4.0), LineProjection { markers: [4f32, 3.0, 2.0, 1.0] }.get_bounds());
}
#[test]
fn valid() {
let poly_a: Polygon<f32, ()> = Polygon {
points: [
- TypedPoint3D::new(0.0, 0.0, 0.0),
- TypedPoint3D::new(1.0, 1.0, 1.0),
- TypedPoint3D::new(1.0, 1.0, 0.0),
- TypedPoint3D::new(0.0, 1.0, 1.0),
+ point3(0.0, 0.0, 0.0),
+ point3(1.0, 1.0, 1.0),
+ point3(1.0, 1.0, 0.0),
+ point3(0.0, 1.0, 1.0),
],
- normal: TypedPoint3D::new(0.0, 1.0, 0.0),
+ normal: vec3(0.0, 1.0, 0.0),
offset: -1.0,
anchor: 0,
};
assert!(!poly_a.is_valid()); // points[0] is outside
let poly_b: Polygon<f32, ()> = Polygon {
points: [
- TypedPoint3D::new(0.0, 1.0, 0.0),
- TypedPoint3D::new(1.0, 1.0, 1.0),
- TypedPoint3D::new(1.0, 1.0, 0.0),
- TypedPoint3D::new(0.0, 1.0, 1.0),
+ point3(0.0, 1.0, 0.0),
+ point3(1.0, 1.0, 1.0),
+ point3(1.0, 1.0, 0.0),
+ point3(0.0, 1.0, 1.0),
],
- normal: TypedPoint3D::new(0.0, 1.0, 0.0),
+ normal: vec3(0.0, 1.0, 0.0),
offset: -1.0,
anchor: 0,
};
assert!(!poly_b.is_valid()); // winding is incorrect
let poly_c: Polygon<f32, ()> = Polygon {
points: [
- TypedPoint3D::new(0.0, 0.0, 1.0),
- TypedPoint3D::new(1.0, 0.0, 1.0),
- TypedPoint3D::new(1.0, 1.0, 1.0),
- TypedPoint3D::new(0.0, 1.0, 1.0),
+ point3(0.0, 0.0, 1.0),
+ point3(1.0, 0.0, 1.0),
+ point3(1.0, 1.0, 1.0),
+ point3(0.0, 1.0, 1.0),
],
- normal: TypedPoint3D::new(0.0, 0.0, 1.0),
+ normal: vec3(0.0, 0.0, 1.0),
offset: -1.0,
anchor: 0,
};
assert!(poly_c.is_valid());
}
#[test]
fn from_transformed_rect() {
- let rect: TypedRect<f32, ()> = TypedRect::new(TypedPoint2D::new(10.0, 10.0), TypedSize2D::new(20.0, 30.0));
- let transform: TypedMatrix4D<f32, (), ()> =
- TypedMatrix4D::create_rotation(0.5f32.sqrt(), 0.0, 0.5f32.sqrt(), Radians::new(5.0))
- .pre_translated(0.0, 0.0, 10.0);
+ let rect: TypedRect<f32, ()> = TypedRect::new(point2(10.0, 10.0), TypedSize2D::new(20.0, 30.0));
+ let transform: TypedTransform3D<f32, (), ()> =
+ TypedTransform3D::create_rotation(0.5f32.sqrt(), 0.0, 0.5f32.sqrt(), Radians::new(5.0))
+ .pre_translate(vec3(0.0, 0.0, 10.0));
let poly = Polygon::from_transformed_rect(rect, transform, 0);
assert!(poly.is_valid());
}
#[test]
fn untransform_point() {
let poly: Polygon<f32, ()> = Polygon {
points: [
- TypedPoint3D::new(0.0, 0.0, 0.0),
- TypedPoint3D::new(0.5, 1.0, 0.0),
- TypedPoint3D::new(1.5, 1.0, 0.0),
- TypedPoint3D::new(1.0, 0.0, 0.0),
+ point3(0.0, 0.0, 0.0),
+ point3(0.5, 1.0, 0.0),
+ point3(1.5, 1.0, 0.0),
+ point3(1.0, 0.0, 0.0),
],
- normal: TypedPoint3D::new(0.0, 1.0, 0.0),
+ normal: vec3(0.0, 1.0, 0.0),
offset: 0.0,
anchor: 0,
};
- assert_eq!(poly.untransform_point(poly.points[0]), Point2D::new(0.0, 0.0));
- assert_eq!(poly.untransform_point(poly.points[1]), Point2D::new(1.0, 0.0));
- assert_eq!(poly.untransform_point(poly.points[2]), Point2D::new(1.0, 1.0));
- assert_eq!(poly.untransform_point(poly.points[3]), Point2D::new(0.0, 1.0));
+ assert_eq!(poly.untransform_point(poly.points[0]), point2(0.0, 0.0));
+ assert_eq!(poly.untransform_point(poly.points[1]), point2(1.0, 0.0));
+ assert_eq!(poly.untransform_point(poly.points[2]), point2(1.0, 1.0));
+ assert_eq!(poly.untransform_point(poly.points[3]), point2(0.0, 1.0));
}
#[test]
fn are_outside() {
let poly: Polygon<f32, ()> = Polygon {
points: [
- TypedPoint3D::new(0.0, 0.0, 1.0),
- TypedPoint3D::new(1.0, 0.0, 1.0),
- TypedPoint3D::new(1.0, 1.0, 1.0),
- TypedPoint3D::new(0.0, 1.0, 1.0),
+ point3(0.0, 0.0, 1.0),
+ point3(1.0, 0.0, 1.0),
+ point3(1.0, 1.0, 1.0),
+ point3(0.0, 1.0, 1.0),
],
- normal: TypedPoint3D::new(0.0, 0.0, 1.0),
+ normal: vec3(0.0, 0.0, 1.0),
offset: -1.0,
anchor: 0,
};
assert!(poly.is_valid());
assert!(poly.are_outside(&[
- TypedPoint3D::new(0.0, 0.0, 1.1),
- TypedPoint3D::new(1.0, 1.0, 2.0),
+ point3(0.0, 0.0, 1.1),
+ point3(1.0, 1.0, 2.0),
]));
assert!(poly.are_outside(&[
- TypedPoint3D::new(0.5, 0.5, 1.0),
+ point3(0.5, 0.5, 1.0),
]));
assert!(!poly.are_outside(&[
- TypedPoint3D::new(0.0, 0.0, 1.0),
- TypedPoint3D::new(0.0, 0.0, -1.0),
+ point3(0.0, 0.0, 1.0),
+ point3(0.0, 0.0, -1.0),
]));
}
#[test]
fn intersect() {
let poly_a: Polygon<f32, ()> = Polygon {
points: [
- TypedPoint3D::new(0.0, 0.0, 1.0),
- TypedPoint3D::new(1.0, 0.0, 1.0),
- TypedPoint3D::new(1.0, 1.0, 1.0),
- TypedPoint3D::new(0.0, 1.0, 1.0),
+ point3(0.0, 0.0, 1.0),
+ point3(1.0, 0.0, 1.0),
+ point3(1.0, 1.0, 1.0),
+ point3(0.0, 1.0, 1.0),
],
- normal: TypedPoint3D::new(0.0, 0.0, 1.0),
+ normal: vec3(0.0, 0.0, 1.0),
offset: -1.0,
anchor: 0,
};
assert!(poly_a.is_valid());
let poly_b: Polygon<f32, ()> = Polygon {
points: [
- TypedPoint3D::new(0.5, 0.0, 2.0),
- TypedPoint3D::new(0.5, 1.0, 2.0),
- TypedPoint3D::new(0.5, 1.0, 0.0),
- TypedPoint3D::new(0.5, 0.0, 0.0),
+ point3(0.5, 0.0, 2.0),
+ point3(0.5, 1.0, 2.0),
+ point3(0.5, 1.0, 0.0),
+ point3(0.5, 0.0, 0.0),
],
- normal: TypedPoint3D::new(1.0, 0.0, 0.0),
+ normal: vec3(1.0, 0.0, 0.0),
offset: -0.5,
anchor: 0,
};
assert!(poly_b.is_valid());
let intersection = match poly_a.intersect(&poly_b) {
Intersection::Inside(result) => result,
_ => panic!("Bad intersection"),
@@ -144,34 +144,34 @@ fn intersect() {
assert!(poly_a.signed_distance_to(&intersection.origin).approx_eq(&0.0));
assert!(poly_b.signed_distance_to(&intersection.origin).approx_eq(&0.0));
// confirm the direction is coplanar to both planes
assert!(poly_a.normal.dot(intersection.dir).approx_eq(&0.0));
assert!(poly_b.normal.dot(intersection.dir).approx_eq(&0.0));
let poly_c: Polygon<f32, ()> = Polygon {
points: [
- TypedPoint3D::new(0.0, -1.0, 2.0),
- TypedPoint3D::new(0.0, -1.0, 0.0),
- TypedPoint3D::new(0.0, 0.0, 0.0),
- TypedPoint3D::new(0.0, 0.0, 2.0),
+ point3(0.0, -1.0, 2.0),
+ point3(0.0, -1.0, 0.0),
+ point3(0.0, 0.0, 0.0),
+ point3(0.0, 0.0, 2.0),
],
- normal: TypedPoint3D::new(1.0, 0.0, 0.0),
+ normal: vec3(1.0, 0.0, 0.0),
offset: 0.0,
anchor: 0,
};
assert!(poly_c.is_valid());
let poly_d: Polygon<f32, ()> = Polygon {
points: [
- TypedPoint3D::new(0.0, 0.0, 0.5),
- TypedPoint3D::new(1.0, 0.0, 0.5),
- TypedPoint3D::new(1.0, 1.0, 0.5),
- TypedPoint3D::new(0.0, 1.0, 0.5),
+ point3(0.0, 0.0, 0.5),
+ point3(1.0, 0.0, 0.5),
+ point3(1.0, 1.0, 0.5),
+ point3(0.0, 1.0, 0.5),
],
- normal: TypedPoint3D::new(0.0, 0.0, 1.0),
+ normal: vec3(0.0, 0.0, 1.0),
offset: -0.5,
anchor: 0,
};
assert!(poly_d.is_valid());
assert!(poly_a.intersect(&poly_c).is_outside());
assert!(poly_a.intersect(&poly_d).is_outside());
}
@@ -190,48 +190,48 @@ fn test_cut(poly_base: &Polygon<f32, ()>
assert!(extra.is_valid() && poly_base.contains(&extra));
}
}
#[test]
fn split() {
let poly: Polygon<f32, ()> = Polygon {
points: [
- TypedPoint3D::new(0.0, 1.0, 0.0),
- TypedPoint3D::new(1.0, 1.0, 0.0),
- TypedPoint3D::new(1.0, 1.0, 1.0),
- TypedPoint3D::new(0.0, 1.0, 1.0),
+ point3(0.0, 1.0, 0.0),
+ point3(1.0, 1.0, 0.0),
+ point3(1.0, 1.0, 1.0),
+ point3(0.0, 1.0, 1.0),
],
- normal: TypedPoint3D::new(0.0, 1.0, 0.0),
+ normal: vec3(0.0, 1.0, 0.0),
offset: -1.0,
anchor: 0,
};
// non-intersecting line
test_cut(&poly, 0, Line {
- origin: TypedPoint3D::new(0.0, 1.0, 0.5),
- dir: TypedPoint3D::new(0.0, 1.0, 0.0),
+ origin: point3(0.0, 1.0, 0.5),
+ dir: vec3(0.0, 1.0, 0.0),
});
// simple cut (diff=2)
test_cut(&poly, 1, Line {
- origin: TypedPoint3D::new(0.0, 1.0, 0.5),
- dir: TypedPoint3D::new(1.0, 0.0, 0.0),
+ origin: point3(0.0, 1.0, 0.5),
+ dir: vec3(1.0, 0.0, 0.0),
});
// complex cut (diff=1, wrapped)
test_cut(&poly, 2, Line {
- origin: TypedPoint3D::new(0.0, 1.0, 0.5),
- dir: TypedPoint3D::new(0.5f32.sqrt(), 0.0, -0.5f32.sqrt()),
+ origin: point3(0.0, 1.0, 0.5),
+ dir: vec3(0.5f32.sqrt(), 0.0, -0.5f32.sqrt()),
});
// complex cut (diff=1, non-wrapped)
test_cut(&poly, 2, Line {
- origin: TypedPoint3D::new(0.5, 1.0, 0.0),
- dir: TypedPoint3D::new(0.5f32.sqrt(), 0.0, 0.5f32.sqrt()),
+ origin: point3(0.5, 1.0, 0.0),
+ dir: vec3(0.5f32.sqrt(), 0.0, 0.5f32.sqrt()),
});
// complex cut (diff=3)
test_cut(&poly, 2, Line {
- origin: TypedPoint3D::new(0.5, 1.0, 0.0),
- dir: TypedPoint3D::new(-0.5f32.sqrt(), 0.0, 0.5f32.sqrt()),
+ origin: point3(0.5, 1.0, 0.0),
+ dir: vec3(-0.5f32.sqrt(), 0.0, 0.5f32.sqrt()),
});
}
--- a/third_party/rust/plane-split/tests/split.rs
+++ b/third_party/rust/plane-split/tests/split.rs
@@ -1,49 +1,49 @@
extern crate euclid;
extern crate plane_split;
use std::f32::consts::FRAC_PI_4;
-use euclid::{Radians, TypedMatrix4D, TypedPoint2D, TypedPoint3D, TypedSize2D, TypedRect};
+use euclid::{Radians, TypedTransform3D, TypedRect, vec3};
use plane_split::{BspSplitter, NaiveSplitter, Polygon, Splitter, _make_grid};
fn grid_impl(count: usize, splitter: &mut Splitter<f32, ()>) {
let polys = _make_grid(count);
- let result = splitter.solve(&polys, TypedPoint3D::new(0.0, 0.0, 1.0));
+ let result = splitter.solve(&polys, vec3(0.0, 0.0, 1.0));
assert_eq!(result.len(), count + count*count + count*count*count);
}
#[test]
fn grid_naive() {
grid_impl(2, &mut NaiveSplitter::new());
}
#[test]
fn grid_bsp() {
grid_impl(2, &mut BspSplitter::new());
}
fn sort_rotation(splitter: &mut Splitter<f32, ()>) {
- let transform0: TypedMatrix4D<f32, (), ()> =
- TypedMatrix4D::create_rotation(0.0, 1.0, 0.0, Radians::new(-FRAC_PI_4));
- let transform1: TypedMatrix4D<f32, (), ()> =
- TypedMatrix4D::create_rotation(0.0, 1.0, 0.0, Radians::new(0.0));
- let transform2: TypedMatrix4D<f32, (), ()> =
- TypedMatrix4D::create_rotation(0.0, 1.0, 0.0, Radians::new(FRAC_PI_4));
+ let transform0: TypedTransform3D<f32, (), ()> =
+ TypedTransform3D::create_rotation(0.0, 1.0, 0.0, Radians::new(-FRAC_PI_4));
+ let transform1: TypedTransform3D<f32, (), ()> =
+ TypedTransform3D::create_rotation(0.0, 1.0, 0.0, Radians::new(0.0));
+ let transform2: TypedTransform3D<f32, (), ()> =
+ TypedTransform3D::create_rotation(0.0, 1.0, 0.0, Radians::new(FRAC_PI_4));
- let rect: TypedRect<f32, ()> = TypedRect::new(TypedPoint2D::new(-10.0, -10.0), TypedSize2D::new(20.0, 20.0));
+ let rect: TypedRect<f32, ()> = euclid::rect(-10.0, -10.0, 20.0, 20.0);
let polys = [
Polygon::from_transformed_rect(rect, transform0, 0),
Polygon::from_transformed_rect(rect, transform1, 1),
Polygon::from_transformed_rect(rect, transform2, 2),
];
- let result = splitter.solve(&polys, TypedPoint3D::new(0.0, 0.0, -1.0));
+ let result = splitter.solve(&polys, vec3(0.0, 0.0, -1.0));
let ids: Vec<_> = result.iter().map(|poly| poly.anchor).collect();
assert_eq!(&ids, &[2, 1, 0, 1, 2]);
}
#[test]
fn rotation_naive() {
sort_rotation(&mut NaiveSplitter::new());
}
@@ -51,23 +51,23 @@ fn rotation_naive() {
#[test]
fn rotation_bsp() {
sort_rotation(&mut BspSplitter::new());
}
fn sort_trivial(splitter: &mut Splitter<f32, ()>) {
let anchors: Vec<_> = (0usize .. 10).collect();
- let rect: TypedRect<f32, ()> = TypedRect::new(TypedPoint2D::new(-10.0, -10.0), TypedSize2D::new(20.0, 20.0));
+ let rect: TypedRect<f32, ()> = euclid::rect(-10.0, -10.0, 20.0, 20.0);
let polys: Vec<_> = anchors.iter().map(|&anchor| {
- let transform: TypedMatrix4D<f32, (), ()> = TypedMatrix4D::create_translation(0.0, 0.0, anchor as f32);
+ let transform: TypedTransform3D<f32, (), ()> = TypedTransform3D::create_translation(0.0, 0.0, anchor as f32);
Polygon::from_transformed_rect(rect, transform, anchor)
}).collect();
- let result = splitter.solve(&polys, TypedPoint3D::new(0.0, 0.0, -1.0));
+ let result = splitter.solve(&polys, vec3(0.0, 0.0, -1.0));
let anchors1: Vec<_> = result.iter().map(|p| p.anchor).collect();
let mut anchors2 = anchors1.clone();
anchors2.sort_by_key(|&a| -(a as i32));
assert_eq!(anchors1, anchors2); //make sure Z is sorted backwards
}
#[test]
fn trivial_naive() {
--- a/toolkit/library/gtest/rust/Cargo.lock
+++ b/toolkit/library/gtest/rust/Cargo.lock
@@ -295,16 +295,27 @@ dependencies = [
"heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "euclid"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "fnv"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "freetype"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -635,21 +646,21 @@ dependencies = [
[[package]]
name = "pkg-config"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "plane-split"
-version = "0.4.1"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "precomputed-hash"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1111,53 +1122,53 @@ dependencies = [
"app_units 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode 1.0.0-alpha6 (registry+https://github.com/rust-lang/crates.io-index)",
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-text 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gamma-lut 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "plane-split 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "plane-split 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender_traits 0.40.0",
]
[[package]]
name = "webrender_bindings"
version = "0.1.0"
dependencies = [
"app_units 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender 0.40.0",
"webrender_traits 0.40.0",
]
[[package]]
name = "webrender_traits"
version = "0.40.0"
dependencies = [
"app_units 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode 1.0.0-alpha6 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1205,16 +1216,17 @@ dependencies = [
"checksum core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ead017dcf77f503dc991f6b52de6084eeea60a94b0a652baa9bf88654a28e83f"
"checksum core-text 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9719616a10f717628e074744f8c55df7b450f7a34d29c196d14f4498aad05d"
"checksum cssparser 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a5ca71edbab09f8dc1e3d1c132717562c3b01c8598ab669183c5195bb1761"
"checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df"
"checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
"checksum dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74114b6b49d6731835da7a28a3642651451e315f7f9b9d04e907e65a45681796"
"checksum env_logger 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ed39959122ea027670b704fb70539f4286ddf4a49eefede23bf0b4b2a069ec03"
"checksum euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6083f113c422ff9cd855a1cf6cc8ec0903606c0eb43a0c6a0ced3bdc9731e4c1"
+"checksum euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995b21c36b37e0f18ed9ba1714378a337e3ff19a6e5e952ea94b0f3dd4e12fbc"
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
"checksum freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fde23272c687e4570aefec06cb71174ec0f5284b725deac4e77ba2665d635faf"
"checksum futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "55f0008e13fc853f79ea8fc86e931486860d4c4c156cdffb59fa5f7fa833660a"
"checksum gamma-lut 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41f72af1e933f296b827361eb9e70d0267abf8ad0de9ec7fa667bbe67177b297"
"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
"checksum gl_generator 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0940975a4ca12b088d32b5d5134826c47d2e73de4b0b459b05244c01503eccbb"
"checksum gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86944a6a4d7f54507f8ee930192d971f18a7b1da526ff529b7a0d4043935380"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
@@ -1242,17 +1254,17 @@ dependencies = [
"checksum parking_lot_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56a19dcbb5d1e32b6cccb8a9aa1fc2a38418c8699652e735e2bf391a3dc0aa16"
"checksum pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ceca1642c89148ca05611cc775a0c383abef355fc4907c4e95f49f7b09d6287c"
"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
"checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
"checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f"
"checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
"checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2"
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
-"checksum plane-split 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f00d5b0bef85e7e218329cde2f9b75784967c62c0cc9b7faa491d81c2d35eb2a"
+"checksum plane-split 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da4c13e9ba1388fd628ec2bcd69f3346dec64357e9b552601b244f92189d4610"
"checksum precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf1fc3616b3ef726a847f2cd2388c646ef6a1f1ba4835c2629004da48184150"
"checksum procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f566249236c6ca4340f7ca78968271f0ed2b0f234007a61b66f9ecd0af09260"
"checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3"
"checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4"
"checksum quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7375cf7ad34a92e8fd18dd9c42f58b9a11def59ab48bec955bf359a788335592"
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
"checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a"
"checksum rayon-core 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd1e76f8ee0322fbbeb0c43a07e1757fcf8ff06bb0ff92da017625882ddc04dd"
--- a/toolkit/library/rust/Cargo.lock
+++ b/toolkit/library/rust/Cargo.lock
@@ -293,16 +293,27 @@ dependencies = [
"heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "euclid"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "fnv"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "freetype"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -622,21 +633,21 @@ dependencies = [
[[package]]
name = "pkg-config"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "plane-split"
-version = "0.4.1"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "precomputed-hash"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1098,53 +1109,53 @@ dependencies = [
"app_units 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode 1.0.0-alpha6 (registry+https://github.com/rust-lang/crates.io-index)",
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-text 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gamma-lut 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "plane-split 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "plane-split 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender_traits 0.40.0",
]
[[package]]
name = "webrender_bindings"
version = "0.1.0"
dependencies = [
"app_units 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender 0.40.0",
"webrender_traits 0.40.0",
]
[[package]]
name = "webrender_traits"
version = "0.40.0"
dependencies = [
"app_units 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode 1.0.0-alpha6 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1192,16 +1203,17 @@ dependencies = [
"checksum core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ead017dcf77f503dc991f6b52de6084eeea60a94b0a652baa9bf88654a28e83f"
"checksum core-text 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9719616a10f717628e074744f8c55df7b450f7a34d29c196d14f4498aad05d"
"checksum cssparser 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a5ca71edbab09f8dc1e3d1c132717562c3b01c8598ab669183c5195bb1761"
"checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df"
"checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
"checksum dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74114b6b49d6731835da7a28a3642651451e315f7f9b9d04e907e65a45681796"
"checksum env_logger 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ed39959122ea027670b704fb70539f4286ddf4a49eefede23bf0b4b2a069ec03"
"checksum euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6083f113c422ff9cd855a1cf6cc8ec0903606c0eb43a0c6a0ced3bdc9731e4c1"
+"checksum euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995b21c36b37e0f18ed9ba1714378a337e3ff19a6e5e952ea94b0f3dd4e12fbc"
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
"checksum freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fde23272c687e4570aefec06cb71174ec0f5284b725deac4e77ba2665d635faf"
"checksum futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "55f0008e13fc853f79ea8fc86e931486860d4c4c156cdffb59fa5f7fa833660a"
"checksum gamma-lut 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41f72af1e933f296b827361eb9e70d0267abf8ad0de9ec7fa667bbe67177b297"
"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
"checksum gl_generator 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0940975a4ca12b088d32b5d5134826c47d2e73de4b0b459b05244c01503eccbb"
"checksum gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86944a6a4d7f54507f8ee930192d971f18a7b1da526ff529b7a0d4043935380"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
@@ -1229,17 +1241,17 @@ dependencies = [
"checksum parking_lot_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56a19dcbb5d1e32b6cccb8a9aa1fc2a38418c8699652e735e2bf391a3dc0aa16"
"checksum pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ceca1642c89148ca05611cc775a0c383abef355fc4907c4e95f49f7b09d6287c"
"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
"checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
"checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f"
"checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
"checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2"
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
-"checksum plane-split 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f00d5b0bef85e7e218329cde2f9b75784967c62c0cc9b7faa491d81c2d35eb2a"
+"checksum plane-split 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da4c13e9ba1388fd628ec2bcd69f3346dec64357e9b552601b244f92189d4610"
"checksum precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf1fc3616b3ef726a847f2cd2388c646ef6a1f1ba4835c2629004da48184150"
"checksum procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f566249236c6ca4340f7ca78968271f0ed2b0f234007a61b66f9ecd0af09260"
"checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3"
"checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4"
"checksum quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7375cf7ad34a92e8fd18dd9c42f58b9a11def59ab48bec955bf359a788335592"
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
"checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a"
"checksum rayon-core 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd1e76f8ee0322fbbeb0c43a07e1757fcf8ff06bb0ff92da017625882ddc04dd"