From 186ad0d7c3bd73e76d328e6fd1a3ffcca03d1355 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 5 Aug 2020 09:15:22 +0000 Subject: [PATCH] Bug 1656236 - Vendor euclid update in stylo. r=emilio Differential Revision: https://phabricator.services.mozilla.com/D85763 --- Cargo.lock | 27 +- .../rust/euclid-0.20.14/.cargo-checksum.json | 1 - third_party/rust/euclid-0.20.14/COPYRIGHT | 5 - third_party/rust/euclid-0.20.14/Cargo.toml | 44 - .../rust/euclid-0.20.14/LICENSE-APACHE | 201 -- third_party/rust/euclid-0.20.14/LICENSE-MIT | 25 - third_party/rust/euclid-0.20.14/README.md | 8 - third_party/rust/euclid-0.20.14/src/angle.rs | 316 --- .../rust/euclid-0.20.14/src/approxeq.rs | 42 - .../rust/euclid-0.20.14/src/approxord.rs | 44 - third_party/rust/euclid-0.20.14/src/box2d.rs | 828 ------ third_party/rust/euclid-0.20.14/src/box3d.rs | 901 ------ .../rust/euclid-0.20.14/src/homogen.rs | 229 -- third_party/rust/euclid-0.20.14/src/length.rs | 574 ---- third_party/rust/euclid-0.20.14/src/lib.rs | 117 - third_party/rust/euclid-0.20.14/src/macros.rs | 30 - .../rust/euclid-0.20.14/src/nonempty.rs | 250 -- third_party/rust/euclid-0.20.14/src/num.rs | 127 - third_party/rust/euclid-0.20.14/src/point.rs | 1988 -------------- third_party/rust/euclid-0.20.14/src/rect.rs | 908 ------- third_party/rust/euclid-0.20.14/src/rigid.rs | 285 -- .../rust/euclid-0.20.14/src/rotation.rs | 1026 ------- third_party/rust/euclid-0.20.14/src/scale.rs | 399 --- .../rust/euclid-0.20.14/src/side_offsets.rs | 438 --- third_party/rust/euclid-0.20.14/src/size.rs | 1718 ------------ .../rust/euclid-0.20.14/src/transform2d.rs | 827 ------ .../rust/euclid-0.20.14/src/transform3d.rs | 1440 ---------- .../rust/euclid-0.20.14/src/translation.rs | 824 ------ third_party/rust/euclid-0.20.14/src/trig.rs | 80 - third_party/rust/euclid-0.20.14/src/vector.rs | 2413 ----------------- 30 files changed, 9 insertions(+), 16106 deletions(-) delete mode 100644 third_party/rust/euclid-0.20.14/.cargo-checksum.json delete mode 100644 third_party/rust/euclid-0.20.14/COPYRIGHT delete mode 100644 third_party/rust/euclid-0.20.14/Cargo.toml delete mode 100644 third_party/rust/euclid-0.20.14/LICENSE-APACHE delete mode 100644 third_party/rust/euclid-0.20.14/LICENSE-MIT delete mode 100644 third_party/rust/euclid-0.20.14/README.md delete mode 100644 third_party/rust/euclid-0.20.14/src/angle.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/approxeq.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/approxord.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/box2d.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/box3d.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/homogen.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/length.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/lib.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/macros.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/nonempty.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/num.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/point.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/rect.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/rigid.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/rotation.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/scale.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/side_offsets.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/size.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/transform2d.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/transform3d.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/translation.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/trig.rs delete mode 100644 third_party/rust/euclid-0.20.14/src/vector.rs diff --git a/Cargo.lock b/Cargo.lock index 45ab30d2a1c9..7a0d07ff2753 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1294,15 +1294,6 @@ dependencies = [ "failure", ] -[[package]] -name = "euclid" -version = "0.20.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb7ef65b3777a325d1eeefefab5b6d4959da54747e33bd6258e789640f307ad" -dependencies = [ - "num-traits", -] - [[package]] name = "euclid" version = "0.22.0" @@ -2789,7 +2780,7 @@ version = "0.0.1" dependencies = [ "app_units", "cssparser", - "euclid 0.22.0", + "euclid", "hashglobe", "selectors", "servo_arc", @@ -3538,7 +3529,7 @@ dependencies = [ name = "peek-poke" version = "0.2.0" dependencies = [ - "euclid 0.22.0", + "euclid", "peek-poke-derive 0.2.1", ] @@ -3702,7 +3693,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2211e7ccc9b6260779dd9bad59f7b10889d6361974623b9e405afd7e7e764654" dependencies = [ "binary-space-partition", - "euclid 0.22.0", + "euclid", "log", "num-traits", ] @@ -4630,7 +4621,7 @@ dependencies = [ "byteorder", "cssparser", "derive_more", - "euclid 0.22.0", + "euclid", "fallible", "fxhash", "hashbrown", @@ -4693,7 +4684,7 @@ dependencies = [ "app_units", "bitflags", "cssparser", - "euclid 0.20.14", + "euclid", "lazy_static", "malloc_size_of", "malloc_size_of_derive", @@ -5549,7 +5540,7 @@ dependencies = [ "core-text", "cstr", "dwrote", - "euclid 0.22.0", + "euclid", "freetype", "fxhash", "gleam", @@ -5587,7 +5578,7 @@ dependencies = [ "core-graphics", "crossbeam-channel", "derive_more", - "euclid 0.22.0", + "euclid", "malloc_size_of_derive", "peek-poke 0.2.0", "serde", @@ -5607,7 +5598,7 @@ dependencies = [ "core-graphics", "dirs", "dwrote", - "euclid 0.22.0", + "euclid", "foreign-types", "fxhash", "gleam", @@ -5775,7 +5766,7 @@ name = "wr_malloc_size_of" version = "0.0.1" dependencies = [ "app_units", - "euclid 0.22.0", + "euclid", ] [[package]] diff --git a/third_party/rust/euclid-0.20.14/.cargo-checksum.json b/third_party/rust/euclid-0.20.14/.cargo-checksum.json deleted file mode 100644 index 16ae20b36f3b..000000000000 --- a/third_party/rust/euclid-0.20.14/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"430f53fbae7381f12155805f713f9b9bb08a9e9ffff3a3f4c887163fb4521e7d","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/angle.rs":"b4b17c16bd135914a6e2ebad54b9cbb8ea475d5992bcb75c397b7813b6f7b8dd","src/approxeq.rs":"8ad9ab7336e1924b0543eb46f975367f4388a4dda91839b7cda7d21eec8991fb","src/approxord.rs":"f1b11ea7603b3dddb0002c7ded934816f5a8bb108e150028b49595b8e3382ac1","src/box2d.rs":"0f7ef877183e25e6b769fc91a0d814e0992b0e6d1c16df415ebbd364d2fd2cf7","src/box3d.rs":"54d6e59622957e784e611a23da9612671a530c61cd364313024d750f953a7564","src/homogen.rs":"3aa960fae9b817057013183f543cf2adc042f5867ece1ee78607e2c46bdbcfed","src/length.rs":"67ef01cfba3f70143c57afda39c8bf9990f29111a031a238de328753ccc2c8a4","src/lib.rs":"d0f1ddda70d8bf3913d9c2c49949dd21ced500cbc0c09d7d08c0aa1570f63df5","src/macros.rs":"3b475e84d00cceee6c7e96e9f2c97ba15d8dc7f4094efb82c5ed10bd60d86a64","src/nonempty.rs":"be5ac81321390d71447607de01811cc6420bcd48aa5274f7a298a99674621846","src/num.rs":"2478501dbe545a73a8b964f4713987b86df8ff0af3d1aba0571cbd00a4e9cbaa","src/point.rs":"6d07046f27dd7a18ba8db8988de82c67cfcdd1b8895a70730123338574e47d39","src/rect.rs":"1391359581ba891a35f390ec3900f1e34ce1e4dc5608fe27662655d3bf443d45","src/rigid.rs":"a9717aac4d254299dc3a60a2a32c5c5309044136702d96030533f7639adeb467","src/rotation.rs":"6cfc7f74a90236c53fa55b83eae373146f7b37a8c400f8f820ebfdbcca245245","src/scale.rs":"197d2d4ba5f6a4fe8d5f0b2b6684499a66727129ad27474b85b0d1ffecd38f05","src/side_offsets.rs":"11b84a7dc620cdf2f1877c82b534947ae337734b9075d34e61306be7f458d127","src/size.rs":"5d5703b464207ff362da650008972ca67fbbc79f7193d0d2a1c7a7873221c24c","src/transform2d.rs":"6b2ff21021d7aa1628585650cc66f18f1a5a6aff5f335ae1ec4f63616c54b3cf","src/transform3d.rs":"83ac57ab5a077127fa7eba401dae2e67f2c129a05081b5b5ed09a2166fa9703f","src/translation.rs":"7847306a3a081559f2839baff9d622e58c63fdcb3981c5ef410b6a8eb8e13ab8","src/trig.rs":"ab09a8503d04ac1d0d6848d074ac18a22d324184e5bb186bbd4287c977894886","src/vector.rs":"f895e029e273defac88b47fef4fb27f627553fb05b8d173cf8f75e28818cd580"},"package":"2bb7ef65b3777a325d1eeefefab5b6d4959da54747e33bd6258e789640f307ad"} \ No newline at end of file diff --git a/third_party/rust/euclid-0.20.14/COPYRIGHT b/third_party/rust/euclid-0.20.14/COPYRIGHT deleted file mode 100644 index 8b7291ad281c..000000000000 --- a/third_party/rust/euclid-0.20.14/COPYRIGHT +++ /dev/null @@ -1,5 +0,0 @@ -Licensed under the Apache License, Version 2.0 or the MIT license -, at your -option. All files in the project carrying such notice may not be -copied, modified, or distributed except according to those terms. diff --git a/third_party/rust/euclid-0.20.14/Cargo.toml b/third_party/rust/euclid-0.20.14/Cargo.toml deleted file mode 100644 index a19e46fbfad5..000000000000 --- a/third_party/rust/euclid-0.20.14/Cargo.toml +++ /dev/null @@ -1,44 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -edition = "2018" -name = "euclid" -version = "0.20.14" -authors = ["The Servo Project Developers"] -description = "Geometry primitives" -documentation = "https://docs.rs/euclid/" -keywords = ["matrix", "vector", "linear-algebra", "geometry"] -categories = ["science"] -license = "MIT / Apache-2.0" -repository = "https://github.com/servo/euclid" -[dependencies.mint] -version = "0.5.1" -optional = true - -[dependencies.num-traits] -version = "0.2.10" -default-features = false - -[dependencies.serde] -version = "1.0" -features = ["serde_derive"] -optional = true -default-features = false -[dev-dependencies.serde_test] -version = "1.0" - -[features] -default = ["std"] -libm = ["num-traits/libm"] -std = ["num-traits/std"] -unstable = [] diff --git a/third_party/rust/euclid-0.20.14/LICENSE-APACHE b/third_party/rust/euclid-0.20.14/LICENSE-APACHE deleted file mode 100644 index 16fe87b06e80..000000000000 --- a/third_party/rust/euclid-0.20.14/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - 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. diff --git a/third_party/rust/euclid-0.20.14/LICENSE-MIT b/third_party/rust/euclid-0.20.14/LICENSE-MIT deleted file mode 100644 index 807526f57f3a..000000000000 --- a/third_party/rust/euclid-0.20.14/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -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. diff --git a/third_party/rust/euclid-0.20.14/README.md b/third_party/rust/euclid-0.20.14/README.md deleted file mode 100644 index 13b488da9f69..000000000000 --- a/third_party/rust/euclid-0.20.14/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# 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) diff --git a/third_party/rust/euclid-0.20.14/src/angle.rs b/third_party/rust/euclid-0.20.14/src/angle.rs deleted file mode 100644 index a0a2f334b10c..000000000000 --- a/third_party/rust/euclid-0.20.14/src/angle.rs +++ /dev/null @@ -1,316 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use crate::approxeq::ApproxEq; -use crate::trig::Trig; -use core::cmp::{Eq, PartialEq}; -use core::hash::Hash; -use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign}; -use num_traits::{Float, FloatConst, NumCast, One, Zero}; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -/// An angle in radians -#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Angle { - pub radians: T, -} - -impl Angle { - #[inline] - pub fn radians(radians: T) -> Self { - Angle { radians } - } - - #[inline] - pub fn get(self) -> T { - self.radians - } -} - -impl Angle -where - T: Trig, -{ - #[inline] - pub fn degrees(deg: T) -> Self { - Angle { - radians: T::degrees_to_radians(deg), - } - } - - #[inline] - pub fn to_degrees(self) -> T { - T::radians_to_degrees(self.radians) - } -} - -impl Angle -where - T: Rem + Sub + Add + Zero + FloatConst + PartialOrd + Copy, -{ - /// Returns this angle in the [0..2*PI[ range. - pub fn positive(&self) -> Self { - let two_pi = T::PI() + T::PI(); - let mut a = self.radians % two_pi; - if a < T::zero() { - a = a + two_pi; - } - Angle::radians(a) - } - - /// Returns this angle in the ]-PI..PI] range. - pub fn signed(&self) -> Self { - Angle::pi() - (Angle::pi() - *self).positive() - } -} - -impl Angle -where - T: Rem - + Mul - + Sub - + Add - + One - + FloatConst - + Copy, -{ - /// Returns the shortest signed angle between two angles. - /// - /// Takes wrapping and signs into account. - pub fn angle_to(&self, to: Self) -> Self { - let two = T::one() + T::one(); - let max = T::PI() * two; - let d = (to.radians - self.radians) % max; - - Angle::radians(two * d % max - d) - } - - /// Linear interpolation between two angles, using the shortest path. - pub fn lerp(&self, other: Self, t: T) -> Self { - *self + self.angle_to(other) * t - } -} - -impl Angle -where - T: Float, -{ - /// Returns (sin(self), cos(self)). - pub fn sin_cos(self) -> (T, T) { - self.radians.sin_cos() - } -} - -impl Angle -where - T: Zero, -{ - pub fn zero() -> Self { - Angle::radians(T::zero()) - } -} - -impl Angle -where - T: FloatConst + Add, -{ - pub fn pi() -> Self { - Angle::radians(T::PI()) - } - - pub fn two_pi() -> Self { - Angle::radians(T::PI() + T::PI()) - } - - pub fn frac_pi_2() -> Self { - Angle::radians(T::FRAC_PI_2()) - } - - pub fn frac_pi_3() -> Self { - Angle::radians(T::FRAC_PI_3()) - } - - pub fn frac_pi_4() -> Self { - Angle::radians(T::FRAC_PI_4()) - } -} - -impl Angle -where - T: NumCast + Copy, -{ - /// Cast from one numeric representation to another. - #[inline] - pub fn cast(&self) -> Angle { - self.try_cast().unwrap() - } - - /// Fallible cast from one numeric representation to another. - pub fn try_cast(&self) -> Option> { - NumCast::from(self.radians).map(|radians| Angle { radians }) - } - - // Convenience functions for common casts. - - /// Cast angle to `f32`. - #[inline] - pub fn to_f32(&self) -> Angle { - self.cast() - } - - /// Cast angle `f64`. - #[inline] - pub fn to_f64(&self) -> Angle { - self.cast() - } -} - -impl> Add for Angle { - type Output = Angle; - fn add(self, other: Angle) -> Angle { - Angle::radians(self.radians + other.radians) - } -} - -impl> AddAssign for Angle { - fn add_assign(&mut self, other: Angle) { - self.radians += other.radians; - } -} - -impl> Sub> for Angle { - type Output = Angle; - fn sub(self, other: Angle) -> ::Output { - Angle::radians(self.radians - other.radians) - } -} - -impl> SubAssign for Angle { - fn sub_assign(&mut self, other: Angle) { - self.radians -= other.radians; - } -} - -impl> Div> for Angle { - type Output = T; - #[inline] - fn div(self, other: Angle) -> T { - self.radians / other.radians - } -} - -impl> Div for Angle { - type Output = Angle; - #[inline] - fn div(self, factor: T) -> Angle { - Angle::radians(self.radians / factor) - } -} - -impl> DivAssign for Angle { - fn div_assign(&mut self, factor: T) { - self.radians /= factor; - } -} - -impl> Mul for Angle { - type Output = Angle; - #[inline] - fn mul(self, factor: T) -> Angle { - Angle::radians(self.radians * factor) - } -} - -impl> MulAssign for Angle { - fn mul_assign(&mut self, factor: T) { - self.radians *= factor; - } -} - -impl> Neg for Angle { - type Output = Self; - fn neg(self) -> Self { - Angle::radians(-self.radians) - } -} - -impl> ApproxEq for Angle { - #[inline] - fn approx_epsilon() -> T { - T::approx_epsilon() - } - - #[inline] - fn approx_eq_eps(&self, other: &Angle, approx_epsilon: &T) -> bool { - self.radians.approx_eq_eps(&other.radians, approx_epsilon) - } -} - -#[test] -fn wrap_angles() { - use core::f32::consts::{FRAC_PI_2, PI}; - - assert!(Angle::radians(0.0).positive().approx_eq(&Angle::zero())); - assert!(Angle::radians(FRAC_PI_2) - .positive() - .approx_eq(&Angle::frac_pi_2())); - assert!(Angle::radians(-FRAC_PI_2) - .positive() - .approx_eq(&Angle::radians(3.0 * FRAC_PI_2))); - assert!(Angle::radians(3.0 * FRAC_PI_2) - .positive() - .approx_eq(&Angle::radians(3.0 * FRAC_PI_2))); - assert!(Angle::radians(5.0 * FRAC_PI_2) - .positive() - .approx_eq(&Angle::frac_pi_2())); - assert!(Angle::radians(2.0 * PI) - .positive() - .approx_eq(&Angle::zero())); - assert!(Angle::radians(-2.0 * PI) - .positive() - .approx_eq(&Angle::zero())); - assert!(Angle::radians(PI).positive().approx_eq(&Angle::pi())); - assert!(Angle::radians(-PI).positive().approx_eq(&Angle::pi())); - - assert!(Angle::radians(FRAC_PI_2) - .signed() - .approx_eq(&Angle::frac_pi_2())); - assert!(Angle::radians(3.0 * FRAC_PI_2) - .signed() - .approx_eq(&-Angle::frac_pi_2())); - assert!(Angle::radians(5.0 * FRAC_PI_2) - .signed() - .approx_eq(&Angle::frac_pi_2())); - assert!(Angle::radians(2.0 * PI).signed().approx_eq(&Angle::zero())); - assert!(Angle::radians(-2.0 * PI).signed().approx_eq(&Angle::zero())); - assert!(Angle::radians(-PI).signed().approx_eq(&Angle::pi())); - assert!(Angle::radians(PI).signed().approx_eq(&Angle::pi())); -} - -#[test] -fn lerp() { - type A = Angle; - - let a = A::radians(1.0); - let b = A::radians(2.0); - assert!(a.lerp(b, 0.25).approx_eq(&Angle::radians(1.25))); - assert!(a.lerp(b, 0.5).approx_eq(&Angle::radians(1.5))); - assert!(a.lerp(b, 0.75).approx_eq(&Angle::radians(1.75))); - assert!(a - .lerp(b + A::two_pi(), 0.75) - .approx_eq(&Angle::radians(1.75))); - assert!(a - .lerp(b - A::two_pi(), 0.75) - .approx_eq(&Angle::radians(1.75))); - assert!(a - .lerp(b + A::two_pi() * 5.0, 0.75) - .approx_eq(&Angle::radians(1.75))); -} diff --git a/third_party/rust/euclid-0.20.14/src/approxeq.rs b/third_party/rust/euclid-0.20.14/src/approxeq.rs deleted file mode 100644 index 911f5268a4fc..000000000000 --- a/third_party/rust/euclid-0.20.14/src/approxeq.rs +++ /dev/null @@ -1,42 +0,0 @@ -// 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 or the MIT license -// , 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 { - /// Default epsilon value - fn approx_epsilon() -> Eps; - - /// Returns `true` is this object is approximately equal to the other one, using - /// a provided epsilon value. - fn approx_eq_eps(&self, other: &Self, approx_epsilon: &Eps) -> bool; - - /// Returns `true` is this object is approximately equal to the other one, using - /// the `approx_epsilon()` epsilon value. - fn approx_eq(&self, other: &Self) -> bool { - self.approx_eq_eps(other, &Self::approx_epsilon()) - } -} - -macro_rules! approx_eq { - ($ty:ty, $eps:expr) => { - impl ApproxEq<$ty> for $ty { - #[inline] - fn approx_epsilon() -> $ty { - $eps - } - #[inline] - fn approx_eq_eps(&self, other: &$ty, approx_epsilon: &$ty) -> bool { - num_traits::Float::abs(*self - *other) < *approx_epsilon - } - } - }; -} - -approx_eq!(f32, 1.0e-6); -approx_eq!(f64, 1.0e-6); diff --git a/third_party/rust/euclid-0.20.14/src/approxord.rs b/third_party/rust/euclid-0.20.14/src/approxord.rs deleted file mode 100644 index db6207da39a2..000000000000 --- a/third_party/rust/euclid-0.20.14/src/approxord.rs +++ /dev/null @@ -1,44 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Utilities for testing approximate ordering - especially true for -//! floating point types, where NaN's cannot be ordered. - -pub fn min(x: T, y: T) -> T { - if x <= y { - x - } else { - y - } -} - -pub fn max(x: T, y: T) -> T { - if x >= y { - x - } else { - y - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_min() { - assert!(min(0u32, 1u32) == 0u32); - assert!(min(-1.0f32, 0.0f32) == -1.0f32); - } - - #[test] - fn test_max() { - assert!(max(0u32, 1u32) == 1u32); - assert!(max(-1.0f32, 0.0f32) == 0.0f32); - } -} diff --git a/third_party/rust/euclid-0.20.14/src/box2d.rs b/third_party/rust/euclid-0.20.14/src/box2d.rs deleted file mode 100644 index 349ef49cbef4..000000000000 --- a/third_party/rust/euclid-0.20.14/src/box2d.rs +++ /dev/null @@ -1,828 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::UnknownUnit; -use crate::approxord::{max, min}; -use crate::nonempty::NonEmpty; -use crate::num::*; -use crate::point::{point2, Point2D}; -use crate::rect::Rect; -use crate::scale::Scale; -use crate::side_offsets::SideOffsets2D; -use crate::size::Size2D; -use crate::vector::{vec2, Vector2D}; - -use num_traits::NumCast; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -use core::borrow::Borrow; -use core::cmp::PartialOrd; -use core::fmt; -use core::hash::{Hash, Hasher}; -use core::ops::{Add, Div, DivAssign, Mul, MulAssign, Sub}; - -/// An axis aligned rectangle represented by its minimum and maximum coordinates. -/// -/// That struct is similar to the [`Rect`] struct, but stores rectangle as two corners -/// instead of origin point and size. Such representation has several advantages over -/// [`Rect`] representation: -/// - Several operations are more efficient with `Box2D`, including [`intersection`], -/// [`union`], and point-in-rect. -/// - The representation is more symmetric, since it stores two quantities of the -/// same kind (two points) rather than a point and a dimension (width/height). -/// - The representation is less susceptible to overflow. With [`Rect`], computation -/// of second point can overflow for a large range of values of origin and size. -/// However, with `Box2D`, computation of [`size`] cannot overflow if the coordinates -/// are signed and the resulting size is unsigned. -/// -/// A known disadvantage of `Box2D` is that translating the rectangle requires translating -/// both points, whereas translating [`Rect`] only requires translating one point. -/// -/// [`Rect`]: struct.Rect.html -/// [`intersection`]: #method.intersection -/// [`union`]: #method.union -/// [`size`]: #method.size -#[repr(C)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "serde", - serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>")) -)] -pub struct Box2D { - pub min: Point2D, - pub max: Point2D, -} - -impl Hash for Box2D { - fn hash(&self, h: &mut H) { - self.min.hash(h); - self.max.hash(h); - } -} - -impl Copy for Box2D {} - -impl Clone for Box2D { - fn clone(&self) -> Self { - Self::new(self.min.clone(), self.max.clone()) - } -} - -impl PartialEq for Box2D { - fn eq(&self, other: &Self) -> bool { - self.min.eq(&other.min) && self.max.eq(&other.max) - } -} - -impl Eq for Box2D {} - -impl fmt::Debug for Box2D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Box2D") - .field(&self.min) - .field(&self.max) - .finish() - } -} - -impl fmt::Display for Box2D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Box2D(")?; - fmt::Display::fmt(&self.min, f)?; - write!(f, ", ")?; - fmt::Display::fmt(&self.max, f)?; - write!(f, ")") - } -} - -impl Box2D { - /// Constructor. - #[inline] - pub const fn new(min: Point2D, max: Point2D) -> Self { - Box2D { min, max } - } -} - -impl Box2D -where - T: PartialOrd, -{ - /// Returns true if the box has a negative area. - /// - /// The common interpretation for a negative box is to consider it empty. It can be obtained - /// by calculating the intersection of two boxes that do not intersect. - #[inline] - pub fn is_negative(&self) -> bool { - self.max.x < self.min.x || self.max.y < self.min.y - } - - /// Returns true if the size is zero or negative. - #[inline] - pub fn is_empty_or_negative(&self) -> bool { - !(self.max.x > self.min.x && self.max.y > self.min.y) - } - - /// Returns `true` if the two boxes intersect. - #[inline] - pub fn intersects(&self, other: &Self) -> bool { - self.min.x < other.max.x - && self.max.x > other.min.x - && self.min.y < other.max.y - && self.max.y > other.min.y - } - - /// Returns `true` if this box contains the point. Points are considered - /// in the box if they are on the front, left or top faces, but outside if they - /// are on the back, right or bottom faces. - #[inline] - pub fn contains(&self, p: Point2D) -> bool { - self.min.x <= p.x && p.x < self.max.x && self.min.y <= p.y && p.y < self.max.y - } - - /// Returns `true` if this box contains the interior of the other box. Always - /// returns `true` if other is empty, and always returns `false` if other is - /// nonempty but this box is empty. - #[inline] - pub fn contains_box(&self, other: &Self) -> bool { - other.is_empty_or_negative() - || (self.min.x <= other.min.x - && other.max.x <= self.max.x - && self.min.y <= other.min.y - && other.max.y <= self.max.y) - } -} - -impl Box2D -where - T: Copy + PartialOrd, -{ - #[inline] - pub fn to_non_empty(&self) -> Option> { - if self.is_empty_or_negative() { - return None; - } - - Some(NonEmpty(*self)) - } - /// Computes the intersection of two boxes. - /// - /// The result is a negative box if the boxes do not intersect. - #[inline] - pub fn intersection(&self, other: &Self) -> Self { - Box2D { - min: point2(max(self.min.x, other.min.x), max(self.min.y, other.min.y)), - max: point2(min(self.max.x, other.max.x), min(self.max.y, other.max.y)), - } - } - - /// Computes the intersection of two boxes, returning `None` if the boxes do not intersect. - #[inline] - pub fn try_intersection(&self, other: &Self) -> Option> { - let intersection = self.intersection(other); - - if intersection.is_negative() { - return None; - } - - Some(NonEmpty(intersection)) - } - - #[inline] - pub fn union(&self, other: &Self) -> Self { - Box2D { - min: point2(min(self.min.x, other.min.x), min(self.min.y, other.min.y)), - max: point2(max(self.max.x, other.max.x), max(self.max.y, other.max.y)), - } - } -} - -impl Box2D -where - T: Copy + Add, -{ - /// Returns the same box, translated by a vector. - #[inline] - pub fn translate(&self, by: Vector2D) -> Self { - Box2D { - min: self.min + by, - max: self.max + by, - } - } -} - -impl Box2D -where - T: Copy + Sub, -{ - #[inline] - pub fn size(&self) -> Size2D { - (self.max - self.min).to_size() - } - - #[inline] - pub fn width(&self) -> T { - self.max.x - self.min.x - } - - #[inline] - pub fn height(&self) -> T { - self.max.y - self.min.y - } - - #[inline] - pub fn to_rect(&self) -> Rect { - Rect { - origin: self.min, - size: self.size(), - } - } -} - -impl Box2D -where - T: Copy + Add + Sub, -{ - /// Inflates the box by the specified sizes on each side respectively. - #[inline] - #[must_use] - pub fn inflate(&self, width: T, height: T) -> Self { - Box2D { - min: point2(self.min.x - width, self.min.y - height), - max: point2(self.max.x + width, self.max.y + height), - } - } - - /// Calculate the size and position of an inner box. - /// - /// Subtracts the side offsets from all sides. The horizontal, vertical - /// and applicate offsets must not be larger than the original side length. - pub fn inner_box(&self, offsets: SideOffsets2D) -> Self { - Box2D { - min: self.min + vec2(offsets.left, offsets.top), - max: self.max - vec2(offsets.right, offsets.bottom), - } - } - - /// Calculate the b and position of an outer box. - /// - /// Add the offsets to all sides. The expanded box is returned. - pub fn outer_box(&self, offsets: SideOffsets2D) -> Self { - Box2D { - min: self.min - vec2(offsets.left, offsets.top), - max: self.max + vec2(offsets.right, offsets.bottom), - } - } -} - -impl Box2D -where - T: Copy + Zero + PartialOrd, -{ - /// Creates a Box2D of the given size, at offset zero. - #[inline] - pub fn from_size(size: Size2D) -> Self { - let zero = Point2D::zero(); - let point = size.to_vector().to_point(); - Box2D::from_points(&[zero, point]) - } - - /// Returns the smallest box containing all of the provided points. - pub fn from_points(points: I) -> Self - where - I: IntoIterator, - I::Item: Borrow>, - { - let mut points = points.into_iter(); - - let (mut min_x, mut min_y) = match points.next() { - Some(first) => first.borrow().to_tuple(), - None => return Box2D::zero(), - }; - - let (mut max_x, mut max_y) = (min_x, min_y); - for point in points { - let p = point.borrow(); - if p.x < min_x { - min_x = p.x - } - if p.x > max_x { - max_x = p.x - } - if p.y < min_y { - min_y = p.y - } - if p.y > max_y { - max_y = p.y - } - } - - Box2D { - min: point2(min_x, min_y), - max: point2(max_x, max_y), - } - } -} - -impl Box2D -where - T: Copy + One + Add + Sub + Mul, -{ - /// Linearly interpolate between this box and another box. - #[inline] - pub fn lerp(&self, other: Self, t: T) -> Self { - Self::new(self.min.lerp(other.min, t), self.max.lerp(other.max, t)) - } -} - -impl Box2D -where - T: Copy + One + Add + Div, -{ - pub fn center(&self) -> Point2D { - let two = T::one() + T::one(); - (self.min + self.max.to_vector()) / two - } -} - -impl Box2D -where - T: Copy + Mul + Sub, -{ - #[inline] - pub fn area(&self) -> T { - let size = self.size(); - size.width * size.height - } -} - -impl Box2D -where - T: Zero, -{ - /// Constructor, setting all sides to zero. - pub fn zero() -> Self { - Box2D::new(Point2D::zero(), Point2D::zero()) - } -} - -impl Box2D -where - T: PartialEq, -{ - /// Returns true if the size is zero. - #[inline] - pub fn is_empty(&self) -> bool { - self.min.x == self.max.x || self.min.y == self.max.y - } -} - -impl Mul for Box2D { - type Output = Box2D; - - #[inline] - fn mul(self, scale: T) -> Self::Output { - Box2D::new(self.min * scale.clone(), self.max * scale) - } -} - -impl MulAssign for Box2D { - #[inline] - fn mul_assign(&mut self, scale: T) { - *self *= Scale::new(scale); - } -} - -impl Div for Box2D { - type Output = Box2D; - - #[inline] - fn div(self, scale: T) -> Self::Output { - Box2D::new(self.min / scale.clone(), self.max / scale) - } -} - -impl DivAssign for Box2D { - #[inline] - fn div_assign(&mut self, scale: T) { - *self /= Scale::new(scale); - } -} - -impl Mul> for Box2D { - type Output = Box2D; - - #[inline] - fn mul(self, scale: Scale) -> Self::Output { - Box2D::new(self.min * scale.clone(), self.max * scale) - } -} - -impl MulAssign> for Box2D { - #[inline] - fn mul_assign(&mut self, scale: Scale) { - self.min *= scale.clone(); - self.max *= scale; - } -} - -impl Div> for Box2D { - type Output = Box2D; - - #[inline] - fn div(self, scale: Scale) -> Self::Output { - Box2D::new(self.min / scale.clone(), self.max / scale) - } -} - -impl DivAssign> for Box2D { - #[inline] - fn div_assign(&mut self, scale: Scale) { - self.min /= scale.clone(); - self.max /= scale; - } -} - -impl Box2D -where - T: Copy, -{ - /// Drop the units, preserving only the numeric value. - #[inline] - pub fn to_untyped(&self) -> Box2D { - Box2D::new(self.min.to_untyped(), self.max.to_untyped()) - } - - /// Tag a unitless value with units. - #[inline] - pub fn from_untyped(c: &Box2D) -> Box2D { - Box2D::new(Point2D::from_untyped(c.min), Point2D::from_untyped(c.max)) - } - - /// Cast the unit - #[inline] - pub fn cast_unit(&self) -> Box2D { - Box2D::new(self.min.cast_unit(), self.max.cast_unit()) - } - - #[inline] - pub fn scale(&self, x: S, y: S) -> Self - where - T: Mul, - { - Box2D { - min: point2(self.min.x * x, self.min.y * y), - max: point2(self.max.x * x, self.max.y * y), - } - } -} - -impl Box2D { - /// 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. - #[inline] - pub fn cast(&self) -> Box2D { - Box2D::new(self.min.cast(), self.max.cast()) - } - - /// Fallible 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 try_cast(&self) -> Option> { - match (self.min.try_cast(), self.max.try_cast()) { - (Some(a), Some(b)) => Some(Box2D::new(a, b)), - _ => None, - } - } - - // Convenience functions for common casts - - /// Cast into an `f32` box. - #[inline] - pub fn to_f32(&self) -> Box2D { - self.cast() - } - - /// Cast into an `f64` box. - #[inline] - pub fn to_f64(&self) -> Box2D { - self.cast() - } - - /// Cast into an `usize` box, truncating decimals if any. - /// - /// When casting from floating point boxes, it is worth considering whether - /// to `round()`, `round_in()` or `round_out()` before the cast in order to - /// obtain the desired conversion behavior. - #[inline] - pub fn to_usize(&self) -> Box2D { - self.cast() - } - - /// Cast into an `u32` box, truncating decimals if any. - /// - /// When casting from floating point boxes, it is worth considering whether - /// to `round()`, `round_in()` or `round_out()` before the cast in order to - /// obtain the desired conversion behavior. - #[inline] - pub fn to_u32(&self) -> Box2D { - self.cast() - } - - /// Cast into an `i32` box, truncating decimals if any. - /// - /// When casting from floating point boxes, it is worth considering whether - /// to `round()`, `round_in()` or `round_out()` before the cast in order to - /// obtain the desired conversion behavior. - #[inline] - pub fn to_i32(&self) -> Box2D { - self.cast() - } - - /// Cast into an `i64` box, truncating decimals if any. - /// - /// When casting from floating point boxes, it is worth considering whether - /// to `round()`, `round_in()` or `round_out()` before the cast in order to - /// obtain the desired conversion behavior. - #[inline] - pub fn to_i64(&self) -> Box2D { - self.cast() - } -} - -impl Box2D -where - T: Round, -{ - /// Return a box with edges rounded to integer coordinates, such that - /// the returned box has the same set of pixel centers as the original - /// one. - /// Values equal to 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 { - Box2D::new(self.min.round(), self.max.round()) - } -} - -impl Box2D -where - T: Floor + Ceil, -{ - /// Return a box with faces/edges rounded to integer coordinates, such that - /// the original box contains the resulting box. - #[must_use] - pub fn round_in(&self) -> Self { - let min = self.min.ceil(); - let max = self.max.floor(); - Box2D { min, max } - } - - /// Return a box with faces/edges rounded to integer coordinates, such that - /// the original box is contained in the resulting box. - #[must_use] - pub fn round_out(&self) -> Self { - let min = self.min.floor(); - let max = self.max.ceil(); - Box2D { min, max } - } -} - -impl From> for Box2D -where - T: Copy + Zero + PartialOrd, -{ - fn from(b: Size2D) -> Self { - Self::from_size(b) - } -} - -#[cfg(test)] -mod tests { - use crate::default::Box2D; - use crate::side_offsets::SideOffsets2D; - use crate::{point2, size2, vec2, Point2D}; - //use super::*; - - #[test] - fn test_size() { - let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0)); - assert_eq!(b.size().width, 20.0); - assert_eq!(b.size().height, 20.0); - } - - #[test] - fn test_width_height() { - let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0)); - assert!(b.width() == 20.0); - assert!(b.height() == 20.0); - } - - #[test] - fn test_center() { - let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0)); - assert_eq!(b.center(), Point2D::zero()); - } - - #[test] - fn test_area() { - let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0)); - assert_eq!(b.area(), 400.0); - } - - #[test] - fn test_from_points() { - let b = Box2D::from_points(&[point2(50.0, 160.0), point2(100.0, 25.0)]); - assert_eq!(b.min, point2(50.0, 25.0)); - assert_eq!(b.max, point2(100.0, 160.0)); - } - - #[test] - fn test_round_in() { - let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round_in(); - assert_eq!(b.min.x, -25.0); - assert_eq!(b.min.y, -40.0); - assert_eq!(b.max.x, 60.0); - assert_eq!(b.max.y, 36.0); - } - - #[test] - fn test_round_out() { - let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round_out(); - assert_eq!(b.min.x, -26.0); - assert_eq!(b.min.y, -41.0); - assert_eq!(b.max.x, 61.0); - assert_eq!(b.max.y, 37.0); - } - - #[test] - fn test_round() { - let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round(); - assert_eq!(b.min.x, -26.0); - assert_eq!(b.min.y, -40.0); - assert_eq!(b.max.x, 60.0); - assert_eq!(b.max.y, 37.0); - } - - #[test] - fn test_from_size() { - let b = Box2D::from_size(size2(30.0, 40.0)); - assert!(b.min == Point2D::zero()); - assert!(b.size().width == 30.0); - assert!(b.size().height == 40.0); - } - - #[test] - fn test_inner_box() { - let b = Box2D::from_points(&[point2(50.0, 25.0), point2(100.0, 160.0)]); - let b = b.inner_box(SideOffsets2D::new(10.0, 20.0, 5.0, 10.0)); - assert_eq!(b.max.x, 80.0); - assert_eq!(b.max.y, 155.0); - assert_eq!(b.min.x, 60.0); - assert_eq!(b.min.y, 35.0); - } - - #[test] - fn test_outer_box() { - let b = Box2D::from_points(&[point2(50.0, 25.0), point2(100.0, 160.0)]); - let b = b.outer_box(SideOffsets2D::new(10.0, 20.0, 5.0, 10.0)); - assert_eq!(b.max.x, 120.0); - assert_eq!(b.max.y, 165.0); - assert_eq!(b.min.x, 40.0); - assert_eq!(b.min.y, 15.0); - } - - #[test] - fn test_translate() { - let size = size2(15.0, 15.0); - let mut center = (size / 2.0).to_vector().to_point(); - let b = Box2D::from_size(size); - assert_eq!(b.center(), center); - let translation = vec2(10.0, 2.5); - let b = b.translate(translation); - center += translation; - assert_eq!(b.center(), center); - assert_eq!(b.max.x, 25.0); - assert_eq!(b.max.y, 17.5); - assert_eq!(b.min.x, 10.0); - assert_eq!(b.min.y, 2.5); - } - - #[test] - fn test_union() { - let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(0.0, 20.0)]); - let b2 = Box2D::from_points(&[point2(0.0, 20.0), point2(20.0, -20.0)]); - let b = b1.union(&b2); - assert_eq!(b.max.x, 20.0); - assert_eq!(b.max.y, 20.0); - assert_eq!(b.min.x, -20.0); - assert_eq!(b.min.y, -20.0); - } - - #[test] - fn test_intersects() { - let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]); - let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]); - assert!(b1.intersects(&b2)); - } - - #[test] - fn test_intersection() { - let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]); - let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]); - let b = b1.intersection(&b2); - assert_eq!(b.max.x, 10.0); - assert_eq!(b.max.y, 20.0); - assert_eq!(b.min.x, -10.0); - assert_eq!(b.min.y, -20.0); - } - - #[test] - fn test_try_intersection() { - let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]); - let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]); - assert!(b1.try_intersection(&b2).is_some()); - - let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(-10.0, 20.0)]); - let b2 = Box2D::from_points(&[point2(10.0, 20.0), point2(15.0, -20.0)]); - assert!(b1.try_intersection(&b2).is_none()); - } - - #[test] - fn test_scale() { - let b = Box2D::from_points(&[point2(-10.0, -10.0), point2(10.0, 10.0)]); - let b = b.scale(0.5, 0.5); - assert_eq!(b.max.x, 5.0); - assert_eq!(b.max.y, 5.0); - assert_eq!(b.min.x, -5.0); - assert_eq!(b.min.y, -5.0); - } - - #[test] - fn test_lerp() { - let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(-10.0, -10.0)]); - let b2 = Box2D::from_points(&[point2(10.0, 10.0), point2(20.0, 20.0)]); - let b = b1.lerp(b2, 0.5); - assert_eq!(b.center(), Point2D::zero()); - assert_eq!(b.size().width, 10.0); - assert_eq!(b.size().height, 10.0); - } - - #[test] - fn test_contains() { - let b = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]); - assert!(b.contains(point2(-15.3, 10.5))); - } - - #[test] - fn test_contains_box() { - let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]); - let b2 = Box2D::from_points(&[point2(-14.3, -16.5), point2(6.7, 17.6)]); - assert!(b1.contains_box(&b2)); - } - - #[test] - fn test_inflate() { - let b = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]); - let b = b.inflate(10.0, 5.0); - assert_eq!(b.size().width, 60.0); - assert_eq!(b.size().height, 50.0); - assert_eq!(b.center(), Point2D::zero()); - } - - #[test] - fn test_is_empty() { - for i in 0..2 { - let mut coords_neg = [-20.0, -20.0]; - let mut coords_pos = [20.0, 20.0]; - coords_neg[i] = 0.0; - coords_pos[i] = 0.0; - let b = Box2D::from_points(&[Point2D::from(coords_neg), Point2D::from(coords_pos)]); - assert!(b.is_empty()); - } - } - - #[test] - fn test_nan_empty_or_negative() { - use std::f32::NAN; - assert!(Box2D { min: point2(NAN, 2.0), max: point2(1.0, 3.0) }.is_empty_or_negative()); - assert!(Box2D { min: point2(0.0, NAN), max: point2(1.0, 2.0) }.is_empty_or_negative()); - assert!(Box2D { min: point2(1.0, -2.0), max: point2(NAN, 2.0) }.is_empty_or_negative()); - assert!(Box2D { min: point2(1.0, -2.0), max: point2(0.0, NAN) }.is_empty_or_negative()); - } -} diff --git a/third_party/rust/euclid-0.20.14/src/box3d.rs b/third_party/rust/euclid-0.20.14/src/box3d.rs deleted file mode 100644 index 96bae5c48fff..000000000000 --- a/third_party/rust/euclid-0.20.14/src/box3d.rs +++ /dev/null @@ -1,901 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::UnknownUnit; -use crate::approxord::{max, min}; -use crate::nonempty::NonEmpty; -use crate::num::*; -use crate::point::{point3, Point3D}; -use crate::scale::Scale; -use crate::size::Size3D; -use crate::vector::Vector3D; - -use num_traits::NumCast; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -use core::borrow::Borrow; -use core::cmp::PartialOrd; -use core::fmt; -use core::hash::{Hash, Hasher}; -use core::ops::{Add, Div, DivAssign, Mul, MulAssign, Sub}; - -/// An axis aligned 3D box represented by its minimum and maximum coordinates. -#[repr(C)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "serde", - serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>")) -)] -pub struct Box3D { - pub min: Point3D, - pub max: Point3D, -} - -impl Hash for Box3D { - fn hash(&self, h: &mut H) { - self.min.hash(h); - self.max.hash(h); - } -} - -impl Copy for Box3D {} - -impl Clone for Box3D { - fn clone(&self) -> Self { - Self::new(self.min.clone(), self.max.clone()) - } -} - -impl PartialEq for Box3D { - fn eq(&self, other: &Self) -> bool { - self.min.eq(&other.min) && self.max.eq(&other.max) - } -} - -impl Eq for Box3D {} - -impl fmt::Debug for Box3D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Box3D") - .field(&self.min) - .field(&self.max) - .finish() - } -} - -impl fmt::Display for Box3D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Box3D(")?; - fmt::Display::fmt(&self.min, f)?; - write!(f, ", ")?; - fmt::Display::fmt(&self.max, f)?; - write!(f, ")") - } -} - -impl Box3D { - /// Constructor. - #[inline] - pub const fn new(min: Point3D, max: Point3D) -> Self { - Box3D { min, max } - } -} - -impl Box3D -where - T: PartialOrd, -{ - /// Returns true if the box has a negative volume. - /// - /// The common interpretation for a negative box is to consider it empty. It can be obtained - /// by calculating the intersection of two boxes that do not intersect. - #[inline] - pub fn is_negative(&self) -> bool { - self.max.x < self.min.x || self.max.y < self.min.y || self.max.z < self.min.z - } - - /// Returns true if the size is zero or negative. - #[inline] - pub fn is_empty_or_negative(&self) -> bool { - !(self.max.x > self.min.x && self.max.y > self.min.y && self.max.z > self.min.z) - } - - #[inline] - pub fn intersects(&self, other: &Self) -> bool { - self.min.x < other.max.x - && self.max.x > other.min.x - && self.min.y < other.max.y - && self.max.y > other.min.y - && self.min.z < other.max.z - && self.max.z > other.min.z - } - - /// Returns `true` if this box3d contains the point. Points are considered - /// in the box3d if they are on the front, left or top faces, but outside if they - /// are on the back, right or bottom faces. - #[inline] - pub fn contains(&self, other: Point3D) -> bool { - self.min.x <= other.x - && other.x < self.max.x - && self.min.y <= other.y - && other.y < self.max.y - && self.min.z <= other.z - && other.z < self.max.z - } - - /// Returns `true` if this box3d contains the interior of the other box3d. Always - /// returns `true` if other is empty, and always returns `false` if other is - /// nonempty but this box3d is empty. - #[inline] - pub fn contains_box(&self, other: &Self) -> bool { - other.is_empty_or_negative() - || (self.min.x <= other.min.x - && other.max.x <= self.max.x - && self.min.y <= other.min.y - && other.max.y <= self.max.y - && self.min.z <= other.min.z - && other.max.z <= self.max.z) - } -} - -impl Box3D -where - T: Copy + PartialOrd, -{ - #[inline] - pub fn to_non_empty(&self) -> Option> { - if self.is_empty_or_negative() { - return None; - } - - Some(NonEmpty(*self)) - } - - #[inline] - pub fn try_intersection(&self, other: &Self) -> Option> { - if !self.intersects(other) { - return None; - } - - Some(NonEmpty(self.intersection(other))) - } - - pub fn intersection(&self, other: &Self) -> Self { - let intersection_min = Point3D::new( - max(self.min.x, other.min.x), - max(self.min.y, other.min.y), - max(self.min.z, other.min.z), - ); - - let intersection_max = Point3D::new( - min(self.max.x, other.max.x), - min(self.max.y, other.max.y), - min(self.max.z, other.max.z), - ); - - Box3D::new(intersection_min, intersection_max) - } - - /// Returns the smallest box containing both of the provided boxes. - #[inline] - pub fn union(&self, other: &Self) -> Self { - Box3D::new( - Point3D::new( - min(self.min.x, other.min.x), - min(self.min.y, other.min.y), - min(self.min.z, other.min.z), - ), - Point3D::new( - max(self.max.x, other.max.x), - max(self.max.y, other.max.y), - max(self.max.z, other.max.z), - ), - ) - } -} - -impl Box3D -where - T: Copy + Add, -{ - /// Returns the same box3d, translated by a vector. - #[inline] - #[must_use] - pub fn translate(&self, by: Vector3D) -> Self { - Box3D { - min: self.min + by, - max: self.max + by, - } - } -} - -impl Box3D -where - T: Copy + Sub, -{ - #[inline] - pub fn size(&self) -> Size3D { - Size3D::new( - self.max.x - self.min.x, - self.max.y - self.min.y, - self.max.z - self.min.z, - ) - } - - #[inline] - pub fn width(&self) -> T { - self.max.x - self.min.x - } - - #[inline] - pub fn height(&self) -> T { - self.max.y - self.min.y - } - - #[inline] - pub fn depth(&self) -> T { - self.max.z - self.min.z - } -} - -impl Box3D -where - T: Copy + Add + Sub, -{ - /// Inflates the box by the specified sizes on each side respectively. - #[inline] - #[must_use] - pub fn inflate(&self, width: T, height: T, depth: T) -> Self { - Box3D::new( - Point3D::new(self.min.x - width, self.min.y - height, self.min.z - depth), - Point3D::new(self.max.x + width, self.max.y + height, self.max.z + depth), - ) - } -} - -impl Box3D -where - T: Copy + Zero + PartialOrd, -{ - /// Creates a Box3D of the given size, at offset zero. - #[inline] - pub fn from_size(size: Size3D) -> Self { - let zero = Point3D::zero(); - let point = size.to_vector().to_point(); - Box3D::from_points(&[zero, point]) - } - - /// Returns the smallest box containing all of the provided points. - pub fn from_points(points: I) -> Self - where - I: IntoIterator, - I::Item: Borrow>, - { - let mut points = points.into_iter(); - - let (mut min_x, mut min_y, mut min_z) = match points.next() { - Some(first) => first.borrow().to_tuple(), - None => return Box3D::zero(), - }; - let (mut max_x, mut max_y, mut max_z) = (min_x, min_y, min_z); - - for point in points { - let p = point.borrow(); - if p.x < min_x { - min_x = p.x - } - if p.x > max_x { - max_x = p.x - } - if p.y < min_y { - min_y = p.y - } - if p.y > max_y { - max_y = p.y - } - if p.z < min_z { - min_z = p.z - } - if p.z > max_z { - max_z = p.z - } - } - - Box3D { - min: point3(min_x, min_y, min_z), - max: point3(max_x, max_y, max_z), - } - } -} - -impl Box3D -where - T: Copy + One + Add + Sub + Mul, -{ - /// Linearly interpolate between this box3d and another box3d. - #[inline] - pub fn lerp(&self, other: Self, t: T) -> Self { - Self::new(self.min.lerp(other.min, t), self.max.lerp(other.max, t)) - } -} - -impl Box3D -where - T: Copy + One + Add + Div, -{ - pub fn center(&self) -> Point3D { - let two = T::one() + T::one(); - (self.min + self.max.to_vector()) / two - } -} - -impl Box3D -where - T: Copy + Mul + Sub, -{ - #[inline] - pub fn volume(&self) -> T { - let size = self.size(); - size.width * size.height * size.depth - } - - #[inline] - pub fn xy_area(&self) -> T { - let size = self.size(); - size.width * size.height - } - - #[inline] - pub fn yz_area(&self) -> T { - let size = self.size(); - size.depth * size.height - } - - #[inline] - pub fn xz_area(&self) -> T { - let size = self.size(); - size.depth * size.width - } -} - -impl Box3D -where - T: Zero, -{ - /// Constructor, setting all sides to zero. - pub fn zero() -> Self { - Box3D::new(Point3D::zero(), Point3D::zero()) - } -} - -impl Box3D -where - T: PartialEq, -{ - /// Returns true if the volume is zero. - #[inline] - pub fn is_empty(&self) -> bool { - self.min.x == self.max.x || self.min.y == self.max.y || self.min.z == self.max.z - } -} - -impl Mul for Box3D { - type Output = Box3D; - - #[inline] - fn mul(self, scale: T) -> Self::Output { - Box3D::new(self.min * scale.clone(), self.max * scale) - } -} - -impl MulAssign for Box3D { - #[inline] - fn mul_assign(&mut self, scale: T) { - self.min *= scale.clone(); - self.max *= scale; - } -} - -impl Div for Box3D { - type Output = Box3D; - - #[inline] - fn div(self, scale: T) -> Self::Output { - Box3D::new(self.min / scale.clone(), self.max / scale) - } -} - -impl DivAssign for Box3D { - #[inline] - fn div_assign(&mut self, scale: T) { - self.min /= scale.clone(); - self.max /= scale; - } -} - -impl Mul> for Box3D { - type Output = Box3D; - - #[inline] - fn mul(self, scale: Scale) -> Self::Output { - Box3D::new(self.min * scale.clone(), self.max * scale) - } -} - -impl MulAssign> for Box3D { - #[inline] - fn mul_assign(&mut self, scale: Scale) { - self.min *= scale.clone(); - self.max *= scale; - } -} - -impl Div> for Box3D { - type Output = Box3D; - - #[inline] - fn div(self, scale: Scale) -> Self::Output { - Box3D::new(self.min / scale.clone(), self.max / scale) - } -} - -impl DivAssign> for Box3D { - #[inline] - fn div_assign(&mut self, scale: Scale) { - self.min /= scale.clone(); - self.max /= scale; - } -} - -impl Box3D -where - T: Copy, -{ - /// Drop the units, preserving only the numeric value. - #[inline] - pub fn to_untyped(&self) -> Box3D { - Box3D { - min: self.min.to_untyped(), - max: self.max.to_untyped(), - } - } - - /// Tag a unitless value with units. - #[inline] - pub fn from_untyped(c: &Box3D) -> Box3D { - Box3D { - min: Point3D::from_untyped(c.min), - max: Point3D::from_untyped(c.max), - } - } - - /// Cast the unit - #[inline] - pub fn cast_unit(&self) -> Box3D { - Box3D::new(self.min.cast_unit(), self.max.cast_unit()) - } - - #[inline] - pub fn scale(&self, x: S, y: S, z: S) -> Self - where - T: Mul, - { - Box3D::new( - Point3D::new(self.min.x * x, self.min.y * y, self.min.z * z), - Point3D::new(self.max.x * x, self.max.y * y, self.max.z * z), - ) - } -} - -impl Box3D { - /// 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. - #[inline] - pub fn cast(&self) -> Box3D { - Box3D::new(self.min.cast(), self.max.cast()) - } - - /// Fallible 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 try_cast(&self) -> Option> { - match (self.min.try_cast(), self.max.try_cast()) { - (Some(a), Some(b)) => Some(Box3D::new(a, b)), - _ => None, - } - } - - // Convenience functions for common casts - - /// Cast into an `f32` box3d. - #[inline] - pub fn to_f32(&self) -> Box3D { - self.cast() - } - - /// Cast into an `f64` box3d. - #[inline] - pub fn to_f64(&self) -> Box3D { - self.cast() - } - - /// Cast into an `usize` box3d, truncating decimals if any. - /// - /// When casting from floating point cuboids, it is worth considering whether - /// to `round()`, `round_in()` or `round_out()` before the cast in order to - /// obtain the desired conversion behavior. - #[inline] - pub fn to_usize(&self) -> Box3D { - self.cast() - } - - /// Cast into an `u32` box3d, truncating decimals if any. - /// - /// When casting from floating point cuboids, it is worth considering whether - /// to `round()`, `round_in()` or `round_out()` before the cast in order to - /// obtain the desired conversion behavior. - #[inline] - pub fn to_u32(&self) -> Box3D { - self.cast() - } - - /// Cast into an `i32` box3d, truncating decimals if any. - /// - /// When casting from floating point cuboids, it is worth considering whether - /// to `round()`, `round_in()` or `round_out()` before the cast in order to - /// obtain the desired conversion behavior. - #[inline] - pub fn to_i32(&self) -> Box3D { - self.cast() - } - - /// Cast into an `i64` box3d, truncating decimals if any. - /// - /// When casting from floating point cuboids, it is worth considering whether - /// to `round()`, `round_in()` or `round_out()` before the cast in order to - /// obtain the desired conversion behavior. - #[inline] - pub fn to_i64(&self) -> Box3D { - self.cast() - } -} - -impl Box3D -where - T: Round, -{ - /// Return a box3d with edges rounded to integer coordinates, such that - /// the returned box3d has the same set of pixel centers as the original - /// one. - /// Values equal to 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 { - Box3D::new(self.min.round(), self.max.round()) - } -} - -impl Box3D -where - T: Floor + Ceil, -{ - /// Return a box3d with faces/edges rounded to integer coordinates, such that - /// the original box3d contains the resulting box3d. - #[must_use] - pub fn round_in(&self) -> Self { - Box3D { - min: self.min.ceil(), - max: self.max.floor(), - } - } - - /// Return a box3d with faces/edges rounded to integer coordinates, such that - /// the original box3d is contained in the resulting box3d. - #[must_use] - pub fn round_out(&self) -> Self { - Box3D { - min: self.min.floor(), - max: self.max.ceil(), - } - } -} - -impl From> for Box3D -where - T: Copy + Zero + PartialOrd, -{ - fn from(b: Size3D) -> Self { - Self::from_size(b) - } -} - -/// Shorthand for `Box3D::new(Point3D::new(x1, y1, z1), Point3D::new(x2, y2, z2))`. -pub fn box3d( - min_x: T, - min_y: T, - min_z: T, - max_x: T, - max_y: T, - max_z: T, -) -> Box3D { - Box3D::new( - Point3D::new(min_x, min_y, min_z), - Point3D::new(max_x, max_y, max_z), - ) -} - -#[cfg(test)] -mod tests { - use crate::default::{Box3D, Point3D}; - use crate::{point3, size3, vec3}; - - #[test] - fn test_new() { - let b = Box3D::new(point3(-1.0, -1.0, -1.0), point3(1.0, 1.0, 1.0)); - assert!(b.min.x == -1.0); - assert!(b.min.y == -1.0); - assert!(b.min.z == -1.0); - assert!(b.max.x == 1.0); - assert!(b.max.y == 1.0); - assert!(b.max.z == 1.0); - } - - #[test] - fn test_size() { - let b = Box3D::new(point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0)); - assert!(b.size().width == 20.0); - assert!(b.size().height == 20.0); - assert!(b.size().depth == 20.0); - } - - #[test] - fn test_width_height_depth() { - let b = Box3D::new(point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0)); - assert!(b.width() == 20.0); - assert!(b.height() == 20.0); - assert!(b.depth() == 20.0); - } - - #[test] - fn test_center() { - let b = Box3D::new(point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0)); - assert!(b.center() == Point3D::zero()); - } - - #[test] - fn test_volume() { - let b = Box3D::new(point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0)); - assert!(b.volume() == 8000.0); - } - - #[test] - fn test_area() { - let b = Box3D::new(point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0)); - assert!(b.xy_area() == 400.0); - assert!(b.yz_area() == 400.0); - assert!(b.xz_area() == 400.0); - } - - #[test] - fn test_from_points() { - let b = Box3D::from_points(&[point3(50.0, 160.0, 12.5), point3(100.0, 25.0, 200.0)]); - assert!(b.min == point3(50.0, 25.0, 12.5)); - assert!(b.max == point3(100.0, 160.0, 200.0)); - } - - #[test] - fn test_min_max() { - let b = Box3D::from_points(&[point3(50.0, 25.0, 12.5), point3(100.0, 160.0, 200.0)]); - assert!(b.min.x == 50.0); - assert!(b.min.y == 25.0); - assert!(b.min.z == 12.5); - assert!(b.max.x == 100.0); - assert!(b.max.y == 160.0); - assert!(b.max.z == 200.0); - } - - #[test] - fn test_round_in() { - let b = - Box3D::from_points(&[point3(-25.5, -40.4, -70.9), point3(60.3, 36.5, 89.8)]).round_in(); - assert!(b.min.x == -25.0); - assert!(b.min.y == -40.0); - assert!(b.min.z == -70.0); - assert!(b.max.x == 60.0); - assert!(b.max.y == 36.0); - assert!(b.max.z == 89.0); - } - - #[test] - fn test_round_out() { - let b = Box3D::from_points(&[point3(-25.5, -40.4, -70.9), point3(60.3, 36.5, 89.8)]) - .round_out(); - assert!(b.min.x == -26.0); - assert!(b.min.y == -41.0); - assert!(b.min.z == -71.0); - assert!(b.max.x == 61.0); - assert!(b.max.y == 37.0); - assert!(b.max.z == 90.0); - } - - #[test] - fn test_round() { - let b = - Box3D::from_points(&[point3(-25.5, -40.4, -70.9), point3(60.3, 36.5, 89.8)]).round(); - assert!(b.min.x == -26.0); - assert!(b.min.y == -40.0); - assert!(b.min.z == -71.0); - assert!(b.max.x == 60.0); - assert!(b.max.y == 37.0); - assert!(b.max.z == 90.0); - } - - #[test] - fn test_from_size() { - let b = Box3D::from_size(size3(30.0, 40.0, 50.0)); - assert!(b.min == Point3D::zero()); - assert!(b.size().width == 30.0); - assert!(b.size().height == 40.0); - assert!(b.size().depth == 50.0); - } - - #[test] - fn test_translate() { - let size = size3(15.0, 15.0, 200.0); - let mut center = (size / 2.0).to_vector().to_point(); - let b = Box3D::from_size(size); - assert!(b.center() == center); - let translation = vec3(10.0, 2.5, 9.5); - let b = b.translate(translation); - center += translation; - assert!(b.center() == center); - assert!(b.max.x == 25.0); - assert!(b.max.y == 17.5); - assert!(b.max.z == 209.5); - assert!(b.min.x == 10.0); - assert!(b.min.y == 2.5); - assert!(b.min.z == 9.5); - } - - #[test] - fn test_union() { - let b1 = Box3D::from_points(&[point3(-20.0, -20.0, -20.0), point3(0.0, 20.0, 20.0)]); - let b2 = Box3D::from_points(&[point3(0.0, 20.0, 20.0), point3(20.0, -20.0, -20.0)]); - let b = b1.union(&b2); - assert!(b.max.x == 20.0); - assert!(b.max.y == 20.0); - assert!(b.max.z == 20.0); - assert!(b.min.x == -20.0); - assert!(b.min.y == -20.0); - assert!(b.min.z == -20.0); - assert!(b.volume() == (40.0 * 40.0 * 40.0)); - } - - #[test] - fn test_intersects() { - let b1 = Box3D::from_points(&[point3(-15.0, -20.0, -20.0), point3(10.0, 20.0, 20.0)]); - let b2 = Box3D::from_points(&[point3(-10.0, 20.0, 20.0), point3(15.0, -20.0, -20.0)]); - assert!(b1.intersects(&b2)); - } - - #[test] - fn test_intersection() { - let b1 = Box3D::from_points(&[point3(-15.0, -20.0, -20.0), point3(10.0, 20.0, 20.0)]); - let b2 = Box3D::from_points(&[point3(-10.0, 20.0, 20.0), point3(15.0, -20.0, -20.0)]); - let b = b1.intersection(&b2); - assert!(b.max.x == 10.0); - assert!(b.max.y == 20.0); - assert!(b.max.z == 20.0); - assert!(b.min.x == -10.0); - assert!(b.min.y == -20.0); - assert!(b.min.z == -20.0); - assert!(b.volume() == (20.0 * 40.0 * 40.0)); - } - - #[test] - fn test_try_intersection() { - let b1 = Box3D::from_points(&[point3(-15.0, -20.0, -20.0), point3(10.0, 20.0, 20.0)]); - let b2 = Box3D::from_points(&[point3(-10.0, 20.0, 20.0), point3(15.0, -20.0, -20.0)]); - assert!(b1.try_intersection(&b2).is_some()); - - let b1 = Box3D::from_points(&[point3(-15.0, -20.0, -20.0), point3(-10.0, 20.0, 20.0)]); - let b2 = Box3D::from_points(&[point3(10.0, 20.0, 20.0), point3(15.0, -20.0, -20.0)]); - assert!(b1.try_intersection(&b2).is_none()); - } - - #[test] - fn test_scale() { - let b = Box3D::from_points(&[point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0)]); - let b = b.scale(0.5, 0.5, 0.5); - assert!(b.max.x == 5.0); - assert!(b.max.y == 5.0); - assert!(b.max.z == 5.0); - assert!(b.min.x == -5.0); - assert!(b.min.y == -5.0); - assert!(b.min.z == -5.0); - } - - #[test] - fn test_zero() { - let b = Box3D::::zero(); - assert!(b.max.x == 0.0); - assert!(b.max.y == 0.0); - assert!(b.max.z == 0.0); - assert!(b.min.x == 0.0); - assert!(b.min.y == 0.0); - assert!(b.min.z == 0.0); - } - - #[test] - fn test_lerp() { - let b1 = Box3D::from_points(&[point3(-20.0, -20.0, -20.0), point3(-10.0, -10.0, -10.0)]); - let b2 = Box3D::from_points(&[point3(10.0, 10.0, 10.0), point3(20.0, 20.0, 20.0)]); - let b = b1.lerp(b2, 0.5); - assert!(b.center() == Point3D::zero()); - assert!(b.size().width == 10.0); - assert!(b.size().height == 10.0); - assert!(b.size().depth == 10.0); - } - - #[test] - fn test_contains() { - let b = Box3D::from_points(&[point3(-20.0, -20.0, -20.0), point3(20.0, 20.0, 20.0)]); - assert!(b.contains(point3(-15.3, 10.5, 18.4))); - } - - #[test] - fn test_contains_box() { - let b1 = Box3D::from_points(&[point3(-20.0, -20.0, -20.0), point3(20.0, 20.0, 20.0)]); - let b2 = Box3D::from_points(&[point3(-14.3, -16.5, -19.3), point3(6.7, 17.6, 2.5)]); - assert!(b1.contains_box(&b2)); - } - - #[test] - fn test_inflate() { - let b = Box3D::from_points(&[point3(-20.0, -20.0, -20.0), point3(20.0, 20.0, 20.0)]); - let b = b.inflate(10.0, 5.0, 2.0); - assert!(b.size().width == 60.0); - assert!(b.size().height == 50.0); - assert!(b.size().depth == 44.0); - assert!(b.center() == Point3D::zero()); - } - - #[test] - fn test_is_empty() { - for i in 0..3 { - let mut coords_neg = [-20.0, -20.0, -20.0]; - let mut coords_pos = [20.0, 20.0, 20.0]; - coords_neg[i] = 0.0; - coords_pos[i] = 0.0; - let b = Box3D::from_points(&[Point3D::from(coords_neg), Point3D::from(coords_pos)]); - assert!(b.is_empty()); - } - } - - #[test] - fn test_nan_empty_or_negative() { - use std::f32::NAN; - assert!(Box3D { min: point3(NAN, 2.0, 1.0), max: point3(1.0, 3.0, 5.0) }.is_empty_or_negative()); - assert!(Box3D { min: point3(0.0, NAN, 1.0), max: point3(1.0, 2.0, 5.0) }.is_empty_or_negative()); - assert!(Box3D { min: point3(1.0, -2.0, NAN), max: point3(3.0, 2.0, 5.0) }.is_empty_or_negative()); - assert!(Box3D { min: point3(1.0, -2.0, 1.0), max: point3(NAN, 2.0, 5.0) }.is_empty_or_negative()); - assert!(Box3D { min: point3(1.0, -2.0, 1.0), max: point3(0.0, NAN, 5.0) }.is_empty_or_negative()); - assert!(Box3D { min: point3(1.0, -2.0, 1.0), max: point3(0.0, 1.0, NAN) }.is_empty_or_negative()); - } -} diff --git a/third_party/rust/euclid-0.20.14/src/homogen.rs b/third_party/rust/euclid-0.20.14/src/homogen.rs deleted file mode 100644 index 272a5f4bd3df..000000000000 --- a/third_party/rust/euclid-0.20.14/src/homogen.rs +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright 2018 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use crate::point::{Point2D, Point3D}; -use crate::vector::{Vector2D, Vector3D}; - -use crate::num::{One, Zero}; - -use core::cmp::{Eq, PartialEq}; -use core::fmt; -use core::hash::Hash; -use core::marker::PhantomData; -use core::ops::Div; -#[cfg(feature = "serde")] -use serde; - -/// Homogeneous vector in 3D space. -#[repr(C)] -pub struct HomogeneousVector { - pub x: T, - pub y: T, - pub z: T, - pub w: T, - #[doc(hidden)] - pub _unit: PhantomData, -} - -impl Copy for HomogeneousVector {} - -impl Clone for HomogeneousVector { - fn clone(&self) -> Self { - HomogeneousVector { - x: self.x.clone(), - y: self.y.clone(), - z: self.z.clone(), - w: self.w.clone(), - _unit: PhantomData, - } - } -} - -#[cfg(feature = "serde")] -impl<'de, T, U> serde::Deserialize<'de> for HomogeneousVector -where - T: serde::Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let (x, y, z, w) = serde::Deserialize::deserialize(deserializer)?; - Ok(HomogeneousVector { - x, - y, - z, - w, - _unit: PhantomData, - }) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for HomogeneousVector -where - T: serde::Serialize, -{ - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - (&self.x, &self.y, &self.z, &self.w).serialize(serializer) - } -} - -impl Eq for HomogeneousVector where T: Eq {} - -impl PartialEq for HomogeneousVector -where - T: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - self.x == other.x && self.y == other.y && self.z == other.z && self.w == other.w - } -} - -impl Hash for HomogeneousVector -where - T: Hash, -{ - fn hash(&self, h: &mut H) { - self.x.hash(h); - self.y.hash(h); - self.z.hash(h); - self.w.hash(h); - } -} - -impl HomogeneousVector { - /// Constructor taking scalar values directly. - #[inline] - pub const fn new(x: T, y: T, z: T, w: T) -> Self { - HomogeneousVector { - x, - y, - z, - w, - _unit: PhantomData, - } - } -} - -impl + Zero + PartialOrd, U> HomogeneousVector { - /// Convert into Cartesian 2D point. - /// - /// Returns None if the point is on or behind the W=0 hemisphere. - #[inline] - pub fn to_point2d(&self) -> Option> { - if self.w > T::zero() { - Some(Point2D::new(self.x / self.w, self.y / self.w)) - } else { - None - } - } - - /// Convert into Cartesian 3D point. - /// - /// Returns None if the point is on or behind the W=0 hemisphere. - #[inline] - pub fn to_point3d(&self) -> Option> { - if self.w > T::zero() { - Some(Point3D::new( - self.x / self.w, - self.y / self.w, - self.z / self.w, - )) - } else { - None - } - } -} - -impl From> for HomogeneousVector { - #[inline] - fn from(v: Vector2D) -> Self { - HomogeneousVector::new(v.x, v.y, T::zero(), T::zero()) - } -} - -impl From> for HomogeneousVector { - #[inline] - fn from(v: Vector3D) -> Self { - HomogeneousVector::new(v.x, v.y, v.z, T::zero()) - } -} - -impl From> for HomogeneousVector { - #[inline] - fn from(p: Point2D) -> Self { - HomogeneousVector::new(p.x, p.y, T::zero(), T::one()) - } -} - -impl From> for HomogeneousVector { - #[inline] - fn from(p: Point3D) -> Self { - HomogeneousVector::new(p.x, p.y, p.z, T::one()) - } -} - -impl fmt::Debug for HomogeneousVector { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("") - .field(&self.x) - .field(&self.y) - .field(&self.z) - .field(&self.w) - .finish() - } -} - -impl fmt::Display for HomogeneousVector { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "(")?; - fmt::Display::fmt(&self.x, f)?; - write!(f, ",")?; - fmt::Display::fmt(&self.y, f)?; - write!(f, ",")?; - fmt::Display::fmt(&self.z, f)?; - write!(f, ",")?; - fmt::Display::fmt(&self.w, f)?; - write!(f, ")") - } -} - -#[cfg(test)] -mod homogeneous { - use super::HomogeneousVector; - use crate::default::{Point2D, Point3D}; - - #[test] - fn roundtrip() { - assert_eq!( - Some(Point2D::new(1.0, 2.0)), - HomogeneousVector::from(Point2D::new(1.0, 2.0)).to_point2d() - ); - assert_eq!( - Some(Point3D::new(1.0, -2.0, 0.1)), - HomogeneousVector::from(Point3D::new(1.0, -2.0, 0.1)).to_point3d() - ); - } - - #[test] - fn negative() { - assert_eq!( - None, - HomogeneousVector::::new(1.0, 2.0, 3.0, 0.0).to_point2d() - ); - assert_eq!( - None, - HomogeneousVector::::new(1.0, -2.0, -3.0, -2.0).to_point3d() - ); - } -} diff --git a/third_party/rust/euclid-0.20.14/src/length.rs b/third_party/rust/euclid-0.20.14/src/length.rs deleted file mode 100644 index 45e07c6bdbb8..000000000000 --- a/third_party/rust/euclid-0.20.14/src/length.rs +++ /dev/null @@ -1,574 +0,0 @@ -// 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 or the MIT license -// , 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 crate::approxeq::ApproxEq; -use crate::num::Zero; -use crate::scale::Scale; - -use crate::num::One; -use core::cmp::Ordering; -use core::fmt; -use core::hash::{Hash, Hasher}; -use core::marker::PhantomData; -use core::ops::{Add, Div, Mul, Neg, Sub}; -use core::ops::{AddAssign, DivAssign, MulAssign, SubAssign}; -use num_traits::{NumCast, Saturating}; -#[cfg(feature = "serde")] -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -/// 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::Scale` to convert it from one unit to -/// another. See the [`Scale`] docs for an example. -/// -/// [`Scale`]: struct.Scale.html -#[repr(C)] -pub struct Length(pub T, #[doc(hidden)] pub PhantomData); - -impl Clone for Length { - fn clone(&self) -> Self { - Length(self.0.clone(), PhantomData) - } -} - -impl Copy for Length {} - -#[cfg(feature = "serde")] -impl<'de, T, U> Deserialize<'de> for Length -where - T: Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Ok(Length(Deserialize::deserialize(deserializer)?, PhantomData)) - } -} - -#[cfg(feature = "serde")] -impl Serialize for Length -where - T: Serialize, -{ - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.0.serialize(serializer) - } -} - -impl Length { - /// Associate a value with a unit of measure. - #[inline] - pub const fn new(x: T) -> Self { - Length(x, PhantomData) - } -} - -impl Length { - /// Unpack the underlying value from the wrapper, cloning it. - pub fn get(&self) -> T { - self.0.clone() - } - - /// Cast the unit - #[inline] - pub fn cast_unit(&self) -> Length { - Length::new(self.0.clone()) - } - - /// Linearly interpolate between this length and another length. - /// - /// # Example - /// - /// ```rust - /// use euclid::default::Length; - /// - /// let from = Length::new(0.0); - /// let to = Length::new(8.0); - /// - /// assert_eq!(from.lerp(to, -1.0), Length::new(-8.0)); - /// assert_eq!(from.lerp(to, 0.0), Length::new( 0.0)); - /// assert_eq!(from.lerp(to, 0.5), Length::new( 4.0)); - /// assert_eq!(from.lerp(to, 1.0), Length::new( 8.0)); - /// assert_eq!(from.lerp(to, 2.0), Length::new(16.0)); - /// ``` - #[inline] - pub fn lerp(&self, other: Self, t: T) -> Self - where - T: One + Sub + Mul + Add, - { - let one_t = T::one() - t.clone(); - Length::new(one_t * self.0.clone() + t * other.0) - } -} - -impl Length { - /// Cast from one numeric representation to another, preserving the units. - #[inline] - pub fn cast(&self) -> Length { - self.try_cast().unwrap() - } - - /// Fallible cast from one numeric representation to another, preserving the units. - pub fn try_cast(&self) -> Option> { - NumCast::from(self.get()).map(Length::new) - } -} - -impl fmt::Debug for Length { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::Display for Length { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl Default for Length { - #[inline] - fn default() -> Self { - Length::new(Default::default()) - } -} - -impl Hash for Length { - fn hash(&self, h: &mut H) { - self.0.hash(h); - } -} - -// length + length -impl Add for Length { - type Output = Length; - - fn add(self, other: Self) -> Self::Output { - Length::new(self.0 + other.0) - } -} - -// length += length -impl AddAssign for Length { - fn add_assign(&mut self, other: Self) { - self.0 += other.0; - } -} - -// length - length -impl Sub for Length { - type Output = Length; - - fn sub(self, other: Length) -> Self::Output { - Length::new(self.0 - other.0) - } -} - -// length -= length -impl SubAssign for Length { - fn sub_assign(&mut self, other: Self) { - self.0 -= other.0; - } -} - -// Saturating length + length and length - length. -impl Saturating for Length { - fn saturating_add(self, other: Self) -> Self { - Length::new(self.0.saturating_add(other.0)) - } - - fn saturating_sub(self, other: Self) -> Self { - Length::new(self.0.saturating_sub(other.0)) - } -} - -// length / length -impl Div> for Length { - type Output = Scale; - - #[inline] - fn div(self, other: Length) -> Self::Output { - Scale::new(self.0 / other.0) - } -} - -// length * scalar -impl Mul for Length { - type Output = Length; - - #[inline] - fn mul(self, scale: T) -> Self::Output { - Length::new(self.0 * scale) - } -} - -// length *= scalar -impl, U> MulAssign for Length { - #[inline] - fn mul_assign(&mut self, scale: T) { - *self = *self * scale - } -} - -// length / scalar -impl Div for Length { - type Output = Length; - - #[inline] - fn div(self, scale: T) -> Self::Output { - Length::new(self.0 / scale) - } -} - -// length /= scalar -impl, U> DivAssign for Length { - #[inline] - fn div_assign(&mut self, scale: T) { - *self = *self / scale - } -} - -// length * scaleFactor -impl Mul> for Length { - type Output = Length; - - #[inline] - fn mul(self, scale: Scale) -> Self::Output { - Length::new(self.0 * scale.0) - } -} - -// length / scaleFactor -impl Div> for Length { - type Output = Length; - - #[inline] - fn div(self, scale: Scale) -> Self::Output { - Length::new(self.0 / scale.0) - } -} - -// -length -impl Neg for Length { - type Output = Length; - - #[inline] - fn neg(self) -> Self::Output { - Length::new(-self.0) - } -} - -impl PartialEq for Length { - fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) - } -} - -impl PartialOrd for Length { - fn partial_cmp(&self, other: &Self) -> Option { - self.0.partial_cmp(&other.0) - } -} - -impl Eq for Length {} - -impl Ord for Length { - fn cmp(&self, other: &Self) -> Ordering { - self.0.cmp(&other.0) - } -} - -impl Zero for Length { - #[inline] - fn zero() -> Self { - Length::new(Zero::zero()) - } -} - -impl> ApproxEq for Length { - #[inline] - fn approx_epsilon() -> T { - T::approx_epsilon() - } - - #[inline] - fn approx_eq_eps(&self, other: &Length, approx_epsilon: &T) -> bool { - self.0.approx_eq_eps(&other.0, approx_epsilon) - } -} - -#[cfg(test)] -mod tests { - use super::Length; - use crate::num::Zero; - - use crate::scale::Scale; - use core::f32::INFINITY; - use num_traits::Saturating; - - enum Inch {} - enum Mm {} - enum Cm {} - enum Second {} - - #[cfg(feature = "serde")] - mod serde { - use super::*; - - extern crate serde_test; - use self::serde_test::assert_tokens; - use self::serde_test::Token; - - #[test] - fn test_length_serde() { - let one_cm: Length = Length::new(10.0); - - assert_tokens(&one_cm, &[Token::F32(10.0)]); - } - } - - #[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 = 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_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, 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_add() { - let length1: Length = Length::new(250); - let length2: Length = Length::new(5); - - let result = length1 + length2; - - assert_eq!(result.get(), 255); - } - - #[test] - fn test_addassign() { - let one_cm: Length = Length::new(10.0); - let mut measurement: Length = Length::new(5.0); - - measurement += one_cm; - - assert_eq!(measurement.get(), 15.0); - } - - #[test] - fn test_sub() { - let length1: Length = Length::new(250); - let length2: Length = Length::new(5); - - let result = length1 - length2; - - assert_eq!(result.get(), 245); - } - - #[test] - fn test_subassign() { - let one_cm: Length = Length::new(10.0); - let mut measurement: Length = Length::new(5.0); - - measurement -= one_cm; - - assert_eq!(measurement.get(), -5.0); - } - - #[test] - fn test_saturating_add() { - let length1: Length = Length::new(250); - let length2: Length = Length::new(6); - - let result = length1.saturating_add(length2); - - assert_eq!(result.get(), 255); - } - - #[test] - fn test_saturating_sub() { - let length1: Length = Length::new(5); - let length2: Length = Length::new(10); - - let result = length1.saturating_sub(length2); - - assert_eq!(result.get(), 0); - } - - #[test] - fn test_division_by_length() { - // Division results in a Scale from denominator units - // to numerator units. - let length: Length = Length::new(5.0); - let duration: Length = Length::new(10.0); - - let result = length / duration; - - let expected: Scale = Scale::new(0.5); - assert_eq!(result, expected); - } - - #[test] - fn test_multiplication() { - let length_mm: Length = Length::new(10.0); - let cm_per_mm: Scale = Scale::new(0.1); - - let result = length_mm * cm_per_mm; - - let expected: Length = Length::new(1.0); - assert_eq!(result, expected); - } - - #[test] - fn test_multiplication_with_scalar() { - let length_mm: Length = Length::new(10.0); - - let result = length_mm * 2.0; - - let expected: Length = Length::new(20.0); - assert_eq!(result, expected); - } - - #[test] - fn test_multiplication_assignment() { - let mut length: Length = Length::new(10.0); - - length *= 2.0; - - let expected: Length = Length::new(20.0); - assert_eq!(length, expected); - } - - #[test] - fn test_division_by_scalefactor() { - let length: Length = Length::new(5.0); - let cm_per_second: Scale = Scale::new(10.0); - - let result = length / cm_per_second; - - let expected: Length = Length::new(0.5); - assert_eq!(result, expected); - } - - #[test] - fn test_division_by_scalar() { - let length: Length = Length::new(5.0); - - let result = length / 2.0; - - let expected: Length = Length::new(2.5); - assert_eq!(result, expected); - } - - #[test] - fn test_division_assignment() { - let mut length: Length = Length::new(10.0); - - length /= 2.0; - - let expected: Length = Length::new(5.0); - assert_eq!(length, expected); - } - - #[test] - fn test_negation() { - let length: Length = Length::new(5.0); - - let result = -length; - - let expected: Length = Length::new(-5.0); - assert_eq!(result, expected); - } - - #[test] - fn test_cast() { - let length_as_i32: Length = Length::new(5); - - let result: Length = length_as_i32.cast(); - - let length_as_f32: Length = Length::new(5.0); - assert_eq!(result, length_as_f32); - } - - #[test] - fn test_equality() { - let length_5_point_0: Length = Length::new(5.0); - let length_5_point_1: Length = Length::new(5.1); - let length_0_point_1: Length = 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 = Length::new(5.0); - let length_5_point_1: Length = Length::new(5.1); - let length_0_point_1: Length = 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; - let length: LengthCm = Length::new(5.0); - - let result = length - LengthCm::zero(); - - assert_eq!(result, length); - } - - #[test] - fn test_zero_division() { - type LengthCm = Length; - let length: LengthCm = Length::new(5.0); - let length_zero: LengthCm = Length::zero(); - - let result = length / length_zero; - - let expected: Scale = Scale::new(INFINITY); - assert_eq!(result, expected); - } -} diff --git a/third_party/rust/euclid-0.20.14/src/lib.rs b/third_party/rust/euclid-0.20.14/src/lib.rs deleted file mode 100644 index aff6c0babc6a..000000000000 --- a/third_party/rust/euclid-0.20.14/src/lib.rs +++ /dev/null @@ -1,117 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg_attr(not(test), no_std)] - -//! 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 structures have an alias -//! with the default unit: `UnknownUnit`. -//! for example ```default::Point2D``` is equivalent to ```Point2D```. -//! 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: -//! -//! ```rust -//! use euclid::*; -//! pub struct ScreenSpace; -//! pub type ScreenPoint = Point2D; -//! pub type ScreenSize = Size2D; -//! pub struct WorldSpace; -//! pub type WorldPoint = Point3D; -//! pub type ProjectionMatrix = Transform3D; -//! // etc... -//! ``` -//! -//! 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)`). -//! -#![deny(unconditional_recursion)] - -pub use crate::angle::Angle; -pub use crate::box2d::Box2D; -pub use crate::homogen::HomogeneousVector; -pub use crate::length::Length; -pub use crate::nonempty::NonEmpty; -pub use crate::point::{point2, point3, Point2D, Point3D}; -pub use crate::scale::Scale; -pub use crate::transform2d::Transform2D; -pub use crate::transform3d::Transform3D; -pub use crate::vector::{bvec2, bvec3, BoolVector2D, BoolVector3D}; -pub use crate::vector::{vec2, vec3, Vector2D, Vector3D}; - -pub use crate::box3d::{box3d, Box3D}; -pub use crate::rect::{rect, Rect}; -pub use crate::rigid::RigidTransform3D; -pub use crate::rotation::{Rotation2D, Rotation3D}; -pub use crate::side_offsets::SideOffsets2D; -pub use crate::size::{size2, size3, Size2D, Size3D}; -pub use crate::translation::{Translation2D, Translation3D}; -pub use crate::trig::Trig; - -#[macro_use] -mod macros; - -mod angle; -pub mod approxeq; -pub mod approxord; -mod box2d; -mod box3d; -mod homogen; -mod length; -mod nonempty; -pub mod num; -mod point; -mod rect; -mod rigid; -mod rotation; -mod scale; -mod side_offsets; -mod size; -mod transform2d; -mod transform3d; -mod translation; -mod trig; -mod vector; - -/// The default unit. -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct UnknownUnit; - -pub mod default { - //! A set of aliases for all types, tagged with the default unknown unit. - - use super::UnknownUnit; - pub type Length = super::Length; - pub type Point2D = super::Point2D; - pub type Point3D = super::Point3D; - pub type Vector2D = super::Vector2D; - pub type Vector3D = super::Vector3D; - pub type HomogeneousVector = super::HomogeneousVector; - pub type Size2D = super::Size2D; - pub type Size3D = super::Size3D; - pub type Rect = super::Rect; - pub type Box2D = super::Box2D; - pub type Box3D = super::Box3D; - pub type SideOffsets2D = super::SideOffsets2D; - pub type Transform2D = super::Transform2D; - pub type Transform3D = super::Transform3D; - pub type Rotation2D = super::Rotation2D; - pub type Rotation3D = super::Rotation3D; - pub type Translation2D = super::Translation2D; - pub type Translation3D = super::Translation3D; - pub type Scale = super::Scale; - pub type RigidTransform3D = super::RigidTransform3D; -} diff --git a/third_party/rust/euclid-0.20.14/src/macros.rs b/third_party/rust/euclid-0.20.14/src/macros.rs deleted file mode 100644 index 9cc392eb30e7..000000000000 --- a/third_party/rust/euclid-0.20.14/src/macros.rs +++ /dev/null @@ -1,30 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -macro_rules! mint_vec { - ($name:ident [ $($field:ident),* ] = $std_name:ident) => { - #[cfg(feature = "mint")] - impl From> for $name { - fn from(v: mint::$std_name) -> Self { - $name { - $( $field: v.$field, )* - _unit: PhantomData, - } - } - } - #[cfg(feature = "mint")] - impl Into> for $name { - fn into(self) -> mint::$std_name { - mint::$std_name { - $( $field: self.$field, )* - } - } - } - } -} diff --git a/third_party/rust/euclid-0.20.14/src/nonempty.rs b/third_party/rust/euclid-0.20.14/src/nonempty.rs deleted file mode 100644 index ae8b77f9d301..000000000000 --- a/third_party/rust/euclid-0.20.14/src/nonempty.rs +++ /dev/null @@ -1,250 +0,0 @@ -use crate::{Box2D, Box3D, Rect, Vector2D, Vector3D}; -use core::cmp::PartialEq; -use core::ops::Deref; -use core::ops::{Add, Sub}; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "serde", serde(transparent))] -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct NonEmpty(pub(crate) T); - -impl Deref for NonEmpty { - type Target = T; - fn deref(&self) -> &T { - &self.0 - } -} - -impl NonEmpty { - #[inline] - pub fn get(&self) -> &T { - &self.0 - } -} - -impl NonEmpty> -where - T: Copy + PartialOrd + Add + Sub, -{ - #[inline] - pub fn union(&self, other: &Self) -> Self { - NonEmpty(self.0.to_box2d().union(&other.0.to_box2d()).to_rect()) - } - - #[inline] - pub fn contains_rect(&self, rect: &Self) -> bool { - 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 translate(&self, by: Vector2D) -> Self { - NonEmpty(self.0.translate(by)) - } -} - -impl NonEmpty> -where - T: Copy + PartialOrd, -{ - #[inline] - pub fn union(&self, other: &Self) -> Self { - NonEmpty(self.0.union(&other.0)) - } - - /// Returns true if this box contains the interior of the other box. - #[inline] - pub fn contains_box(&self, other: &Self) -> bool { - self.min.x <= other.min.x - && other.max.x <= self.max.x - && self.min.y <= other.min.y - && other.max.y <= self.max.y - } -} - -impl NonEmpty> -where - T: Copy + Add, -{ - #[inline] - pub fn translate(&self, by: Vector2D) -> Self { - NonEmpty(self.0.translate(by)) - } -} - -impl NonEmpty> -where - T: Copy + PartialOrd, -{ - #[inline] - pub fn union(&self, other: &Self) -> Self { - NonEmpty(self.0.union(&other.0)) - } - - /// Returns true if this box contains the interior of the other box. - #[inline] - pub fn contains_box(&self, other: &Self) -> bool { - self.min.x <= other.min.x - && other.max.x <= self.max.x - && self.min.y <= other.min.y - && other.max.y <= self.max.y - && self.min.z <= other.min.z - && other.max.z <= self.max.z - } -} - -impl NonEmpty> -where - T: Copy + Add, -{ - #[inline] - pub fn translate(&self, by: Vector3D) -> Self { - NonEmpty(self.0.translate(by)) - } -} - -#[test] -fn empty_nonempty() { - use crate::default; - use crate::point2; - - // zero-width - let box1: default::Box2D = Box2D { - min: point2(-10, 2), - max: point2(-10, 12), - }; - // zero-height - let box2: default::Box2D = Box2D { - min: point2(0, 11), - max: point2(2, 11), - }; - // negative width - let box3: default::Box2D = Box2D { - min: point2(1, 11), - max: point2(0, 12), - }; - // negative height - let box4: default::Box2D = Box2D { - min: point2(0, 11), - max: point2(5, 10), - }; - - assert!(box1.to_non_empty().is_none()); - assert!(box2.to_non_empty().is_none()); - assert!(box3.to_non_empty().is_none()); - assert!(box4.to_non_empty().is_none()); -} - -#[test] -fn nonempty_union() { - use crate::default; - use crate::{point2, point3, size2}; - - let box1: default::Box2D = Box2D { - min: point2(-10, 2), - max: point2(15, 12), - }; - let box2 = Box2D { - min: point2(-2, -5), - max: point2(10, 5), - }; - - assert_eq!( - box1.union(&box2), - *box1 - .to_non_empty() - .unwrap() - .union(&box2.to_non_empty().unwrap()) - ); - - let box3: default::Box3D = Box3D { - min: point3(1, -10, 2), - max: point3(6, 15, 12), - }; - let box4 = Box3D { - min: point3(0, -2, -5), - max: point3(7, 10, 5), - }; - - assert_eq!( - box3.union(&box4), - *box3 - .to_non_empty() - .unwrap() - .union(&box4.to_non_empty().unwrap()) - ); - - let rect1: default::Rect = Rect { - origin: point2(1, 2), - size: size2(3, 4), - }; - let rect2 = Rect { - origin: point2(-1, 5), - size: size2(1, 10), - }; - - assert_eq!( - rect1.union(&rect2), - *rect1 - .to_non_empty() - .unwrap() - .union(&rect2.to_non_empty().unwrap()) - ); -} - -#[test] -fn nonempty_contains() { - use crate::default; - use crate::{point2, point3, size2, vec2, vec3}; - - let r: NonEmpty> = Rect { - origin: point2(-20, 15), - size: size2(100, 200), - } - .to_non_empty() - .unwrap(); - - assert!(r.contains_rect(&r)); - assert!(!r.contains_rect(&r.translate(vec2(1, 0)))); - assert!(!r.contains_rect(&r.translate(vec2(-1, 0)))); - assert!(!r.contains_rect(&r.translate(vec2(0, 1)))); - assert!(!r.contains_rect(&r.translate(vec2(0, -1)))); - - let b: NonEmpty> = Box2D { - min: point2(-10, 5), - max: point2(30, 100), - } - .to_non_empty() - .unwrap(); - - assert!(b.contains_box(&b)); - assert!(!b.contains_box(&b.translate(vec2(1, 0)))); - assert!(!b.contains_box(&b.translate(vec2(-1, 0)))); - assert!(!b.contains_box(&b.translate(vec2(0, 1)))); - assert!(!b.contains_box(&b.translate(vec2(0, -1)))); - - let b: NonEmpty> = Box3D { - min: point3(-1, -10, 5), - max: point3(10, 30, 100), - } - .to_non_empty() - .unwrap(); - - assert!(b.contains_box(&b)); - assert!(!b.contains_box(&b.translate(vec3(0, 1, 0)))); - assert!(!b.contains_box(&b.translate(vec3(0, -1, 0)))); - assert!(!b.contains_box(&b.translate(vec3(0, 0, 1)))); - assert!(!b.contains_box(&b.translate(vec3(0, 0, -1)))); - assert!(!b.contains_box(&b.translate(vec3(1, 1, 0)))); - assert!(!b.contains_box(&b.translate(vec3(1, -1, 0)))); - assert!(!b.contains_box(&b.translate(vec3(1, 0, 1)))); - assert!(!b.contains_box(&b.translate(vec3(1, 0, -1)))); - assert!(!b.contains_box(&b.translate(vec3(-1, 1, 0)))); - assert!(!b.contains_box(&b.translate(vec3(-1, -1, 0)))); - assert!(!b.contains_box(&b.translate(vec3(-1, 0, 1)))); - assert!(!b.contains_box(&b.translate(vec3(-1, 0, -1)))); -} diff --git a/third_party/rust/euclid-0.20.14/src/num.rs b/third_party/rust/euclid-0.20.14/src/num.rs deleted file mode 100644 index f91232279cae..000000000000 --- a/third_party/rust/euclid-0.20.14/src/num.rs +++ /dev/null @@ -1,127 +0,0 @@ -// 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 or the MIT license -// , 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; - -// Euclid has its own Zero and One traits instead of of using the num_traits equivalents. -// Unfortunately, num_traits::Zero requires Add, which opens a bag of sad things: -// - Most importantly, for Point2D to implement Zero it would need to implement Add which we -// don't want (we allow "Point + Vector" and "Vector + Vector" semantics and purposefully disallow -// "Point + Point". -// - Some operations that require, say, One and Div (for example Scale::inv) currently return a -// type parameterized over T::Output which is ambiguous with num_traits::One because it inherits -// Mul which also has an Output associated type. To fix it need to complicate type signatures -// by using ::Output which makes the code and documentation harder to read. -// -// On the other hand, euclid::num::Zero/One are automatically implemented for all types that -// implement their num_traits counterpart. Euclid users never need to explicitly use -// euclid::num::Zero/One and can/should only manipulate the num_traits equivalents without risk -// of compatibility issues with euclid. - -pub trait Zero { - fn zero() -> Self; -} - -impl Zero for T { - fn zero() -> T { - num_traits::Zero::zero() - } -} - -pub trait One { - fn one() -> Self; -} - -impl One for T { - fn one() -> T { - num_traits::One::one() - } -} - -/// Defines the nearest integer value to the original value. -pub trait Round: Copy { - /// Rounds to the nearest integer value. - /// - /// This behavior is preserved for negative values (unlike the basic cast). - #[must_use] - fn round(self) -> Self; -} -/// Defines the biggest integer equal or lower than the original value. -pub trait Floor: Copy { - /// Rounds to the biggest integer equal or lower than the original value. - /// - /// This behavior is preserved for negative values (unlike the basic cast). - #[must_use] - fn floor(self) -> Self; -} -/// Defines the smallest integer equal or greater than the original value. -pub trait Ceil: Copy { - /// Rounds to the smallest integer equal or greater than the original value. - /// - /// This behavior is preserved for negative values (unlike the basic cast). - #[must_use] - 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 { - num_traits::Float::round(self) - } - } - impl Floor for $ty { - #[inline] - fn floor(self) -> $ty { - num_traits::Float::floor(self) - } - } - impl Ceil for $ty { - #[inline] - fn ceil(self) -> $ty { - num_traits::Float::ceil(self) - } - } - }; -} - -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); diff --git a/third_party/rust/euclid-0.20.14/src/point.rs b/third_party/rust/euclid-0.20.14/src/point.rs deleted file mode 100644 index ad8e6583b248..000000000000 --- a/third_party/rust/euclid-0.20.14/src/point.rs +++ /dev/null @@ -1,1988 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::UnknownUnit; -use crate::approxeq::ApproxEq; -use crate::approxord::{max, min}; -use crate::length::Length; -use crate::num::*; -use crate::scale::Scale; -use crate::size::{Size2D, Size3D}; -use crate::vector::{vec2, vec3, Vector2D, Vector3D}; -use core::cmp::{Eq, PartialEq}; -use core::fmt; -use core::hash::Hash; -use core::marker::PhantomData; -use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -#[cfg(feature = "mint")] -use mint; -use num_traits::{Float, NumCast}; -#[cfg(feature = "serde")] -use serde; - -/// A 2d Point tagged with a unit. -#[repr(C)] -pub struct Point2D { - pub x: T, - pub y: T, - #[doc(hidden)] - pub _unit: PhantomData, -} - -impl Copy for Point2D {} - -impl Clone for Point2D { - fn clone(&self) -> Self { - Point2D { - x: self.x.clone(), - y: self.y.clone(), - _unit: PhantomData, - } - } -} - -#[cfg(feature = "serde")] -impl<'de, T, U> serde::Deserialize<'de> for Point2D -where - T: serde::Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let (x, y) = serde::Deserialize::deserialize(deserializer)?; - Ok(Point2D { - x, - y, - _unit: PhantomData, - }) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for Point2D -where - T: serde::Serialize, -{ - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - (&self.x, &self.y).serialize(serializer) - } -} - -impl Eq for Point2D where T: Eq {} - -impl PartialEq for Point2D -where - T: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - self.x == other.x && self.y == other.y - } -} - -impl Hash for Point2D -where - T: Hash, -{ - fn hash(&self, h: &mut H) { - self.x.hash(h); - self.y.hash(h); - } -} - -mint_vec!(Point2D[x, y] = Point2); - -impl fmt::Debug for Point2D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("").field(&self.x).field(&self.y).finish() - } -} - -impl fmt::Display for Point2D { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "(")?; - fmt::Display::fmt(&self.x, formatter)?; - write!(formatter, ",")?; - fmt::Display::fmt(&self.y, formatter)?; - write!(formatter, ")") - } -} - -impl Default for Point2D { - fn default() -> Self { - Point2D::new(Default::default(), Default::default()) - } -} - -impl Point2D { - /// Constructor, setting all components to zero. - #[inline] - pub fn origin() -> Self - where - T: Zero, - { - point2(Zero::zero(), Zero::zero()) - } - - /// The same as [`origin()`](#method.origin). - #[inline] - pub fn zero() -> Self - where - T: Zero, - { - Self::origin() - } - - /// Constructor taking scalar values directly. - #[inline] - pub const fn new(x: T, y: T) -> Self { - Point2D { - x, - y, - _unit: PhantomData, - } - } - - /// Constructor taking properly Lengths instead of scalar values. - #[inline] - pub fn from_lengths(x: Length, y: Length) -> Self { - point2(x.0, y.0) - } - - /// Tag a unitless value with units. - #[inline] - pub fn from_untyped(p: Point2D) -> Self { - point2(p.x, p.y) - } -} - -impl Point2D { - /// Create a 3d point from this one, using the specified z value. - #[inline] - pub fn extend(&self, z: T) -> Point3D { - point3(self.x, self.y, z) - } - - /// Cast this point into a vector. - /// - /// Equivalent to subtracting the origin from this point. - #[inline] - pub fn to_vector(&self) -> Vector2D { - Vector2D { - x: self.x, - y: self.y, - _unit: PhantomData, - } - } - - /// Swap x and y. - /// - /// # Example - /// - /// ```rust - /// # use euclid::{Point2D, point2}; - /// enum Mm {} - /// - /// let point: Point2D<_, Mm> = point2(1, -8); - /// - /// assert_eq!(point.yx(), point2(-8, 1)); - /// ``` - #[inline] - pub fn yx(&self) -> Self { - point2(self.y, self.x) - } - - /// Drop the units, preserving only the numeric value. - /// - /// # Example - /// - /// ```rust - /// # use euclid::{Point2D, point2}; - /// enum Mm {} - /// - /// let point: Point2D<_, Mm> = point2(1, -8); - /// - /// assert_eq!(point.x, point.to_untyped().x); - /// assert_eq!(point.y, point.to_untyped().y); - /// ``` - #[inline] - pub fn to_untyped(&self) -> Point2D { - point2(self.x, self.y) - } - - /// Cast the unit, preserving the numeric value. - /// - /// # Example - /// - /// ```rust - /// # use euclid::{Point2D, point2}; - /// enum Mm {} - /// enum Cm {} - /// - /// let point: Point2D<_, Mm> = point2(1, -8); - /// - /// assert_eq!(point.x, point.cast_unit::().x); - /// assert_eq!(point.y, point.cast_unit::().y); - /// ``` - #[inline] - pub fn cast_unit(&self) -> Point2D { - point2(self.x, self.y) - } - - /// Cast into an array with x and y. - /// - /// # Example - /// - /// ```rust - /// # use euclid::{Point2D, point2}; - /// enum Mm {} - /// - /// let point: Point2D<_, Mm> = point2(1, -8); - /// - /// assert_eq!(point.to_array(), [1, -8]); - /// ``` - #[inline] - pub fn to_array(&self) -> [T; 2] { - [self.x, self.y] - } - - /// Cast into a tuple with x and y. - /// - /// # Example - /// - /// ```rust - /// # use euclid::{Point2D, point2}; - /// enum Mm {} - /// - /// let point: Point2D<_, Mm> = point2(1, -8); - /// - /// assert_eq!(point.to_tuple(), (1, -8)); - /// ``` - #[inline] - pub fn to_tuple(&self) -> (T, T) { - (self.x, self.y) - } - - /// Convert into a 3d point with z-coordinate equals to zero. - #[inline] - pub fn to_3d(&self) -> Point3D - where - T: Zero, - { - point3(self.x, self.y, Zero::zero()) - } - - /// Rounds each component to the nearest integer value. - /// - /// This behavior is preserved for negative values (unlike the basic cast). - /// - /// ```rust - /// # use euclid::point2; - /// enum Mm {} - /// - /// assert_eq!(point2::<_, Mm>(-0.1, -0.8).round(), point2::<_, Mm>(0.0, -1.0)) - /// ``` - #[inline] - #[must_use] - pub fn round(&self) -> Self - where - T: Round, - { - point2(self.x.round(), self.y.round()) - } - - /// 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). - /// - /// ```rust - /// # use euclid::point2; - /// enum Mm {} - /// - /// assert_eq!(point2::<_, Mm>(-0.1, -0.8).ceil(), point2::<_, Mm>(0.0, 0.0)) - /// ``` - #[inline] - #[must_use] - pub fn ceil(&self) -> Self - where - T: Ceil, - { - point2(self.x.ceil(), self.y.ceil()) - } - - /// 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). - /// - /// ```rust - /// # use euclid::point2; - /// enum Mm {} - /// - /// assert_eq!(point2::<_, Mm>(-0.1, -0.8).floor(), point2::<_, Mm>(-1.0, -1.0)) - /// ``` - #[inline] - #[must_use] - pub fn floor(&self) -> Self - where - T: Floor, - { - point2(self.x.floor(), self.y.floor()) - } - - /// Linearly interpolate between this point and another point. - /// - /// # Example - /// - /// ```rust - /// use euclid::point2; - /// use euclid::default::Point2D; - /// - /// let from: Point2D<_> = point2(0.0, 10.0); - /// let to: Point2D<_> = point2(8.0, -4.0); - /// - /// assert_eq!(from.lerp(to, -1.0), point2(-8.0, 24.0)); - /// assert_eq!(from.lerp(to, 0.0), point2( 0.0, 10.0)); - /// assert_eq!(from.lerp(to, 0.5), point2( 4.0, 3.0)); - /// assert_eq!(from.lerp(to, 1.0), point2( 8.0, -4.0)); - /// assert_eq!(from.lerp(to, 2.0), point2(16.0, -18.0)); - /// ``` - #[inline] - pub fn lerp(&self, other: Self, t: T) -> Self - where - T: One + Sub + Mul + Add, - { - let one_t = T::one() - t; - point2(one_t * self.x + t * other.x, one_t * self.y + t * other.y) - } -} - -impl Point2D { - #[inline] - pub fn min(self, other: Self) -> Self { - point2(min(self.x, other.x), min(self.y, other.y)) - } - - #[inline] - pub fn max(self, other: Self) -> Self { - point2(max(self.x, other.x), max(self.y, other.y)) - } - - /// Returns the point each component of which clamped by corresponding - /// components of `start` and `end`. - /// - /// Shortcut for `self.max(start).min(end)`. - #[inline] - pub fn clamp(&self, start: Self, end: Self) -> Self - where - T: Copy, - { - self.max(start).min(end) - } -} - -impl Point2D { - /// 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(&self) -> Point2D { - self.try_cast().unwrap() - } - - /// Fallible 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 try_cast(&self) -> Option> { - match (NumCast::from(self.x), NumCast::from(self.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) -> Point2D { - self.cast() - } - - /// Cast into an `f64` point. - #[inline] - pub fn to_f64(&self) -> Point2D { - self.cast() - } - - /// 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) -> Point2D { - self.cast() - } - - /// Cast into an `u32` 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_u32(&self) -> Point2D { - self.cast() - } - - /// 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) -> Point2D { - self.cast() - } - - /// 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) -> Point2D { - self.cast() - } -} - -impl, U> Point2D { - #[inline] - pub fn add_size(&self, other: &Size2D) -> Self { - point2(self.x + other.width, self.y + other.height) - } -} - -impl, U> Point2D { - #[inline] - pub fn distance_to(self, other: Self) -> T { - (self - other).length() - } -} - -impl Neg for Point2D { - type Output = Point2D; - - #[inline] - fn neg(self) -> Self::Output { - point2(-self.x, -self.y) - } -} - -impl Add> for Point2D { - type Output = Point2D; - - #[inline] - fn add(self, other: Size2D) -> Self::Output { - point2(self.x + other.width, self.y + other.height) - } -} - -impl AddAssign> for Point2D { - #[inline] - fn add_assign(&mut self, other: Size2D) { - self.x += other.width; - self.y += other.height; - } -} - -impl Add> for Point2D { - type Output = Point2D; - - #[inline] - fn add(self, other: Vector2D) -> Self::Output { - point2(self.x + other.x, self.y + other.y) - } -} - -impl, U> AddAssign> for Point2D { - #[inline] - fn add_assign(&mut self, other: Vector2D) { - *self = *self + other - } -} - -impl Sub for Point2D { - type Output = Vector2D; - - #[inline] - fn sub(self, other: Self) -> Self::Output { - vec2(self.x - other.x, self.y - other.y) - } -} - -impl Sub> for Point2D { - type Output = Point2D; - - #[inline] - fn sub(self, other: Size2D) -> Self::Output { - point2(self.x - other.width, self.y - other.height) - } -} - -impl SubAssign> for Point2D { - #[inline] - fn sub_assign(&mut self, other: Size2D) { - self.x -= other.width; - self.y -= other.height; - } -} - -impl Sub> for Point2D { - type Output = Point2D; - - #[inline] - fn sub(self, other: Vector2D) -> Self::Output { - point2(self.x - other.x, self.y - other.y) - } -} - -impl, U> SubAssign> for Point2D { - #[inline] - fn sub_assign(&mut self, other: Vector2D) { - *self = *self - other - } -} - -impl Mul for Point2D { - type Output = Point2D; - - #[inline] - fn mul(self, scale: T) -> Self::Output { - point2(self.x * scale.clone(), self.y * scale) - } -} - -impl, U> MulAssign for Point2D { - #[inline] - fn mul_assign(&mut self, scale: T) { - *self = *self * scale - } -} - -impl Mul> for Point2D { - type Output = Point2D; - - #[inline] - fn mul(self, scale: Scale) -> Self::Output { - point2(self.x * scale.0.clone(), self.y * scale.0) - } -} - -impl MulAssign> for Point2D { - #[inline] - fn mul_assign(&mut self, scale: Scale) { - self.x *= scale.0.clone(); - self.y *= scale.0; - } -} - -impl Div for Point2D { - type Output = Point2D; - - #[inline] - fn div(self, scale: T) -> Self::Output { - point2(self.x / scale.clone(), self.y / scale) - } -} - -impl, U> DivAssign for Point2D { - #[inline] - fn div_assign(&mut self, scale: T) { - *self = *self / scale - } -} - -impl Div> for Point2D { - type Output = Point2D; - - #[inline] - fn div(self, scale: Scale) -> Self::Output { - point2(self.x / scale.0.clone(), self.y / scale.0) - } -} - -impl DivAssign> for Point2D { - #[inline] - fn div_assign(&mut self, scale: Scale) { - self.x /= scale.0.clone(); - self.y /= scale.0; - } -} - -impl Zero for Point2D { - #[inline] - fn zero() -> Self { - Self::origin() - } -} - -impl Round for Point2D { - /// See [Point2D::round()](#method.round) - #[inline] - fn round(self) -> Self { - (&self).round() - } -} - -impl Ceil for Point2D { - /// See [Point2D::ceil()](#method.ceil) - #[inline] - fn ceil(self) -> Self { - (&self).ceil() - } -} - -impl Floor for Point2D { - /// See [Point2D::floor()](#method.floor) - #[inline] - fn floor(self) -> Self { - (&self).floor() - } -} - -impl, U> ApproxEq> for Point2D { - #[inline] - fn approx_epsilon() -> Self { - point2(T::approx_epsilon(), T::approx_epsilon()) - } - - #[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 Into<[T; 2]> for Point2D { - fn into(self) -> [T; 2] { - [self.x, self.y] - } -} - -impl From<[T; 2]> for Point2D { - fn from([x, y]: [T; 2]) -> Self { - point2(x, y) - } -} - -impl Into<(T, T)> for Point2D { - fn into(self) -> (T, T) { - (self.x, self.y) - } -} - -impl From<(T, T)> for Point2D { - fn from(tuple: (T, T)) -> Self { - point2(tuple.0, tuple.1) - } -} - -/// A 3d Point tagged with a unit. -#[repr(C)] -pub struct Point3D { - pub x: T, - pub y: T, - pub z: T, - #[doc(hidden)] - pub _unit: PhantomData, -} - -mint_vec!(Point3D[x, y, z] = Point3); - -impl Copy for Point3D {} - -impl Clone for Point3D { - fn clone(&self) -> Self { - Point3D { - x: self.x.clone(), - y: self.y.clone(), - z: self.z.clone(), - _unit: PhantomData, - } - } -} - -#[cfg(feature = "serde")] -impl<'de, T, U> serde::Deserialize<'de> for Point3D -where - T: serde::Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let (x, y, z) = serde::Deserialize::deserialize(deserializer)?; - Ok(Point3D { - x, - y, - z, - _unit: PhantomData, - }) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for Point3D -where - T: serde::Serialize, -{ - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - (&self.x, &self.y, &self.z).serialize(serializer) - } -} - -impl Eq for Point3D where T: Eq {} - -impl PartialEq for Point3D -where - T: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - self.x == other.x && self.y == other.y && self.z == other.z - } -} - -impl Hash for Point3D -where - T: Hash, -{ - fn hash(&self, h: &mut H) { - self.x.hash(h); - self.y.hash(h); - self.z.hash(h); - } -} - -impl fmt::Debug for Point3D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("") - .field(&self.x) - .field(&self.y) - .field(&self.z) - .finish() - } -} - -impl fmt::Display for Point3D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "(")?; - fmt::Display::fmt(&self.x, f)?; - write!(f, ",")?; - fmt::Display::fmt(&self.y, f)?; - write!(f, ",")?; - fmt::Display::fmt(&self.z, f)?; - write!(f, ")") - } -} - -impl Default for Point3D { - fn default() -> Self { - Point3D::new(Default::default(), Default::default(), Default::default()) - } -} - -impl Point3D { - /// Constructor, setting all components to zero. - #[inline] - pub fn origin() -> Self - where - T: Zero, - { - point3(Zero::zero(), Zero::zero(), Zero::zero()) - } - - /// The same as [`origin()`](#method.origin). - #[inline] - pub fn zero() -> Self - where - T: Zero, - { - Self::origin() - } - - /// Constructor taking scalar values directly. - #[inline] - pub const fn new(x: T, y: T, z: T) -> Self { - Point3D { - x, - y, - z, - _unit: PhantomData, - } - } - - /// Constructor taking properly Lengths instead of scalar values. - #[inline] - pub fn from_lengths(x: Length, y: Length, z: Length) -> Self { - point3(x.0, y.0, z.0) - } - - /// Tag a unitless value with units. - #[inline] - pub fn from_untyped(p: Point3D) -> Self { - point3(p.x, p.y, p.z) - } -} - -impl Point3D { - /// Cast this point into a vector. - /// - /// Equivalent to subtracting the origin to this point. - #[inline] - pub fn to_vector(&self) -> Vector3D { - Vector3D { - x: self.x, - y: self.y, - z: self.z, - _unit: PhantomData, - } - } - - /// Returns a 2d point using this point's x and y coordinates - #[inline] - pub fn xy(&self) -> Point2D { - point2(self.x, self.y) - } - - /// Returns a 2d point using this point's x and z coordinates - #[inline] - pub fn xz(&self) -> Point2D { - point2(self.x, self.z) - } - - /// Returns a 2d point using this point's x and z coordinates - #[inline] - pub fn yz(&self) -> Point2D { - point2(self.y, self.z) - } - - /// Cast into an array with x, y and z. - /// - /// # Example - /// - /// ```rust - /// # use euclid::{Point3D, point3}; - /// enum Mm {} - /// - /// let point: Point3D<_, Mm> = point3(1, -8, 0); - /// - /// assert_eq!(point.to_array(), [1, -8, 0]); - /// ``` - #[inline] - pub fn to_array(&self) -> [T; 3] { - [self.x, self.y, self.z] - } - - #[inline] - pub fn to_array_4d(&self) -> [T; 4] - where - T: One, - { - [self.x, self.y, self.z, One::one()] - } - - /// Cast into a tuple with x, y and z. - /// - /// # Example - /// - /// ```rust - /// # use euclid::{Point3D, point3}; - /// enum Mm {} - /// - /// let point: Point3D<_, Mm> = point3(1, -8, 0); - /// - /// assert_eq!(point.to_tuple(), (1, -8, 0)); - /// ``` - #[inline] - pub fn to_tuple(&self) -> (T, T, T) { - (self.x, self.y, self.z) - } - - #[inline] - pub fn to_tuple_4d(&self) -> (T, T, T, T) - where - T: One, - { - (self.x, self.y, self.z, One::one()) - } - - /// Drop the units, preserving only the numeric value. - /// - /// # Example - /// - /// ```rust - /// # use euclid::{Point3D, point3}; - /// enum Mm {} - /// - /// let point: Point3D<_, Mm> = point3(1, -8, 0); - /// - /// assert_eq!(point.x, point.to_untyped().x); - /// assert_eq!(point.y, point.to_untyped().y); - /// assert_eq!(point.z, point.to_untyped().z); - /// ``` - #[inline] - pub fn to_untyped(&self) -> Point3D { - point3(self.x, self.y, self.z) - } - - /// Cast the unit, preserving the numeric value. - /// - /// # Example - /// - /// ```rust - /// # use euclid::{Point3D, point3}; - /// enum Mm {} - /// enum Cm {} - /// - /// let point: Point3D<_, Mm> = point3(1, -8, 0); - /// - /// assert_eq!(point.x, point.cast_unit::().x); - /// assert_eq!(point.y, point.cast_unit::().y); - /// assert_eq!(point.z, point.cast_unit::().z); - /// ``` - #[inline] - pub fn cast_unit(&self) -> Point3D { - point3(self.x, self.y, self.z) - } - - /// Convert into a 2d point. - #[inline] - pub fn to_2d(&self) -> Point2D { - self.xy() - } - - /// Rounds each component to the nearest integer value. - /// - /// This behavior is preserved for negative values (unlike the basic cast). - /// - /// ```rust - /// # use euclid::point3; - /// enum Mm {} - /// - /// assert_eq!(point3::<_, Mm>(-0.1, -0.8, 0.4).round(), point3::<_, Mm>(0.0, -1.0, 0.0)) - /// ``` - #[inline] - #[must_use] - pub fn round(&self) -> Self - where - T: Round, - { - point3(self.x.round(), self.y.round(), self.z.round()) - } - - /// 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). - /// - /// ```rust - /// # use euclid::point3; - /// enum Mm {} - /// - /// assert_eq!(point3::<_, Mm>(-0.1, -0.8, 0.4).ceil(), point3::<_, Mm>(0.0, 0.0, 1.0)) - /// ``` - #[inline] - #[must_use] - pub fn ceil(&self) -> Self - where - T: Ceil, - { - point3(self.x.ceil(), self.y.ceil(), self.z.ceil()) - } - - /// 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). - /// - /// ```rust - /// # use euclid::point3; - /// enum Mm {} - /// - /// assert_eq!(point3::<_, Mm>(-0.1, -0.8, 0.4).floor(), point3::<_, Mm>(-1.0, -1.0, 0.0)) - /// ``` - #[inline] - #[must_use] - pub fn floor(&self) -> Self - where - T: Floor, - { - point3(self.x.floor(), self.y.floor(), self.z.floor()) - } - - /// Linearly interpolate between this point and another point. - /// - /// # Example - /// - /// ```rust - /// use euclid::point3; - /// use euclid::default::Point3D; - /// - /// let from: Point3D<_> = point3(0.0, 10.0, -1.0); - /// let to: Point3D<_> = point3(8.0, -4.0, 0.0); - /// - /// assert_eq!(from.lerp(to, -1.0), point3(-8.0, 24.0, -2.0)); - /// assert_eq!(from.lerp(to, 0.0), point3( 0.0, 10.0, -1.0)); - /// assert_eq!(from.lerp(to, 0.5), point3( 4.0, 3.0, -0.5)); - /// assert_eq!(from.lerp(to, 1.0), point3( 8.0, -4.0, 0.0)); - /// assert_eq!(from.lerp(to, 2.0), point3(16.0, -18.0, 1.0)); - /// ``` - #[inline] - pub fn lerp(&self, other: Self, t: T) -> Self - where - T: One + Sub + Mul + Add, - { - 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 Point3D { - #[inline] - pub fn min(self, other: Self) -> Self { - point3( - min(self.x, other.x), - min(self.y, other.y), - min(self.z, other.z), - ) - } - - #[inline] - pub fn max(self, other: Self) -> Self { - point3( - max(self.x, other.x), - max(self.y, other.y), - max(self.z, other.z), - ) - } - - /// Returns the point each component of which clamped by corresponding - /// components of `start` and `end`. - /// - /// Shortcut for `self.max(start).min(end)`. - #[inline] - pub fn clamp(&self, start: Self, end: Self) -> Self - where - T: Copy, - { - self.max(start).min(end) - } -} - -impl Point3D { - /// 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(&self) -> Point3D { - self.try_cast().unwrap() - } - - /// Fallible 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 try_cast(&self) -> Option> { - match ( - NumCast::from(self.x), - NumCast::from(self.y), - NumCast::from(self.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) -> Point3D { - self.cast() - } - - /// Cast into an `f64` point. - #[inline] - pub fn to_f64(&self) -> Point3D { - self.cast() - } - - /// 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) -> Point3D { - self.cast() - } - - /// Cast into an `u32` 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_u32(&self) -> Point3D { - self.cast() - } - - /// 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) -> Point3D { - self.cast() - } - - /// 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) -> Point3D { - self.cast() - } -} - -impl, U> Point3D { - #[inline] - pub fn add_size(&self, other: &Size3D) -> Self { - point3( - self.x + other.width, - self.y + other.height, - self.z + other.depth, - ) - } -} - -impl, U> Point3D { - #[inline] - pub fn distance_to(self, other: Self) -> T { - (self - other).length() - } -} - -impl Neg for Point3D { - type Output = Point3D; - - #[inline] - fn neg(self) -> Self::Output { - point3(-self.x, -self.y, -self.z) - } -} - -impl Add> for Point3D { - type Output = Point3D; - - #[inline] - fn add(self, other: Size3D) -> Self::Output { - point3( - self.x + other.width, - self.y + other.height, - self.z + other.depth, - ) - } -} - -impl AddAssign> for Point3D { - #[inline] - fn add_assign(&mut self, other: Size3D) { - self.x += other.width; - self.y += other.height; - self.z += other.depth; - } -} - -impl Add> for Point3D { - type Output = Point3D; - - #[inline] - fn add(self, other: Vector3D) -> Self::Output { - point3(self.x + other.x, self.y + other.y, self.z + other.z) - } -} - -impl, U> AddAssign> for Point3D { - #[inline] - fn add_assign(&mut self, other: Vector3D) { - *self = *self + other - } -} - -impl Sub for Point3D { - type Output = Vector3D; - - #[inline] - fn sub(self, other: Self) -> Self::Output { - vec3(self.x - other.x, self.y - other.y, self.z - other.z) - } -} - -impl Sub> for Point3D { - type Output = Point3D; - - #[inline] - fn sub(self, other: Size3D) -> Self::Output { - point3( - self.x - other.width, - self.y - other.height, - self.z - other.depth, - ) - } -} - -impl SubAssign> for Point3D { - #[inline] - fn sub_assign(&mut self, other: Size3D) { - self.x -= other.width; - self.y -= other.height; - self.z -= other.depth; - } -} - -impl Sub> for Point3D { - type Output = Point3D; - - #[inline] - fn sub(self, other: Vector3D) -> Self::Output { - point3(self.x - other.x, self.y - other.y, self.z - other.z) - } -} - -impl, U> SubAssign> for Point3D { - #[inline] - fn sub_assign(&mut self, other: Vector3D) { - *self = *self - other - } -} - -impl Mul for Point3D { - type Output = Point3D; - - #[inline] - fn mul(self, scale: T) -> Self::Output { - point3( - self.x * scale.clone(), - self.y * scale.clone(), - self.z * scale, - ) - } -} - -impl MulAssign for Point3D { - #[inline] - fn mul_assign(&mut self, scale: T) { - self.x *= scale.clone(); - self.y *= scale.clone(); - self.z *= scale; - } -} - -impl Mul> for Point3D { - type Output = Point3D; - - #[inline] - fn mul(self, scale: Scale) -> Self::Output { - point3( - self.x * scale.0.clone(), - self.y * scale.0.clone(), - self.z * scale.0, - ) - } -} - -impl MulAssign> for Point3D { - #[inline] - fn mul_assign(&mut self, scale: Scale) { - *self *= scale.0; - } -} - -impl Div for Point3D { - type Output = Point3D; - - #[inline] - fn div(self, scale: T) -> Self::Output { - point3( - self.x / scale.clone(), - self.y / scale.clone(), - self.z / scale, - ) - } -} - -impl DivAssign for Point3D { - #[inline] - fn div_assign(&mut self, scale: T) { - self.x /= scale.clone(); - self.y /= scale.clone(); - self.z /= scale; - } -} - -impl Div> for Point3D { - type Output = Point3D; - - #[inline] - fn div(self, scale: Scale) -> Self::Output { - point3( - self.x / scale.0.clone(), - self.y / scale.0.clone(), - self.z / scale.0, - ) - } -} - -impl DivAssign> for Point3D { - #[inline] - fn div_assign(&mut self, scale: Scale) { - *self /= scale.0; - } -} - -impl Zero for Point3D { - #[inline] - fn zero() -> Self { - Self::origin() - } -} - -impl Round for Point3D { - /// See [Point3D::round()](#method.round) - #[inline] - fn round(self) -> Self { - (&self).round() - } -} - -impl Ceil for Point3D { - /// See [Point3D::ceil()](#method.ceil) - #[inline] - fn ceil(self) -> Self { - (&self).ceil() - } -} - -impl Floor for Point3D { - /// See [Point3D::floor()](#method.floor) - #[inline] - fn floor(self) -> Self { - (&self).floor() - } -} - -impl, U> ApproxEq> for Point3D { - #[inline] - fn approx_epsilon() -> Self { - point3( - T::approx_epsilon(), - T::approx_epsilon(), - T::approx_epsilon(), - ) - } - - #[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 Into<[T; 3]> for Point3D { - fn into(self) -> [T; 3] { - [self.x, self.y, self.z] - } -} - -impl From<[T; 3]> for Point3D { - fn from([x, y, z]: [T; 3]) -> Self { - point3(x, y, z) - } -} - -impl Into<(T, T, T)> for Point3D { - fn into(self) -> (T, T, T) { - (self.x, self.y, self.z) - } -} - -impl From<(T, T, T)> for Point3D { - fn from(tuple: (T, T, T)) -> Self { - point3(tuple.0, tuple.1, tuple.2) - } -} - -/// Shorthand for `Point2D::new(x, y)`. -#[inline] -pub const fn point2(x: T, y: T) -> Point2D { - Point2D { - x, - y, - _unit: PhantomData, - } -} - -/// Shorthand for `Point3D::new(x, y)`. -#[inline] -pub const fn point3(x: T, y: T, z: T) -> Point3D { - Point3D { - x, - y, - z, - _unit: PhantomData, - } -} - -#[cfg(test)] -mod point2d { - use crate::default::Point2D; - use crate::point2; - - #[cfg(feature = "mint")] - use mint; - - #[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(feature = "mint")] - #[test] - pub fn test_mint() { - let p1 = Point2D::new(1.0, 3.0); - let pm: mint::Point2<_> = p1.into(); - let p2 = Point2D::from(pm); - - assert_eq!(p1, p2); - } - - #[test] - pub fn test_conv_vector() { - 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 = point2(x, y); - assert_eq!(p.to_vector().to_point(), p); - } - } - - #[test] - pub fn test_swizzling() { - let p: Point2D = point2(1, 2); - assert_eq!(p.yx(), point2(2, 1)); - } - - #[test] - pub fn test_distance_to() { - let p1 = Point2D::new(1.0, 2.0); - let p2 = Point2D::new(2.0, 2.0); - - assert_eq!(p1.distance_to(p2), 1.0); - - let p1 = Point2D::new(1.0, 2.0); - let p2 = Point2D::new(1.0, 4.0); - - assert_eq!(p1.distance_to(p2), 2.0); - } - - mod ops { - use crate::default::Point2D; - use crate::scale::Scale; - use crate::{size2, vec2, Vector2D}; - - pub enum Mm {} - pub enum Cm {} - - pub type Point2DMm = crate::Point2D; - pub type Point2DCm = crate::Point2D; - - #[test] - pub fn test_neg() { - assert_eq!(-Point2D::new(1.0, 2.0), Point2D::new(-1.0, -2.0)); - assert_eq!(-Point2D::new(0.0, 0.0), Point2D::new(-0.0, -0.0)); - assert_eq!(-Point2D::new(-1.0, -2.0), Point2D::new(1.0, 2.0)); - } - - #[test] - pub fn test_add_size() { - let p1 = Point2DMm::new(1.0, 2.0); - let p2 = size2(3.0, 4.0); - - let result = p1 + p2; - - assert_eq!(result, Point2DMm::new(4.0, 6.0)); - } - - #[test] - pub fn test_add_assign_size() { - let mut p1 = Point2DMm::new(1.0, 2.0); - - p1 += size2(3.0, 4.0); - - assert_eq!(p1, Point2DMm::new(4.0, 6.0)); - } - - #[test] - pub fn test_add_vec() { - let p1 = Point2DMm::new(1.0, 2.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_vec() { - 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_sub() { - let p1 = Point2DMm::new(1.0, 2.0); - let p2 = Point2DMm::new(3.0, 4.0); - - let result = p1 - p2; - - assert_eq!(result, Vector2D::<_, Mm>::new(-2.0, -2.0)); - } - - #[test] - pub fn test_sub_size() { - let p1 = Point2DMm::new(1.0, 2.0); - let p2 = size2(3.0, 4.0); - - let result = p1 - p2; - - assert_eq!(result, Point2DMm::new(-2.0, -2.0)); - } - - #[test] - pub fn test_sub_assign_size() { - let mut p1 = Point2DMm::new(1.0, 2.0); - - p1 -= size2(3.0, 4.0); - - assert_eq!(p1, Point2DMm::new(-2.0, -2.0)); - } - - #[test] - pub fn test_sub_vec() { - let p1 = Point2DMm::new(1.0, 2.0); - let p2 = vec2(3.0, 4.0); - - let result = p1 - p2; - - assert_eq!(result, Point2DMm::new(-2.0, -2.0)); - } - - #[test] - pub fn test_sub_assign_vec() { - let mut p1 = Point2DMm::new(1.0, 2.0); - - p1 -= vec2(3.0, 4.0); - - assert_eq!(p1, Point2DMm::new(-2.0, -2.0)); - } - - #[test] - pub fn test_mul_scalar() { - let p1: Point2D = Point2D::new(3.0, 5.0); - - let result = p1 * 5.0; - - assert_eq!(result, Point2D::new(15.0, 25.0)); - } - - #[test] - pub fn test_mul_assign_scalar() { - let mut p1 = Point2D::new(3.0, 5.0); - - p1 *= 5.0; - - assert_eq!(p1, Point2D::new(15.0, 25.0)); - } - - #[test] - pub fn test_mul_scale() { - let p1 = Point2DMm::new(1.0, 2.0); - let cm_per_mm: Scale = Scale::new(0.1); - - let result = p1 * cm_per_mm; - - assert_eq!(result, Point2DCm::new(0.1, 0.2)); - } - - #[test] - pub fn test_mul_assign_scale() { - let mut p1 = Point2DMm::new(1.0, 2.0); - let scale: Scale = Scale::new(0.1); - - p1 *= scale; - - assert_eq!(p1, Point2DMm::new(0.1, 0.2)); - } - - #[test] - pub fn test_div_scalar() { - let p1: Point2D = Point2D::new(15.0, 25.0); - - let result = p1 / 5.0; - - assert_eq!(result, Point2D::new(3.0, 5.0)); - } - - #[test] - pub fn test_div_assign_scalar() { - let mut p1: Point2D = Point2D::new(15.0, 25.0); - - p1 /= 5.0; - - assert_eq!(p1, Point2D::new(3.0, 5.0)); - } - - #[test] - pub fn test_div_scale() { - let p1 = Point2DCm::new(0.1, 0.2); - let cm_per_mm: Scale = Scale::new(0.1); - - let result = p1 / cm_per_mm; - - assert_eq!(result, Point2DMm::new(1.0, 2.0)); - } - - #[test] - pub fn test_div_assign_scale() { - let mut p1 = Point2DMm::new(0.1, 0.2); - let scale: Scale = Scale::new(0.1); - - p1 /= scale; - - assert_eq!(p1, Point2DMm::new(1.0, 2.0)); - } - - #[test] - pub fn test_point_debug_formatting() { - let n = 1.23456789; - let p1 = Point2D::new(n, -n); - let should_be = format!("({:.4}, {:.4})", n, -n); - - let got = format!("{:.4?}", p1); - - assert_eq!(got, should_be); - } - } -} - -#[cfg(test)] -mod point3d { - use crate::default; - use crate::default::Point3D; - use crate::{point2, point3}; - #[cfg(feature = "mint")] - use mint; - - #[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)); - } - - #[test] - pub fn test_conv_vector() { - use crate::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 = point3(x, y, z); - assert_eq!(p.to_vector().to_point(), p); - } - } - - #[test] - pub fn test_swizzling() { - let p: default::Point3D = point3(1, 2, 3); - assert_eq!(p.xy(), point2(1, 2)); - assert_eq!(p.xz(), point2(1, 3)); - assert_eq!(p.yz(), point2(2, 3)); - } - - #[test] - pub fn test_distance_to() { - let p1 = Point3D::new(1.0, 2.0, 3.0); - let p2 = Point3D::new(2.0, 2.0, 3.0); - - assert_eq!(p1.distance_to(p2), 1.0); - - let p1 = Point3D::new(1.0, 2.0, 3.0); - let p2 = Point3D::new(1.0, 4.0, 3.0); - - assert_eq!(p1.distance_to(p2), 2.0); - - let p1 = Point3D::new(1.0, 2.0, 3.0); - let p2 = Point3D::new(1.0, 2.0, 6.0); - - assert_eq!(p1.distance_to(p2), 3.0); - } - - #[cfg(feature = "mint")] - #[test] - pub fn test_mint() { - let p1 = Point3D::new(1.0, 3.0, 5.0); - let pm: mint::Point3<_> = p1.into(); - let p2 = Point3D::from(pm); - - assert_eq!(p1, p2); - } - - mod ops { - use crate::default::Point3D; - use crate::scale::Scale; - use crate::{size3, vec3, Vector3D}; - - pub enum Mm {} - pub enum Cm {} - - pub type Point3DMm = crate::Point3D; - pub type Point3DCm = crate::Point3D; - - #[test] - pub fn test_neg() { - assert_eq!(-Point3D::new(1.0, 2.0, 3.0), Point3D::new(-1.0, -2.0, -3.0)); - assert_eq!(-Point3D::new(0.0, 0.0, 0.0), Point3D::new(-0.0, -0.0, -0.0)); - assert_eq!(-Point3D::new(-1.0, -2.0, -3.0), Point3D::new(1.0, 2.0, 3.0)); - } - - #[test] - pub fn test_add_size() { - let p1 = Point3DMm::new(1.0, 2.0, 3.0); - let p2 = size3(4.0, 5.0, 6.0); - - let result = p1 + p2; - - assert_eq!(result, Point3DMm::new(5.0, 7.0, 9.0)); - } - - #[test] - pub fn test_add_assign_size() { - let mut p1 = Point3DMm::new(1.0, 2.0, 3.0); - - p1 += size3(4.0, 5.0, 6.0); - - assert_eq!(p1, Point3DMm::new(5.0, 7.0, 9.0)); - } - - #[test] - pub fn test_add_vec() { - let p1 = Point3DMm::new(1.0, 2.0, 3.0); - let p2 = vec3(4.0, 5.0, 6.0); - - let result = p1 + p2; - - assert_eq!(result, Point3DMm::new(5.0, 7.0, 9.0)); - } - - #[test] - pub fn test_add_assign_vec() { - let mut p1 = Point3DMm::new(1.0, 2.0, 3.0); - - p1 += vec3(4.0, 5.0, 6.0); - - assert_eq!(p1, Point3DMm::new(5.0, 7.0, 9.0)); - } - - #[test] - pub fn test_sub() { - let p1 = Point3DMm::new(1.0, 2.0, 3.0); - let p2 = Point3DMm::new(4.0, 5.0, 6.0); - - let result = p1 - p2; - - assert_eq!(result, Vector3D::<_, Mm>::new(-3.0, -3.0, -3.0)); - } - - #[test] - pub fn test_sub_size() { - let p1 = Point3DMm::new(1.0, 2.0, 3.0); - let p2 = size3(4.0, 5.0, 6.0); - - let result = p1 - p2; - - assert_eq!(result, Point3DMm::new(-3.0, -3.0, -3.0)); - } - - #[test] - pub fn test_sub_assign_size() { - let mut p1 = Point3DMm::new(1.0, 2.0, 3.0); - - p1 -= size3(4.0, 5.0, 6.0); - - assert_eq!(p1, Point3DMm::new(-3.0, -3.0, -3.0)); - } - - #[test] - pub fn test_sub_vec() { - let p1 = Point3DMm::new(1.0, 2.0, 3.0); - let p2 = vec3(4.0, 5.0, 6.0); - - let result = p1 - p2; - - assert_eq!(result, Point3DMm::new(-3.0, -3.0, -3.0)); - } - - #[test] - pub fn test_sub_assign_vec() { - let mut p1 = Point3DMm::new(1.0, 2.0, 3.0); - - p1 -= vec3(4.0, 5.0, 6.0); - - assert_eq!(p1, Point3DMm::new(-3.0, -3.0, -3.0)); - } - - #[test] - pub fn test_mul_scalar() { - let p1: Point3D = Point3D::new(3.0, 5.0, 7.0); - - let result = p1 * 5.0; - - assert_eq!(result, Point3D::new(15.0, 25.0, 35.0)); - } - - #[test] - pub fn test_mul_assign_scalar() { - let mut p1: Point3D = Point3D::new(3.0, 5.0, 7.0); - - p1 *= 5.0; - - assert_eq!(p1, Point3D::new(15.0, 25.0, 35.0)); - } - - #[test] - pub fn test_mul_scale() { - let p1 = Point3DMm::new(1.0, 2.0, 3.0); - let cm_per_mm: Scale = Scale::new(0.1); - - let result = p1 * cm_per_mm; - - assert_eq!(result, Point3DCm::new(0.1, 0.2, 0.3)); - } - - #[test] - pub fn test_mul_assign_scale() { - let mut p1 = Point3DMm::new(1.0, 2.0, 3.0); - let scale: Scale = Scale::new(0.1); - - p1 *= scale; - - assert_eq!(p1, Point3DMm::new(0.1, 0.2, 0.3)); - } - - #[test] - pub fn test_div_scalar() { - let p1: Point3D = Point3D::new(15.0, 25.0, 35.0); - - let result = p1 / 5.0; - - assert_eq!(result, Point3D::new(3.0, 5.0, 7.0)); - } - - #[test] - pub fn test_div_assign_scalar() { - let mut p1: Point3D = Point3D::new(15.0, 25.0, 35.0); - - p1 /= 5.0; - - assert_eq!(p1, Point3D::new(3.0, 5.0, 7.0)); - } - - #[test] - pub fn test_div_scale() { - let p1 = Point3DCm::new(0.1, 0.2, 0.3); - let cm_per_mm: Scale = Scale::new(0.1); - - let result = p1 / cm_per_mm; - - assert_eq!(result, Point3DMm::new(1.0, 2.0, 3.0)); - } - - #[test] - pub fn test_div_assign_scale() { - let mut p1 = Point3DMm::new(0.1, 0.2, 0.3); - let scale: Scale = Scale::new(0.1); - - p1 /= scale; - - assert_eq!(p1, Point3DMm::new(1.0, 2.0, 3.0)); - } - } -} diff --git a/third_party/rust/euclid-0.20.14/src/rect.rs b/third_party/rust/euclid-0.20.14/src/rect.rs deleted file mode 100644 index 8edd6d2137ee..000000000000 --- a/third_party/rust/euclid-0.20.14/src/rect.rs +++ /dev/null @@ -1,908 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::UnknownUnit; -use crate::box2d::Box2D; -use crate::nonempty::NonEmpty; -use crate::num::*; -use crate::point::Point2D; -use crate::scale::Scale; -use crate::side_offsets::SideOffsets2D; -use crate::size::Size2D; -use crate::vector::Vector2D; - -use num_traits::NumCast; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -use core::borrow::Borrow; -use core::cmp::PartialOrd; -use core::fmt; -use core::hash::{Hash, Hasher}; -use core::ops::{Add, Div, DivAssign, Mul, MulAssign, Range, Sub}; - -/// A 2d Rectangle optionally tagged with a unit. -#[repr(C)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "serde", - serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>")) -)] -pub struct Rect { - pub origin: Point2D, - pub size: Size2D, -} - -impl Hash for Rect { - fn hash(&self, h: &mut H) { - self.origin.hash(h); - self.size.hash(h); - } -} - -impl Copy for Rect {} - -impl Clone for Rect { - fn clone(&self) -> Self { - Self::new(self.origin.clone(), self.size.clone()) - } -} - -impl PartialEq for Rect { - fn eq(&self, other: &Self) -> bool { - self.origin.eq(&other.origin) && self.size.eq(&other.size) - } -} - -impl Eq for Rect {} - -impl fmt::Debug for Rect { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Rect(")?; - fmt::Debug::fmt(&self.size, f)?; - write!(f, " at ")?; - fmt::Debug::fmt(&self.origin, f)?; - write!(f, ")") - } -} - -impl fmt::Display for Rect { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Rect(")?; - fmt::Display::fmt(&self.size, f)?; - write!(f, " at ")?; - fmt::Display::fmt(&self.origin, f)?; - write!(f, ")") - } -} - -impl Default for Rect { - fn default() -> Self { - Rect::new(Default::default(), Default::default()) - } -} - -impl Rect { - /// Constructor. - #[inline] - pub const fn new(origin: Point2D, size: Size2D) -> Self { - Rect { origin, size } - } -} - -impl Rect -where - T: Zero, -{ - /// Constructor, setting all sides to zero. - #[inline] - pub fn zero() -> Self { - Rect::new(Point2D::origin(), Size2D::zero()) - } - - /// Creates a rect of the given size, at offset zero. - #[inline] - pub fn from_size(size: Size2D) -> Self { - Rect { - origin: Point2D::zero(), - size, - } - } -} - -impl Rect -where - T: Copy + Add, -{ - #[inline] - pub fn min(&self) -> Point2D { - self.origin - } - - #[inline] - pub fn max(&self) -> Point2D { - self.origin + self.size - } - - #[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 width(&self) -> T { - self.size.width - } - - #[inline] - pub fn height(&self) -> T { - self.size.height - } - - #[inline] - pub fn x_range(&self) -> Range { - self.min_x()..self.max_x() - } - - #[inline] - pub fn y_range(&self) -> Range { - self.min_y()..self.max_y() - } - - /// Returns the same rectangle, translated by a vector. - #[inline] - #[must_use] - pub fn translate(&self, by: Vector2D) -> Self { - Self::new(self.origin + by, self.size) - } - - #[inline] - pub fn to_box2d(&self) -> Box2D { - Box2D { - min: self.min(), - max: self.max(), - } - } -} - -impl Rect -where - T: Copy + PartialOrd + Add, -{ - /// 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, p: Point2D) -> bool { - self.to_box2d().contains(p) - } - - #[inline] - pub fn intersects(&self, other: &Self) -> bool { - self.to_box2d().intersects(&other.to_box2d()) - } -} - -impl Rect -where - T: Copy + PartialOrd + Add + Sub, -{ - #[inline] - pub fn intersection(&self, other: &Self) -> Option { - let box2d = self.to_box2d().intersection(&other.to_box2d()); - if box2d.is_empty_or_negative() { - return None; - } - - Some(box2d.to_rect()) - } -} - -impl Rect -where - T: Copy + Add + Sub, -{ - #[inline] - #[must_use] - pub fn inflate(&self, width: T, height: T) -> Self { - Rect::new( - Point2D::new(self.origin.x - width, self.origin.y - height), - Size2D::new( - self.size.width + width + width, - self.size.height + height + height, - ), - ) - } -} - -impl Rect -where - T: Copy + Zero + PartialOrd + Add, -{ - /// 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: &Self) -> bool { - rect.is_empty_or_negative() - || (self.min_x() <= rect.min_x() - && rect.max_x() <= self.max_x() - && self.min_y() <= rect.min_y() - && rect.max_y() <= self.max_y()) - } -} - -impl Rect -where - T: Copy + Zero + PartialOrd + Add + Sub, -{ - /// Calculate the size and position of an inner rectangle. - /// - /// Subtracts the side offsets from all sides. The horizontal and vertical - /// offsets must not be larger than the original side length. - /// This method assumes y oriented downward. - pub fn inner_rect(&self, offsets: SideOffsets2D) -> Self { - let rect = Rect::new( - Point2D::new(self.origin.x + offsets.left, self.origin.y + offsets.top), - Size2D::new( - self.size.width - offsets.horizontal(), - self.size.height - offsets.vertical(), - ), - ); - debug_assert!(rect.size.width >= Zero::zero()); - debug_assert!(rect.size.height >= Zero::zero()); - rect - } -} - -impl Rect -where - T: Copy + Add + Sub, -{ - /// Calculate the size and position of an outer rectangle. - /// - /// Add the offsets to all sides. The expanded rectangle is returned. - /// This method assumes y oriented downward. - pub fn outer_rect(&self, offsets: SideOffsets2D) -> Self { - Rect::new( - Point2D::new(self.origin.x - offsets.left, self.origin.y - offsets.top), - Size2D::new( - self.size.width + offsets.horizontal(), - self.size.height + offsets.vertical(), - ), - ) - } -} - -impl Rect -where - T: Copy + Zero + PartialOrd + Sub, -{ - /// Returns the smallest rectangle defined by the top/bottom/left/right-most - /// points provided as parameter. - /// - /// Note: This function has a behavior that can be surprising because - /// the right-most and bottom-most points are exactly on the edge - /// of the rectangle while the `contains` function is has exclusive - /// semantic on these edges. This means that the right-most and bottom-most - /// points provided to `from_points` will count as not contained by the rect. - /// This behavior may change in the future. - pub fn from_points(points: I) -> Self - where - I: IntoIterator, - I::Item: Borrow>, - { - Box2D::from_points(points).to_rect() - } -} - -impl Rect -where - T: Copy + One + Add + Sub + Mul, -{ - /// Linearly interpolate between this rectangle and another rectangle. - #[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 Rect -where - T: Copy + One + Add + Div, -{ - pub fn center(&self) -> Point2D { - let two = T::one() + T::one(); - self.origin + self.size.to_vector() / two - } -} - -impl Rect -where - T: Copy + PartialOrd + Add + Sub + Zero, -{ - #[inline] - pub fn union(&self, other: &Self) -> Self { - if self.size == Zero::zero() { - return *other; - } - if other.size == Zero::zero() { - return *self; - } - - self.to_box2d().union(&other.to_box2d()).to_rect() - } -} - -impl Rect { - #[inline] - pub fn scale(&self, x: S, y: S) -> Self - where - T: Copy + Mul, - { - Rect::new( - Point2D::new(self.origin.x * x, self.origin.y * y), - Size2D::new(self.size.width * x, self.size.height * y), - ) - } -} - -impl, U> Rect { - #[inline] - pub fn area(&self) -> T { - self.size.area() - } -} - -impl Rect { - /// 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() - } -} - -impl Rect { - #[inline] - pub fn is_empty_or_negative(&self) -> bool { - self.size.is_empty_or_negative() - } -} - -impl Rect { - #[inline] - pub fn to_non_empty(&self) -> Option> { - if self.is_empty_or_negative() { - return None; - } - - Some(NonEmpty(*self)) - } -} - -impl Mul for Rect { - type Output = Rect; - - #[inline] - fn mul(self, scale: T) -> Self::Output { - Rect::new(self.origin * scale.clone(), self.size * scale) - } -} - -impl MulAssign for Rect { - #[inline] - fn mul_assign(&mut self, scale: T) { - *self *= Scale::new(scale); - } -} - -impl Div for Rect { - type Output = Rect; - - #[inline] - fn div(self, scale: T) -> Self::Output { - Rect::new(self.origin / scale.clone(), self.size / scale) - } -} - -impl DivAssign for Rect { - #[inline] - fn div_assign(&mut self, scale: T) { - *self /= Scale::new(scale); - } -} - -impl Mul> for Rect { - type Output = Rect; - - #[inline] - fn mul(self, scale: Scale) -> Self::Output { - Rect::new(self.origin * scale.clone(), self.size * scale) - } -} - -impl MulAssign> for Rect { - #[inline] - fn mul_assign(&mut self, scale: Scale) { - self.origin *= scale.clone(); - self.size *= scale; - } -} - -impl Div> for Rect { - type Output = Rect; - - #[inline] - fn div(self, scale: Scale) -> Self::Output { - Rect::new(self.origin / scale.clone(), self.size / scale) - } -} - -impl DivAssign> for Rect { - #[inline] - fn div_assign(&mut self, scale: Scale) { - self.origin /= scale.clone(); - self.size /= scale; - } -} - -impl Rect { - /// Drop the units, preserving only the numeric value. - #[inline] - pub fn to_untyped(&self) -> Rect { - Rect::new(self.origin.to_untyped(), self.size.to_untyped()) - } - - /// Tag a unitless value with units. - #[inline] - pub fn from_untyped(r: &Rect) -> Rect { - Rect::new( - Point2D::from_untyped(r.origin), - Size2D::from_untyped(r.size), - ) - } - - /// Cast the unit - #[inline] - pub fn cast_unit(&self) -> Rect { - Rect::new(self.origin.cast_unit(), self.size.cast_unit()) - } -} - -impl Rect { - /// 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. - #[inline] - pub fn cast(&self) -> Rect { - Rect::new(self.origin.cast(), self.size.cast()) - } - - /// Fallible 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 try_cast(&self) -> Option> { - match (self.origin.try_cast(), self.size.try_cast()) { - (Some(origin), Some(size)) => Some(Rect::new(origin, size)), - _ => None, - } - } - - // Convenience functions for common casts - - /// Cast into an `f32` rectangle. - #[inline] - pub fn to_f32(&self) -> Rect { - self.cast() - } - - /// Cast into an `f64` rectangle. - #[inline] - pub fn to_f64(&self) -> Rect { - self.cast() - } - - /// 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. - #[inline] - pub fn to_usize(&self) -> Rect { - self.cast() - } - - /// Cast into an `u32` 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. - #[inline] - pub fn to_u32(&self) -> Rect { - self.cast() - } - - /// Cast into an `u64` 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. - #[inline] - pub fn to_u64(&self) -> Rect { - self.cast() - } - - /// 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. - #[inline] - pub fn to_i32(&self) -> Rect { - self.cast() - } - - /// 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. - #[inline] - pub fn to_i64(&self) -> Rect { - self.cast() - } -} - -impl + Sub, U> Rect { - /// 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). - /// - /// # Usage notes - /// Note, that when using with floating-point `T` types that method can significantly - /// loose precision for large values, so if you need to call this method very often it - /// is better to use [`Box2D`]. - /// - /// [`Box2D`]: struct.Box2D.html - #[must_use] - pub fn round(&self) -> Self { - self.to_box2d().round().to_rect() - } - - /// Return a rectangle with edges rounded to integer coordinates, such that - /// the original rectangle contains the resulting rectangle. - /// - /// # Usage notes - /// Note, that when using with floating-point `T` types that method can significantly - /// loose precision for large values, so if you need to call this method very often it - /// is better to use [`Box2D`]. - /// - /// [`Box2D`]: struct.Box2D.html - #[must_use] - pub fn round_in(&self) -> Self { - self.to_box2d().round_in().to_rect() - } - - /// Return a rectangle with edges rounded to integer coordinates, such that - /// the original rectangle is contained in the resulting rectangle. - /// - /// # Usage notes - /// Note, that when using with floating-point `T` types that method can significantly - /// loose precision for large values, so if you need to call this method very often it - /// is better to use [`Box2D`]. - /// - /// [`Box2D`]: struct.Box2D.html - #[must_use] - pub fn round_out(&self) -> Self { - self.to_box2d().round_out().to_rect() - } -} - -impl From> for Rect -where - T: Zero, -{ - fn from(size: Size2D) -> Self { - Self::from_size(size) - } -} - -/// Shorthand for `Rect::new(Point2D::new(x, y), Size2D::new(w, h))`. -pub const fn rect(x: T, y: T, w: T, h: T) -> Rect { - Rect::new(Point2D::new(x, y), Size2D::new(w, h)) -} - -#[cfg(test)] -mod tests { - use crate::default::{Point2D, Rect, Size2D}; - use crate::side_offsets::SideOffsets2D; - use crate::{point2, rect, size2, vec2}; - - #[test] - fn test_translate() { - let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32)); - 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(vec2(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_intersection_overflow() { - // test some scenarios where the intersection can overflow but - // the min_x() and max_x() don't. Gecko currently fails these cases - let p = Rect::new(Point2D::new(-2147483648, -2147483648), Size2D::new(0, 0)); - let q = Rect::new( - Point2D::new(2136893440, 2136893440), - Size2D::new(279552, 279552), - ); - let r = Rect::new(Point2D::new(-2147483648, -2147483648), Size2D::new(1, 1)); - - assert!(p.is_empty()); - let pq = p.intersection(&q); - assert!(pq.is_none()); - - 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(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] - 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_inner_outer_rect() { - let inner_rect = Rect::new(point2(20, 40), size2(80, 100)); - let offsets = SideOffsets2D::new(20, 10, 10, 10); - let outer_rect = inner_rect.outer_rect(offsets); - assert_eq!(outer_rect.origin.x, 10); - assert_eq!(outer_rect.origin.y, 20); - assert_eq!(outer_rect.size.width, 100); - assert_eq!(outer_rect.size.height, 130); - assert_eq!(outer_rect.inner_rect(offsets), inner_rect); - } - - #[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_width_height() { - let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40)); - assert!(r.width() == 50); - assert!(r.height() == 40); - } - - #[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 - } - } - - #[test] - fn test_center() { - let r: Rect = rect(-2, 5, 4, 10); - assert_eq!(r.center(), point2(0, 10)); - - let r: Rect = rect(1.0, 2.0, 3.0, 4.0); - assert_eq!(r.center(), point2(2.5, 4.0)); - } - - #[test] - fn test_nan() { - let r1: Rect = rect(-2.0, 5.0, 4.0, std::f32::NAN); - let r2: Rect = rect(std::f32::NAN, -1.0, 3.0, 10.0); - - assert_eq!(r1.intersection(&r2), None); - } -} diff --git a/third_party/rust/euclid-0.20.14/src/rigid.rs b/third_party/rust/euclid-0.20.14/src/rigid.rs deleted file mode 100644 index e6042bf14b09..000000000000 --- a/third_party/rust/euclid-0.20.14/src/rigid.rs +++ /dev/null @@ -1,285 +0,0 @@ -//! All matrix multiplication in this module is in row-vector notation, -//! i.e. a vector `v` is transformed with `v * T`, and if you want to apply `T1` -//! before `T2` you use `T1 * T2` - -use crate::approxeq::ApproxEq; -use crate::trig::Trig; -use crate::{Rotation3D, Transform3D, UnknownUnit, Vector3D}; -use num_traits::Float; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -/// A rigid transformation. All lengths are preserved under such a transformation. -/// -/// -/// Internally, this is a rotation and a translation, with the rotation -/// applied first (i.e. `Rotation * Translation`, in row-vector notation) -/// -/// This can be more efficient to use over full matrices, especially if you -/// have to deal with the decomposed quantities often. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[repr(C)] -pub struct RigidTransform3D { - pub rotation: Rotation3D, - pub translation: Vector3D, -} - -impl RigidTransform3D { - /// Construct a new rigid transformation, where the `rotation` applies first - #[inline] - pub const fn new(rotation: Rotation3D, translation: Vector3D) -> Self { - Self { - rotation, - translation, - } - } -} - -impl RigidTransform3D { - pub fn cast_unit(&self) -> RigidTransform3D { - RigidTransform3D { - rotation: self.rotation.cast_unit(), - translation: self.translation.cast_unit(), - } - } -} - -impl, Src, Dst> RigidTransform3D { - /// Construct an identity transform - #[inline] - pub fn identity() -> Self { - Self { - rotation: Rotation3D::identity(), - translation: Vector3D::zero(), - } - } - - /// Construct a new rigid transformation, where the `translation` applies first - #[inline] - pub fn new_from_reversed( - translation: Vector3D, - rotation: Rotation3D, - ) -> Self { - // T * R - // = (R * R^-1) * T * R - // = R * (R^-1 * T * R) - // = R * T' - // - // T' = (R^-1 * T * R) is also a translation matrix - // It is equivalent to the translation matrix obtained by rotating the - // translation by R - - let translation = rotation.transform_vector3d(translation); - Self { - rotation, - translation, - } - } - - #[inline] - pub fn from_rotation(rotation: Rotation3D) -> Self { - Self { - rotation, - translation: Vector3D::zero(), - } - } - - #[inline] - pub fn from_translation(translation: Vector3D) -> Self { - Self { - translation, - rotation: Rotation3D::identity(), - } - } - - /// Decompose this into a translation and an rotation to be applied in the opposite order - /// - /// i.e., the translation is applied _first_ - #[inline] - pub fn decompose_reversed(&self) -> (Vector3D, Rotation3D) { - // self = R * T - // = R * T * (R^-1 * R) - // = (R * T * R^-1) * R) - // = T' * R - // - // T' = (R^ * T * R^-1) is T rotated by R^-1 - - let translation = self.rotation.inverse().transform_vector3d(self.translation); - (translation, self.rotation) - } - - /// Returns the multiplication of the two transforms such that - /// other's transformation applies after self's transformation. - /// - /// i.e., this produces `self * other` in row-vector notation - #[inline] - pub fn post_transform( - &self, - other: &RigidTransform3D, - ) -> RigidTransform3D { - // self = R1 * T1 - // other = R2 * T2 - // result = R1 * T1 * R2 * T2 - // = R1 * (R2 * R2^-1) * T1 * R2 * T2 - // = (R1 * R2) * (R2^-1 * T1 * R2) * T2 - // = R' * T' * T2 - // = R' * T'' - // - // (R2^-1 * T2 * R2^) = T' = T2 rotated by R2 - // R1 * R2 = R' - // T' * T2 = T'' = vector addition of translations T2 and T' - - let t_prime = other.rotation.transform_vector3d(self.translation); - let r_prime = self.rotation.post_rotate(&other.rotation); - let t_prime2 = t_prime + other.translation; - RigidTransform3D { - rotation: r_prime, - translation: t_prime2, - } - } - - /// Returns the multiplication of the two transforms such that - /// self's transformation applies after other's transformation. - /// - /// i.e., this produces `other * self` in row-vector notation - #[inline] - pub fn pre_transform( - &self, - other: &RigidTransform3D, - ) -> RigidTransform3D { - other.post_transform(&self) - } - - /// Inverts the transformation - #[inline] - pub fn inverse(&self) -> RigidTransform3D { - // result = (self)^-1 - // = (R * T)^-1 - // = T^-1 * R^-1 - // = (R^-1 * R) * T^-1 * R^-1 - // = R^-1 * (R * T^-1 * R^-1) - // = R' * T' - // - // T' = (R * T^-1 * R^-1) = (-T) rotated by R^-1 - // R' = R^-1 - // - // An easier way of writing this is to use new_from_reversed() with R^-1 and T^-1 - - RigidTransform3D::new_from_reversed(-self.translation, self.rotation.inverse()) - } - - pub fn to_transform(&self) -> Transform3D - where - T: Trig, - { - self.translation - .to_transform() - .pre_transform(&self.rotation.to_transform()) - } - - /// Drop the units, preserving only the numeric value. - #[inline] - pub fn to_untyped(&self) -> RigidTransform3D { - RigidTransform3D { - rotation: self.rotation.to_untyped(), - translation: self.translation.to_untyped(), - } - } - - /// Tag a unitless value with units. - #[inline] - pub fn from_untyped(transform: &RigidTransform3D) -> Self { - RigidTransform3D { - rotation: Rotation3D::from_untyped(&transform.rotation), - translation: Vector3D::from_untyped(transform.translation), - } - } -} - -impl, Src, Dst> From> - for RigidTransform3D -{ - fn from(rot: Rotation3D) -> Self { - Self::from_rotation(rot) - } -} - -impl, Src, Dst> From> for RigidTransform3D { - fn from(t: Vector3D) -> Self { - Self::from_translation(t) - } -} - -#[cfg(test)] -mod test { - use super::RigidTransform3D; - use crate::default::{Rotation3D, Transform3D, Vector3D}; - - #[test] - fn test_rigid_construction() { - let translation = Vector3D::new(12.1, 17.8, -5.5); - let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3); - - let rigid = RigidTransform3D::new(rotation, translation); - assert!(rigid.to_transform().approx_eq( - &translation - .to_transform() - .pre_transform(&rotation.to_transform()) - )); - - let rigid = RigidTransform3D::new_from_reversed(translation, rotation); - assert!(rigid.to_transform().approx_eq( - &translation - .to_transform() - .post_transform(&rotation.to_transform()) - )); - } - - #[test] - fn test_rigid_decomposition() { - let translation = Vector3D::new(12.1, 17.8, -5.5); - let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3); - - let rigid = RigidTransform3D::new(rotation, translation); - let (t2, r2) = rigid.decompose_reversed(); - assert!(rigid - .to_transform() - .approx_eq(&t2.to_transform().post_transform(&r2.to_transform()))); - } - - #[test] - fn test_rigid_inverse() { - let translation = Vector3D::new(12.1, 17.8, -5.5); - let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3); - - let rigid = RigidTransform3D::new(rotation, translation); - let inverse = rigid.inverse(); - assert!(rigid - .post_transform(&inverse) - .to_transform() - .approx_eq(&Transform3D::identity())); - assert!(inverse - .to_transform() - .approx_eq(&rigid.to_transform().inverse().unwrap())); - } - - #[test] - fn test_rigid_multiply() { - let translation = Vector3D::new(12.1, 17.8, -5.5); - let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3); - let translation2 = Vector3D::new(9.3, -3.9, 1.1); - let rotation2 = Rotation3D::unit_quaternion(0.1, 0.2, 0.3, -0.4); - let rigid = RigidTransform3D::new(rotation, translation); - let rigid2 = RigidTransform3D::new(rotation2, translation2); - - assert!(rigid - .post_transform(&rigid2) - .to_transform() - .approx_eq(&rigid.to_transform().post_transform(&rigid2.to_transform()))); - assert!(rigid - .pre_transform(&rigid2) - .to_transform() - .approx_eq(&rigid.to_transform().pre_transform(&rigid2.to_transform()))); - } -} diff --git a/third_party/rust/euclid-0.20.14/src/rotation.rs b/third_party/rust/euclid-0.20.14/src/rotation.rs deleted file mode 100644 index 1738e026d1b2..000000000000 --- a/third_party/rust/euclid-0.20.14/src/rotation.rs +++ /dev/null @@ -1,1026 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use crate::approxeq::ApproxEq; -use crate::trig::Trig; -use crate::{point2, point3, vec3, Angle, Point2D, Point3D, Vector2D, Vector3D}; -use crate::{Transform2D, Transform3D, UnknownUnit}; -use core::cmp::{Eq, PartialEq}; -use core::fmt; -use core::hash::Hash; -use core::marker::PhantomData; -use core::ops::{Add, Mul, Neg, Sub}; -use num_traits::{Float, NumCast, One, Zero}; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -/// A transform that can represent rotations in 2d, represented as an angle in radians. -#[repr(C)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "serde", - serde(bound( - serialize = "T: serde::Serialize", - deserialize = "T: serde::Deserialize<'de>" - )) -)] -pub struct Rotation2D { - /// Angle in radians - pub angle: T, - #[doc(hidden)] - pub _unit: PhantomData<(Src, Dst)>, -} - -impl Copy for Rotation2D {} - -impl Clone for Rotation2D { - fn clone(&self) -> Self { - Rotation2D { - angle: self.angle.clone(), - _unit: PhantomData, - } - } -} - -impl Eq for Rotation2D where T: Eq {} - -impl PartialEq for Rotation2D -where - T: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - self.angle == other.angle - } -} - -impl Hash for Rotation2D -where - T: Hash, -{ - fn hash(&self, h: &mut H) { - self.angle.hash(h); - } -} - -impl Rotation2D { - /// Creates a rotation from an angle in radians. - #[inline] - pub fn new(angle: Angle) -> Self { - Rotation2D { - angle: angle.radians, - _unit: PhantomData, - } - } - - /// Creates a rotation from an angle in radians. - pub fn radians(angle: T) -> Self { - Self::new(Angle::radians(angle)) - } - - /// Creates the identity rotation. - #[inline] - pub fn identity() -> Self - where - T: Zero, - { - Self::radians(T::zero()) - } -} - -impl Rotation2D { - /// Cast the unit, preserving the numeric value. - /// - /// # Example - /// - /// ```rust - /// # use euclid::Rotation2D; - /// enum Local {} - /// enum World {} - /// - /// enum Local2 {} - /// enum World2 {} - /// - /// let to_world: Rotation2D<_, Local, World> = Rotation2D::radians(42); - /// - /// assert_eq!(to_world.angle, to_world.cast_unit::().angle); - /// ``` - #[inline] - pub fn cast_unit(&self) -> Rotation2D { - Rotation2D { - angle: self.angle, - _unit: PhantomData, - } - } - - /// Drop the units, preserving only the numeric value. - /// - /// # Example - /// - /// ```rust - /// # use euclid::Rotation2D; - /// enum Local {} - /// enum World {} - /// - /// let to_world: Rotation2D<_, Local, World> = Rotation2D::radians(42); - /// - /// assert_eq!(to_world.angle, to_world.to_untyped().angle); - /// ``` - #[inline] - pub fn to_untyped(&self) -> Rotation2D { - self.cast_unit() - } - - /// Tag a unitless value with units. - /// - /// # Example - /// - /// ```rust - /// # use euclid::Rotation2D; - /// use euclid::UnknownUnit; - /// enum Local {} - /// enum World {} - /// - /// let rot: Rotation2D<_, UnknownUnit, UnknownUnit> = Rotation2D::radians(42); - /// - /// assert_eq!(rot.angle, Rotation2D::<_, Local, World>::from_untyped(&rot).angle); - /// ``` - #[inline] - pub fn from_untyped(r: &Rotation2D) -> Self { - r.cast_unit() - } -} - -impl Rotation2D -where - T: Clone, -{ - /// Returns self.angle as a strongly typed `Angle`. - pub fn get_angle(&self) -> Angle { - Angle::radians(self.angle.clone()) - } -} - -impl Rotation2D { - /// Creates a 3d rotation (around the z axis) from this 2d rotation. - #[inline] - pub fn to_3d(&self) -> Rotation3D { - Rotation3D::around_z(self.get_angle()) - } - - /// Returns the inverse of this rotation. - #[inline] - pub fn inverse(&self) -> Rotation2D { - Rotation2D::radians(-self.angle) - } - - /// Returns a rotation representing the other rotation followed by this rotation. - #[inline] - pub fn pre_rotate( - &self, - other: &Rotation2D, - ) -> Rotation2D { - Rotation2D::radians(self.angle + other.angle) - } - - /// Returns a rotation representing this rotation followed by the other rotation. - #[inline] - pub fn post_rotate( - &self, - other: &Rotation2D, - ) -> Rotation2D { - other.pre_rotate(self) - } - - /// Returns the given 2d point transformed by this rotation. - /// - /// The input point must be use the unit Src, and the returned point has the unit Dst. - #[inline] - pub fn transform_point(&self, point: Point2D) -> Point2D { - let (sin, cos) = Float::sin_cos(self.angle); - point2(point.x * cos - point.y * sin, point.y * cos + point.x * sin) - } - - /// Returns the given 2d vector transformed by this rotation. - /// - /// The input point must be use the unit Src, and the returned point has the unit Dst. - #[inline] - pub fn transform_vector(&self, vector: Vector2D) -> Vector2D { - self.transform_point(vector.to_point()).to_vector() - } -} - -impl Rotation2D -where - T: Copy + Add + Sub + Mul + Zero + Trig, -{ - /// Returns the matrix representation of this rotation. - #[inline] - pub fn to_transform(&self) -> Transform2D { - Transform2D::create_rotation(self.get_angle()) - } -} - -/// A transform that can represent rotations in 3d, represented as a quaternion. -/// -/// Most methods expect the quaternion to be normalized. -/// When in doubt, use `unit_quaternion` instead of `quaternion` to create -/// a rotation as the former will ensure that its result is normalized. -/// -/// Some people use the `x, y, z, w` (or `w, x, y, z`) notations. The equivalence is -/// as follows: `x -> i`, `y -> j`, `z -> k`, `w -> r`. -/// The memory layout of this type corresponds to the `x, y, z, w` notation -#[repr(C)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "serde", - serde(bound( - serialize = "T: serde::Serialize", - deserialize = "T: serde::Deserialize<'de>" - )) -)] -pub struct Rotation3D { - /// Component multiplied by the imaginary number `i`. - pub i: T, - /// Component multiplied by the imaginary number `j`. - pub j: T, - /// Component multiplied by the imaginary number `k`. - pub k: T, - /// The real part. - pub r: T, - #[doc(hidden)] - pub _unit: PhantomData<(Src, Dst)>, -} - -impl Copy for Rotation3D {} - -impl Clone for Rotation3D { - fn clone(&self) -> Self { - Rotation3D { - i: self.i.clone(), - j: self.j.clone(), - k: self.k.clone(), - r: self.r.clone(), - _unit: PhantomData, - } - } -} - -impl Eq for Rotation3D where T: Eq {} - -impl PartialEq for Rotation3D -where - T: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - self.i == other.i && self.j == other.j && self.k == other.k && self.r == other.r - } -} - -impl Hash for Rotation3D -where - T: Hash, -{ - fn hash(&self, h: &mut H) { - self.i.hash(h); - self.j.hash(h); - self.k.hash(h); - self.r.hash(h); - } -} - -impl Rotation3D { - /// Creates a rotation around from a quaternion representation. - /// - /// The parameters are a, b, c and r compose the quaternion `a*i + b*j + c*k + r` - /// where `a`, `b` and `c` describe the vector part and the last parameter `r` is - /// the real part. - /// - /// The resulting quaternion is not necessarily normalized. See [`unit_quaternion`]. - /// - /// [`unit_quaternion`]: #method.unit_quaternion - #[inline] - pub fn quaternion(a: T, b: T, c: T, r: T) -> Self { - Rotation3D { - i: a, - j: b, - k: c, - r, - _unit: PhantomData, - } - } - - /// Creates the identity rotation. - #[inline] - pub fn identity() -> Self - where - T: Zero + One, - { - Self::quaternion(T::zero(), T::zero(), T::zero(), T::one()) - } -} - -impl Rotation3D -where - T: Copy, -{ - /// Returns the vector part (i, j, k) of this quaternion. - #[inline] - pub fn vector_part(&self) -> Vector3D { - vec3(self.i, self.j, self.k) - } - - /// Cast the unit, preserving the numeric value. - /// - /// # Example - /// - /// ```rust - /// # use euclid::Rotation3D; - /// enum Local {} - /// enum World {} - /// - /// enum Local2 {} - /// enum World2 {} - /// - /// let to_world: Rotation3D<_, Local, World> = Rotation3D::quaternion(1, 2, 3, 4); - /// - /// assert_eq!(to_world.i, to_world.cast_unit::().i); - /// assert_eq!(to_world.j, to_world.cast_unit::().j); - /// assert_eq!(to_world.k, to_world.cast_unit::().k); - /// assert_eq!(to_world.r, to_world.cast_unit::().r); - /// ``` - #[inline] - pub fn cast_unit(&self) -> Rotation3D { - Rotation3D { - i: self.i, - j: self.j, - k: self.k, - r: self.r, - _unit: PhantomData, - } - } - - /// Drop the units, preserving only the numeric value. - /// - /// # Example - /// - /// ```rust - /// # use euclid::Rotation3D; - /// enum Local {} - /// enum World {} - /// - /// let to_world: Rotation3D<_, Local, World> = Rotation3D::quaternion(1, 2, 3, 4); - /// - /// assert_eq!(to_world.i, to_world.to_untyped().i); - /// assert_eq!(to_world.j, to_world.to_untyped().j); - /// assert_eq!(to_world.k, to_world.to_untyped().k); - /// assert_eq!(to_world.r, to_world.to_untyped().r); - /// ``` - #[inline] - pub fn to_untyped(&self) -> Rotation3D { - self.cast_unit() - } - - /// Tag a unitless value with units. - /// - /// # Example - /// - /// ```rust - /// # use euclid::Rotation3D; - /// use euclid::UnknownUnit; - /// enum Local {} - /// enum World {} - /// - /// let rot: Rotation3D<_, UnknownUnit, UnknownUnit> = Rotation3D::quaternion(1, 2, 3, 4); - /// - /// assert_eq!(rot.i, Rotation3D::<_, Local, World>::from_untyped(&rot).i); - /// assert_eq!(rot.j, Rotation3D::<_, Local, World>::from_untyped(&rot).j); - /// assert_eq!(rot.k, Rotation3D::<_, Local, World>::from_untyped(&rot).k); - /// assert_eq!(rot.r, Rotation3D::<_, Local, World>::from_untyped(&rot).r); - /// ``` - #[inline] - pub fn from_untyped(r: &Rotation3D) -> Self { - r.cast_unit() - } -} - -impl Rotation3D -where - T: Float, -{ - /// Creates a rotation around from a quaternion representation and normalizes it. - /// - /// The parameters are a, b, c and r compose the quaternion `a*i + b*j + c*k + r` - /// before normalization, where `a`, `b` and `c` describe the vector part and the - /// last parameter `r` is the real part. - #[inline] - pub fn unit_quaternion(i: T, j: T, k: T, r: T) -> Self { - Self::quaternion(i, j, k, r).normalize() - } - - /// Creates a rotation around a given axis. - pub fn around_axis(axis: Vector3D, angle: Angle) -> Self { - let axis = axis.normalize(); - let two = T::one() + T::one(); - let (sin, cos) = Angle::sin_cos(angle / two); - Self::quaternion(axis.x * sin, axis.y * sin, axis.z * sin, cos) - } - - /// Creates a rotation around the x axis. - pub fn around_x(angle: Angle) -> Self { - let zero = Zero::zero(); - let two = T::one() + T::one(); - let (sin, cos) = Angle::sin_cos(angle / two); - Self::quaternion(sin, zero, zero, cos) - } - - /// Creates a rotation around the y axis. - pub fn around_y(angle: Angle) -> Self { - let zero = Zero::zero(); - let two = T::one() + T::one(); - let (sin, cos) = Angle::sin_cos(angle / two); - Self::quaternion(zero, sin, zero, cos) - } - - /// Creates a rotation around the z axis. - pub fn around_z(angle: Angle) -> Self { - let zero = Zero::zero(); - let two = T::one() + T::one(); - let (sin, cos) = Angle::sin_cos(angle / two); - Self::quaternion(zero, zero, sin, cos) - } - - /// Creates a rotation from Euler angles. - /// - /// The rotations are applied in roll then pitch then yaw order. - /// - /// - Roll (also called bank) is a rotation around the x axis. - /// - Pitch (also called bearing) is a rotation around the y axis. - /// - Yaw (also called heading) is a rotation around the z axis. - pub fn euler(roll: Angle, pitch: Angle, yaw: Angle) -> Self { - let half = T::one() / (T::one() + T::one()); - - let (sy, cy) = Float::sin_cos(half * yaw.get()); - let (sp, cp) = Float::sin_cos(half * pitch.get()); - let (sr, cr) = Float::sin_cos(half * roll.get()); - - Self::quaternion( - cy * sr * cp - sy * cr * sp, - cy * cr * sp + sy * sr * cp, - sy * cr * cp - cy * sr * sp, - cy * cr * cp + sy * sr * sp, - ) - } - - /// Returns the inverse of this rotation. - #[inline] - pub fn inverse(&self) -> Rotation3D { - Rotation3D::quaternion(-self.i, -self.j, -self.k, self.r) - } - - /// Computes the norm of this quaternion. - #[inline] - pub fn norm(&self) -> T { - self.square_norm().sqrt() - } - - /// Computes the squared norm of this quaternion. - #[inline] - pub fn square_norm(&self) -> T { - self.i * self.i + self.j * self.j + self.k * self.k + self.r * self.r - } - - /// Returns a [unit quaternion] from this one. - /// - /// [unit quaternion]: https://en.wikipedia.org/wiki/Quaternion#Unit_quaternion - #[inline] - pub fn normalize(&self) -> Self { - self.mul(T::one() / self.norm()) - } - - /// Returns `true` if [norm] of this quaternion is (approximately) one. - /// - /// [norm]: #method.norm - #[inline] - pub fn is_normalized(&self) -> bool - where - T: ApproxEq, - { - let eps = NumCast::from(1.0e-5).unwrap(); - self.square_norm().approx_eq_eps(&T::one(), &eps) - } - - /// Spherical linear interpolation between this rotation and another rotation. - /// - /// `t` is expected to be between zero and one. - pub fn slerp(&self, other: &Self, t: T) -> Self - where - T: ApproxEq, - { - debug_assert!(self.is_normalized()); - debug_assert!(other.is_normalized()); - - let r1 = *self; - let mut r2 = *other; - - let mut dot = r1.i * r2.i + r1.j * r2.j + r1.k * r2.k + r1.r * r2.r; - - let one = T::one(); - - if dot.approx_eq(&T::one()) { - // If the inputs are too close, linearly interpolate to avoid precision issues. - return r1.lerp(&r2, t); - } - - // If the dot product is negative, the quaternions - // have opposite handed-ness and slerp won't take - // the shorter path. Fix by reversing one quaternion. - if dot < T::zero() { - r2 = r2.mul(-T::one()); - dot = -dot; - } - - // For robustness, stay within the domain of acos. - dot = Float::min(dot, one); - - // Angle between r1 and the result. - let theta = Float::acos(dot) * t; - - // r1 and r3 form an orthonormal basis. - let r3 = r2.sub(r1.mul(dot)).normalize(); - let (sin, cos) = Float::sin_cos(theta); - r1.mul(cos).add(r3.mul(sin)) - } - - /// Basic Linear interpolation between this rotation and another rotation. - #[inline] - pub fn lerp(&self, other: &Self, t: T) -> Self { - let one_t = T::one() - t; - self.mul(one_t).add(other.mul(t)).normalize() - } - - /// Returns the given 3d point transformed by this rotation. - /// - /// The input point must be use the unit Src, and the returned point has the unit Dst. - pub fn transform_point3d(&self, point: Point3D) -> Point3D - where - T: ApproxEq, - { - debug_assert!(self.is_normalized()); - - let two = T::one() + T::one(); - let cross = self.vector_part().cross(point.to_vector().to_untyped()) * two; - - point3( - point.x + self.r * cross.x + self.j * cross.z - self.k * cross.y, - point.y + self.r * cross.y + self.k * cross.x - self.i * cross.z, - point.z + self.r * cross.z + self.i * cross.y - self.j * cross.x, - ) - } - - /// Returns the given 2d point transformed by this rotation then projected on the xy plane. - /// - /// The input point must be use the unit Src, and the returned point has the unit Dst. - #[inline] - pub fn transform_point2d(&self, point: Point2D) -> Point2D - where - T: ApproxEq, - { - self.transform_point3d(point.to_3d()).xy() - } - - /// Returns the given 3d vector transformed by this rotation. - /// - /// The input vector must be use the unit Src, and the returned point has the unit Dst. - #[inline] - pub fn transform_vector3d(&self, vector: Vector3D) -> Vector3D - where - T: ApproxEq, - { - self.transform_point3d(vector.to_point()).to_vector() - } - - /// Returns the given 2d vector transformed by this rotation then projected on the xy plane. - /// - /// The input vector must be use the unit Src, and the returned point has the unit Dst. - #[inline] - pub fn transform_vector2d(&self, vector: Vector2D) -> Vector2D - where - T: ApproxEq, - { - self.transform_vector3d(vector.to_3d()).xy() - } - - /// Returns the matrix representation of this rotation. - #[inline] - pub fn to_transform(&self) -> Transform3D - where - T: ApproxEq, - { - debug_assert!(self.is_normalized()); - - let i2 = self.i + self.i; - let j2 = self.j + self.j; - let k2 = self.k + self.k; - let ii = self.i * i2; - let ij = self.i * j2; - let ik = self.i * k2; - let jj = self.j * j2; - let jk = self.j * k2; - let kk = self.k * k2; - let ri = self.r * i2; - let rj = self.r * j2; - let rk = self.r * k2; - - let one = T::one(); - let zero = T::zero(); - - let m11 = one - (jj + kk); - let m12 = ij + rk; - let m13 = ik - rj; - - let m21 = ij - rk; - let m22 = one - (ii + kk); - let m23 = jk + ri; - - let m31 = ik + rj; - let m32 = jk - ri; - let m33 = one - (ii + jj); - - Transform3D::row_major( - m11, m12, m13, zero, m21, m22, m23, zero, m31, m32, m33, zero, zero, zero, zero, one, - ) - } - - /// Returns a rotation representing the other rotation followed by this rotation. - pub fn pre_rotate( - &self, - other: &Rotation3D, - ) -> Rotation3D - where - T: ApproxEq, - { - debug_assert!(self.is_normalized()); - Rotation3D::quaternion( - self.i * other.r + self.r * other.i + self.j * other.k - self.k * other.j, - self.j * other.r + self.r * other.j + self.k * other.i - self.i * other.k, - self.k * other.r + self.r * other.k + self.i * other.j - self.j * other.i, - self.r * other.r - self.i * other.i - self.j * other.j - self.k * other.k, - ) - } - - /// Returns a rotation representing this rotation followed by the other rotation. - #[inline] - pub fn post_rotate( - &self, - other: &Rotation3D, - ) -> Rotation3D - where - T: ApproxEq, - { - other.pre_rotate(self) - } - - // add, sub and mul are used internally for intermediate computation but aren't public - // because they don't carry real semantic meanings (I think?). - - #[inline] - fn add(&self, other: Self) -> Self { - Self::quaternion( - self.i + other.i, - self.j + other.j, - self.k + other.k, - self.r + other.r, - ) - } - - #[inline] - fn sub(&self, other: Self) -> Self { - Self::quaternion( - self.i - other.i, - self.j - other.j, - self.k - other.k, - self.r - other.r, - ) - } - - #[inline] - fn mul(&self, factor: T) -> Self { - Self::quaternion( - self.i * factor, - self.j * factor, - self.k * factor, - self.r * factor, - ) - } -} - -impl fmt::Debug for Rotation3D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "Quat({:?}*i + {:?}*j + {:?}*k + {:?})", - self.i, self.j, self.k, self.r - ) - } -} - -impl fmt::Display for Rotation3D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "Quat({}*i + {}*j + {}*k + {})", - self.i, self.j, self.k, self.r - ) - } -} - -impl ApproxEq for Rotation3D -where - T: Copy + Neg + ApproxEq, -{ - fn approx_epsilon() -> T { - T::approx_epsilon() - } - - fn approx_eq_eps(&self, other: &Self, eps: &T) -> bool { - (self.i.approx_eq_eps(&other.i, eps) - && self.j.approx_eq_eps(&other.j, eps) - && self.k.approx_eq_eps(&other.k, eps) - && self.r.approx_eq_eps(&other.r, eps)) - || (self.i.approx_eq_eps(&-other.i, eps) - && self.j.approx_eq_eps(&-other.j, eps) - && self.k.approx_eq_eps(&-other.k, eps) - && self.r.approx_eq_eps(&-other.r, eps)) - } -} - -#[test] -fn simple_rotation_2d() { - use crate::default::Rotation2D; - use core::f32::consts::{FRAC_PI_2, PI}; - - let ri = Rotation2D::identity(); - let r90 = Rotation2D::radians(FRAC_PI_2); - let rm90 = Rotation2D::radians(-FRAC_PI_2); - let r180 = Rotation2D::radians(PI); - - assert!(ri - .transform_point(point2(1.0, 2.0)) - .approx_eq(&point2(1.0, 2.0))); - assert!(r90 - .transform_point(point2(1.0, 2.0)) - .approx_eq(&point2(-2.0, 1.0))); - assert!(rm90 - .transform_point(point2(1.0, 2.0)) - .approx_eq(&point2(2.0, -1.0))); - assert!(r180 - .transform_point(point2(1.0, 2.0)) - .approx_eq(&point2(-1.0, -2.0))); - - assert!(r90 - .inverse() - .inverse() - .transform_point(point2(1.0, 2.0)) - .approx_eq(&r90.transform_point(point2(1.0, 2.0)))); -} - -#[test] -fn simple_rotation_3d_in_2d() { - use crate::default::Rotation3D; - use core::f32::consts::{FRAC_PI_2, PI}; - - let ri = Rotation3D::identity(); - let r90 = Rotation3D::around_z(Angle::radians(FRAC_PI_2)); - let rm90 = Rotation3D::around_z(Angle::radians(-FRAC_PI_2)); - let r180 = Rotation3D::around_z(Angle::radians(PI)); - - assert!(ri - .transform_point2d(point2(1.0, 2.0)) - .approx_eq(&point2(1.0, 2.0))); - assert!(r90 - .transform_point2d(point2(1.0, 2.0)) - .approx_eq(&point2(-2.0, 1.0))); - assert!(rm90 - .transform_point2d(point2(1.0, 2.0)) - .approx_eq(&point2(2.0, -1.0))); - assert!(r180 - .transform_point2d(point2(1.0, 2.0)) - .approx_eq(&point2(-1.0, -2.0))); - - assert!(r90 - .inverse() - .inverse() - .transform_point2d(point2(1.0, 2.0)) - .approx_eq(&r90.transform_point2d(point2(1.0, 2.0)))); -} - -#[test] -fn pre_post() { - use crate::default::Rotation3D; - use core::f32::consts::FRAC_PI_2; - - let r1 = Rotation3D::around_x(Angle::radians(FRAC_PI_2)); - let r2 = Rotation3D::around_y(Angle::radians(FRAC_PI_2)); - let r3 = Rotation3D::around_z(Angle::radians(FRAC_PI_2)); - - let t1 = r1.to_transform(); - let t2 = r2.to_transform(); - let t3 = r3.to_transform(); - - let p = point3(1.0, 2.0, 3.0); - - // Check that the order of transformations is correct (corresponds to what - // we do in Transform3D). - let p1 = r1.post_rotate(&r2).post_rotate(&r3).transform_point3d(p); - let p2 = t1 - .post_transform(&t2) - .post_transform(&t3) - .transform_point3d(p); - - assert!(p1.approx_eq(&p2.unwrap())); - - // Check that changing the order indeed matters. - let p3 = t3 - .post_transform(&t1) - .post_transform(&t2) - .transform_point3d(p); - assert!(!p1.approx_eq(&p3.unwrap())); -} - -#[test] -fn to_transform3d() { - use crate::default::Rotation3D; - - use core::f32::consts::{FRAC_PI_2, PI}; - let rotations = [ - Rotation3D::identity(), - Rotation3D::around_x(Angle::radians(FRAC_PI_2)), - Rotation3D::around_x(Angle::radians(-FRAC_PI_2)), - Rotation3D::around_x(Angle::radians(PI)), - Rotation3D::around_y(Angle::radians(FRAC_PI_2)), - Rotation3D::around_y(Angle::radians(-FRAC_PI_2)), - Rotation3D::around_y(Angle::radians(PI)), - Rotation3D::around_z(Angle::radians(FRAC_PI_2)), - Rotation3D::around_z(Angle::radians(-FRAC_PI_2)), - Rotation3D::around_z(Angle::radians(PI)), - ]; - - let points = [ - point3(0.0, 0.0, 0.0), - point3(1.0, 2.0, 3.0), - point3(-5.0, 3.0, -1.0), - point3(-0.5, -1.0, 1.5), - ]; - - for rotation in &rotations { - for &point in &points { - let p1 = rotation.transform_point3d(point); - let p2 = rotation.to_transform().transform_point3d(point); - assert!(p1.approx_eq(&p2.unwrap())); - } - } -} - -#[test] -fn slerp() { - use crate::default::Rotation3D; - - let q1 = Rotation3D::quaternion(1.0, 0.0, 0.0, 0.0); - let q2 = Rotation3D::quaternion(0.0, 1.0, 0.0, 0.0); - let q3 = Rotation3D::quaternion(0.0, 0.0, -1.0, 0.0); - - // The values below can be obtained with a python program: - // import numpy - // import quaternion - // q1 = numpy.quaternion(1, 0, 0, 0) - // q2 = numpy.quaternion(0, 1, 0, 0) - // quaternion.slerp_evaluate(q1, q2, 0.2) - - assert!(q1.slerp(&q2, 0.0).approx_eq(&q1)); - assert!(q1.slerp(&q2, 0.2).approx_eq(&Rotation3D::quaternion( - 0.951056516295154, - 0.309016994374947, - 0.0, - 0.0 - ))); - assert!(q1.slerp(&q2, 0.4).approx_eq(&Rotation3D::quaternion( - 0.809016994374947, - 0.587785252292473, - 0.0, - 0.0 - ))); - assert!(q1.slerp(&q2, 0.6).approx_eq(&Rotation3D::quaternion( - 0.587785252292473, - 0.809016994374947, - 0.0, - 0.0 - ))); - assert!(q1.slerp(&q2, 0.8).approx_eq(&Rotation3D::quaternion( - 0.309016994374947, - 0.951056516295154, - 0.0, - 0.0 - ))); - assert!(q1.slerp(&q2, 1.0).approx_eq(&q2)); - - assert!(q1.slerp(&q3, 0.0).approx_eq(&q1)); - assert!(q1.slerp(&q3, 0.2).approx_eq(&Rotation3D::quaternion( - 0.951056516295154, - 0.0, - -0.309016994374947, - 0.0 - ))); - assert!(q1.slerp(&q3, 0.4).approx_eq(&Rotation3D::quaternion( - 0.809016994374947, - 0.0, - -0.587785252292473, - 0.0 - ))); - assert!(q1.slerp(&q3, 0.6).approx_eq(&Rotation3D::quaternion( - 0.587785252292473, - 0.0, - -0.809016994374947, - 0.0 - ))); - assert!(q1.slerp(&q3, 0.8).approx_eq(&Rotation3D::quaternion( - 0.309016994374947, - 0.0, - -0.951056516295154, - 0.0 - ))); - assert!(q1.slerp(&q3, 1.0).approx_eq(&q3)); -} - -#[test] -fn around_axis() { - use crate::default::Rotation3D; - use core::f32::consts::{FRAC_PI_2, PI}; - - // Two sort of trivial cases: - let r1 = Rotation3D::around_axis(vec3(1.0, 1.0, 0.0), Angle::radians(PI)); - let r2 = Rotation3D::around_axis(vec3(1.0, 1.0, 0.0), Angle::radians(FRAC_PI_2)); - assert!(r1 - .transform_point3d(point3(1.0, 2.0, 0.0)) - .approx_eq(&point3(2.0, 1.0, 0.0))); - assert!(r2 - .transform_point3d(point3(1.0, 0.0, 0.0)) - .approx_eq(&point3(0.5, 0.5, -0.5.sqrt()))); - - // A more arbitrary test (made up with numpy): - let r3 = Rotation3D::around_axis(vec3(0.5, 1.0, 2.0), Angle::radians(2.291288)); - assert!(r3 - .transform_point3d(point3(1.0, 0.0, 0.0)) - .approx_eq(&point3(-0.58071821, 0.81401868, -0.01182979))); -} - -#[test] -fn from_euler() { - use crate::default::Rotation3D; - use core::f32::consts::FRAC_PI_2; - - // First test simple separate yaw pitch and roll rotations, because it is easy to come - // up with the corresponding quaternion. - // Since several quaternions can represent the same transformation we compare the result - // of transforming a point rather than the values of each quaternions. - let p = point3(1.0, 2.0, 3.0); - - let angle = Angle::radians(FRAC_PI_2); - let zero = Angle::radians(0.0); - - // roll - let roll_re = Rotation3D::euler(angle, zero, zero); - let roll_rq = Rotation3D::around_x(angle); - let roll_pe = roll_re.transform_point3d(p); - let roll_pq = roll_rq.transform_point3d(p); - - // pitch - let pitch_re = Rotation3D::euler(zero, angle, zero); - let pitch_rq = Rotation3D::around_y(angle); - let pitch_pe = pitch_re.transform_point3d(p); - let pitch_pq = pitch_rq.transform_point3d(p); - - // yaw - let yaw_re = Rotation3D::euler(zero, zero, angle); - let yaw_rq = Rotation3D::around_z(angle); - let yaw_pe = yaw_re.transform_point3d(p); - let yaw_pq = yaw_rq.transform_point3d(p); - - assert!(roll_pe.approx_eq(&roll_pq)); - assert!(pitch_pe.approx_eq(&pitch_pq)); - assert!(yaw_pe.approx_eq(&yaw_pq)); - - // Now check that the yaw pitch and roll transformations when combined are applied in - // the proper order: roll -> pitch -> yaw. - let ypr_e = Rotation3D::euler(angle, angle, angle); - let ypr_q = roll_rq.post_rotate(&pitch_rq).post_rotate(&yaw_rq); - let ypr_pe = ypr_e.transform_point3d(p); - let ypr_pq = ypr_q.transform_point3d(p); - - assert!(ypr_pe.approx_eq(&ypr_pq)); -} diff --git a/third_party/rust/euclid-0.20.14/src/scale.rs b/third_party/rust/euclid-0.20.14/src/scale.rs deleted file mode 100644 index 2b4a0c5a8982..000000000000 --- a/third_party/rust/euclid-0.20.14/src/scale.rs +++ /dev/null @@ -1,399 +0,0 @@ -// 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 or the MIT license -// , 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 crate::num::One; - -use crate::{Point2D, Rect, Size2D, Vector2D}; -use core::cmp::Ordering; -use core::fmt; -use core::hash::{Hash, Hasher}; -use core::marker::PhantomData; -use core::ops::{Add, Div, Mul, Neg, Sub}; -use num_traits::NumCast; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -/// 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 `Scale`. They -/// may be types without values, such as empty enums. For example: -/// -/// ```rust -/// use euclid::Scale; -/// use euclid::Length; -/// enum Mm {}; -/// enum Inch {}; -/// -/// let mm_per_inch: Scale = Scale::new(25.4); -/// -/// let one_foot: Length = Length::new(12.0); -/// let one_foot_in_mm: Length = one_foot * mm_per_inch; -/// ``` -#[repr(C)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "serde", - serde(bound( - serialize = "T: serde::Serialize", - deserialize = "T: serde::Deserialize<'de>" - )) -)] -pub struct Scale(pub T, #[doc(hidden)] pub PhantomData<(Src, Dst)>); - -impl Scale { - #[inline] - pub const fn new(x: T) -> Self { - Scale(x, PhantomData) - } - - /// Returns the given point transformed by this scale. - /// - /// # Example - /// - /// ```rust - /// use euclid::{Scale, point2}; - /// enum Mm {}; - /// enum Cm {}; - /// - /// let to_mm: Scale = Scale::new(10); - /// - /// assert_eq!(to_mm.transform_point(point2(42, -42)), point2(420, -420)); - /// ``` - #[inline] - pub fn transform_point(&self, point: Point2D) -> Point2D - where - T: Clone + Mul, - { - Point2D::new(point.x * self.get(), point.y * self.get()) - } - - /// Returns the given vector transformed by this scale. - /// - /// # Example - /// - /// ```rust - /// use euclid::{Scale, vec2}; - /// enum Mm {}; - /// enum Cm {}; - /// - /// let to_mm: Scale = Scale::new(10); - /// - /// assert_eq!(to_mm.transform_vector(vec2(42, -42)), vec2(420, -420)); - /// ``` - #[inline] - pub fn transform_vector(&self, vec: Vector2D) -> Vector2D - where - T: Clone + Mul, - { - Vector2D::new(vec.x * self.get(), vec.y * self.get()) - } - - /// Returns the given vector transformed by this scale. - /// - /// # Example - /// - /// ```rust - /// use euclid::{Scale, size2}; - /// enum Mm {}; - /// enum Cm {}; - /// - /// let to_mm: Scale = Scale::new(10); - /// - /// assert_eq!(to_mm.transform_size(size2(42, -42)), size2(420, -420)); - /// ``` - #[inline] - pub fn transform_size(&self, size: Size2D) -> Size2D - where - T: Clone + Mul, - { - Size2D::new(size.width * self.get(), size.height * self.get()) - } - - /// Returns the given rect transformed by this scale. - /// - /// # Example - /// - /// ```rust - /// use euclid::{Scale, rect}; - /// enum Mm {}; - /// enum Cm {}; - /// - /// let to_mm: Scale = Scale::new(10); - /// - /// assert_eq!(to_mm.transform_rect(&rect(1, 2, 42, -42)), rect(10, 20, 420, -420)); - /// ``` - #[inline] - pub fn transform_rect(&self, rect: &Rect) -> Rect - where - T: Copy + Mul, - { - Rect::new( - self.transform_point(rect.origin), - self.transform_size(rect.size), - ) - } - - /// Returns the inverse of this scale. - #[inline] - pub fn inverse(&self) -> Scale - where - T: Clone + Neg, - { - Scale::new(-self.get()) - } - - /// Returns `true` if this scale has no effect. - /// - /// # Example - /// - /// ```rust - /// use euclid::Scale; - /// use euclid::num::One; - /// enum Mm {}; - /// enum Cm {}; - /// - /// let cm_per_mm: Scale = Scale::new(0.1); - /// let mm_per_mm: Scale = Scale::new(1.0); - /// - /// assert_eq!(cm_per_mm.is_identity(), false); - /// assert_eq!(mm_per_mm.is_identity(), true); - /// assert_eq!(mm_per_mm, Scale::one()); - /// ``` - #[inline] - pub fn is_identity(&self) -> bool - where - T: PartialEq + One, - { - self.0 == T::one() - } -} - -impl Scale { - #[inline] - pub fn get(&self) -> T { - self.0.clone() - } - - /// The inverse Scale (1.0 / self). - /// - /// # Example - /// - /// ```rust - /// use euclid::Scale; - /// enum Mm {}; - /// enum Cm {}; - /// - /// let cm_per_mm: Scale = Scale::new(0.1); - /// - /// assert_eq!(cm_per_mm.inv(), Scale::new(10.0)); - /// ``` - pub fn inv(&self) -> Scale - where - T: One + Div, - { - let one: T = One::one(); - Scale::new(one / self.0.clone()) - } -} - -impl Scale { - /// Cast from one numeric representation to another, preserving the units. - /// - /// # Panics - /// - /// If the source value cannot be represented by the target type `NewT`, then - /// method panics. Use `try_cast` if that must be case. - /// - /// # Example - /// - /// ```rust - /// use euclid::Scale; - /// enum Mm {}; - /// enum Cm {}; - /// - /// let to_mm: Scale = Scale::new(10); - /// - /// assert_eq!(to_mm.cast::(), Scale::new(10.0)); - /// ``` - /// That conversion will panic, because `i32` not enough to store such big numbers: - /// ```rust,should_panic - /// use euclid::Scale; - /// enum Mm {};// millimeter = 10^-2 meters - /// enum Em {};// exameter = 10^18 meters - /// - /// // Panics - /// let to_em: Scale = Scale::new(10e20).cast(); - /// ``` - #[inline] - pub fn cast(&self) -> Scale { - self.try_cast().unwrap() - } - - /// Fallible cast from one numeric representation to another, preserving the units. - /// If the source value cannot be represented by the target type `NewT`, then `None` - /// is returned. - /// - /// # Example - /// - /// ```rust - /// use euclid::Scale; - /// enum Mm {}; - /// enum Cm {}; - /// enum Em {};// Exameter = 10^18 meters - /// - /// let to_mm: Scale = Scale::new(10); - /// let to_em: Scale = Scale::new(10e20); - /// - /// assert_eq!(to_mm.try_cast::(), Some(Scale::new(10.0))); - /// // Integer to small to store that number - /// assert_eq!(to_em.try_cast::(), None); - /// ``` - pub fn try_cast(&self) -> Option> { - NumCast::from(self.get()).map(Scale::new) - } -} - -impl Scale { - /// Identity scaling, could be used to safely transit from one space to another. - pub const ONE: Self = Scale(1.0, PhantomData); -} - -// scale0 * scale1 -// (A,B) * (B,C) = (A,C) -impl Mul> for Scale { - type Output = Scale; - - #[inline] - fn mul(self, other: Scale) -> Self::Output { - Scale::new(self.0 * other.0) - } -} - -// scale0 + scale1 -impl Add for Scale { - type Output = Scale; - - #[inline] - fn add(self, other: Scale) -> Self::Output { - Scale::new(self.0 + other.0) - } -} - -// scale0 - scale1 -impl Sub for Scale { - type Output = Scale; - - #[inline] - fn sub(self, other: Scale) -> Self::Output { - Scale::new(self.0 - other.0) - } -} - -// FIXME: Switch to `derive(PartialEq, Clone)` after this Rust issue is fixed: -// https://github.com/rust-lang/rust/issues/26925 - -impl PartialEq for Scale { - fn eq(&self, other: &Scale) -> bool { - self.0 == other.0 - } -} - -impl Eq for Scale {} - -impl PartialOrd for Scale { - fn partial_cmp(&self, other: &Self) -> Option { - self.0.partial_cmp(&other.0) - } -} - -impl Ord for Scale { - fn cmp(&self, other: &Self) -> Ordering { - self.0.cmp(&other.0) - } -} - -impl Clone for Scale { - fn clone(&self) -> Scale { - Scale::new(self.get()) - } -} - -impl Copy for Scale {} - -impl fmt::Debug for Scale { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::Display for Scale { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl Default for Scale { - fn default() -> Self { - Self::new(T::default()) - } -} - -impl Hash for Scale { - fn hash(&self, state: &mut H) { - self.0.hash(state) - } -} - -impl One for Scale { - #[inline] - fn one() -> Self { - Scale::new(T::one()) - } -} - -#[cfg(test)] -mod tests { - use super::Scale; - - enum Inch {} - enum Cm {} - enum Mm {} - - #[test] - fn test_scale() { - let mm_per_inch: Scale = Scale::new(25.4); - let cm_per_mm: Scale = Scale::new(0.1); - - let mm_per_cm: Scale = cm_per_mm.inv(); - assert_eq!(mm_per_cm.get(), 10.0); - - let one: Scale = cm_per_mm * mm_per_cm; - assert_eq!(one.get(), 1.0); - - let one: Scale = mm_per_cm * cm_per_mm; - assert_eq!(one.get(), 1.0); - - let cm_per_inch: Scale = mm_per_inch * cm_per_mm; - // mm cm cm - // ---- x ---- = ---- - // inch mm inch - assert_eq!(cm_per_inch, Scale::new(2.54)); - - let a: Scale = Scale::new(2); - let b: Scale = Scale::new(3); - assert_ne!(a, b); - assert_eq!(a, a.clone()); - assert_eq!(a.clone() + b.clone(), Scale::new(5)); - assert_eq!(a - b, Scale::new(-1)); - } -} diff --git a/third_party/rust/euclid-0.20.14/src/side_offsets.rs b/third_party/rust/euclid-0.20.14/src/side_offsets.rs deleted file mode 100644 index e2ed922a4229..000000000000 --- a/third_party/rust/euclid-0.20.14/src/side_offsets.rs +++ /dev/null @@ -1,438 +0,0 @@ -// 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 or the MIT license -// , 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 crate::length::Length; -use crate::num::Zero; -use crate::scale::Scale; -use crate::Vector2D; -use core::cmp::{Eq, PartialEq}; -use core::fmt; -use core::hash::Hash; -use core::marker::PhantomData; -use core::ops::{Add, Div, DivAssign, Mul, MulAssign, Neg}; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -/// A group of 2D side offsets, which correspond to top/right/bottom/left for borders, padding, -/// and margins in CSS, optionally tagged with a unit. -#[repr(C)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "serde", - serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>")) -)] -pub struct SideOffsets2D { - pub top: T, - pub right: T, - pub bottom: T, - pub left: T, - #[doc(hidden)] - pub _unit: PhantomData, -} - -impl Copy for SideOffsets2D {} - -impl Clone for SideOffsets2D { - fn clone(&self) -> Self { - SideOffsets2D { - top: self.top.clone(), - right: self.right.clone(), - bottom: self.bottom.clone(), - left: self.left.clone(), - _unit: PhantomData, - } - } -} - -impl Eq for SideOffsets2D where T: Eq {} - -impl PartialEq for SideOffsets2D -where - T: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - self.top == other.top - && self.right == other.right - && self.bottom == other.bottom - && self.left == other.left - } -} - -impl Hash for SideOffsets2D -where - T: Hash, -{ - fn hash(&self, h: &mut H) { - self.top.hash(h); - self.right.hash(h); - self.bottom.hash(h); - self.left.hash(h); - } -} - -impl fmt::Debug for SideOffsets2D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "({:?},{:?},{:?},{:?})", - self.top, self.right, self.bottom, self.left - ) - } -} - -impl Default for SideOffsets2D { - fn default() -> Self { - SideOffsets2D { - top: Default::default(), - right: Default::default(), - bottom: Default::default(), - left: Default::default(), - _unit: PhantomData, - } - } -} - -impl SideOffsets2D { - /// Constructor taking a scalar for each side. - /// - /// Sides are specified in top-right-bottom-left order following - /// CSS's convention. - pub const fn new(top: T, right: T, bottom: T, left: T) -> Self { - SideOffsets2D { - top, - right, - bottom, - left, - _unit: PhantomData, - } - } - - /// Constructor taking a typed Length for each side. - /// - /// Sides are specified in top-right-bottom-left order following - /// CSS's convention. - pub fn from_lengths( - top: Length, - right: Length, - bottom: Length, - left: Length, - ) -> Self { - SideOffsets2D::new(top.0, right.0, bottom.0, left.0) - } - - /// Construct side offsets from min and a max vector offsets. - /// - /// The outer rect of the resulting side offsets is equivalent to translating - /// a rectangle's upper-left corner with the min vector and translating the - /// bottom-right corner with the max vector. - pub fn from_vectors_outer(min: Vector2D, max: Vector2D) -> Self - where - T: Neg, - { - SideOffsets2D { - left: -min.x, - top: -min.y, - right: max.x, - bottom: max.y, - _unit: PhantomData, - } - } - - /// Construct side offsets from min and a max vector offsets. - /// - /// The inner rect of the resulting side offsets is equivalent to translating - /// a rectangle's upper-left corner with the min vector and translating the - /// bottom-right corner with the max vector. - pub fn from_vectors_inner(min: Vector2D, max: Vector2D) -> Self - where - T: Neg, - { - SideOffsets2D { - left: min.x, - top: min.y, - right: -max.x, - bottom: -max.y, - _unit: PhantomData, - } - } - - /// Returns `true` if all side offsets are zero. - pub fn is_zero(&self) -> bool - where - T: Zero + PartialEq, - { - let zero = T::zero(); - self.top == zero && self.right == zero && self.bottom == zero && self.left == zero - } -} - -impl SideOffsets2D { - /// Constructor setting the same value to all sides, taking a scalar value directly. - pub fn new_all_same(all: T) -> Self { - SideOffsets2D::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) -> Self { - SideOffsets2D::new_all_same(all.0) - } -} - -impl SideOffsets2D -where - T: Add + Copy, -{ - pub fn horizontal(&self) -> T { - self.left + self.right - } - - pub fn vertical(&self) -> T { - self.top + self.bottom - } -} - -impl Add for SideOffsets2D -where - T: Add, -{ - type Output = Self; - fn add(self, other: Self) -> Self { - SideOffsets2D::new( - self.top + other.top, - self.right + other.right, - self.bottom + other.bottom, - self.left + other.left, - ) - } -} - -impl SideOffsets2D { - /// Constructor, setting all sides to zero. - pub fn zero() -> Self { - SideOffsets2D::new(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero()) - } -} - -impl Mul for SideOffsets2D { - type Output = SideOffsets2D; - - #[inline] - fn mul(self, scale: T) -> Self::Output { - SideOffsets2D::new( - self.top * scale.clone(), - self.right * scale.clone(), - self.bottom * scale.clone(), - self.left * scale, - ) - } -} - -impl MulAssign for SideOffsets2D { - #[inline] - fn mul_assign(&mut self, other: T) { - self.top *= other.clone(); - self.right *= other.clone(); - self.bottom *= other.clone(); - self.left *= other; - } -} - -impl Mul> for SideOffsets2D { - type Output = SideOffsets2D; - - #[inline] - fn mul(self, scale: Scale) -> Self::Output { - SideOffsets2D::new( - self.top * scale.0.clone(), - self.right * scale.0.clone(), - self.bottom * scale.0.clone(), - self.left * scale.0, - ) - } -} - -impl MulAssign> for SideOffsets2D { - #[inline] - fn mul_assign(&mut self, other: Scale) { - *self *= other.0; - } -} - -impl Div for SideOffsets2D { - type Output = SideOffsets2D; - - #[inline] - fn div(self, scale: T) -> Self::Output { - SideOffsets2D::new( - self.top / scale.clone(), - self.right / scale.clone(), - self.bottom / scale.clone(), - self.left / scale, - ) - } -} - -impl DivAssign for SideOffsets2D { - #[inline] - fn div_assign(&mut self, other: T) { - self.top /= other.clone(); - self.right /= other.clone(); - self.bottom /= other.clone(); - self.left /= other; - } -} - -impl Div> for SideOffsets2D { - type Output = SideOffsets2D; - - #[inline] - fn div(self, scale: Scale) -> Self::Output { - SideOffsets2D::new( - self.top / scale.0.clone(), - self.right / scale.0.clone(), - self.bottom / scale.0.clone(), - self.left / scale.0, - ) - } -} - -impl DivAssign> for SideOffsets2D { - fn div_assign(&mut self, other: Scale) { - *self /= other.0; - } -} - -#[test] -fn from_vectors() { - use crate::{point2, vec2}; - type Box2D = crate::default::Box2D; - - let b = Box2D { - min: point2(10, 10), - max: point2(20, 20), - }; - - let outer = b.outer_box(SideOffsets2D::from_vectors_outer(vec2(-1, -2), vec2(3, 4))); - let inner = b.inner_box(SideOffsets2D::from_vectors_inner(vec2(1, 2), vec2(-3, -4))); - - assert_eq!( - outer, - Box2D { - min: point2(9, 8), - max: point2(23, 24) - } - ); - assert_eq!( - inner, - Box2D { - min: point2(11, 12), - max: point2(17, 16) - } - ); -} - -#[test] -fn test_is_zero() { - let s1: SideOffsets2D = SideOffsets2D::new_all_same(0.0); - assert!(s1.is_zero()); - - let s2: SideOffsets2D = SideOffsets2D::new(1.0, 2.0, 3.0, 4.0); - assert!(!s2.is_zero()); -} - -#[cfg(test)] -mod ops { - use crate::Scale; - - pub enum Mm {} - pub enum Cm {} - - type SideOffsets2D = crate::default::SideOffsets2D; - type SideOffsets2DMm = crate::SideOffsets2D; - type SideOffsets2DCm = crate::SideOffsets2D; - - #[test] - fn test_mul_scalar() { - let s = SideOffsets2D::new(1.0, 2.0, 3.0, 4.0); - - let result = s * 3.0; - - assert_eq!(result, SideOffsets2D::new(3.0, 6.0, 9.0, 12.0)); - } - - #[test] - fn test_mul_assign_scalar() { - let mut s = SideOffsets2D::new(1.0, 2.0, 3.0, 4.0); - - s *= 2.0; - - assert_eq!(s, SideOffsets2D::new(2.0, 4.0, 6.0, 8.0)); - } - - #[test] - fn test_mul_scale() { - let s = SideOffsets2DMm::new(0.0, 1.0, 3.0, 2.0); - let cm_per_mm: Scale = Scale::new(0.1); - - let result = s * cm_per_mm; - - assert_eq!(result, SideOffsets2DCm::new(0.0, 0.1, 0.3, 0.2)); - } - - #[test] - fn test_mul_assign_scale() { - let mut s = SideOffsets2DMm::new(2.0, 4.0, 6.0, 8.0); - let scale: Scale = Scale::new(0.1); - - s *= scale; - - assert_eq!(s, SideOffsets2DMm::new(0.2, 0.4, 0.6, 0.8)); - } - - #[test] - fn test_div_scalar() { - let s = SideOffsets2D::new(10.0, 20.0, 30.0, 40.0); - - let result = s / 10.0; - - assert_eq!(result, SideOffsets2D::new(1.0, 2.0, 3.0, 4.0)); - } - - #[test] - fn test_div_assign_scalar() { - let mut s = SideOffsets2D::new(10.0, 20.0, 30.0, 40.0); - - s /= 10.0; - - assert_eq!(s, SideOffsets2D::new(1.0, 2.0, 3.0, 4.0)); - } - - #[test] - fn test_div_scale() { - let s = SideOffsets2DCm::new(0.1, 0.2, 0.3, 0.4); - let cm_per_mm: Scale = Scale::new(0.1); - - let result = s / cm_per_mm; - - assert_eq!(result, SideOffsets2DMm::new(1.0, 2.0, 3.0, 4.0)); - } - - #[test] - fn test_div_assign_scale() { - let mut s = SideOffsets2DMm::new(0.1, 0.2, 0.3, 0.4); - let scale: Scale = Scale::new(0.1); - - s /= scale; - - assert_eq!(s, SideOffsets2DMm::new(1.0, 2.0, 3.0, 4.0)); - } -} diff --git a/third_party/rust/euclid-0.20.14/src/size.rs b/third_party/rust/euclid-0.20.14/src/size.rs deleted file mode 100644 index 85472e2bdebb..000000000000 --- a/third_party/rust/euclid-0.20.14/src/size.rs +++ /dev/null @@ -1,1718 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::UnknownUnit; -use crate::approxord::{max, min}; -use crate::length::Length; -use crate::num::*; -use crate::scale::Scale; -use crate::vector::{vec2, BoolVector2D, Vector2D}; -use crate::vector::{vec3, BoolVector3D, Vector3D}; -#[cfg(feature = "mint")] -use mint; - -use core::cmp::{Eq, PartialEq}; -use core::fmt; -use core::hash::Hash; -use core::marker::PhantomData; -use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -use num_traits::{NumCast, Signed}; -#[cfg(feature = "serde")] -use serde; - -/// A 2d size tagged with a unit. -#[repr(C)] -pub struct Size2D { - /// The extent of the element in the `U` units along the `x` axis (usually horizontal). - pub width: T, - /// The extent of the element in the `U` units along the `y` axis (usually vertical). - pub height: T, - #[doc(hidden)] - pub _unit: PhantomData, -} - -impl Copy for Size2D {} - -impl Clone for Size2D { - fn clone(&self) -> Self { - Size2D { - width: self.width.clone(), - height: self.height.clone(), - _unit: PhantomData, - } - } -} - -#[cfg(feature = "serde")] -impl<'de, T, U> serde::Deserialize<'de> for Size2D -where - T: serde::Deserialize<'de>, -{ - /// Deserializes 2d size from tuple of width and height. - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let (width, height) = serde::Deserialize::deserialize(deserializer)?; - Ok(Size2D { - width, - height, - _unit: PhantomData, - }) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for Size2D -where - T: serde::Serialize, -{ - /// Serializes 2d size to tuple of width and height. - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - (&self.width, &self.height).serialize(serializer) - } -} - -impl Eq for Size2D where T: Eq {} - -impl PartialEq for Size2D -where - T: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - self.width == other.width && self.height == other.height - } -} - -impl Hash for Size2D -where - T: Hash, -{ - fn hash(&self, h: &mut H) { - self.width.hash(h); - self.height.hash(h); - } -} - -impl fmt::Debug for Size2D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.width, f)?; - write!(f, "x")?; - fmt::Debug::fmt(&self.height, f) - } -} - -impl fmt::Display for Size2D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "(")?; - fmt::Display::fmt(&self.width, f)?; - write!(f, "x")?; - fmt::Display::fmt(&self.height, f)?; - write!(f, ")") - } -} - -impl Default for Size2D { - fn default() -> Self { - Size2D::new(Default::default(), Default::default()) - } -} - -impl Size2D { - /// The same as [`Zero::zero()`] but available without importing trait. - /// - /// [`Zero::zero()`]: ./num/trait.Zero.html#tymethod.zero - #[inline] - pub fn zero() -> Self - where - T: Zero, - { - Size2D::new(Zero::zero(), Zero::zero()) - } - - /// Constructor taking scalar values. - #[inline] - pub const fn new(width: T, height: T) -> Self { - Size2D { - width, - height, - _unit: PhantomData, - } - } - /// Constructor taking scalar strongly typed lengths. - #[inline] - pub fn from_lengths(width: Length, height: Length) -> Self { - Size2D::new(width.0, height.0) - } - - /// Tag a unitless value with units. - #[inline] - pub fn from_untyped(p: Size2D) -> Self { - Size2D::new(p.width, p.height) - } -} - -impl Size2D { - /// Return this size as an array of two elements (width, then height). - #[inline] - pub fn to_array(&self) -> [T; 2] { - [self.width, self.height] - } - - /// Return this size as a tuple of two elements (width, then height). - #[inline] - pub fn to_tuple(&self) -> (T, T) { - (self.width, self.height) - } - - /// Return this size as a vector with width and height. - #[inline] - pub fn to_vector(&self) -> Vector2D { - vec2(self.width, self.height) - } - - /// Drop the units, preserving only the numeric value. - #[inline] - pub fn to_untyped(&self) -> Size2D { - self.cast_unit() - } - - /// Cast the unit - #[inline] - pub fn cast_unit(&self) -> Size2D { - Size2D::new(self.width, self.height) - } - - /// Rounds each component to the nearest integer value. - /// - /// This behavior is preserved for negative values (unlike the basic cast). - /// - /// ```rust - /// # use euclid::size2; - /// enum Mm {} - /// - /// assert_eq!(size2::<_, Mm>(-0.1, -0.8).round(), size2::<_, Mm>(0.0, -1.0)) - /// ``` - #[inline] - #[must_use] - pub fn round(&self) -> Self - where - T: Round, - { - Size2D::new(self.width.round(), self.height.round()) - } - - /// 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). - /// - /// ```rust - /// # use euclid::size2; - /// enum Mm {} - /// - /// assert_eq!(size2::<_, Mm>(-0.1, -0.8).ceil(), size2::<_, Mm>(0.0, 0.0)) - /// ``` - #[inline] - #[must_use] - pub fn ceil(&self) -> Self - where - T: Ceil, - { - Size2D::new(self.width.ceil(), self.height.ceil()) - } - - /// 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). - /// - /// ```rust - /// # use euclid::size2; - /// enum Mm {} - /// - /// assert_eq!(size2::<_, Mm>(-0.1, -0.8).floor(), size2::<_, Mm>(-1.0, -1.0)) - /// ``` - #[inline] - #[must_use] - pub fn floor(&self) -> Self - where - T: Floor, - { - Size2D::new(self.width.floor(), self.height.floor()) - } - - /// Returns result of multiplication of both components - pub fn area(&self) -> T::Output - where - T: Mul, - { - self.width * self.height - } - - /// Linearly interpolate each component between this size and another size. - /// - /// # Example - /// - /// ```rust - /// use euclid::size2; - /// use euclid::default::Size2D; - /// - /// let from: Size2D<_> = size2(0.0, 10.0); - /// let to: Size2D<_> = size2(8.0, -4.0); - /// - /// assert_eq!(from.lerp(to, -1.0), size2(-8.0, 24.0)); - /// assert_eq!(from.lerp(to, 0.0), size2( 0.0, 10.0)); - /// assert_eq!(from.lerp(to, 0.5), size2( 4.0, 3.0)); - /// assert_eq!(from.lerp(to, 1.0), size2( 8.0, -4.0)); - /// assert_eq!(from.lerp(to, 2.0), size2(16.0, -18.0)); - /// ``` - #[inline] - pub fn lerp(&self, other: Self, t: T) -> Self - where - T: One + Sub + Mul + Add, - { - let one_t = T::one() - t; - (*self) * one_t + other * t - } -} - -impl Size2D { - /// 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(&self) -> Size2D { - self.try_cast().unwrap() - } - - /// Fallible 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 try_cast(&self) -> Option> { - match (NumCast::from(self.width), NumCast::from(self.height)) { - (Some(w), Some(h)) => Some(Size2D::new(w, h)), - _ => None, - } - } - - // Convenience functions for common casts - - /// Cast into an `f32` size. - #[inline] - pub fn to_f32(&self) -> Size2D { - self.cast() - } - - /// Cast into an `f64` size. - #[inline] - pub fn to_f64(&self) -> Size2D { - self.cast() - } - - /// 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. - #[inline] - pub fn to_usize(&self) -> Size2D { - self.cast() - } - - /// Cast into an `u32` 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. - #[inline] - pub fn to_u32(&self) -> Size2D { - self.cast() - } - - /// Cast into an `u64` 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. - #[inline] - pub fn to_u64(&self) -> Size2D { - self.cast() - } - - /// 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. - #[inline] - pub fn to_i32(&self) -> Size2D { - self.cast() - } - - /// 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. - #[inline] - pub fn to_i64(&self) -> Size2D { - self.cast() - } -} - -impl Size2D { - /// Computes the absolute value of each component. - /// - /// For `f32` and `f64`, `NaN` will be returned for component if the component is `NaN`. - /// - /// For signed integers, `::MIN` will be returned for component if the component is `::MIN`. - pub fn abs(&self) -> Self { - size2(self.width.abs(), self.height.abs()) - } - - /// Returns `true` if both components is positive and `false` any component is zero or negative. - pub fn is_positive(&self) -> bool { - self.width.is_positive() && self.height.is_positive() - } -} - -impl Size2D { - /// Returns the size each component of which are minimum of this size and another. - #[inline] - pub fn min(self, other: Self) -> Self { - size2(min(self.width, other.width), min(self.height, other.height)) - } - - /// Returns the size each component of which are maximum of this size and another. - #[inline] - pub fn max(self, other: Self) -> Self { - size2(max(self.width, other.width), max(self.height, other.height)) - } - - /// Returns the size each component of which clamped by corresponding - /// components of `start` and `end`. - /// - /// Shortcut for `self.max(start).min(end)`. - #[inline] - pub fn clamp(&self, start: Self, end: Self) -> Self - where - T: Copy, - { - self.max(start).min(end) - } - - /// Returns vector with results of "greater then" operation on each component. - pub fn greater_than(&self, other: Self) -> BoolVector2D { - BoolVector2D { - x: self.width > other.width, - y: self.height > other.height, - } - } - - /// Returns vector with results of "lower then" operation on each component. - pub fn lower_than(&self, other: Self) -> BoolVector2D { - BoolVector2D { - x: self.width < other.width, - y: self.height < other.height, - } - } - - /// Returns `true` if any component of size is zero or negative. - pub fn is_empty_or_negative(&self) -> bool - where - T: Zero, - { - let zero = T::zero(); - // The condition is experessed this way so that we return true in - // the presence of NaN. - !(self.width > zero && self.height > zero) - } -} - -impl Size2D { - /// Returns vector with results of "equal" operation on each component. - pub fn equal(&self, other: Self) -> BoolVector2D { - BoolVector2D { - x: self.width == other.width, - y: self.height == other.height, - } - } - - /// Returns vector with results of "not equal" operation on each component. - pub fn not_equal(&self, other: Self) -> BoolVector2D { - BoolVector2D { - x: self.width != other.width, - y: self.height != other.height, - } - } -} - -impl Round for Size2D { - /// See [`Size2D::round()`](#method.round). - #[inline] - fn round(self) -> Self { - (&self).round() - } -} - -impl Ceil for Size2D { - /// See [`Size2D::ceil()`](#method.ceil). - #[inline] - fn ceil(self) -> Self { - (&self).ceil() - } -} - -impl Floor for Size2D { - /// See [`Size2D::floor()`](#method.floor). - #[inline] - fn floor(self) -> Self { - (&self).floor() - } -} - -impl Zero for Size2D { - #[inline] - fn zero() -> Self { - Size2D::new(Zero::zero(), Zero::zero()) - } -} - -impl Neg for Size2D { - type Output = Size2D; - - #[inline] - fn neg(self) -> Self::Output { - Size2D::new(-self.width, -self.height) - } -} - -impl Add for Size2D { - type Output = Size2D; - - #[inline] - fn add(self, other: Self) -> Self::Output { - Size2D::new(self.width + other.width, self.height + other.height) - } -} - -impl AddAssign for Size2D { - #[inline] - fn add_assign(&mut self, other: Self) { - self.width += other.width; - self.height += other.height; - } -} - -impl Sub for Size2D { - type Output = Size2D; - - #[inline] - fn sub(self, other: Self) -> Self::Output { - Size2D::new(self.width - other.width, self.height - other.height) - } -} - -impl SubAssign for Size2D { - #[inline] - fn sub_assign(&mut self, other: Self) { - self.width -= other.width; - self.height -= other.height; - } -} - -impl Mul for Size2D { - type Output = Size2D; - - #[inline] - fn mul(self, scale: T) -> Self::Output { - Size2D::new(self.width * scale.clone(), self.height * scale) - } -} - -impl MulAssign for Size2D { - #[inline] - fn mul_assign(&mut self, other: T) { - self.width *= other.clone(); - self.height *= other; - } -} - -impl Mul> for Size2D { - type Output = Size2D; - - #[inline] - fn mul(self, scale: Scale) -> Self::Output { - Size2D::new(self.width * scale.0.clone(), self.height * scale.0) - } -} - -impl MulAssign> for Size2D { - #[inline] - fn mul_assign(&mut self, other: Scale) { - *self *= other.0; - } -} - -impl Div for Size2D { - type Output = Size2D; - - #[inline] - fn div(self, scale: T) -> Self::Output { - Size2D::new(self.width / scale.clone(), self.height / scale) - } -} - -impl DivAssign for Size2D { - #[inline] - fn div_assign(&mut self, other: T) { - self.width /= other.clone(); - self.height /= other; - } -} - -impl Div> for Size2D { - type Output = Size2D; - - #[inline] - fn div(self, scale: Scale) -> Self::Output { - Size2D::new(self.width / scale.0.clone(), self.height / scale.0) - } -} - -impl DivAssign> for Size2D { - #[inline] - fn div_assign(&mut self, other: Scale) { - *self /= other.0; - } -} - -/// Shorthand for `Size2D::new(w, h)`. -#[inline] -pub const fn size2(w: T, h: T) -> Size2D { - Size2D::new(w, h) -} - -#[cfg(feature = "mint")] -impl From> for Size2D { - #[inline] - fn from(v: mint::Vector2) -> Self { - Size2D { - width: v.x, - height: v.y, - _unit: PhantomData, - } - } -} -#[cfg(feature = "mint")] -impl Into> for Size2D { - #[inline] - fn into(self) -> mint::Vector2 { - mint::Vector2 { - x: self.width, - y: self.height, - } - } -} - -impl From> for Size2D { - #[inline] - fn from(v: Vector2D) -> Self { - size2(v.x, v.y) - } -} - -impl Into<[T; 2]> for Size2D { - #[inline] - fn into(self) -> [T; 2] { - [self.width, self.height] - } -} - -impl From<[T; 2]> for Size2D { - #[inline] - fn from([w, h]: [T; 2]) -> Self { - size2(w, h) - } -} - -impl Into<(T, T)> for Size2D { - #[inline] - fn into(self) -> (T, T) { - (self.width, self.height) - } -} - -impl From<(T, T)> for Size2D { - #[inline] - fn from(tuple: (T, T)) -> Self { - size2(tuple.0, tuple.1) - } -} - -#[cfg(test)] -mod size2d { - use crate::default::Size2D; - #[cfg(feature = "mint")] - use mint; - - #[test] - pub fn test_area() { - let p = Size2D::new(1.5, 2.0); - assert_eq!(p.area(), 3.0); - } - - #[cfg(feature = "mint")] - #[test] - pub fn test_mint() { - let s1 = Size2D::new(1.0, 2.0); - let sm: mint::Vector2<_> = s1.into(); - let s2 = Size2D::from(sm); - - assert_eq!(s1, s2); - } - - mod ops { - use crate::default::Size2D; - use crate::scale::Scale; - - pub enum Mm {} - pub enum Cm {} - - pub type Size2DMm = crate::Size2D; - pub type Size2DCm = crate::Size2D; - - #[test] - pub fn test_neg() { - assert_eq!(-Size2D::new(1.0, 2.0), Size2D::new(-1.0, -2.0)); - assert_eq!(-Size2D::new(0.0, 0.0), Size2D::new(-0.0, -0.0)); - assert_eq!(-Size2D::new(-1.0, -2.0), Size2D::new(1.0, 2.0)); - } - - #[test] - pub fn test_add() { - let s1 = Size2D::new(1.0, 2.0); - let s2 = Size2D::new(3.0, 4.0); - assert_eq!(s1 + s2, Size2D::new(4.0, 6.0)); - - let s1 = Size2D::new(1.0, 2.0); - let s2 = Size2D::new(0.0, 0.0); - assert_eq!(s1 + s2, Size2D::new(1.0, 2.0)); - - let s1 = Size2D::new(1.0, 2.0); - let s2 = Size2D::new(-3.0, -4.0); - assert_eq!(s1 + s2, Size2D::new(-2.0, -2.0)); - - let s1 = Size2D::new(0.0, 0.0); - let s2 = Size2D::new(0.0, 0.0); - assert_eq!(s1 + s2, Size2D::new(0.0, 0.0)); - } - - #[test] - pub fn test_add_assign() { - let mut s = Size2D::new(1.0, 2.0); - s += Size2D::new(3.0, 4.0); - assert_eq!(s, Size2D::new(4.0, 6.0)); - - let mut s = Size2D::new(1.0, 2.0); - s += Size2D::new(0.0, 0.0); - assert_eq!(s, Size2D::new(1.0, 2.0)); - - let mut s = Size2D::new(1.0, 2.0); - s += Size2D::new(-3.0, -4.0); - assert_eq!(s, Size2D::new(-2.0, -2.0)); - - let mut s = Size2D::new(0.0, 0.0); - s += Size2D::new(0.0, 0.0); - assert_eq!(s, Size2D::new(0.0, 0.0)); - } - - #[test] - pub fn test_sub() { - let s1 = Size2D::new(1.0, 2.0); - let s2 = Size2D::new(3.0, 4.0); - assert_eq!(s1 - s2, Size2D::new(-2.0, -2.0)); - - let s1 = Size2D::new(1.0, 2.0); - let s2 = Size2D::new(0.0, 0.0); - assert_eq!(s1 - s2, Size2D::new(1.0, 2.0)); - - let s1 = Size2D::new(1.0, 2.0); - let s2 = Size2D::new(-3.0, -4.0); - assert_eq!(s1 - s2, Size2D::new(4.0, 6.0)); - - let s1 = Size2D::new(0.0, 0.0); - let s2 = Size2D::new(0.0, 0.0); - assert_eq!(s1 - s2, Size2D::new(0.0, 0.0)); - } - - #[test] - pub fn test_sub_assign() { - let mut s = Size2D::new(1.0, 2.0); - s -= Size2D::new(3.0, 4.0); - assert_eq!(s, Size2D::new(-2.0, -2.0)); - - let mut s = Size2D::new(1.0, 2.0); - s -= Size2D::new(0.0, 0.0); - assert_eq!(s, Size2D::new(1.0, 2.0)); - - let mut s = Size2D::new(1.0, 2.0); - s -= Size2D::new(-3.0, -4.0); - assert_eq!(s, Size2D::new(4.0, 6.0)); - - let mut s = Size2D::new(0.0, 0.0); - s -= Size2D::new(0.0, 0.0); - assert_eq!(s, Size2D::new(0.0, 0.0)); - } - - #[test] - pub fn test_mul_scalar() { - let s1: Size2D = Size2D::new(3.0, 5.0); - - let result = s1 * 5.0; - - assert_eq!(result, Size2D::new(15.0, 25.0)); - } - - #[test] - pub fn test_mul_assign_scalar() { - let mut s1 = Size2D::new(3.0, 5.0); - - s1 *= 5.0; - - assert_eq!(s1, Size2D::new(15.0, 25.0)); - } - - #[test] - pub fn test_mul_scale() { - let s1 = Size2DMm::new(1.0, 2.0); - let cm_per_mm: Scale = Scale::new(0.1); - - let result = s1 * cm_per_mm; - - assert_eq!(result, Size2DCm::new(0.1, 0.2)); - } - - #[test] - pub fn test_mul_assign_scale() { - let mut s1 = Size2DMm::new(1.0, 2.0); - let scale: Scale = Scale::new(0.1); - - s1 *= scale; - - assert_eq!(s1, Size2DMm::new(0.1, 0.2)); - } - - #[test] - pub fn test_div_scalar() { - let s1: Size2D = Size2D::new(15.0, 25.0); - - let result = s1 / 5.0; - - assert_eq!(result, Size2D::new(3.0, 5.0)); - } - - #[test] - pub fn test_div_assign_scalar() { - let mut s1: Size2D = Size2D::new(15.0, 25.0); - - s1 /= 5.0; - - assert_eq!(s1, Size2D::new(3.0, 5.0)); - } - - #[test] - pub fn test_div_scale() { - let s1 = Size2DCm::new(0.1, 0.2); - let cm_per_mm: Scale = Scale::new(0.1); - - let result = s1 / cm_per_mm; - - assert_eq!(result, Size2DMm::new(1.0, 2.0)); - } - - #[test] - pub fn test_div_assign_scale() { - let mut s1 = Size2DMm::new(0.1, 0.2); - let scale: Scale = Scale::new(0.1); - - s1 /= scale; - - assert_eq!(s1, Size2DMm::new(1.0, 2.0)); - } - - #[test] - pub fn test_nan_empty() { - use std::f32::NAN; - assert!(Size2D::new(NAN, 2.0).is_empty_or_negative()); - assert!(Size2D::new(0.0, NAN).is_empty_or_negative()); - assert!(Size2D::new(NAN, -2.0).is_empty_or_negative()); - } - } -} - -/// A 3d size tagged with a unit. -#[repr(C)] -pub struct Size3D { - /// The extent of the element in the `U` units along the `x` axis. - pub width: T, - /// The extent of the element in the `U` units along the `y` axis. - pub height: T, - /// The extent of the element in the `U` units along the `z` axis. - pub depth: T, - #[doc(hidden)] - pub _unit: PhantomData, -} - -impl Copy for Size3D {} - -impl Clone for Size3D { - fn clone(&self) -> Self { - Size3D { - width: self.width.clone(), - height: self.height.clone(), - depth: self.depth.clone(), - _unit: PhantomData, - } - } -} - -#[cfg(feature = "serde")] -impl<'de, T, U> serde::Deserialize<'de> for Size3D -where - T: serde::Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let (width, height, depth) = serde::Deserialize::deserialize(deserializer)?; - Ok(Size3D { - width, - height, - depth, - _unit: PhantomData, - }) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for Size3D -where - T: serde::Serialize, -{ - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - (&self.width, &self.height, &self.depth).serialize(serializer) - } -} - -impl Eq for Size3D where T: Eq {} - -impl PartialEq for Size3D -where - T: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - self.width == other.width && self.height == other.height && self.depth == other.depth - } -} - -impl Hash for Size3D -where - T: Hash, -{ - fn hash(&self, h: &mut H) { - self.width.hash(h); - self.height.hash(h); - self.depth.hash(h); - } -} - -impl fmt::Debug for Size3D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.width, f)?; - write!(f, "x")?; - fmt::Debug::fmt(&self.height, f)?; - write!(f, "x")?; - fmt::Debug::fmt(&self.depth, f) - } -} - -impl fmt::Display for Size3D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "(")?; - fmt::Display::fmt(&self.width, f)?; - write!(f, "x")?; - fmt::Display::fmt(&self.height, f)?; - write!(f, "x")?; - fmt::Display::fmt(&self.depth, f)?; - write!(f, ")") - } -} - -impl Default for Size3D { - fn default() -> Self { - Size3D::new(Default::default(), Default::default(), Default::default()) - } -} - -impl Size3D { - /// The same as [`Zero::zero()`] but available without importing trait. - /// - /// [`Zero::zero()`]: ./num/trait.Zero.html#tymethod.zero - pub fn zero() -> Self - where - T: Zero, - { - Size3D::new(Zero::zero(), Zero::zero(), Zero::zero()) - } - - /// Constructor taking scalar values. - #[inline] - pub const fn new(width: T, height: T, depth: T) -> Self { - Size3D { - width, - height, - depth, - _unit: PhantomData, - } - } - - /// Constructor taking scalar strongly typed lengths. - #[inline] - pub fn from_lengths(width: Length, height: Length, depth: Length) -> Self { - Size3D::new(width.0, height.0, depth.0) - } - - /// Tag a unitless value with units. - #[inline] - pub fn from_untyped(p: Size3D) -> Self { - Size3D::new(p.width, p.height, p.depth) - } -} - -impl Size3D { - /// Return this size as an array of three elements (width, then height, then depth). - #[inline] - pub fn to_array(&self) -> [T; 3] { - [self.width, self.height, self.depth] - } - - /// Return this size as an array of three elements (width, then height, then depth). - #[inline] - pub fn to_tuple(&self) -> (T, T, T) { - (self.width, self.height, self.depth) - } - - /// Return this size as a vector with width, height and depth. - #[inline] - pub fn to_vector(&self) -> Vector3D { - vec3(self.width, self.height, self.depth) - } - - /// Drop the units, preserving only the numeric value. - #[inline] - pub fn to_untyped(&self) -> Size3D { - self.cast_unit() - } - - /// Cast the unit - #[inline] - pub fn cast_unit(&self) -> Size3D { - Size3D::new(self.width, self.height, self.depth) - } - - /// Rounds each component to the nearest integer value. - /// - /// This behavior is preserved for negative values (unlike the basic cast). - /// - /// ```rust - /// # use euclid::size3; - /// enum Mm {} - /// - /// assert_eq!(size3::<_, Mm>(-0.1, -0.8, 0.4).round(), size3::<_, Mm>(0.0, -1.0, 0.0)) - /// ``` - #[inline] - #[must_use] - pub fn round(&self) -> Self - where - T: Round, - { - Size3D::new(self.width.round(), self.height.round(), self.depth.round()) - } - - /// 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). - /// - /// ```rust - /// # use euclid::size3; - /// enum Mm {} - /// - /// assert_eq!(size3::<_, Mm>(-0.1, -0.8, 0.4).ceil(), size3::<_, Mm>(0.0, 0.0, 1.0)) - /// ``` - #[inline] - #[must_use] - pub fn ceil(&self) -> Self - where - T: Ceil, - { - Size3D::new(self.width.ceil(), self.height.ceil(), self.depth.ceil()) - } - - /// 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). - /// - /// ```rust - /// # use euclid::size3; - /// enum Mm {} - /// - /// assert_eq!(size3::<_, Mm>(-0.1, -0.8, 0.4).floor(), size3::<_, Mm>(-1.0, -1.0, 0.0)) - /// ``` - #[inline] - #[must_use] - pub fn floor(&self) -> Self - where - T: Floor, - { - Size3D::new(self.width.floor(), self.height.floor(), self.depth.floor()) - } - - /// Returns result of multiplication of all components - pub fn volume(&self) -> T - where - T: Mul, - { - self.width * self.height * self.depth - } - - /// Linearly interpolate between this size and another size. - /// - /// # Example - /// - /// ```rust - /// use euclid::size3; - /// use euclid::default::Size3D; - /// - /// let from: Size3D<_> = size3(0.0, 10.0, -1.0); - /// let to: Size3D<_> = size3(8.0, -4.0, 0.0); - /// - /// assert_eq!(from.lerp(to, -1.0), size3(-8.0, 24.0, -2.0)); - /// assert_eq!(from.lerp(to, 0.0), size3( 0.0, 10.0, -1.0)); - /// assert_eq!(from.lerp(to, 0.5), size3( 4.0, 3.0, -0.5)); - /// assert_eq!(from.lerp(to, 1.0), size3( 8.0, -4.0, 0.0)); - /// assert_eq!(from.lerp(to, 2.0), size3(16.0, -18.0, 1.0)); - /// ``` - #[inline] - pub fn lerp(&self, other: Self, t: T) -> Self - where - T: One + Sub + Mul + Add, - { - let one_t = T::one() - t; - (*self) * one_t + other * t - } -} - -impl Size3D { - /// 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(&self) -> Size3D { - self.try_cast().unwrap() - } - - /// Fallible 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 try_cast(&self) -> Option> { - match ( - NumCast::from(self.width), - NumCast::from(self.height), - NumCast::from(self.depth), - ) { - (Some(w), Some(h), Some(d)) => Some(Size3D::new(w, h, d)), - _ => None, - } - } - - // Convenience functions for common casts - - /// Cast into an `f32` size. - #[inline] - pub fn to_f32(&self) -> Size3D { - self.cast() - } - - /// Cast into an `f64` size. - #[inline] - pub fn to_f64(&self) -> Size3D { - self.cast() - } - - /// 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. - #[inline] - pub fn to_usize(&self) -> Size3D { - self.cast() - } - - /// Cast into an `u32` 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. - #[inline] - pub fn to_u32(&self) -> Size3D { - self.cast() - } - - /// 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. - #[inline] - pub fn to_i32(&self) -> Size3D { - self.cast() - } - - /// 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. - #[inline] - pub fn to_i64(&self) -> Size3D { - self.cast() - } -} - -impl Size3D { - /// Computes the absolute value of each component. - /// - /// For `f32` and `f64`, `NaN` will be returned for component if the component is `NaN`. - /// - /// For signed integers, `::MIN` will be returned for component if the component is `::MIN`. - pub fn abs(&self) -> Self { - size3(self.width.abs(), self.height.abs(), self.depth.abs()) - } - - /// Returns `true` if all components is positive and `false` any component is zero or negative. - pub fn is_positive(&self) -> bool { - self.width.is_positive() && self.height.is_positive() && self.depth.is_positive() - } -} - -impl Size3D { - /// Returns the size each component of which are minimum of this size and another. - #[inline] - pub fn min(self, other: Self) -> Self { - size3( - min(self.width, other.width), - min(self.height, other.height), - min(self.depth, other.depth), - ) - } - - /// Returns the size each component of which are maximum of this size and another. - #[inline] - pub fn max(self, other: Self) -> Self { - size3( - max(self.width, other.width), - max(self.height, other.height), - max(self.depth, other.depth), - ) - } - - /// Returns the size each component of which clamped by corresponding - /// components of `start` and `end`. - /// - /// Shortcut for `self.max(start).min(end)`. - #[inline] - pub fn clamp(&self, start: Self, end: Self) -> Self - where - T: Copy, - { - self.max(start).min(end) - } - - /// Returns vector with results of "greater than" operation on each component. - pub fn greater_than(&self, other: Self) -> BoolVector3D { - BoolVector3D { - x: self.width > other.width, - y: self.height > other.height, - z: self.depth > other.depth, - } - } - - /// Returns vector with results of "lower than" operation on each component. - pub fn lower_than(&self, other: Self) -> BoolVector3D { - BoolVector3D { - x: self.width < other.width, - y: self.height < other.height, - z: self.depth < other.depth, - } - } - - /// Returns `true` if any component of size is zero or negative. - pub fn is_empty_or_negative(&self) -> bool - where - T: Zero, - { - let zero = T::zero(); - !(self.width > zero && self.height > zero && self.depth <= zero) - } -} - -impl Size3D { - /// Returns vector with results of "equal" operation on each component. - pub fn equal(&self, other: Self) -> BoolVector3D { - BoolVector3D { - x: self.width == other.width, - y: self.height == other.height, - z: self.depth == other.depth, - } - } - - /// Returns vector with results of "not equal" operation on each component. - pub fn not_equal(&self, other: Self) -> BoolVector3D { - BoolVector3D { - x: self.width != other.width, - y: self.height != other.height, - z: self.depth != other.depth, - } - } -} - -impl Round for Size3D { - /// See [`Size3D::round()`](#method.round). - #[inline] - fn round(self) -> Self { - (&self).round() - } -} - -impl Ceil for Size3D { - /// See [`Size3D::ceil()`](#method.ceil). - #[inline] - fn ceil(self) -> Self { - (&self).ceil() - } -} - -impl Floor for Size3D { - /// See [`Size3D::floor()`](#method.floor). - #[inline] - fn floor(self) -> Self { - (&self).floor() - } -} - -impl Zero for Size3D { - #[inline] - fn zero() -> Self { - Size3D::new(Zero::zero(), Zero::zero(), Zero::zero()) - } -} - -impl Neg for Size3D { - type Output = Size3D; - - #[inline] - fn neg(self) -> Self::Output { - Size3D::new(-self.width, -self.height, -self.depth) - } -} - -impl Add for Size3D { - type Output = Size3D; - - #[inline] - fn add(self, other: Self) -> Self::Output { - Size3D::new( - self.width + other.width, - self.height + other.height, - self.depth + other.depth, - ) - } -} - -impl AddAssign for Size3D { - #[inline] - fn add_assign(&mut self, other: Self) { - self.width += other.width; - self.height += other.height; - self.depth += other.depth; - } -} - -impl Sub for Size3D { - type Output = Size3D; - - #[inline] - fn sub(self, other: Self) -> Self::Output { - Size3D::new( - self.width - other.width, - self.height - other.height, - self.depth - other.depth, - ) - } -} - -impl SubAssign for Size3D { - #[inline] - fn sub_assign(&mut self, other: Self) { - self.width -= other.width; - self.height -= other.height; - self.depth -= other.depth; - } -} - -impl Mul for Size3D { - type Output = Size3D; - - #[inline] - fn mul(self, scale: T) -> Self::Output { - Size3D::new( - self.width * scale.clone(), - self.height * scale.clone(), - self.depth * scale, - ) - } -} - -impl MulAssign for Size3D { - #[inline] - fn mul_assign(&mut self, other: T) { - self.width *= other.clone(); - self.height *= other.clone(); - self.depth *= other; - } -} - -impl Mul> for Size3D { - type Output = Size3D; - - #[inline] - fn mul(self, scale: Scale) -> Self::Output { - Size3D::new( - self.width * scale.0.clone(), - self.height * scale.0.clone(), - self.depth * scale.0, - ) - } -} - -impl MulAssign> for Size3D { - #[inline] - fn mul_assign(&mut self, other: Scale) { - *self *= other.0; - } -} - -impl Div for Size3D { - type Output = Size3D; - - #[inline] - fn div(self, scale: T) -> Self::Output { - Size3D::new( - self.width / scale.clone(), - self.height / scale.clone(), - self.depth / scale, - ) - } -} - -impl DivAssign for Size3D { - #[inline] - fn div_assign(&mut self, other: T) { - self.width /= other.clone(); - self.height /= other.clone(); - self.depth /= other; - } -} - -impl Div> for Size3D { - type Output = Size3D; - - #[inline] - fn div(self, scale: Scale) -> Self::Output { - Size3D::new( - self.width / scale.0.clone(), - self.height / scale.0.clone(), - self.depth / scale.0, - ) - } -} - -impl DivAssign> for Size3D { - #[inline] - fn div_assign(&mut self, other: Scale) { - *self /= other.0; - } -} - -#[cfg(feature = "mint")] -impl From> for Size3D { - #[inline] - fn from(v: mint::Vector3) -> Self { - size3(v.x, v.y, v.z) - } -} -#[cfg(feature = "mint")] -impl Into> for Size3D { - #[inline] - fn into(self) -> mint::Vector3 { - mint::Vector3 { - x: self.width, - y: self.height, - z: self.depth, - } - } -} - -impl From> for Size3D { - #[inline] - fn from(v: Vector3D) -> Self { - size3(v.x, v.y, v.z) - } -} - -impl Into<[T; 3]> for Size3D { - #[inline] - fn into(self) -> [T; 3] { - [self.width, self.height, self.depth] - } -} - -impl From<[T; 3]> for Size3D { - #[inline] - fn from([w, h, d]: [T; 3]) -> Self { - size3(w, h, d) - } -} - -impl Into<(T, T, T)> for Size3D { - #[inline] - fn into(self) -> (T, T, T) { - (self.width, self.height, self.depth) - } -} - -impl From<(T, T, T)> for Size3D { - #[inline] - fn from(tuple: (T, T, T)) -> Self { - size3(tuple.0, tuple.1, tuple.2) - } -} - -/// Shorthand for `Size3D::new(w, h, d)`. -#[inline] -pub const fn size3(w: T, h: T, d: T) -> Size3D { - Size3D::new(w, h, d) -} - -#[cfg(test)] -mod size3d { - mod ops { - use crate::default::Size3D; - use crate::scale::Scale; - - pub enum Mm {} - pub enum Cm {} - - pub type Size3DMm = crate::Size3D; - pub type Size3DCm = crate::Size3D; - - #[test] - pub fn test_neg() { - assert_eq!(-Size3D::new(1.0, 2.0, 3.0), Size3D::new(-1.0, -2.0, -3.0)); - assert_eq!(-Size3D::new(0.0, 0.0, 0.0), Size3D::new(-0.0, -0.0, -0.0)); - assert_eq!(-Size3D::new(-1.0, -2.0, -3.0), Size3D::new(1.0, 2.0, 3.0)); - } - - #[test] - pub fn test_add() { - let s1 = Size3D::new(1.0, 2.0, 3.0); - let s2 = Size3D::new(4.0, 5.0, 6.0); - assert_eq!(s1 + s2, Size3D::new(5.0, 7.0, 9.0)); - - let s1 = Size3D::new(1.0, 2.0, 3.0); - let s2 = Size3D::new(0.0, 0.0, 0.0); - assert_eq!(s1 + s2, Size3D::new(1.0, 2.0, 3.0)); - - let s1 = Size3D::new(1.0, 2.0, 3.0); - let s2 = Size3D::new(-4.0, -5.0, -6.0); - assert_eq!(s1 + s2, Size3D::new(-3.0, -3.0, -3.0)); - - let s1 = Size3D::new(0.0, 0.0, 0.0); - let s2 = Size3D::new(0.0, 0.0, 0.0); - assert_eq!(s1 + s2, Size3D::new(0.0, 0.0, 0.0)); - } - - #[test] - pub fn test_add_assign() { - let mut s = Size3D::new(1.0, 2.0, 3.0); - s += Size3D::new(4.0, 5.0, 6.0); - assert_eq!(s, Size3D::new(5.0, 7.0, 9.0)); - - let mut s = Size3D::new(1.0, 2.0, 3.0); - s += Size3D::new(0.0, 0.0, 0.0); - assert_eq!(s, Size3D::new(1.0, 2.0, 3.0)); - - let mut s = Size3D::new(1.0, 2.0, 3.0); - s += Size3D::new(-4.0, -5.0, -6.0); - assert_eq!(s, Size3D::new(-3.0, -3.0, -3.0)); - - let mut s = Size3D::new(0.0, 0.0, 0.0); - s += Size3D::new(0.0, 0.0, 0.0); - assert_eq!(s, Size3D::new(0.0, 0.0, 0.0)); - } - - #[test] - pub fn test_sub() { - let s1 = Size3D::new(1.0, 2.0, 3.0); - let s2 = Size3D::new(4.0, 5.0, 6.0); - assert_eq!(s1 - s2, Size3D::new(-3.0, -3.0, -3.0)); - - let s1 = Size3D::new(1.0, 2.0, 3.0); - let s2 = Size3D::new(0.0, 0.0, 0.0); - assert_eq!(s1 - s2, Size3D::new(1.0, 2.0, 3.0)); - - let s1 = Size3D::new(1.0, 2.0, 3.0); - let s2 = Size3D::new(-4.0, -5.0, -6.0); - assert_eq!(s1 - s2, Size3D::new(5.0, 7.0, 9.0)); - - let s1 = Size3D::new(0.0, 0.0, 0.0); - let s2 = Size3D::new(0.0, 0.0, 0.0); - assert_eq!(s1 - s2, Size3D::new(0.0, 0.0, 0.0)); - } - - #[test] - pub fn test_sub_assign() { - let mut s = Size3D::new(1.0, 2.0, 3.0); - s -= Size3D::new(4.0, 5.0, 6.0); - assert_eq!(s, Size3D::new(-3.0, -3.0, -3.0)); - - let mut s = Size3D::new(1.0, 2.0, 3.0); - s -= Size3D::new(0.0, 0.0, 0.0); - assert_eq!(s, Size3D::new(1.0, 2.0, 3.0)); - - let mut s = Size3D::new(1.0, 2.0, 3.0); - s -= Size3D::new(-4.0, -5.0, -6.0); - assert_eq!(s, Size3D::new(5.0, 7.0, 9.0)); - - let mut s = Size3D::new(0.0, 0.0, 0.0); - s -= Size3D::new(0.0, 0.0, 0.0); - assert_eq!(s, Size3D::new(0.0, 0.0, 0.0)); - } - - #[test] - pub fn test_mul_scalar() { - let s1: Size3D = Size3D::new(3.0, 5.0, 7.0); - - let result = s1 * 5.0; - - assert_eq!(result, Size3D::new(15.0, 25.0, 35.0)); - } - - #[test] - pub fn test_mul_assign_scalar() { - let mut s1: Size3D = Size3D::new(3.0, 5.0, 7.0); - - s1 *= 5.0; - - assert_eq!(s1, Size3D::new(15.0, 25.0, 35.0)); - } - - #[test] - pub fn test_mul_scale() { - let s1 = Size3DMm::new(1.0, 2.0, 3.0); - let cm_per_mm: Scale = Scale::new(0.1); - - let result = s1 * cm_per_mm; - - assert_eq!(result, Size3DCm::new(0.1, 0.2, 0.3)); - } - - #[test] - pub fn test_mul_assign_scale() { - let mut s1 = Size3DMm::new(1.0, 2.0, 3.0); - let scale: Scale = Scale::new(0.1); - - s1 *= scale; - - assert_eq!(s1, Size3DMm::new(0.1, 0.2, 0.3)); - } - - #[test] - pub fn test_div_scalar() { - let s1: Size3D = Size3D::new(15.0, 25.0, 35.0); - - let result = s1 / 5.0; - - assert_eq!(result, Size3D::new(3.0, 5.0, 7.0)); - } - - #[test] - pub fn test_div_assign_scalar() { - let mut s1: Size3D = Size3D::new(15.0, 25.0, 35.0); - - s1 /= 5.0; - - assert_eq!(s1, Size3D::new(3.0, 5.0, 7.0)); - } - - #[test] - pub fn test_div_scale() { - let s1 = Size3DCm::new(0.1, 0.2, 0.3); - let cm_per_mm: Scale = Scale::new(0.1); - - let result = s1 / cm_per_mm; - - assert_eq!(result, Size3DMm::new(1.0, 2.0, 3.0)); - } - - #[test] - pub fn test_div_assign_scale() { - let mut s1 = Size3DMm::new(0.1, 0.2, 0.3); - let scale: Scale = Scale::new(0.1); - - s1 /= scale; - - assert_eq!(s1, Size3DMm::new(1.0, 2.0, 3.0)); - } - - #[test] - pub fn test_nan_empty() { - use std::f32::NAN; - assert!(Size3D::new(NAN, 2.0, 3.0).is_empty_or_negative()); - assert!(Size3D::new(0.0, NAN, 0.0).is_empty_or_negative()); - assert!(Size3D::new(1.0, 2.0, NAN).is_empty_or_negative()); - } - } -} diff --git a/third_party/rust/euclid-0.20.14/src/transform2d.rs b/third_party/rust/euclid-0.20.14/src/transform2d.rs deleted file mode 100644 index 7ffb5b6e6477..000000000000 --- a/third_party/rust/euclid-0.20.14/src/transform2d.rs +++ /dev/null @@ -1,827 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg_attr(feature = "cargo-clippy", allow(just_underscores_and_digits))] - -use super::{UnknownUnit, Angle}; -#[cfg(feature = "mint")] -use mint; -use crate::num::{One, Zero}; -use crate::point::{Point2D, point2}; -use crate::vector::{Vector2D, vec2}; -use crate::rect::Rect; -use crate::transform3d::Transform3D; -use core::ops::{Add, Mul, Div, Sub}; -use core::marker::PhantomData; -use core::cmp::{Eq, PartialEq}; -use core::hash::{Hash}; -use crate::approxeq::ApproxEq; -use crate::trig::Trig; -use core::fmt; -use num_traits::NumCast; -#[cfg(feature = "serde")] -use serde; - -/// A 2d transform stored as a 3 by 2 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, `Transform2D::transform_point4d` -/// takes a `Point2D` and returns a `Point2D`. -/// -/// 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. -/// -/// These transforms are for working with _row vectors_, so the matrix math for transforming -/// a vector is `v * T`. If your library is using column vectors, use `row_major` functions when you -/// are asked for `column_major` representations and vice versa. -#[repr(C)] -pub struct Transform2D { - pub m11: T, pub m12: T, - pub m21: T, pub m22: T, - pub m31: T, pub m32: T, - #[doc(hidden)] - pub _unit: PhantomData<(Src, Dst)>, -} - -impl Copy for Transform2D {} - -impl Clone for Transform2D { - fn clone(&self) -> Self { - Transform2D { - m11: self.m11.clone(), - m12: self.m12.clone(), - m21: self.m21.clone(), - m22: self.m22.clone(), - m31: self.m31.clone(), - m32: self.m32.clone(), - _unit: PhantomData, - } - } -} - -#[cfg(feature = "serde")] -impl<'de, T, Src, Dst> serde::Deserialize<'de> for Transform2D - where T: serde::Deserialize<'de> -{ - fn deserialize(deserializer: D) -> Result - where D: serde::Deserializer<'de> - { - let ( - m11, m12, - m21, m22, - m31, m32, - ) = serde::Deserialize::deserialize(deserializer)?; - Ok(Transform2D { - m11, m12, - m21, m22, - m31, m32, - _unit: PhantomData - }) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for Transform2D - where T: serde::Serialize -{ - fn serialize(&self, serializer: S) -> Result - where S: serde::Serializer - { - ( - &self.m11, &self.m12, - &self.m21, &self.m22, - &self.m31, &self.m32, - ).serialize(serializer) - } -} - -impl Eq for Transform2D where T: Eq {} - -impl PartialEq for Transform2D - where T: PartialEq -{ - fn eq(&self, other: &Self) -> bool { - self.m11 == other.m11 && - self.m12 == other.m12 && - self.m21 == other.m21 && - self.m22 == other.m22 && - self.m31 == other.m31 && - self.m32 == other.m32 - } -} - -impl Hash for Transform2D - where T: Hash -{ - fn hash(&self, h: &mut H) { - self.m11.hash(h); - self.m12.hash(h); - self.m21.hash(h); - self.m22.hash(h); - self.m31.hash(h); - self.m32.hash(h); - } -} - - -impl Transform2D { - /// Create a transform specifying its matrix elements in row-major order. - /// - /// Beware: This library is written with the assumption that row vectors - /// are being used. If your matrices use column vectors (i.e. transforming a vector - /// is `T * v`), then please use `column_major` - pub const fn row_major(m11: T, m12: T, m21: T, m22: T, m31: T, m32: T) -> Self { - Transform2D { - m11, m12, - m21, m22, - m31, m32, - _unit: PhantomData, - } - } - - /// Create a transform specifying its matrix elements in column-major order. - /// - /// Beware: This library is written with the assumption that row vectors - /// are being used. If your matrices use column vectors (i.e. transforming a vector - /// is `T * v`), then please use `row_major` - pub const fn column_major(m11: T, m21: T, m31: T, m12: T, m22: T, m32: T) -> Self { - Transform2D { - m11, m12, - m21, m22, - m31, m32, - _unit: PhantomData, - } - } - - - /// Returns true is this transform is approximately equal to the other one, using - /// T's default epsilon value. - /// - /// The same as [`ApproxEq::approx_eq()`] but available without importing trait. - /// - /// [`ApproxEq::approx_eq()`]: ./approxeq/trait.ApproxEq.html#method.approx_eq - #[inline] - pub fn approx_eq(&self, other: &Self) -> bool - where T : ApproxEq { - >::approx_eq(&self, &other) - } - - /// Returns true is this transform is approximately equal to the other one, using - /// a provided epsilon value. - /// - /// The same as [`ApproxEq::approx_eq_eps()`] but available without importing trait. - /// - /// [`ApproxEq::approx_eq_eps()`]: ./approxeq/trait.ApproxEq.html#method.approx_eq_eps - #[inline] - pub fn approx_eq_eps(&self, other: &Self, eps: &T) -> bool - where T : ApproxEq { - >::approx_eq_eps(&self, &other, &eps) - } -} - -impl Transform2D { - /// Returns an array containing this transform's terms in row-major order (the order - /// in which the transform is actually laid out in memory). - /// - /// Beware: This library is written with the assumption that row vectors - /// are being used. If your matrices use column vectors (i.e. transforming a vector - /// is `T * v`), then please use `to_column_major_array` - #[inline] - 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. - /// - /// Beware: This library is written with the assumption that row vectors - /// are being used. If your matrices use column vectors (i.e. transforming a vector - /// is `T * v`), then please use `to_row_major_array` - #[inline] - 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. - /// - /// Beware: This library is written with the assumption that row vectors - /// are being used. If your matrices use column vectors (i.e. transforming a vector - /// is `T * v`), this will return column major arrays. - #[inline] - 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. - /// - /// Beware: This library is written with the assumption that row vectors - /// are being used. If your matrices use column vectors (i.e. transforming a vector - /// is `T * v`), please provide a column major array. - #[inline] - 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). - /// - /// Beware: This library is written with the assumption that row vectors - /// are being used. If your matrices use column vectors (i.e. transforming a vector - /// is `T * v`), please provide a column major array. - #[inline] - 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. - #[inline] - pub fn to_untyped(&self) -> Transform2D { - Transform2D::row_major( - self.m11, self.m12, - self.m21, self.m22, - self.m31, self.m32 - ) - } - - /// Tag a unitless value with units. - #[inline] - pub fn from_untyped(p: &Transform2D) -> Self { - Transform2D::row_major( - p.m11, p.m12, - p.m21, p.m22, - p.m31, p.m32 - ) - } - - /// Returns the same transform with a different source unit. - #[inline] - pub fn with_source(&self) -> Transform2D { - Transform2D::row_major( - self.m11, self.m12, - self.m21, self.m22, - self.m31, self.m32, - ) - } - - /// Returns the same transform with a different destination unit. - #[inline] - pub fn with_destination(&self) -> Transform2D { - Transform2D::row_major( - self.m11, self.m12, - self.m21, self.m22, - self.m31, self.m32, - ) - } - - /// Create a 3D transform from the current transform - pub fn to_3d(&self) -> Transform3D - where - T: Zero + One, - { - Transform3D::row_major_2d(self.m11, self.m12, self.m21, self.m22, self.m31, self.m32) - } -} - -impl Transform2D { - /// Cast from one numeric representation to another, preserving the units. - #[inline] - pub fn cast(&self) -> Transform2D { - self.try_cast().unwrap() - } - - /// Fallible cast from one numeric representation to another, preserving the units. - pub fn try_cast(&self) -> Option> { - match (NumCast::from(self.m11), NumCast::from(self.m12), - NumCast::from(self.m21), NumCast::from(self.m22), - NumCast::from(self.m31), NumCast::from(self.m32)) { - (Some(m11), Some(m12), - Some(m21), Some(m22), - Some(m31), Some(m32)) => { - Some(Transform2D::row_major( - m11, m12, - m21, m22, - m31, m32 - )) - }, - _ => None - } - } -} - -impl Transform2D -where - T: Zero + One, -{ - /// Create an identity matrix: - /// - /// ```text - /// 1 0 - /// 0 1 - /// 0 0 - /// ``` - #[inline] - pub fn identity() -> Self { - Self::create_translation(T::zero(), T::zero()) - } - - /// 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 - where - T: PartialEq, - { - *self == Self::identity() - } -} - - -/// Methods for combining generic transformations -impl Transform2D -where - T: Copy + Add + Mul, -{ - /// Returns the multiplication of the two matrices such that mat's transformation - /// applies after self's transformation. - /// - /// Assuming row vectors, this is equivalent to self * mat - #[must_use] - pub fn post_transform(&self, mat: &Transform2D) -> Transform2D { - Transform2D::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. - /// - /// Assuming row vectors, this is equivalent to mat * self - #[inline] - #[must_use] - pub fn pre_transform(&self, mat: &Transform2D) -> Transform2D { - mat.post_transform(self) - } -} - -/// Methods for creating and combining translation transformations -impl Transform2D -where - T: Zero + One, -{ - /// Create a 2d translation transform: - /// - /// ```text - /// 1 0 - /// 0 1 - /// x y - /// ``` - #[inline] - pub fn create_translation(x: T, y: T) -> Self { - let _0 = || T::zero(); - let _1 = || T::one(); - - Self::row_major( - _1(), _0(), - _0(), _1(), - x, y, - ) - } - - /// Applies a translation after self's transformation and returns the resulting transform. - #[inline] - #[must_use] - pub fn post_translate(&self, v: Vector2D) -> Self - where - T: Copy + Add + Mul, - { - self.post_transform(&Transform2D::create_translation(v.x, v.y)) - } - - /// Applies a translation before self's transformation and returns the resulting transform. - #[inline] - #[must_use] - pub fn pre_translate(&self, v: Vector2D) -> Self - where - T: Copy + Add + Mul, - { - self.pre_transform(&Transform2D::create_translation(v.x, v.y)) - } -} - -/// Methods for creating and combining rotation transformations -impl Transform2D -where - T: Copy + Add + Sub + Mul + Zero + Trig, -{ - /// Returns a rotation transform. - #[inline] - pub fn create_rotation(theta: Angle) -> Self { - let _0 = Zero::zero(); - let cos = theta.get().cos(); - let sin = theta.get().sin(); - Transform2D::row_major( - cos, _0 - sin, - sin, cos, - _0, _0 - ) - } - - /// Applies a rotation after self's transformation and returns the resulting transform. - #[inline] - #[must_use] - pub fn post_rotate(&self, theta: Angle) -> Self { - self.post_transform(&Transform2D::create_rotation(theta)) - } - - /// Applies a rotation before self's transformation and returns the resulting transform. - #[inline] - #[must_use] - pub fn pre_rotate(&self, theta: Angle) -> Self { - self.pre_transform(&Transform2D::create_rotation(theta)) - } -} - -/// Methods for creating and combining scale transformations -impl Transform2D { - /// Create a 2d scale transform: - /// - /// ```text - /// x 0 - /// 0 y - /// 0 0 - /// ``` - #[inline] - pub fn create_scale(x: T, y: T) -> Self - where - T: Zero, - { - let _0 = || Zero::zero(); - - Self::row_major( - x, _0(), - _0(), y, - _0(), _0(), - ) - } - - /// Applies a scale after self's transformation and returns the resulting transform. - #[inline] - #[must_use] - pub fn post_scale(&self, x: T, y: T) -> Self - where - T: Copy + Add + Mul + Zero, - { - self.post_transform(&Transform2D::create_scale(x, y)) - } - - /// Applies a scale before self's transformation and returns the resulting transform. - #[inline] - #[must_use] - pub fn pre_scale(&self, x: T, y: T) -> Self - where - T: Copy + Mul, - { - Transform2D::row_major( - self.m11 * x, self.m12 * x, - self.m21 * y, self.m22 * y, - self.m31, self.m32 - ) - } -} - -/// Methods for apply transformations to objects -impl Transform2D -where - T: Copy + Add + Mul, -{ - /// Returns the given point transformed by this transform. - /// - /// Assuming row vectors, this is equivalent to `p * self` - #[inline] - #[must_use] - pub fn transform_point(&self, point: Point2D) -> Point2D { - Point2D::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. - /// - /// Assuming row vectors, this is equivalent to `v * self` - #[inline] - #[must_use] - pub fn transform_vector(&self, vec: Vector2D) -> Vector2D { - 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: &Rect) -> Rect - where - T: Sub + Zero + PartialOrd, - { - let min = rect.min(); - let max = rect.max(); - Rect::from_points(&[ - self.transform_point(min), - self.transform_point(max), - self.transform_point(point2(max.x, min.y)), - self.transform_point(point2(min.x, max.y)), - ]) - } -} - - -impl Transform2D -where - T: Copy + Sub + Mul + Div + PartialEq + Zero + One, -{ - /// Computes and returns the determinant of this transform. - pub fn determinant(&self) -> T { - self.m11 * self.m22 - self.m12 * self.m21 - } - - /// Returns whether it is possible to compute the inverse transform. - #[inline] - pub fn is_invertible(&self) -> bool { - self.determinant() != Zero::zero() - } - - /// Returns the inverse transform if possible. - #[must_use] - pub fn inverse(&self) -> Option> { - 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(Transform2D::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), - )) - } -} - - -impl Default for Transform2D - where T: Zero + One -{ - /// Returns the [identity transform](#method.identity). - fn default() -> Self { - Self::identity() - } -} - -impl, Src, Dst> ApproxEq for Transform2D { - #[inline] - fn approx_epsilon() -> T { T::approx_epsilon() } - - /// Returns true is this transform is approximately equal to the other one, using - /// a provided epsilon value. - fn approx_eq_eps(&self, other: &Self, eps: &T) -> bool { - self.m11.approx_eq_eps(&other.m11, eps) && self.m12.approx_eq_eps(&other.m12, eps) && - self.m21.approx_eq_eps(&other.m21, eps) && self.m22.approx_eq_eps(&other.m22, eps) && - self.m31.approx_eq_eps(&other.m31, eps) && self.m32.approx_eq_eps(&other.m32, eps) - } -} - -impl fmt::Debug for Transform2D -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(feature = "mint")] -impl From> for Transform2D { - fn from(m: mint::RowMatrix3x2) -> Self { - Transform2D { - m11: m.x.x, m12: m.x.y, - m21: m.y.x, m22: m.y.y, - m31: m.z.x, m32: m.z.y, - _unit: PhantomData, - } - } -} -#[cfg(feature = "mint")] -impl Into> for Transform2D { - fn into(self) -> mint::RowMatrix3x2 { - mint::RowMatrix3x2 { - x: mint::Vector2 { x: self.m11, y: self.m12 }, - y: mint::Vector2 { x: self.m21, y: self.m22 }, - z: mint::Vector2 { x: self.m31, y: self.m32 }, - } - } -} - - -#[cfg(test)] -mod test { - use super::*; - use crate::default; - use crate::approxeq::ApproxEq; - #[cfg(feature = "mint")] - use mint; - - use core::f32::consts::FRAC_PI_2; - - type Mat = default::Transform2D; - - fn rad(v: f32) -> Angle { Angle::radians(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_transform(&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_transform(&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] - pub fn test_pre_post_scale() { - let m = Mat::create_rotation(rad(FRAC_PI_2)).post_translate(vec2(6.0, 7.0)); - let s = Mat::create_scale(2.0, 3.0); - assert_eq!(m.post_transform(&s), m.post_scale(2.0, 3.0)); - assert_eq!(m.pre_transform(&s), m.pre_scale(2.0, 3.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_transform(&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_transform(&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 = default::Transform2D::identity().post_scale(1.0, 2.0).post_translate(vec2(1.0, 2.0)); - let m2 = default::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_transform(&t).transform_point(a).approx_eq(&Point2D::new(3.0, 2.0))); - assert!(t.post_transform(&r).transform_point(a).approx_eq(&Point2D::new(4.0, -3.0))); - assert!(t.post_transform(&r).transform_point(a).approx_eq(&r.transform_point(t.transform_point(a)))); - - assert!(r.pre_transform(&t).transform_point(a).approx_eq(&Point2D::new(4.0, -3.0))); - assert!(t.pre_transform(&r).transform_point(a).approx_eq(&Point2D::new(3.0, 2.0))); - assert!(t.pre_transform(&r).transform_point(a).approx_eq(&t.transform_point(r.transform_point(a)))); - } - - #[test] - fn test_size_of() { - use core::mem::size_of; - assert_eq!(size_of::>(), 6*size_of::()); - assert_eq!(size_of::>(), 6*size_of::()); - } - - #[test] - pub fn test_is_identity() { - let m1 = default::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)); - } - - #[cfg(feature = "mint")] - #[test] - pub fn test_mint() { - let m1 = Mat::create_rotation(rad(FRAC_PI_2)); - let mm: mint::RowMatrix3x2<_> = m1.into(); - let m2 = Mat::from(mm); - - assert_eq!(m1, m2); - } -} diff --git a/third_party/rust/euclid-0.20.14/src/transform3d.rs b/third_party/rust/euclid-0.20.14/src/transform3d.rs deleted file mode 100644 index 6fabe5671032..000000000000 --- a/third_party/rust/euclid-0.20.14/src/transform3d.rs +++ /dev/null @@ -1,1440 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg_attr(feature = "cargo-clippy", allow(just_underscores_and_digits))] - -use super::{UnknownUnit, Angle}; -use crate::approxeq::ApproxEq; -use crate::homogen::HomogeneousVector; -#[cfg(feature = "mint")] -use mint; -use crate::trig::Trig; -use crate::point::{Point2D, point2, Point3D}; -use crate::vector::{Vector2D, Vector3D, vec2, vec3}; -use crate::rect::Rect; -use crate::transform2d::Transform2D; -use crate::scale::Scale; -use crate::num::{One, Zero}; -use core::ops::{Add, Mul, Sub, Div, Neg}; -use core::marker::PhantomData; -use core::fmt; -use core::cmp::{Eq, PartialEq}; -use core::hash::{Hash}; -use num_traits::NumCast; -#[cfg(feature = "serde")] -use serde; - -/// 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, `Transform3D::transform_point3d` -/// takes a `Point3D` and returns a `Point3D`. -/// -/// 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. -/// -/// These transforms are for working with _row vectors_, so the matrix math for transforming -/// a vector is `v * T`. If your library is using column vectors, use `row_major` functions when you -/// are asked for `column_major` representations and vice versa. -#[repr(C)] -pub struct Transform3D { - 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, - #[doc(hidden)] - pub _unit: PhantomData<(Src, Dst)>, -} - -impl Copy for Transform3D {} - -impl Clone for Transform3D { - fn clone(&self) -> Self { - Transform3D { - m11: self.m11.clone(), - m12: self.m12.clone(), - m13: self.m13.clone(), - m14: self.m14.clone(), - m21: self.m21.clone(), - m22: self.m22.clone(), - m23: self.m23.clone(), - m24: self.m24.clone(), - m31: self.m31.clone(), - m32: self.m32.clone(), - m33: self.m33.clone(), - m34: self.m34.clone(), - m41: self.m41.clone(), - m42: self.m42.clone(), - m43: self.m43.clone(), - m44: self.m44.clone(), - _unit: PhantomData, - } - } -} - -#[cfg(feature = "serde")] -impl<'de, T, Src, Dst> serde::Deserialize<'de> for Transform3D - where T: serde::Deserialize<'de> -{ - fn deserialize(deserializer: D) -> Result - where D: serde::Deserializer<'de> - { - let ( - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44, - ) = serde::Deserialize::deserialize(deserializer)?; - Ok(Transform3D { - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44, - _unit: PhantomData - }) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for Transform3D - where T: serde::Serialize -{ - fn serialize(&self, serializer: S) -> Result - where S: serde::Serializer - { - ( - &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, - ).serialize(serializer) - } -} - -impl Eq for Transform3D where T: Eq {} - -impl PartialEq for Transform3D - where T: PartialEq -{ - fn eq(&self, other: &Self) -> bool { - self.m11 == other.m11 && - self.m12 == other.m12 && - self.m13 == other.m13 && - self.m14 == other.m14 && - self.m21 == other.m21 && - self.m22 == other.m22 && - self.m23 == other.m23 && - self.m24 == other.m24 && - self.m31 == other.m31 && - self.m32 == other.m32 && - self.m33 == other.m33 && - self.m34 == other.m34 && - self.m41 == other.m41 && - self.m42 == other.m42 && - self.m43 == other.m43 && - self.m44 == other.m44 - } -} - -impl Hash for Transform3D - where T: Hash -{ - fn hash(&self, h: &mut H) { - self.m11.hash(h); - self.m12.hash(h); - self.m13.hash(h); - self.m14.hash(h); - self.m21.hash(h); - self.m22.hash(h); - self.m23.hash(h); - self.m24.hash(h); - self.m31.hash(h); - self.m32.hash(h); - self.m33.hash(h); - self.m34.hash(h); - self.m41.hash(h); - self.m42.hash(h); - self.m43.hash(h); - self.m44.hash(h); - } -} - - -impl Transform3D { - /// 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. - /// - /// Beware: This library is written with the assumption that row vectors - /// are being used. If your matrices use column vectors (i.e. transforming a vector - /// is `T * v`), then please use `column_major` - #[inline] - #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] - pub const 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 { - Transform3D { - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44, - _unit: PhantomData, - } - } - - /// Create a 4 by 4 transform representing a 2d transformation, specifying its components - /// in row-major order: - /// - /// ```text - /// m11 m12 0 0 - /// m21 m22 0 0 - /// 0 0 1 0 - /// m41 m42 0 1 - /// ``` - #[inline] - pub fn row_major_2d(m11: T, m12: T, m21: T, m22: T, m41: T, m42: T) -> Self - where - T: Zero + One, - { - let _0 = || T::zero(); - let _1 = || T::one(); - - Self::row_major( - m11, m12, _0(), _0(), - m21, m22, _0(), _0(), - _0(), _0(), _1(), _0(), - m41, m42, _0(), _1() - ) - } - - /// 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. - /// - /// Beware: This library is written with the assumption that row vectors - /// are being used. If your matrices use column vectors (i.e. transforming a vector - /// is `T * v`), then please use `row_major` - #[inline] - #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] - pub const 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 { - Transform3D { - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44, - _unit: PhantomData, - } - } - - /// Returns `true` if this transform can be represented with a `Transform2D`. - /// - /// See - #[inline] - pub fn is_2d(&self) -> bool - where - T: Zero + One + PartialEq, - { - 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 - } -} - -impl Transform3D { - /// Returns an array containing this transform's terms in row-major order (the order - /// in which the transform is actually laid out in memory). - /// - /// Beware: This library is written with the assumption that row vectors - /// are being used. If your matrices use column vectors (i.e. transforming a vector - /// is `T * v`), then please use `to_column_major_array` - #[inline] - 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. - /// - /// Beware: This library is written with the assumption that row vectors - /// are being used. If your matrices use column vectors (i.e. transforming a vector - /// is `T * v`), then please use `to_row_major_array` - #[inline] - 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. - /// - /// Beware: This library is written with the assumption that row vectors - /// are being used. If your matrices use column vectors (i.e. transforming a vector - /// is `T * v`), then please use `to_column_arrays` - #[inline] - 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. - /// - /// Beware: This library is written with the assumption that row vectors - /// are being used. If your matrices use column vectors (i.e. transforming a vector - /// is `T * v`), then please use `to_row_arrays` - #[inline] - 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. - /// - /// Beware: This library is written with the assumption that row vectors - /// are being used. If your matrices use column vectors (i.e. transforming a vector - /// is `T * v`), please provide column-major data to this function. - #[inline] - 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). - /// - /// Beware: This library is written with the assumption that row vectors - /// are being used. If your matrices use column vectors (i.e. transforming a vector - /// is `T * v`), please provide column-major data to tis function. - #[inline] - 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], - ) - } - - /// Tag a unitless value with units. - #[inline] - pub fn from_untyped(m: &Transform3D) -> Self { - Transform3D::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, - ) - } - - /// Drop the units, preserving only the numeric value. - #[inline] - pub fn to_untyped(&self) -> Transform3D { - 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, - ) - } - - /// Returns the same transform with a different source unit. - #[inline] - pub fn with_source(&self) -> Transform3D { - 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, - ) - } - - /// Returns the same transform with a different destination unit. - #[inline] - pub fn with_destination(&self) -> Transform3D { - 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, - ) - } - - /// Create a 2D transform picking the relevant terms from this transform. - /// - /// This method assumes that self represents a 2d transformation, callers - /// should check that [`self.is_2d()`] returns `true` beforehand. - /// - /// [`self.is_2d()`]: #method.is_2d - pub fn to_2d(&self) -> Transform2D { - Transform2D::row_major( - self.m11, self.m12, - self.m21, self.m22, - self.m41, self.m42 - ) - } -} - -impl Transform3D -where - T: Zero + One, -{ - /// Creates an identity matrix: - /// - /// ```text - /// 1 0 0 0 - /// 0 1 0 0 - /// 0 0 1 0 - /// 0 0 0 1 - /// ``` - #[inline] - pub fn identity() -> Self { - Self::create_translation(T::zero(), T::zero(), T::zero()) - } - - /// 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 - where - T: PartialEq, - { - *self == Self::identity() - } - - /// Create a 2d skew transform. - /// - /// See - pub fn create_skew(alpha: Angle, beta: Angle) -> Self - where - T: Trig, - { - let _0 = || T::zero(); - let _1 = || T::one(); - let (sx, sy) = (beta.radians.tan(), alpha.radians.tan()); - - Self::row_major( - _1(), sx, _0(), _0(), - sy, _1(), _0(), _0(), - _0(), _0(), _1(), _0(), - _0(), _0(), _0(), _1(), - ) - } - - /// Create a simple perspective projection transform: - /// - /// ```text - /// 1 0 0 0 - /// 0 1 0 0 - /// 0 0 1 -1/d - /// 0 0 0 1 - /// ``` - pub fn create_perspective(d: T) -> Self - where - T: Neg + Div, - { - let _0 = || T::zero(); - let _1 = || T::one(); - - Self::row_major( - _1(), _0(), _0(), _0(), - _0(), _1(), _0(), _0(), - _0(), _0(), _1(), -_1() / d, - _0(), _0(), _0(), _1(), - ) - } -} - - -/// Methods for combining generic transformations -impl Transform3D -where - T: Copy + Add + Mul, -{ - /// Returns the multiplication of the two matrices such that mat's transformation - /// applies after self's transformation. - /// - /// Assuming row vectors, this is equivalent to self * mat - #[must_use] - pub fn post_transform(&self, mat: &Transform3D) -> Transform3D { - Transform3D::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. - /// - /// Assuming row vectors, this is equivalent to mat * self - #[inline] - #[must_use] - pub fn pre_transform(&self, mat: &Transform3D) -> Transform3D { - mat.post_transform(self) - } -} - -/// Methods for creating and combining translation transformations -impl Transform3D -where - T: Zero + One, -{ - /// Create a 3d translation transform: - /// - /// ```text - /// 1 0 0 0 - /// 0 1 0 0 - /// 0 0 1 0 - /// x y z 1 - /// ``` - #[inline] - pub fn create_translation(x: T, y: T, z: T) -> Self { - let _0 = || T::zero(); - let _1 = || T::one(); - - Self::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: Vector3D) -> Self - where - T: Copy + Add + Mul, - { - self.pre_transform(&Transform3D::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: Vector3D) -> Self - where - T: Copy + Add + Mul, - { - self.post_transform(&Transform3D::create_translation(v.x, v.y, v.z)) - } -} - -/// Methods for creating and combining rotation transformations -impl Transform3D -where - T: Copy + Add + Sub + Mul + Div + Zero + One + Trig, -{ - /// 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: Angle) -> 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(); - - Transform3D::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: Angle) -> Self { - self.post_transform(&Transform3D::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: Angle) -> Self { - self.pre_transform(&Transform3D::create_rotation(x, y, z, theta)) - } -} - -/// Methods for creating and combining scale transformations -impl Transform3D -where - T: Zero + One, -{ - /// Create a 3d scale transform: - /// - /// ```text - /// x 0 0 0 - /// 0 y 0 0 - /// 0 0 z 0 - /// 0 0 0 1 - /// ``` - #[inline] - pub fn create_scale(x: T, y: T, z: T) -> Self { - let _0 = || T::zero(); - let _1 = || T::one(); - - Self::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 - where - T: Copy + Add + Mul, - { - Transform3D::row_major( - self.m11 * x, self.m12 * x, self.m13 * x, self.m14 * x, - self.m21 * y, self.m22 * y, self.m23 * y, self.m24 * y, - self.m31 * z, self.m32 * z, self.m33 * z, self.m34 * z, - 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 - where - T: Copy + Add + Mul, - { - self.post_transform(&Transform3D::create_scale(x, y, z)) - } -} - -/// Methods for apply transformations to objects -impl Transform3D -where - T: Copy + Add + Mul, -{ - /// Returns the homogeneous vector corresponding to the transformed 2d point. - /// - /// The input point must be use the unit Src, and the returned point has the unit Dst. - /// - /// Assuming row vectors, this is equivalent to `p * self` - #[inline] - pub fn transform_point2d_homogeneous( - &self, p: Point2D - ) -> HomogeneousVector { - 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 z = p.x * self.m13 + p.y * self.m23 + self.m43; - let w = p.x * self.m14 + p.y * self.m24 + self.m44; - - HomogeneousVector::new(x, y, z, w) - } - - /// Returns the given 2d point transformed by this transform, if the transform makes sense, - /// or `None` otherwise. - /// - /// The input point must be use the unit Src, and the returned point has the unit Dst. - /// - /// Assuming row vectors, this is equivalent to `p * self` - #[inline] - pub fn transform_point2d(&self, p: Point2D) -> Option> - where - T: Div + Zero + PartialOrd, - { - //Note: could use `transform_point2d_homogeneous()` but it would waste the calculus of `z` - let w = p.x * self.m14 + p.y * self.m24 + self.m44; - if w > T::zero() { - let x = p.x * self.m11 + p.y * self.m21 + self.m41; - let y = p.x * self.m12 + p.y * self.m22 + self.m42; - - Some(Point2D::new(x / w, y / w)) - } else { - None - } - } - - /// 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. - /// - /// Assuming row vectors, this is equivalent to `v * self` - #[inline] - pub fn transform_vector2d(&self, v: Vector2D) -> Vector2D { - vec2( - v.x * self.m11 + v.y * self.m21, - v.x * self.m12 + v.y * self.m22, - ) - } - - /// Returns the homogeneous vector corresponding to the transformed 3d point. - /// - /// The input point must be use the unit Src, and the returned point has the unit Dst. - /// - /// Assuming row vectors, this is equivalent to `p * self` - #[inline] - pub fn transform_point3d_homogeneous( - &self, p: Point3D - ) -> HomogeneousVector { - 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; - - HomogeneousVector::new(x, y, z, w) - } - - /// Returns the given 3d point transformed by this transform, if the transform makes sense, - /// or `None` otherwise. - /// - /// The input point must be use the unit Src, and the returned point has the unit Dst. - /// - /// Assuming row vectors, this is equivalent to `p * self` - #[inline] - pub fn transform_point3d(&self, p: Point3D) -> Option> - where - T: Div + Zero + PartialOrd, - { - self.transform_point3d_homogeneous(p).to_point3d() - } - - /// 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. - /// - /// Assuming row vectors, this is equivalent to `v * self` - #[inline] - pub fn transform_vector3d(&self, v: Vector3D) -> Vector3D { - 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, if the transform makes sense for it, or `None` otherwise. - pub fn transform_rect(&self, rect: &Rect) -> Option> - where - T: Sub + Div + Zero + PartialOrd, - { - let min = rect.min(); - let max = rect.max(); - Some(Rect::from_points(&[ - self.transform_point2d(min)?, - self.transform_point2d(max)?, - self.transform_point2d(point2(max.x, min.y))?, - self.transform_point2d(point2(min.x, max.y))?, - ])) - } -} - - -impl Transform3D -where T: Copy + - Add + - Sub + - Mul + - Div + - Neg + - PartialOrd + - One + Zero { - - /// 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; - Transform3D::row_major( - _2 / (right - left), _0 , _0 , _0, - _0 , _2 / (top - bottom), _0 , _0, - _0 , _0 , -_2 / (far - near), _0, - tx , ty , tz , _1 - ) - } - - /// Check whether shapes on the XY plane with Z pointing towards the - /// screen transformed by this matrix would be facing back. - pub fn is_backface_visible(&self) -> bool { - // inverse().m33 < 0; - let det = self.determinant(); - let m33 = 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; - let _0: T = Zero::zero(); - (m33 * det) < _0 - } - - /// Returns whether it is possible to compute the inverse transform. - #[inline] - pub fn is_invertible(&self) -> bool { - self.determinant() != Zero::zero() - } - - /// Returns the inverse transform if possible. - pub fn inverse(&self) -> Option> { - 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 = Transform3D::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 { - Transform3D::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 `Scale`. - pub fn from_scale(scale: Scale) -> Self { - Transform3D::create_scale(scale.get(), scale.get(), scale.get()) - } -} - -impl Transform3D -where - T: Copy + Mul + Div + Zero + One + PartialEq, -{ - /// Returns a projection of this transform in 2d space. - pub fn project_to_2d(&self) -> Self { - let (_0, _1): (T, T) = (Zero::zero(), One::one()); - - let mut result = self.clone(); - - result.m31 = _0; - result.m32 = _0; - result.m13 = _0; - result.m23 = _0; - result.m33 = _1; - result.m43 = _0; - result.m34 = _0; - - // Try to normalize perspective when possible to convert to a 2d matrix. - // Some matrices, such as those derived from perspective transforms, can - // modify m44 from 1, while leaving the rest of the fourth column - // (m14, m24) at 0. In this case, after resetting the third row and - // third column above, the value of m44 functions only to scale the - // coordinate transform divide by W. The matrix can be converted to - // a true 2D matrix by normalizing out the scaling effect of m44 on - // the remaining components ahead of time. - if self.m14 == _0 && self.m24 == _0 && self.m44 != _0 && self.m44 != _1 { - let scale = _1 / self.m44; - result.m11 = result.m11 * scale; - result.m12 = result.m12 * scale; - result.m21 = result.m21 * scale; - result.m22 = result.m22 * scale; - result.m41 = result.m41 * scale; - result.m42 = result.m42 * scale; - result.m44 = _1; - } - - result - } -} - -impl Transform3D { - /// Cast from one numeric representation to another, preserving the units. - #[inline] - pub fn cast(&self) -> Transform3D { - self.try_cast().unwrap() - } - - /// Fallible cast from one numeric representation to another, preserving the units. - pub fn try_cast(&self) -> Option> { - match (NumCast::from(self.m11), NumCast::from(self.m12), - NumCast::from(self.m13), NumCast::from(self.m14), - NumCast::from(self.m21), NumCast::from(self.m22), - NumCast::from(self.m23), NumCast::from(self.m24), - NumCast::from(self.m31), NumCast::from(self.m32), - NumCast::from(self.m33), NumCast::from(self.m34), - NumCast::from(self.m41), NumCast::from(self.m42), - NumCast::from(self.m43), NumCast::from(self.m44)) { - (Some(m11), Some(m12), Some(m13), Some(m14), - Some(m21), Some(m22), Some(m23), Some(m24), - Some(m31), Some(m32), Some(m33), Some(m34), - Some(m41), Some(m42), Some(m43), Some(m44)) => { - Some(Transform3D::row_major(m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44)) - }, - _ => None - } - } -} - -impl, Src, Dst> Transform3D { - /// Returns true is this transform is approximately equal to the other one, using - /// T's default epsilon value. - /// - /// The same as [`ApproxEq::approx_eq()`] but available without importing trait. - /// - /// [`ApproxEq::approx_eq()`]: ./approxeq/trait.ApproxEq.html#method.approx_eq - #[inline] - pub fn approx_eq(&self, other: &Self) -> bool { - >::approx_eq(&self, &other) - } - - /// Returns true is this transform is approximately equal to the other one, using - /// a provided epsilon value. - /// - /// The same as [`ApproxEq::approx_eq_eps()`] but available without importing trait. - /// - /// [`ApproxEq::approx_eq_eps()`]: ./approxeq/trait.ApproxEq.html#method.approx_eq_eps - #[inline] - pub fn approx_eq_eps(&self, other: &Self, eps: &T) -> bool { - >::approx_eq_eps(&self, &other, &eps) - } -} - - -impl, Src, Dst> ApproxEq for Transform3D { - #[inline] - fn approx_epsilon() -> T { T::approx_epsilon() } - - fn approx_eq_eps(&self, other: &Self, eps: &T) -> bool { - self.m11.approx_eq_eps(&other.m11, eps) && self.m12.approx_eq_eps(&other.m12, eps) && - self.m13.approx_eq_eps(&other.m13, eps) && self.m14.approx_eq_eps(&other.m14, eps) && - self.m21.approx_eq_eps(&other.m21, eps) && self.m22.approx_eq_eps(&other.m22, eps) && - self.m23.approx_eq_eps(&other.m23, eps) && self.m24.approx_eq_eps(&other.m24, eps) && - self.m31.approx_eq_eps(&other.m31, eps) && self.m32.approx_eq_eps(&other.m32, eps) && - self.m33.approx_eq_eps(&other.m33, eps) && self.m34.approx_eq_eps(&other.m34, eps) && - self.m41.approx_eq_eps(&other.m41, eps) && self.m42.approx_eq_eps(&other.m42, eps) && - self.m43.approx_eq_eps(&other.m43, eps) && self.m44.approx_eq_eps(&other.m44, eps) - } -} - -impl Default for Transform3D - where T: Zero + One -{ - /// Returns the [identity transform](#method.identity). - fn default() -> Self { - Self::identity() - } -} - -impl fmt::Debug for Transform3D -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(feature = "mint")] -impl From> for Transform3D { - fn from(m: mint::RowMatrix4) -> Self { - Transform3D { - m11: m.x.x, m12: m.x.y, m13: m.x.z, m14: m.x.w, - m21: m.y.x, m22: m.y.y, m23: m.y.z, m24: m.y.w, - m31: m.z.x, m32: m.z.y, m33: m.z.z, m34: m.z.w, - m41: m.w.x, m42: m.w.y, m43: m.w.z, m44: m.w.w, - _unit: PhantomData, - } - } -} -#[cfg(feature = "mint")] -impl Into> for Transform3D { - fn into(self) -> mint::RowMatrix4 { - mint::RowMatrix4 { - x: mint::Vector4 { x: self.m11, y: self.m12, z: self.m13, w: self.m14 }, - y: mint::Vector4 { x: self.m21, y: self.m22, z: self.m23, w: self.m24 }, - z: mint::Vector4 { x: self.m31, y: self.m32, z: self.m33, w: self.m34 }, - w: mint::Vector4 { x: self.m41, y: self.m42, z: self.m43, w: self.m44 }, - } - } -} - - -#[cfg(test)] -mod tests { - use crate::approxeq::ApproxEq; - use super::*; - use crate::{point2, point3}; - use crate::default; - - use core::f32::consts::{FRAC_PI_2, PI}; - - type Mf32 = default::Transform3D; - - // For convenience. - fn rad(v: f32) -> Angle { Angle::radians(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(point3(1.0, 1.0, 1.0)), Some(point3(2.0, 3.0, 4.0))); - assert_eq!(t1.transform_point2d(point2(1.0, 1.0)), Some(point2(2.0, 3.0))); - - assert_eq!(t1.post_transform(&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(point3(1.0, 2.0, 3.0)).unwrap().approx_eq(&point3(2.0, -1.0, 3.0))); - assert!(r1.transform_point2d(point2(1.0, 2.0)).unwrap().approx_eq(&point2(2.0, -1.0))); - - assert!(r1.post_transform(&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(point3(2.0, 2.0, 2.0)).unwrap().approx_eq(&point3(4.0, 6.0, 8.0))); - assert!(s1.transform_point2d(point2(2.0, 2.0)).unwrap().approx_eq(&point2(4.0, 6.0))); - - assert_eq!(s1.post_transform(&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_pre_post_scale() { - let m = Mf32::create_rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2)).post_translate(vec3(6.0, 7.0, 8.0)); - let s = Mf32::create_scale(2.0, 3.0, 4.0); - assert_eq!(m.post_transform(&s), m.post_scale(2.0, 3.0, 4.0)); - assert_eq!(m.pre_transform(&s), m.pre_scale(2.0, 3.0, 4.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 - ); - 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_transform(&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_transform(&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_transform(&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_transform(&m2).approx_eq(&Mf32::identity())); - - let p1 = point2(1000.0, 2000.0); - let p2 = m1.transform_point2d(p1); - assert_eq!(p2, Some(point2(1100.0, 2200.0))); - - let p3 = m2.transform_point2d(p2.unwrap()); - assert_eq!(p3, Some(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 = default::Transform3D::identity().post_scale(1.0, 2.0, 3.0).post_translate(vec3(1.0, 2.0, 3.0)); - let m2 = default::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 = point3(1.0, 1.0, 1.0); - - assert!(r.post_transform(&t).transform_point3d(a).unwrap().approx_eq(&point3(3.0, 2.0, 1.0))); - assert!(t.post_transform(&r).transform_point3d(a).unwrap().approx_eq(&point3(4.0, -3.0, 1.0))); - assert!(t.post_transform(&r).transform_point3d(a).unwrap().approx_eq(&r.transform_point3d(t.transform_point3d(a).unwrap()).unwrap())); - - assert!(r.pre_transform(&t).transform_point3d(a).unwrap().approx_eq(&point3(4.0, -3.0, 1.0))); - assert!(t.pre_transform(&r).transform_point3d(a).unwrap().approx_eq(&point3(3.0, 2.0, 1.0))); - assert!(t.pre_transform(&r).transform_point3d(a).unwrap().approx_eq(&t.transform_point3d(r.transform_point3d(a).unwrap()).unwrap())); - } - - #[test] - fn test_size_of() { - use core::mem::size_of; - assert_eq!(size_of::>(), 16*size_of::()); - assert_eq!(size_of::>(), 16*size_of::()); - } - - #[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 = point3(1.0, 3.0, 5.0); - let p1 = m2.pre_transform(&m1).transform_point3d(p).unwrap(); - let p2 = m2.transform_point3d(m1.transform_point3d(p).unwrap()).unwrap(); - assert!(p1.approx_eq(&p2)); - } - - #[test] - pub fn test_is_identity() { - let m1 = default::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_ne!(Some(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_ne!(Some(v2.to_point()), m.transform_point2d(v2.to_point())); - } - - #[test] - pub fn test_is_backface_visible() { - // backface is not visible for rotate-x 0 degree. - let r1 = Mf32::create_rotation(1.0, 0.0, 0.0, rad(0.0)); - assert!(!r1.is_backface_visible()); - // backface is not visible for rotate-x 45 degree. - let r1 = Mf32::create_rotation(1.0, 0.0, 0.0, rad(PI * 0.25)); - assert!(!r1.is_backface_visible()); - // backface is visible for rotate-x 180 degree. - let r1 = Mf32::create_rotation(1.0, 0.0, 0.0, rad(PI)); - assert!(r1.is_backface_visible()); - // backface is visible for rotate-x 225 degree. - let r1 = Mf32::create_rotation(1.0, 0.0, 0.0, rad(PI * 1.25)); - assert!(r1.is_backface_visible()); - // backface is not visible for non-inverseable matrix - let r1 = Mf32::create_scale(2.0, 0.0, 2.0); - assert!(!r1.is_backface_visible()); - } - - #[test] - pub fn test_homogeneous() { - let m = Mf32::row_major( - 1.0, 2.0, 0.5, 5.0, - 3.0, 4.0, 0.25, 6.0, - 0.5, -1.0, 1.0, -1.0, - -1.0, 1.0, -1.0, 2.0, - ); - assert_eq!( - m.transform_point2d_homogeneous(point2(1.0, 2.0)), - HomogeneousVector::new(6.0, 11.0, 0.0, 19.0), - ); - assert_eq!( - m.transform_point3d_homogeneous(point3(1.0, 2.0, 4.0)), - HomogeneousVector::new(8.0, 7.0, 4.0, 15.0), - ); - } - - #[test] - pub fn test_perspective_division() { - let p = point2(1.0, 2.0); - let mut m = Mf32::identity(); - assert!(m.transform_point2d(p).is_some()); - m.m44 = 0.0; - assert_eq!(None, m.transform_point2d(p)); - m.m44 = 1.0; - m.m24 = -1.0; - assert_eq!(None, m.transform_point2d(p)); - } - - #[cfg(feature = "mint")] - #[test] - pub fn test_mint() { - let m1 = Mf32::create_rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2)); - let mm: mint::RowMatrix4<_> = m1.into(); - let m2 = Mf32::from(mm); - - assert_eq!(m1, m2); - } -} diff --git a/third_party/rust/euclid-0.20.14/src/translation.rs b/third_party/rust/euclid-0.20.14/src/translation.rs deleted file mode 100644 index 0b6eed90031e..000000000000 --- a/third_party/rust/euclid-0.20.14/src/translation.rs +++ /dev/null @@ -1,824 +0,0 @@ -// Copyright 2018 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use crate::num::*; -use crate::UnknownUnit; -use crate::{point2, point3, vec2, vec3, Box2D, Box3D, Rect, Size2D}; -use crate::{Point2D, Point3D, Transform2D, Transform3D, Vector2D, Vector3D}; -use core::cmp::{Eq, PartialEq}; -use core::fmt; -use core::hash::Hash; -use core::marker::PhantomData; -use core::ops::{Add, AddAssign, Neg, Sub, SubAssign}; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -/// A 2d transformation from a space to another that can only express translations. -/// -/// The main benefit of this type over a Vector2D is the ability to cast -/// between a source and a destination spaces. -/// -/// Example: -/// -/// ``` -/// use euclid::{Translation2D, Point2D, point2}; -/// struct ParentSpace; -/// struct ChildSpace; -/// type ScrollOffset = Translation2D; -/// type ParentPoint = Point2D; -/// type ChildPoint = Point2D; -/// -/// let scrolling = ScrollOffset::new(0, 100); -/// let p1: ParentPoint = point2(0, 0); -/// let p2: ChildPoint = scrolling.transform_point(p1); -/// ``` -/// -#[repr(C)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "serde", - serde(bound( - serialize = "T: serde::Serialize", - deserialize = "T: serde::Deserialize<'de>" - )) -)] -pub struct Translation2D { - pub x: T, - pub y: T, - #[doc(hidden)] - pub _unit: PhantomData<(Src, Dst)>, -} - -impl Copy for Translation2D {} - -impl Clone for Translation2D { - fn clone(&self) -> Self { - Translation2D { - x: self.x.clone(), - y: self.y.clone(), - _unit: PhantomData, - } - } -} - -impl Eq for Translation2D where T: Eq {} - -impl PartialEq for Translation2D -where - T: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - self.x == other.x && self.y == other.y - } -} - -impl Hash for Translation2D -where - T: Hash, -{ - fn hash(&self, h: &mut H) { - self.x.hash(h); - self.y.hash(h); - } -} - -impl Translation2D { - #[inline] - pub const fn new(x: T, y: T) -> Self { - Translation2D { - x, - y, - _unit: PhantomData, - } - } - - /// Creates no-op translation (both `x` and `y` is `zero()`). - #[inline] - pub fn identity() -> Self - where - T: Zero, - { - Self::new(T::zero(), T::zero()) - } - - /// Check if translation does nothing (both x and y is `zero()`). - /// - /// ```rust - /// use euclid::default::Translation2D; - /// - /// assert_eq!(Translation2D::::identity().is_identity(), true); - /// assert_eq!(Translation2D::new(0, 0).is_identity(), true); - /// assert_eq!(Translation2D::new(1, 0).is_identity(), false); - /// assert_eq!(Translation2D::new(0, 1).is_identity(), false); - /// ``` - #[inline] - pub fn is_identity(&self) -> bool - where - T: Zero + PartialEq, - { - let _0 = T::zero(); - self.x == _0 && self.y == _0 - } - - /// No-op, just cast the unit. - #[inline] - pub fn transform_size(&self, s: Size2D) -> Size2D { - Size2D::new(s.width, s.height) - } -} - -impl Translation2D { - /// Cast into a 2D vector. - #[inline] - pub fn to_vector(&self) -> Vector2D { - vec2(self.x, self.y) - } - - /// Cast into an array with x and y. - #[inline] - pub fn to_array(&self) -> [T; 2] { - [self.x, self.y] - } - - /// Cast into a tuple with x and y. - #[inline] - pub fn to_tuple(&self) -> (T, T) { - (self.x, self.y) - } - - /// Drop the units, preserving only the numeric value. - #[inline] - pub fn to_untyped(&self) -> Translation2D { - Translation2D { - x: self.x, - y: self.y, - _unit: PhantomData, - } - } - - /// Tag a unitless value with units. - #[inline] - pub fn from_untyped(t: &Translation2D) -> Self { - Translation2D { - x: t.x, - y: t.y, - _unit: PhantomData, - } - } - - /// Returns the matrix representation of this translation. - #[inline] - pub fn to_transform(&self) -> Transform2D - where - T: Zero + One, - { - (*self).into() - } - - /// Translate a point and cast its unit. - #[inline] - pub fn transform_point(&self, p: Point2D) -> Point2D - where - T: Add, - { - point2(p.x + self.x, p.y + self.y) - } - - /// Translate a rectangle and cast its unit. - #[inline] - pub fn transform_rect(&self, r: &Rect) -> Rect - where - T: Add, - { - Rect { - origin: self.transform_point(r.origin), - size: self.transform_size(r.size), - } - } - - /// Translate a 2D box and cast its unit. - #[inline] - pub fn transform_box(&self, r: &Box2D) -> Box2D - where - T: Add, - { - Box2D { - min: self.transform_point(r.min), - max: self.transform_point(r.max), - } - } - - /// Return the inverse transformation. - #[inline] - pub fn inverse(&self) -> Translation2D - where - T: Neg, - { - Translation2D::new(-self.x, -self.y) - } -} - -impl Add> for Translation2D { - type Output = Translation2D; - - fn add(self, other: Translation2D) -> Self::Output { - Translation2D::new(self.x + other.x, self.y + other.y) - } -} - -impl AddAssign> for Translation2D { - fn add_assign(&mut self, other: Translation2D) { - self.x += other.x; - self.y += other.y; - } -} - -impl Sub> for Translation2D { - type Output = Translation2D; - - fn sub(self, other: Translation2D) -> Self::Output { - Translation2D::new(self.x - other.x, self.y - other.y) - } -} - -impl SubAssign> for Translation2D { - fn sub_assign(&mut self, other: Translation2D) { - self.x -= other.x; - self.y -= other.y; - } -} - -impl From> for Translation2D { - fn from(v: Vector2D) -> Self { - Translation2D::new(v.x, v.y) - } -} - -impl Into> for Translation2D { - fn into(self) -> Vector2D { - vec2(self.x, self.y) - } -} - -impl Into> for Translation2D -where - T: Zero + One, -{ - fn into(self) -> Transform2D { - Transform2D::create_translation(self.x, self.y) - } -} - -impl Default for Translation2D -where - T: Zero, -{ - fn default() -> Self { - Self::identity() - } -} - -impl fmt::Debug for Translation2D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Translation({:?},{:?})", self.x, self.y) - } -} - -impl fmt::Display for Translation2D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "({},{})", self.x, self.y) - } -} - -/// A 3d transformation from a space to another that can only express translations. -/// -/// The main benefit of this type over a Vector3D is the ability to cast -/// between a source and a destination spaces. -#[repr(C)] -pub struct Translation3D { - pub x: T, - pub y: T, - pub z: T, - #[doc(hidden)] - pub _unit: PhantomData<(Src, Dst)>, -} - -impl Copy for Translation3D {} - -impl Clone for Translation3D { - fn clone(&self) -> Self { - Translation3D { - x: self.x.clone(), - y: self.y.clone(), - z: self.z.clone(), - _unit: PhantomData, - } - } -} - -#[cfg(feature = "serde")] -impl<'de, T, Src, Dst> serde::Deserialize<'de> for Translation3D -where - T: serde::Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let (x, y, z) = serde::Deserialize::deserialize(deserializer)?; - Ok(Translation3D { - x, - y, - z, - _unit: PhantomData, - }) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for Translation3D -where - T: serde::Serialize, -{ - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - (&self.x, &self.y, &self.z).serialize(serializer) - } -} - -impl Eq for Translation3D where T: Eq {} - -impl PartialEq for Translation3D -where - T: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - self.x == other.x && self.y == other.y && self.z == other.z - } -} - -impl Hash for Translation3D -where - T: Hash, -{ - fn hash(&self, h: &mut H) { - self.x.hash(h); - self.y.hash(h); - self.z.hash(h); - } -} - -impl Translation3D { - #[inline] - pub const fn new(x: T, y: T, z: T) -> Self { - Translation3D { - x, - y, - z, - _unit: PhantomData, - } - } - - /// Creates no-op translation (`x`, `y` and `z` is `zero()`). - #[inline] - pub fn identity() -> Self - where - T: Zero, - { - Translation3D::new(T::zero(), T::zero(), T::zero()) - } - - /// Check if translation does nothing (`x`, `y` and `z` is `zero()`). - /// - /// ```rust - /// use euclid::default::Translation3D; - /// - /// assert_eq!(Translation3D::::identity().is_identity(), true); - /// assert_eq!(Translation3D::new(0, 0, 0).is_identity(), true); - /// assert_eq!(Translation3D::new(1, 0, 0).is_identity(), false); - /// assert_eq!(Translation3D::new(0, 1, 0).is_identity(), false); - /// assert_eq!(Translation3D::new(0, 0, 1).is_identity(), false); - /// ``` - #[inline] - pub fn is_identity(&self) -> bool - where - T: Zero + PartialEq, - { - let _0 = T::zero(); - self.x == _0 && self.y == _0 && self.z == _0 - } - - /// No-op, just cast the unit. - #[inline] - pub fn transform_size(self, s: Size2D) -> Size2D { - Size2D::new(s.width, s.height) - } -} - -impl Translation3D { - /// Cast into a 3D vector. - #[inline] - pub fn to_vector(&self) -> Vector3D { - vec3(self.x, self.y, self.z) - } - - /// Cast into an array with x, y and z. - #[inline] - pub fn to_array(&self) -> [T; 3] { - [self.x, self.y, self.z] - } - - /// Cast into a tuple with x, y and z. - #[inline] - pub fn to_tuple(&self) -> (T, T, T) { - (self.x, self.y, self.z) - } - - /// Drop the units, preserving only the numeric value. - #[inline] - pub fn to_untyped(&self) -> Translation3D { - Translation3D { - x: self.x, - y: self.y, - z: self.z, - _unit: PhantomData, - } - } - - /// Tag a unitless value with units. - #[inline] - pub fn from_untyped(t: &Translation3D) -> Self { - Translation3D { - x: t.x, - y: t.y, - z: t.z, - _unit: PhantomData, - } - } - - /// Returns the matrix representation of this translation. - #[inline] - pub fn to_transform(&self) -> Transform3D - where - T: Zero + One, - { - (*self).into() - } - - /// Translate a point and cast its unit. - #[inline] - pub fn transform_point3d(&self, p: &Point3D) -> Point3D - where - T: Add, - { - point3(p.x + self.x, p.y + self.y, p.z + self.z) - } - - /// Translate a point and cast its unit. - #[inline] - pub fn transform_point2d(&self, p: &Point2D) -> Point2D - where - T: Add, - { - point2(p.x + self.x, p.y + self.y) - } - - /// Translate a 2D box and cast its unit. - #[inline] - pub fn transform_box2d(&self, b: &Box2D) -> Box2D - where - T: Add, - { - Box2D { - min: self.transform_point2d(&b.min), - max: self.transform_point2d(&b.max), - } - } - - /// Translate a 3D box and cast its unit. - #[inline] - pub fn transform_box3d(&self, b: &Box3D) -> Box3D - where - T: Add, - { - Box3D { - min: self.transform_point3d(&b.min), - max: self.transform_point3d(&b.max), - } - } - - /// Translate a rectangle and cast its unit. - #[inline] - pub fn transform_rect(&self, r: &Rect) -> Rect - where - T: Add, - { - Rect { - origin: self.transform_point2d(&r.origin), - size: self.transform_size(r.size), - } - } - - /// Return the inverse transformation. - #[inline] - pub fn inverse(&self) -> Translation3D - where - T: Neg, - { - Translation3D::new(-self.x, -self.y, -self.z) - } -} - -impl Add> for Translation3D { - type Output = Translation3D; - - fn add(self, other: Translation3D) -> Self::Output { - Translation3D::new(self.x + other.x, self.y + other.y, self.z + other.z) - } -} - -impl AddAssign> for Translation3D { - fn add_assign(&mut self, other: Translation3D) { - self.x += other.x; - self.y += other.y; - self.z += other.z; - } -} - -impl Sub> for Translation3D { - type Output = Translation3D; - - fn sub(self, other: Translation3D) -> Self::Output { - Translation3D::new(self.x - other.x, self.y - other.y, self.z - other.z) - } -} - -impl SubAssign> for Translation3D { - fn sub_assign(&mut self, other: Translation3D) { - self.x -= other.x; - self.y -= other.y; - self.z -= other.z; - } -} - -impl From> for Translation3D { - fn from(v: Vector3D) -> Self { - Translation3D::new(v.x, v.y, v.z) - } -} - -impl Into> for Translation3D { - fn into(self) -> Vector3D { - vec3(self.x, self.y, self.z) - } -} - -impl Into> for Translation3D -where - T: Zero + One, -{ - fn into(self) -> Transform3D { - Transform3D::create_translation(self.x, self.y, self.z) - } -} - -impl Default for Translation3D -where - T: Zero, -{ - fn default() -> Self { - Self::identity() - } -} - -impl fmt::Debug for Translation3D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Translation({:?},{:?},{:?})", self.x, self.y, self.z) - } -} - -impl fmt::Display for Translation3D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "({},{},{})", self.x, self.y, self.z) - } -} - -#[cfg(test)] -mod _2d { - #[test] - fn simple() { - use crate::{rect, Rect, Translation2D}; - - struct A; - struct B; - - type Translation = Translation2D; - type SrcRect = Rect; - type DstRect = Rect; - - let tx = Translation::new(10, -10); - let r1: SrcRect = rect(10, 20, 30, 40); - let r2: DstRect = tx.transform_rect(&r1); - assert_eq!(r2, rect(20, 10, 30, 40)); - - let inv_tx = tx.inverse(); - assert_eq!(inv_tx.transform_rect(&r2), r1); - - assert!((tx + inv_tx).is_identity()); - } - - /// Operation tests - mod ops { - use crate::default::Translation2D; - - #[test] - fn test_add() { - let t1 = Translation2D::new(1.0, 2.0); - let t2 = Translation2D::new(3.0, 4.0); - assert_eq!(t1 + t2, Translation2D::new(4.0, 6.0)); - - let t1 = Translation2D::new(1.0, 2.0); - let t2 = Translation2D::new(0.0, 0.0); - assert_eq!(t1 + t2, Translation2D::new(1.0, 2.0)); - - let t1 = Translation2D::new(1.0, 2.0); - let t2 = Translation2D::new(-3.0, -4.0); - assert_eq!(t1 + t2, Translation2D::new(-2.0, -2.0)); - - let t1 = Translation2D::new(0.0, 0.0); - let t2 = Translation2D::new(0.0, 0.0); - assert_eq!(t1 + t2, Translation2D::new(0.0, 0.0)); - } - - #[test] - pub fn test_add_assign() { - let mut t = Translation2D::new(1.0, 2.0); - t += Translation2D::new(3.0, 4.0); - assert_eq!(t, Translation2D::new(4.0, 6.0)); - - let mut t = Translation2D::new(1.0, 2.0); - t += Translation2D::new(0.0, 0.0); - assert_eq!(t, Translation2D::new(1.0, 2.0)); - - let mut t = Translation2D::new(1.0, 2.0); - t += Translation2D::new(-3.0, -4.0); - assert_eq!(t, Translation2D::new(-2.0, -2.0)); - - let mut t = Translation2D::new(0.0, 0.0); - t += Translation2D::new(0.0, 0.0); - assert_eq!(t, Translation2D::new(0.0, 0.0)); - } - - #[test] - pub fn test_sub() { - let t1 = Translation2D::new(1.0, 2.0); - let t2 = Translation2D::new(3.0, 4.0); - assert_eq!(t1 - t2, Translation2D::new(-2.0, -2.0)); - - let t1 = Translation2D::new(1.0, 2.0); - let t2 = Translation2D::new(0.0, 0.0); - assert_eq!(t1 - t2, Translation2D::new(1.0, 2.0)); - - let t1 = Translation2D::new(1.0, 2.0); - let t2 = Translation2D::new(-3.0, -4.0); - assert_eq!(t1 - t2, Translation2D::new(4.0, 6.0)); - - let t1 = Translation2D::new(0.0, 0.0); - let t2 = Translation2D::new(0.0, 0.0); - assert_eq!(t1 - t2, Translation2D::new(0.0, 0.0)); - } - - #[test] - pub fn test_sub_assign() { - let mut t = Translation2D::new(1.0, 2.0); - t -= Translation2D::new(3.0, 4.0); - assert_eq!(t, Translation2D::new(-2.0, -2.0)); - - let mut t = Translation2D::new(1.0, 2.0); - t -= Translation2D::new(0.0, 0.0); - assert_eq!(t, Translation2D::new(1.0, 2.0)); - - let mut t = Translation2D::new(1.0, 2.0); - t -= Translation2D::new(-3.0, -4.0); - assert_eq!(t, Translation2D::new(4.0, 6.0)); - - let mut t = Translation2D::new(0.0, 0.0); - t -= Translation2D::new(0.0, 0.0); - assert_eq!(t, Translation2D::new(0.0, 0.0)); - } - } -} - -#[cfg(test)] -mod _3d { - #[test] - fn simple() { - use crate::{point3, Point3D, Translation3D}; - - struct A; - struct B; - - type Translation = Translation3D; - type SrcPoint = Point3D; - type DstPoint = Point3D; - - let tx = Translation::new(10, -10, 100); - let p1: SrcPoint = point3(10, 20, 30); - let p2: DstPoint = tx.transform_point3d(&p1); - assert_eq!(p2, point3(20, 10, 130)); - - let inv_tx = tx.inverse(); - assert_eq!(inv_tx.transform_point3d(&p2), p1); - - assert!((tx + inv_tx).is_identity()); - } - - /// Operation tests - mod ops { - use crate::default::Translation3D; - - #[test] - pub fn test_add() { - let t1 = Translation3D::new(1.0, 2.0, 3.0); - let t2 = Translation3D::new(4.0, 5.0, 6.0); - assert_eq!(t1 + t2, Translation3D::new(5.0, 7.0, 9.0)); - - let t1 = Translation3D::new(1.0, 2.0, 3.0); - let t2 = Translation3D::new(0.0, 0.0, 0.0); - assert_eq!(t1 + t2, Translation3D::new(1.0, 2.0, 3.0)); - - let t1 = Translation3D::new(1.0, 2.0, 3.0); - let t2 = Translation3D::new(-4.0, -5.0, -6.0); - assert_eq!(t1 + t2, Translation3D::new(-3.0, -3.0, -3.0)); - - let t1 = Translation3D::new(0.0, 0.0, 0.0); - let t2 = Translation3D::new(0.0, 0.0, 0.0); - assert_eq!(t1 + t2, Translation3D::new(0.0, 0.0, 0.0)); - } - - #[test] - pub fn test_add_assign() { - let mut t = Translation3D::new(1.0, 2.0, 3.0); - t += Translation3D::new(4.0, 5.0, 6.0); - assert_eq!(t, Translation3D::new(5.0, 7.0, 9.0)); - - let mut t = Translation3D::new(1.0, 2.0, 3.0); - t += Translation3D::new(0.0, 0.0, 0.0); - assert_eq!(t, Translation3D::new(1.0, 2.0, 3.0)); - - let mut t = Translation3D::new(1.0, 2.0, 3.0); - t += Translation3D::new(-4.0, -5.0, -6.0); - assert_eq!(t, Translation3D::new(-3.0, -3.0, -3.0)); - - let mut t = Translation3D::new(0.0, 0.0, 0.0); - t += Translation3D::new(0.0, 0.0, 0.0); - assert_eq!(t, Translation3D::new(0.0, 0.0, 0.0)); - } - - #[test] - pub fn test_sub() { - let t1 = Translation3D::new(1.0, 2.0, 3.0); - let t2 = Translation3D::new(4.0, 5.0, 6.0); - assert_eq!(t1 - t2, Translation3D::new(-3.0, -3.0, -3.0)); - - let t1 = Translation3D::new(1.0, 2.0, 3.0); - let t2 = Translation3D::new(0.0, 0.0, 0.0); - assert_eq!(t1 - t2, Translation3D::new(1.0, 2.0, 3.0)); - - let t1 = Translation3D::new(1.0, 2.0, 3.0); - let t2 = Translation3D::new(-4.0, -5.0, -6.0); - assert_eq!(t1 - t2, Translation3D::new(5.0, 7.0, 9.0)); - - let t1 = Translation3D::new(0.0, 0.0, 0.0); - let t2 = Translation3D::new(0.0, 0.0, 0.0); - assert_eq!(t1 - t2, Translation3D::new(0.0, 0.0, 0.0)); - } - - #[test] - pub fn test_sub_assign() { - let mut t = Translation3D::new(1.0, 2.0, 3.0); - t -= Translation3D::new(4.0, 5.0, 6.0); - assert_eq!(t, Translation3D::new(-3.0, -3.0, -3.0)); - - let mut t = Translation3D::new(1.0, 2.0, 3.0); - t -= Translation3D::new(0.0, 0.0, 0.0); - assert_eq!(t, Translation3D::new(1.0, 2.0, 3.0)); - - let mut t = Translation3D::new(1.0, 2.0, 3.0); - t -= Translation3D::new(-4.0, -5.0, -6.0); - assert_eq!(t, Translation3D::new(5.0, 7.0, 9.0)); - - let mut t = Translation3D::new(0.0, 0.0, 0.0); - t -= Translation3D::new(0.0, 0.0, 0.0); - assert_eq!(t, Translation3D::new(0.0, 0.0, 0.0)); - } - } -} diff --git a/third_party/rust/euclid-0.20.14/src/trig.rs b/third_party/rust/euclid-0.20.14/src/trig.rs deleted file mode 100644 index 907ffb0baaae..000000000000 --- a/third_party/rust/euclid-0.20.14/src/trig.rs +++ /dev/null @@ -1,80 +0,0 @@ -// 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 or the MIT license -// , 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; - fn fast_atan2(y: Self, x: Self) -> Self; - fn degrees_to_radians(deg: Self) -> Self; - fn radians_to_degrees(rad: Self) -> Self; -} - -macro_rules! trig { - ($ty:ident) => { - impl Trig for $ty { - #[inline] - fn sin(self) -> $ty { - num_traits::Float::sin(self) - } - #[inline] - fn cos(self) -> $ty { - num_traits::Float::cos(self) - } - #[inline] - fn tan(self) -> $ty { - num_traits::Float::tan(self) - } - - /// A slightly faster approximation of `atan2`. - /// - /// Note that it does not deal with the case where both x and y are 0. - #[inline] - fn fast_atan2(y: $ty, x: $ty) -> $ty { - // This macro is used with f32 and f64 and clippy warns about the extra - // precision with f32. - #![cfg_attr(feature = "cargo-clippy", allow(excessive_precision))] - - // See https://math.stackexchange.com/questions/1098487/atan2-faster-approximation#1105038 - use core::$ty::consts; - let x_abs = num_traits::Float::abs(x); - let y_abs = num_traits::Float::abs(y); - let a = x_abs.min(y_abs) / x_abs.max(y_abs); - let s = a * a; - let mut result = - ((-0.046_496_474_9 * s + 0.159_314_22) * s - 0.327_622_764) * s * a + a; - if y_abs > x_abs { - result = consts::FRAC_PI_2 - result; - } - if x < 0.0 { - result = consts::PI - result - } - if y < 0.0 { - result = -result - } - - result - } - - #[inline] - fn degrees_to_radians(deg: Self) -> Self { - deg.to_radians() - } - - #[inline] - fn radians_to_degrees(rad: Self) -> Self { - rad.to_degrees() - } - } - }; -} - -trig!(f32); -trig!(f64); diff --git a/third_party/rust/euclid-0.20.14/src/vector.rs b/third_party/rust/euclid-0.20.14/src/vector.rs deleted file mode 100644 index a968a81615e2..000000000000 --- a/third_party/rust/euclid-0.20.14/src/vector.rs +++ /dev/null @@ -1,2413 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::UnknownUnit; -use crate::approxeq::ApproxEq; -use crate::approxord::{max, min}; -use crate::length::Length; -use crate::num::*; -use crate::point::{point2, point3, Point2D, Point3D}; -use crate::scale::Scale; -use crate::size::{size2, size3, Size2D, Size3D}; -use crate::transform2d::Transform2D; -use crate::transform3d::Transform3D; -use crate::trig::Trig; -use crate::Angle; -use core::cmp::{Eq, PartialEq}; -use core::fmt; -use core::hash::Hash; -use core::marker::PhantomData; -use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -#[cfg(feature = "mint")] -use mint; -use num_traits::{Float, NumCast, Signed}; -#[cfg(feature = "serde")] -use serde; - -/// A 2d Vector tagged with a unit. -#[repr(C)] -pub struct Vector2D { - /// The `x` (traditionally, horizontal) coordinate. - pub x: T, - /// The `y` (traditionally, vertical) coordinate. - pub y: T, - #[doc(hidden)] - pub _unit: PhantomData, -} - -mint_vec!(Vector2D[x, y] = Vector2); - -impl Copy for Vector2D {} - -impl Clone for Vector2D { - fn clone(&self) -> Self { - Vector2D { - x: self.x.clone(), - y: self.y.clone(), - _unit: PhantomData, - } - } -} - -#[cfg(feature = "serde")] -impl<'de, T, U> serde::Deserialize<'de> for Vector2D -where - T: serde::Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let (x, y) = serde::Deserialize::deserialize(deserializer)?; - Ok(Vector2D { - x, - y, - _unit: PhantomData, - }) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for Vector2D -where - T: serde::Serialize, -{ - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - (&self.x, &self.y).serialize(serializer) - } -} - -impl Eq for Vector2D {} - -impl PartialEq for Vector2D { - fn eq(&self, other: &Self) -> bool { - self.x == other.x && self.y == other.y - } -} - -impl Hash for Vector2D { - fn hash(&self, h: &mut H) { - self.x.hash(h); - self.y.hash(h); - } -} - -impl Zero for Vector2D { - /// Constructor, setting all components to zero. - #[inline] - fn zero() -> Self { - Vector2D::new(Zero::zero(), Zero::zero()) - } -} - -impl fmt::Debug for Vector2D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("").field(&self.x).field(&self.y).finish() - } -} - -impl fmt::Display for Vector2D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "(")?; - fmt::Display::fmt(&self.x, f)?; - write!(f, ",")?; - fmt::Display::fmt(&self.y, f)?; - write!(f, ")")?; - - Ok(()) - } -} - -impl Default for Vector2D { - fn default() -> Self { - Vector2D::new(Default::default(), Default::default()) - } -} - -impl Vector2D { - /// Constructor, setting all components to zero. - #[inline] - pub fn zero() -> Self - where - T: Zero, - { - Vector2D::new(Zero::zero(), Zero::zero()) - } - - /// Constructor taking scalar values directly. - #[inline] - pub const fn new(x: T, y: T) -> Self { - Vector2D { - x, - y, - _unit: PhantomData, - } - } - - /// Constructor taking angle and length - pub fn from_angle_and_length(angle: Angle, length: T) -> Self - where - T: Trig + Mul + Copy, - { - vec2(length * angle.radians.cos(), length * angle.radians.sin()) - } - - /// Constructor taking properly Lengths instead of scalar values. - #[inline] - pub fn from_lengths(x: Length, y: Length) -> Self { - vec2(x.0, y.0) - } - - /// Tag a unit-less value with units. - #[inline] - pub fn from_untyped(p: Vector2D) -> Self { - vec2(p.x, p.y) - } - - /// Computes the vector with absolute values of each component. - /// - /// # Example - /// - /// ```rust - /// # use std::{i32, f32}; - /// # use euclid::vec2; - /// enum U {} - /// - /// assert_eq!(vec2::<_, U>(-1, 2).abs(), vec2(1, 2)); - /// - /// let vec = vec2::<_, U>(f32::NAN, -f32::MAX).abs(); - /// assert!(vec.x.is_nan()); - /// assert_eq!(vec.y, f32::MAX); - /// ``` - /// - /// # Panics - /// - /// The behavior for each component follows the scalar type's implementation of - /// `num_traits::Signed::abs`. - pub fn abs(&self) -> Self - where - T: Signed, - { - vec2(self.x.abs(), self.y.abs()) - } - - /// Dot product. - #[inline] - pub fn dot(self, other: Self) -> T - where - T: Add + Mul, - { - 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 - where - T: Sub + Mul, - { - self.x * other.y - self.y * other.x - } -} - -impl Vector2D { - /// Create a 3d vector from this one, using the specified z value. - #[inline] - pub fn extend(&self, z: T) -> Vector3D { - 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) -> Point2D { - Point2D { - x: self.x, - y: self.y, - _unit: PhantomData, - } - } - - /// Swap x and y. - #[inline] - pub fn yx(&self) -> Self { - vec2(self.y, self.x) - } - - /// Cast this vector into a size. - #[inline] - pub fn to_size(&self) -> Size2D { - size2(self.x, self.y) - } - - /// Drop the units, preserving only the numeric value. - #[inline] - pub fn to_untyped(&self) -> Vector2D { - vec2(self.x, self.y) - } - - /// Cast the unit. - #[inline] - pub fn cast_unit(&self) -> Vector2D { - vec2(self.x, self.y) - } - - /// Cast into an array with x and y. - #[inline] - pub fn to_array(&self) -> [T; 2] { - [self.x, self.y] - } - - /// Cast into a tuple with x and y. - #[inline] - pub fn to_tuple(&self) -> (T, T) { - (self.x, self.y) - } - - /// Convert into a 3d vector with `z` coordinate equals to `T::zero()`. - #[inline] - pub fn to_3d(&self) -> Vector3D - where - T: Zero, - { - vec3(self.x, self.y, Zero::zero()) - } - - /// Rounds each component to the nearest integer value. - /// - /// This behavior is preserved for negative values (unlike the basic cast). - /// - /// ```rust - /// # use euclid::vec2; - /// enum Mm {} - /// - /// assert_eq!(vec2::<_, Mm>(-0.1, -0.8).round(), vec2::<_, Mm>(0.0, -1.0)) - /// ``` - #[inline] - #[must_use] - pub fn round(&self) -> Self - where - T: Round, - { - vec2(self.x.round(), self.y.round()) - } - - /// 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). - /// - /// ```rust - /// # use euclid::vec2; - /// enum Mm {} - /// - /// assert_eq!(vec2::<_, Mm>(-0.1, -0.8).ceil(), vec2::<_, Mm>(0.0, 0.0)) - /// ``` - #[inline] - #[must_use] - pub fn ceil(&self) -> Self - where - T: Ceil, - { - vec2(self.x.ceil(), self.y.ceil()) - } - - /// 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). - /// - /// ```rust - /// # use euclid::vec2; - /// enum Mm {} - /// - /// assert_eq!(vec2::<_, Mm>(-0.1, -0.8).floor(), vec2::<_, Mm>(-1.0, -1.0)) - /// ``` - #[inline] - #[must_use] - pub fn floor(&self) -> Self - where - T: Floor, - { - vec2(self.x.floor(), self.y.floor()) - } - - /// Returns the signed angle between this vector and the x axis. - /// Positive values counted counterclockwise, where 0 is `+x` axis, `PI/2` - /// is `+y` axis. - /// - /// The returned angle is between -PI and PI. - pub fn angle_from_x_axis(&self) -> Angle - where - T: Trig, - { - Angle::radians(Trig::fast_atan2(self.y, self.x)) - } - - /// Creates translation by this vector in vector units. - #[inline] - pub fn to_transform(&self) -> Transform2D - where - T: Zero + One, - { - Transform2D::create_translation(self.x, self.y) - } -} - -impl Vector2D -where - T: Copy + Mul + Add, -{ - /// Returns the vector's length squared. - #[inline] - pub fn square_length(&self) -> T { - self.x * self.x + self.y * self.y - } - - /// Returns this vector projected onto another one. - /// - /// Projecting onto a nil vector will cause a division by zero. - #[inline] - pub fn project_onto_vector(&self, onto: Self) -> Self - where - T: Sub + Div, - { - onto * (self.dot(onto) / onto.square_length()) - } - - /// Returns the signed angle between this vector and another vector. - /// - /// The returned angle is between -PI and PI. - pub fn angle_to(&self, other: Self) -> Angle - where - T: Sub + Trig, - { - Angle::radians(Trig::fast_atan2(self.cross(other), self.dot(other))) - } -} - -impl Vector2D { - /// Returns the vector length. - #[inline] - pub fn length(&self) -> T { - self.square_length().sqrt() - } - - /// Returns the vector with length of one unit. - #[inline] - #[must_use] - pub fn normalize(self) -> Self { - self / self.length() - } - - /// Returns the vector with length of one unit. - /// - /// Unlike [`Vector2D::normalize`](#method.normalize), this returns None in the case that the - /// length of the vector is zero. - #[inline] - #[must_use] - pub fn try_normalize(self) -> Option { - let len = self.length(); - if len == T::zero() { - None - } else { - Some(self / len) - } - } - - /// Return the normalized vector even if the length is larger than the max value of Float. - #[inline] - #[must_use] - pub fn robust_normalize(self) -> Self { - let length = self.length(); - if length.is_infinite() { - let scaled = self / T::max_value(); - scaled / scaled.length() - } else { - self / length - } - } - - /// Return this vector capped to a maximum length. - #[inline] - pub fn with_max_length(&self, max_length: T) -> Self { - let square_length = self.square_length(); - if square_length > max_length * max_length { - return (*self) * (max_length / square_length.sqrt()); - } - - *self - } - - /// Return this vector with a minimum length applied. - #[inline] - pub fn with_min_length(&self, min_length: T) -> Self { - let square_length = self.square_length(); - if square_length < min_length * min_length { - return (*self) * (min_length / square_length.sqrt()); - } - - *self - } - - /// Return this vector with minimum and maximum lengths applied. - #[inline] - pub fn clamp_length(&self, min: T, max: T) -> Self { - debug_assert!(min <= max); - self.with_min_length(min).with_max_length(max) - } -} - -impl Vector2D -where - T: Copy + One + Add + Sub + Mul, -{ - /// Linearly interpolate each component between this vector and another vector. - /// - /// # Example - /// - /// ```rust - /// use euclid::vec2; - /// use euclid::default::Vector2D; - /// - /// let from: Vector2D<_> = vec2(0.0, 10.0); - /// let to: Vector2D<_> = vec2(8.0, -4.0); - /// - /// assert_eq!(from.lerp(to, -1.0), vec2(-8.0, 24.0)); - /// assert_eq!(from.lerp(to, 0.0), vec2( 0.0, 10.0)); - /// assert_eq!(from.lerp(to, 0.5), vec2( 4.0, 3.0)); - /// assert_eq!(from.lerp(to, 1.0), vec2( 8.0, -4.0)); - /// assert_eq!(from.lerp(to, 2.0), vec2(16.0, -18.0)); - /// ``` - #[inline] - pub fn lerp(&self, other: Self, t: T) -> Self { - let one_t = T::one() - t; - (*self) * one_t + other * t - } - - /// Returns a reflection vector using an incident ray and a surface normal. - #[inline] - pub fn reflect(&self, normal: Self) -> Self { - let two = T::one() + T::one(); - *self - normal * two * self.dot(normal) - } -} - -impl Vector2D { - /// Returns the vector each component of which are minimum of this vector and another. - #[inline] - pub fn min(self, other: Self) -> Self { - vec2(min(self.x, other.x), min(self.y, other.y)) - } - - /// Returns the vector each component of which are maximum of this vector and another. - #[inline] - pub fn max(self, other: Self) -> Self { - vec2(max(self.x, other.x), max(self.y, other.y)) - } - - /// Returns the vector each component of which is clamped by corresponding - /// components of `start` and `end`. - /// - /// Shortcut for `self.max(start).min(end)`. - #[inline] - pub fn clamp(&self, start: Self, end: Self) -> Self - where - T: Copy, - { - self.max(start).min(end) - } - - /// Returns vector with results of "greater than" operation on each component. - #[inline] - pub fn greater_than(&self, other: Self) -> BoolVector2D { - BoolVector2D { - x: self.x > other.x, - y: self.y > other.y, - } - } - - /// Returns vector with results of "lower than" operation on each component. - #[inline] - pub fn lower_than(&self, other: Self) -> BoolVector2D { - BoolVector2D { - x: self.x < other.x, - y: self.y < other.y, - } - } -} - -impl Vector2D { - /// Returns vector with results of "equal" operation on each component. - #[inline] - pub fn equal(&self, other: Self) -> BoolVector2D { - BoolVector2D { - x: self.x == other.x, - y: self.y == other.y, - } - } - - /// Returns vector with results of "not equal" operation on each component. - #[inline] - pub fn not_equal(&self, other: Self) -> BoolVector2D { - BoolVector2D { - x: self.x != other.x, - y: self.y != other.y, - } - } -} - -impl Vector2D { - /// 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(&self) -> Vector2D { - self.try_cast().unwrap() - } - - /// Fallible 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. - pub fn try_cast(&self) -> Option> { - match (NumCast::from(self.x), NumCast::from(self.y)) { - (Some(x), Some(y)) => Some(Vector2D::new(x, y)), - _ => None, - } - } - - // Convenience functions for common casts. - - /// Cast into an `f32` vector. - #[inline] - pub fn to_f32(&self) -> Vector2D { - self.cast() - } - - /// Cast into an `f64` vector. - #[inline] - pub fn to_f64(&self) -> Vector2D { - self.cast() - } - - /// 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) -> Vector2D { - self.cast() - } - - /// Cast into an `u32` 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_u32(&self) -> Vector2D { - self.cast() - } - - /// 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) -> Vector2D { - self.cast() - } - - /// 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) -> Vector2D { - self.cast() - } -} - -impl Neg for Vector2D { - type Output = Vector2D; - - #[inline] - fn neg(self) -> Self::Output { - vec2(-self.x, -self.y) - } -} - -impl Add for Vector2D { - type Output = Vector2D; - - #[inline] - fn add(self, other: Self) -> Self::Output { - Vector2D::new(self.x + other.x, self.y + other.y) - } -} - -impl, U> AddAssign for Vector2D { - #[inline] - fn add_assign(&mut self, other: Self) { - *self = *self + other - } -} - -impl Sub for Vector2D { - type Output = Vector2D; - - #[inline] - fn sub(self, other: Self) -> Self::Output { - vec2(self.x - other.x, self.y - other.y) - } -} - -impl, U> SubAssign> for Vector2D { - #[inline] - fn sub_assign(&mut self, other: Self) { - *self = *self - other - } -} - -impl Mul for Vector2D { - type Output = Vector2D; - - #[inline] - fn mul(self, scale: T) -> Self::Output { - vec2(self.x * scale.clone(), self.y * scale) - } -} - -impl, U> MulAssign for Vector2D { - #[inline] - fn mul_assign(&mut self, scale: T) { - *self = *self * scale - } -} - -impl Mul> for Vector2D { - type Output = Vector2D; - - #[inline] - fn mul(self, scale: Scale) -> Self::Output { - vec2(self.x * scale.0.clone(), self.y * scale.0) - } -} - -impl MulAssign> for Vector2D { - #[inline] - fn mul_assign(&mut self, scale: Scale) { - self.x *= scale.0.clone(); - self.y *= scale.0; - } -} - -impl Div for Vector2D { - type Output = Vector2D; - - #[inline] - fn div(self, scale: T) -> Self::Output { - vec2(self.x / scale.clone(), self.y / scale) - } -} - -impl, U> DivAssign for Vector2D { - #[inline] - fn div_assign(&mut self, scale: T) { - *self = *self / scale - } -} - -impl Div> for Vector2D { - type Output = Vector2D; - - #[inline] - fn div(self, scale: Scale) -> Self::Output { - vec2(self.x / scale.0.clone(), self.y / scale.0) - } -} - -impl DivAssign> for Vector2D { - #[inline] - fn div_assign(&mut self, scale: Scale) { - self.x /= scale.0.clone(); - self.y /= scale.0; - } -} - -impl Round for Vector2D { - /// See [`Vector2D::round()`](#method.round) - #[inline] - fn round(self) -> Self { - (&self).round() - } -} - -impl Ceil for Vector2D { - /// See [`Vector2D::ceil()`](#method.ceil) - #[inline] - fn ceil(self) -> Self { - (&self).ceil() - } -} - -impl Floor for Vector2D { - /// See [`Vector2D::floor()`](#method.floor) - #[inline] - fn floor(self) -> Self { - (&self).floor() - } -} - -impl, U> ApproxEq> for Vector2D { - #[inline] - fn approx_epsilon() -> Self { - vec2(T::approx_epsilon(), T::approx_epsilon()) - } - - #[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 Into<[T; 2]> for Vector2D { - fn into(self) -> [T; 2] { - [self.x, self.y] - } -} - -impl From<[T; 2]> for Vector2D { - fn from([x, y]: [T; 2]) -> Self { - vec2(x, y) - } -} - -impl Into<(T, T)> for Vector2D { - fn into(self) -> (T, T) { - (self.x, self.y) - } -} - -impl From<(T, T)> for Vector2D { - fn from(tuple: (T, T)) -> Self { - vec2(tuple.0, tuple.1) - } -} - -impl From> for Vector2D { - fn from(size: Size2D) -> Self { - vec2(size.width, size.height) - } -} - -/// A 3d Vector tagged with a unit. -#[repr(C)] -pub struct Vector3D { - /// The `x` (traditionally, horizontal) coordinate. - pub x: T, - /// The `y` (traditionally, vertical) coordinate. - pub y: T, - /// The `z` (traditionally, depth) coordinate. - pub z: T, - #[doc(hidden)] - pub _unit: PhantomData, -} - -mint_vec!(Vector3D[x, y, z] = Vector3); - -impl Copy for Vector3D {} - -impl Clone for Vector3D { - fn clone(&self) -> Self { - Vector3D { - x: self.x.clone(), - y: self.y.clone(), - z: self.z.clone(), - _unit: PhantomData, - } - } -} - -#[cfg(feature = "serde")] -impl<'de, T, U> serde::Deserialize<'de> for Vector3D -where - T: serde::Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let (x, y, z) = serde::Deserialize::deserialize(deserializer)?; - Ok(Vector3D { - x, - y, - z, - _unit: PhantomData, - }) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for Vector3D -where - T: serde::Serialize, -{ - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - (&self.x, &self.y, &self.z).serialize(serializer) - } -} - -impl Eq for Vector3D {} - -impl PartialEq for Vector3D { - fn eq(&self, other: &Self) -> bool { - self.x == other.x && self.y == other.y && self.z == other.z - } -} - -impl Hash for Vector3D { - fn hash(&self, h: &mut H) { - self.x.hash(h); - self.y.hash(h); - self.z.hash(h); - } -} - -impl Zero for Vector3D { - /// Constructor, setting all components to zero. - #[inline] - fn zero() -> Self { - vec3(Zero::zero(), Zero::zero(), Zero::zero()) - } -} - -impl fmt::Debug for Vector3D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("") - .field(&self.x) - .field(&self.y) - .field(&self.z) - .finish() - } -} - -impl fmt::Display for Vector3D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "(")?; - fmt::Display::fmt(&self.x, f)?; - write!(f, ",")?; - fmt::Display::fmt(&self.y, f)?; - write!(f, ",")?; - fmt::Display::fmt(&self.z, f)?; - write!(f, ")") - } -} - -impl Default for Vector3D { - fn default() -> Self { - Vector3D::new(Default::default(), Default::default(), Default::default()) - } -} - -impl Vector3D { - /// Constructor, setting all components to zero. - #[inline] - pub fn zero() -> Self - where - T: Zero, - { - vec3(Zero::zero(), Zero::zero(), Zero::zero()) - } - - /// Constructor taking scalar values directly. - #[inline] - pub const fn new(x: T, y: T, z: T) -> Self { - Vector3D { - x, - y, - z, - _unit: PhantomData, - } - } - - /// Constructor taking properly Lengths instead of scalar values. - #[inline] - pub fn from_lengths(x: Length, y: Length, z: Length) -> Vector3D { - vec3(x.0, y.0, z.0) - } - - /// Tag a unitless value with units. - #[inline] - pub fn from_untyped(p: Vector3D) -> Self { - vec3(p.x, p.y, p.z) - } - - /// Computes the vector with absolute values of each component. - /// - /// # Example - /// - /// ```rust - /// # use std::{i32, f32}; - /// # use euclid::vec3; - /// enum U {} - /// - /// assert_eq!(vec3::<_, U>(-1, 0, 2).abs(), vec3(1, 0, 2)); - /// - /// let vec = vec3::<_, U>(f32::NAN, 0.0, -f32::MAX).abs(); - /// assert!(vec.x.is_nan()); - /// assert_eq!(vec.y, 0.0); - /// assert_eq!(vec.z, f32::MAX); - /// ``` - /// - /// # Panics - /// - /// The behavior for each component follows the scalar type's implementation of - /// `num_traits::Signed::abs`. - pub fn abs(&self) -> Self - where - T: Signed, - { - vec3(self.x.abs(), self.y.abs(), self.z.abs()) - } - - /// Dot product. - #[inline] - pub fn dot(self, other: Self) -> T - where - T: Add + Mul, - { - self.x * other.x + self.y * other.y + self.z * other.z - } -} - -impl Vector3D { - /// Cross product. - #[inline] - pub fn cross(self, other: Self) -> Self - where - T: Sub + Mul, - { - 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, - ) - } - - /// Cast this vector into a point. - /// - /// Equivalent to adding this vector to the origin. - #[inline] - pub fn to_point(&self) -> Point3D { - point3(self.x, self.y, self.z) - } - - /// Returns a 2d vector using this vector's x and y coordinates - #[inline] - pub fn xy(&self) -> Vector2D { - vec2(self.x, self.y) - } - - /// Returns a 2d vector using this vector's x and z coordinates - #[inline] - pub fn xz(&self) -> Vector2D { - vec2(self.x, self.z) - } - - /// Returns a 2d vector using this vector's x and z coordinates - #[inline] - pub fn yz(&self) -> Vector2D { - vec2(self.y, self.z) - } - - /// Cast into an array with x, y and z. - #[inline] - pub fn to_array(&self) -> [T; 3] { - [self.x, self.y, self.z] - } - - /// Cast into an array with x, y, z and 0. - #[inline] - pub fn to_array_4d(&self) -> [T; 4] - where - T: Zero, - { - [self.x, self.y, self.z, Zero::zero()] - } - - /// Cast into a tuple with x, y and z. - #[inline] - pub fn to_tuple(&self) -> (T, T, T) { - (self.x, self.y, self.z) - } - - /// Cast into a tuple with x, y, z and 0. - #[inline] - pub fn to_tuple_4d(&self) -> (T, T, T, T) - where - T: Zero, - { - (self.x, self.y, self.z, Zero::zero()) - } - - /// Drop the units, preserving only the numeric value. - #[inline] - pub fn to_untyped(&self) -> Vector3D { - vec3(self.x, self.y, self.z) - } - - /// Cast the unit. - #[inline] - pub fn cast_unit(&self) -> Vector3D { - vec3(self.x, self.y, self.z) - } - - /// Convert into a 2d vector. - #[inline] - pub fn to_2d(&self) -> Vector2D { - self.xy() - } - - /// Rounds each component to the nearest integer value. - /// - /// This behavior is preserved for negative values (unlike the basic cast). - /// - /// ```rust - /// # use euclid::vec3; - /// enum Mm {} - /// - /// assert_eq!(vec3::<_, Mm>(-0.1, -0.8, 0.4).round(), vec3::<_, Mm>(0.0, -1.0, 0.0)) - /// ``` - #[inline] - #[must_use] - pub fn round(&self) -> Self - where - T: Round, - { - vec3(self.x.round(), self.y.round(), self.z.round()) - } - - /// 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). - /// - /// ```rust - /// # use euclid::vec3; - /// enum Mm {} - /// - /// assert_eq!(vec3::<_, Mm>(-0.1, -0.8, 0.4).ceil(), vec3::<_, Mm>(0.0, 0.0, 1.0)) - /// ``` - #[inline] - #[must_use] - pub fn ceil(&self) -> Self - where - T: Ceil, - { - vec3(self.x.ceil(), self.y.ceil(), self.z.ceil()) - } - - /// 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). - /// - /// ```rust - /// # use euclid::vec3; - /// enum Mm {} - /// - /// assert_eq!(vec3::<_, Mm>(-0.1, -0.8, 0.4).floor(), vec3::<_, Mm>(-1.0, -1.0, 0.0)) - /// ``` - #[inline] - #[must_use] - pub fn floor(&self) -> Self - where - T: Floor, - { - vec3(self.x.floor(), self.y.floor(), self.z.floor()) - } - - /// Creates translation by this vector in vector units - #[inline] - pub fn to_transform(&self) -> Transform3D - where - T: Zero + One, - { - Transform3D::create_translation(self.x, self.y, self.z) - } -} - -impl Vector3D -where - T: Copy + Mul + Add, -{ - /// Returns the vector's length squared. - #[inline] - pub fn square_length(&self) -> T { - self.x * self.x + self.y * self.y + self.z * self.z - } - - /// Returns this vector projected onto another one. - /// - /// Projecting onto a nil vector will cause a division by zero. - #[inline] - pub fn project_onto_vector(&self, onto: Self) -> Self - where - T: Sub + Div, - { - onto * (self.dot(onto) / onto.square_length()) - } -} - -impl Vector3D { - /// Returns the positive angle between this vector and another vector. - /// - /// The returned angle is between 0 and PI. - pub fn angle_to(&self, other: Self) -> Angle - where - T: Trig, - { - Angle::radians(Trig::fast_atan2( - self.cross(other).length(), - self.dot(other), - )) - } - - /// Returns the vector length. - #[inline] - pub fn length(&self) -> T { - self.square_length().sqrt() - } - - /// Returns the vector with length of one unit - #[inline] - #[must_use] - pub fn normalize(self) -> Self { - self / self.length() - } - - /// Returns the vector with length of one unit. - /// - /// Unlike [`Vector2D::normalize`](#method.normalize), this returns None in the case that the - /// length of the vector is zero. - #[inline] - #[must_use] - pub fn try_normalize(self) -> Option { - let len = self.length(); - if len == T::zero() { - None - } else { - Some(self / len) - } - } - - /// Return the normalized vector even if the length is larger than the max value of Float. - #[inline] - #[must_use] - pub fn robust_normalize(self) -> Self { - let length = self.length(); - if length.is_infinite() { - let scaled = self / T::max_value(); - scaled / scaled.length() - } else { - self / length - } - } - - /// Return this vector capped to a maximum length. - #[inline] - pub fn with_max_length(&self, max_length: T) -> Self { - let square_length = self.square_length(); - if square_length > max_length * max_length { - return (*self) * (max_length / square_length.sqrt()); - } - - *self - } - - /// Return this vector with a minimum length applied. - #[inline] - pub fn with_min_length(&self, min_length: T) -> Self { - let square_length = self.square_length(); - if square_length < min_length * min_length { - return (*self) * (min_length / square_length.sqrt()); - } - - *self - } - - /// Return this vector with minimum and maximum lengths applied. - #[inline] - pub fn clamp_length(&self, min: T, max: T) -> Self { - debug_assert!(min <= max); - self.with_min_length(min).with_max_length(max) - } -} - -impl Vector3D -where - T: Copy + One + Add + Sub + Mul, -{ - /// Linearly interpolate each component between this vector and another vector. - /// - /// # Example - /// - /// ```rust - /// use euclid::vec3; - /// use euclid::default::Vector3D; - /// - /// let from: Vector3D<_> = vec3(0.0, 10.0, -1.0); - /// let to: Vector3D<_> = vec3(8.0, -4.0, 0.0); - /// - /// assert_eq!(from.lerp(to, -1.0), vec3(-8.0, 24.0, -2.0)); - /// assert_eq!(from.lerp(to, 0.0), vec3( 0.0, 10.0, -1.0)); - /// assert_eq!(from.lerp(to, 0.5), vec3( 4.0, 3.0, -0.5)); - /// assert_eq!(from.lerp(to, 1.0), vec3( 8.0, -4.0, 0.0)); - /// assert_eq!(from.lerp(to, 2.0), vec3(16.0, -18.0, 1.0)); - /// ``` - #[inline] - pub fn lerp(&self, other: Self, t: T) -> Self { - let one_t = T::one() - t; - (*self) * one_t + other * t - } - - /// Returns a reflection vector using an incident ray and a surface normal. - #[inline] - pub fn reflect(&self, normal: Self) -> Self { - let two = T::one() + T::one(); - *self - normal * two * self.dot(normal) - } -} - -impl Vector3D { - /// Returns the vector each component of which are minimum of this vector and another. - #[inline] - pub fn min(self, other: Self) -> Self { - vec3( - min(self.x, other.x), - min(self.y, other.y), - min(self.z, other.z), - ) - } - - /// Returns the vector each component of which are maximum of this vector and another. - #[inline] - pub fn max(self, other: Self) -> Self { - vec3( - max(self.x, other.x), - max(self.y, other.y), - max(self.z, other.z), - ) - } - - /// Returns the vector each component of which is clamped by corresponding - /// components of `start` and `end`. - /// - /// Shortcut for `self.max(start).min(end)`. - #[inline] - pub fn clamp(&self, start: Self, end: Self) -> Self - where - T: Copy, - { - self.max(start).min(end) - } - - /// Returns vector with results of "greater than" operation on each component. - #[inline] - pub fn greater_than(&self, other: Self) -> BoolVector3D { - BoolVector3D { - x: self.x > other.x, - y: self.y > other.y, - z: self.z > other.z, - } - } - - /// Returns vector with results of "lower than" operation on each component. - #[inline] - pub fn lower_than(&self, other: Self) -> BoolVector3D { - BoolVector3D { - x: self.x < other.x, - y: self.y < other.y, - z: self.z < other.z, - } - } -} - -impl Vector3D { - /// Returns vector with results of "equal" operation on each component. - #[inline] - pub fn equal(&self, other: Self) -> BoolVector3D { - BoolVector3D { - x: self.x == other.x, - y: self.y == other.y, - z: self.z == other.z, - } - } - - /// Returns vector with results of "not equal" operation on each component. - #[inline] - pub fn not_equal(&self, other: Self) -> BoolVector3D { - BoolVector3D { - x: self.x != other.x, - y: self.y != other.y, - z: self.z != other.z, - } - } -} - -impl Vector3D { - /// 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(&self) -> Vector3D { - self.try_cast().unwrap() - } - - /// Fallible 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. - pub fn try_cast(&self) -> Option> { - 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) -> Vector3D { - self.cast() - } - - /// Cast into an `f64` vector. - #[inline] - pub fn to_f64(&self) -> Vector3D { - self.cast() - } - - /// 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) -> Vector3D { - self.cast() - } - - /// Cast into an `u32` 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_u32(&self) -> Vector3D { - self.cast() - } - - /// 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) -> Vector3D { - self.cast() - } - - /// 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) -> Vector3D { - self.cast() - } -} - -impl Neg for Vector3D { - type Output = Vector3D; - - #[inline] - fn neg(self) -> Self::Output { - vec3(-self.x, -self.y, -self.z) - } -} - -impl Add for Vector3D { - type Output = Vector3D; - - #[inline] - fn add(self, other: Self) -> Self::Output { - vec3(self.x + other.x, self.y + other.y, self.z + other.z) - } -} - -impl, U> AddAssign for Vector3D { - #[inline] - fn add_assign(&mut self, other: Self) { - *self = *self + other - } -} - -impl Sub for Vector3D { - type Output = Vector3D; - - #[inline] - fn sub(self, other: Self) -> Self::Output { - vec3(self.x - other.x, self.y - other.y, self.z - other.z) - } -} - -impl, U> SubAssign> for Vector3D { - #[inline] - fn sub_assign(&mut self, other: Self) { - *self = *self - other - } -} - -impl Mul for Vector3D { - type Output = Vector3D; - - #[inline] - fn mul(self, scale: T) -> Self::Output { - vec3( - self.x * scale.clone(), - self.y * scale.clone(), - self.z * scale, - ) - } -} - -impl, U> MulAssign for Vector3D { - #[inline] - fn mul_assign(&mut self, scale: T) { - *self = *self * scale - } -} - -impl Mul> for Vector3D { - type Output = Vector3D; - - #[inline] - fn mul(self, scale: Scale) -> Self::Output { - vec3( - self.x * scale.0.clone(), - self.y * scale.0.clone(), - self.z * scale.0, - ) - } -} - -impl MulAssign> for Vector3D { - #[inline] - fn mul_assign(&mut self, scale: Scale) { - self.x *= scale.0.clone(); - self.y *= scale.0.clone(); - self.z *= scale.0; - } -} - -impl Div for Vector3D { - type Output = Vector3D; - - #[inline] - fn div(self, scale: T) -> Self::Output { - vec3( - self.x / scale.clone(), - self.y / scale.clone(), - self.z / scale, - ) - } -} - -impl, U> DivAssign for Vector3D { - #[inline] - fn div_assign(&mut self, scale: T) { - *self = *self / scale - } -} - -impl Div> for Vector3D { - type Output = Vector3D; - - #[inline] - fn div(self, scale: Scale) -> Self::Output { - vec3( - self.x / scale.0.clone(), - self.y / scale.0.clone(), - self.z / scale.0, - ) - } -} - -impl DivAssign> for Vector3D { - #[inline] - fn div_assign(&mut self, scale: Scale) { - self.x /= scale.0.clone(); - self.y /= scale.0.clone(); - self.z /= scale.0; - } -} - -impl Round for Vector3D { - /// See [`Vector3D::round()`](#method.round) - #[inline] - fn round(self) -> Self { - (&self).round() - } -} - -impl Ceil for Vector3D { - /// See [`Vector3D::ceil()`](#method.ceil) - #[inline] - fn ceil(self) -> Self { - (&self).ceil() - } -} - -impl Floor for Vector3D { - /// See [`Vector3D::floor()`](#method.floor) - #[inline] - fn floor(self) -> Self { - (&self).floor() - } -} - -impl, U> ApproxEq> for Vector3D { - #[inline] - fn approx_epsilon() -> Self { - vec3( - T::approx_epsilon(), - T::approx_epsilon(), - T::approx_epsilon(), - ) - } - - #[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 Into<[T; 3]> for Vector3D { - fn into(self) -> [T; 3] { - [self.x, self.y, self.z] - } -} - -impl From<[T; 3]> for Vector3D { - fn from([x, y, z]: [T; 3]) -> Self { - vec3(x, y, z) - } -} - -impl Into<(T, T, T)> for Vector3D { - fn into(self) -> (T, T, T) { - (self.x, self.y, self.z) - } -} - -impl From<(T, T, T)> for Vector3D { - fn from(tuple: (T, T, T)) -> Self { - vec3(tuple.0, tuple.1, tuple.2) - } -} - -/// A 2d vector of booleans, useful for component-wise logic operations. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct BoolVector2D { - pub x: bool, - pub y: bool, -} - -/// A 3d vector of booleans, useful for component-wise logic operations. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct BoolVector3D { - pub x: bool, - pub y: bool, - pub z: bool, -} - -impl BoolVector2D { - /// Returns `true` if all components are `true` and `false` otherwise. - #[inline] - pub fn all(&self) -> bool { - self.x && self.y - } - - /// Returns `true` if any component are `true` and `false` otherwise. - #[inline] - pub fn any(&self) -> bool { - self.x || self.y - } - - /// Returns `true` if all components are `false` and `false` otherwise. Negation of `any()`. - #[inline] - pub fn none(&self) -> bool { - !self.any() - } - - /// Returns new vector with by-component AND operation applied. - #[inline] - pub fn and(&self, other: Self) -> Self { - BoolVector2D { - x: self.x && other.x, - y: self.y && other.y, - } - } - - /// Returns new vector with by-component OR operation applied. - #[inline] - pub fn or(&self, other: Self) -> Self { - BoolVector2D { - x: self.x || other.x, - y: self.y || other.y, - } - } - - /// Returns new vector with results of negation operation on each component. - #[inline] - pub fn not(&self) -> Self { - BoolVector2D { - x: !self.x, - y: !self.y, - } - } - - /// Returns point, each component of which or from `a`, or from `b` depending on truly value - /// of corresponding vector component. `true` selects value from `a` and `false` from `b`. - #[inline] - pub fn select_point(&self, a: Point2D, b: Point2D) -> Point2D { - point2( - if self.x { a.x } else { b.x }, - if self.y { a.y } else { b.y }, - ) - } - - /// Returns vector, each component of which or from `a`, or from `b` depending on truly value - /// of corresponding vector component. `true` selects value from `a` and `false` from `b`. - #[inline] - pub fn select_vector(&self, a: Vector2D, b: Vector2D) -> Vector2D { - vec2( - if self.x { a.x } else { b.x }, - if self.y { a.y } else { b.y }, - ) - } - - /// Returns size, each component of which or from `a`, or from `b` depending on truly value - /// of corresponding vector component. `true` selects value from `a` and `false` from `b`. - #[inline] - pub fn select_size(&self, a: Size2D, b: Size2D) -> Size2D { - size2( - if self.x { a.width } else { b.width }, - if self.y { a.height } else { b.height }, - ) - } -} - -impl BoolVector3D { - /// Returns `true` if all components are `true` and `false` otherwise. - #[inline] - pub fn all(&self) -> bool { - self.x && self.y && self.z - } - - /// Returns `true` if any component are `true` and `false` otherwise. - #[inline] - pub fn any(&self) -> bool { - self.x || self.y || self.z - } - - /// Returns `true` if all components are `false` and `false` otherwise. Negation of `any()`. - #[inline] - pub fn none(&self) -> bool { - !self.any() - } - - /// Returns new vector with by-component AND operation applied. - #[inline] - pub fn and(&self, other: Self) -> Self { - BoolVector3D { - x: self.x && other.x, - y: self.y && other.y, - z: self.z && other.z, - } - } - - /// Returns new vector with by-component OR operation applied. - #[inline] - pub fn or(&self, other: Self) -> Self { - BoolVector3D { - x: self.x || other.x, - y: self.y || other.y, - z: self.z || other.z, - } - } - - /// Returns new vector with results of negation operation on each component. - #[inline] - pub fn not(&self) -> Self { - BoolVector3D { - x: !self.x, - y: !self.y, - z: !self.z, - } - } - - /// Returns point, each component of which or from `a`, or from `b` depending on truly value - /// of corresponding vector component. `true` selects value from `a` and `false` from `b`. - #[inline] - pub fn select_point(&self, a: Point3D, b: Point3D) -> Point3D { - point3( - if self.x { a.x } else { b.x }, - if self.y { a.y } else { b.y }, - if self.z { a.z } else { b.z }, - ) - } - - /// Returns vector, each component of which or from `a`, or from `b` depending on truly value - /// of corresponding vector component. `true` selects value from `a` and `false` from `b`. - #[inline] - pub fn select_vector(&self, a: Vector3D, b: Vector3D) -> Vector3D { - vec3( - if self.x { a.x } else { b.x }, - if self.y { a.y } else { b.y }, - if self.z { a.z } else { b.z }, - ) - } - - /// Returns size, each component of which or from `a`, or from `b` depending on truly value - /// of corresponding vector component. `true` selects value from `a` and `false` from `b`. - #[inline] - #[must_use] - pub fn select_size(&self, a: Size3D, b: Size3D) -> Size3D { - size3( - if self.x { a.width } else { b.width }, - if self.y { a.height } else { b.height }, - if self.z { a.depth } else { b.depth }, - ) - } - - /// Returns a 2d vector using this vector's x and y coordinates. - #[inline] - pub fn xy(&self) -> BoolVector2D { - BoolVector2D { - x: self.x, - y: self.y, - } - } - - /// Returns a 2d vector using this vector's x and z coordinates. - #[inline] - pub fn xz(&self) -> BoolVector2D { - BoolVector2D { - x: self.x, - y: self.z, - } - } - - /// Returns a 2d vector using this vector's y and z coordinates. - #[inline] - pub fn yz(&self) -> BoolVector2D { - BoolVector2D { - x: self.y, - y: self.z, - } - } -} - -/// Convenience constructor. -#[inline] -pub fn vec2(x: T, y: T) -> Vector2D { - Vector2D { - x, - y, - _unit: PhantomData, - } -} - -/// Convenience constructor. -#[inline] -pub fn vec3(x: T, y: T, z: T) -> Vector3D { - Vector3D { - x, - y, - z, - _unit: PhantomData, - } -} - -/// Shorthand for `BoolVector2D { x, y }`. -#[inline] -pub fn bvec2(x: bool, y: bool) -> BoolVector2D { - BoolVector2D { x, y } -} - -/// Shorthand for `BoolVector3D { x, y, z }`. -#[inline] -pub fn bvec3(x: bool, y: bool, z: bool) -> BoolVector3D { - BoolVector3D { x, y, z } -} - -#[cfg(test)] -mod vector2d { - use crate::scale::Scale; - use crate::{default, vec2}; - - #[cfg(feature = "mint")] - use mint; - type Vec2 = default::Vector2D; - - #[test] - pub fn test_scalar_mul() { - let p1: Vec2 = vec2(3.0, 5.0); - - let result = p1 * 5.0; - - assert_eq!(result, Vec2::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() { - use std::f32; - - let p0: Vec2 = Vec2::zero(); - let p1: Vec2 = vec2(4.0, 0.0); - let p2: Vec2 = vec2(3.0, -4.0); - assert!(p0.normalize().x.is_nan() && p0.normalize().y.is_nan()); - assert_eq!(p1.normalize(), vec2(1.0, 0.0)); - assert_eq!(p2.normalize(), vec2(0.6, -0.8)); - - let p3: Vec2 = vec2(::std::f32::MAX, ::std::f32::MAX); - assert_ne!( - p3.normalize(), - vec2(1.0 / 2.0f32.sqrt(), 1.0 / 2.0f32.sqrt()) - ); - assert_eq!( - p3.robust_normalize(), - vec2(1.0 / 2.0f32.sqrt(), 1.0 / 2.0f32.sqrt()) - ); - - let p4: Vec2 = Vec2::zero(); - assert!(p4.try_normalize().is_none()); - let p5: Vec2 = Vec2::new(f32::MIN_POSITIVE, f32::MIN_POSITIVE); - assert!(p5.try_normalize().is_none()); - - let p6: Vec2 = vec2(4.0, 0.0); - let p7: Vec2 = vec2(3.0, -4.0); - assert_eq!(p6.try_normalize().unwrap(), vec2(1.0, 0.0)); - assert_eq!(p7.try_normalize().unwrap(), 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)); - } - - #[test] - pub fn test_angle_from_x_axis() { - use crate::approxeq::ApproxEq; - use core::f32::consts::FRAC_PI_2; - - let right: Vec2 = vec2(10.0, 0.0); - let down: Vec2 = vec2(0.0, 4.0); - let up: Vec2 = vec2(0.0, -1.0); - - assert!(right.angle_from_x_axis().get().approx_eq(&0.0)); - assert!(down.angle_from_x_axis().get().approx_eq(&FRAC_PI_2)); - assert!(up.angle_from_x_axis().get().approx_eq(&-FRAC_PI_2)); - } - - #[test] - pub fn test_angle_to() { - use crate::approxeq::ApproxEq; - use core::f32::consts::FRAC_PI_2; - - let right: Vec2 = vec2(10.0, 0.0); - let right2: Vec2 = vec2(1.0, 0.0); - let up: Vec2 = vec2(0.0, -1.0); - let up_left: Vec2 = vec2(-1.0, -1.0); - - assert!(right.angle_to(right2).get().approx_eq(&0.0)); - assert!(right.angle_to(up).get().approx_eq(&-FRAC_PI_2)); - assert!(up.angle_to(right).get().approx_eq(&FRAC_PI_2)); - assert!(up_left - .angle_to(up) - .get() - .approx_eq_eps(&(0.5 * FRAC_PI_2), &0.0005)); - } - - #[test] - pub fn test_with_max_length() { - use crate::approxeq::ApproxEq; - - let v1: Vec2 = vec2(0.5, 0.5); - let v2: Vec2 = vec2(1.0, 0.0); - let v3: Vec2 = vec2(0.1, 0.2); - let v4: Vec2 = vec2(2.0, -2.0); - let v5: Vec2 = vec2(1.0, 2.0); - let v6: Vec2 = vec2(-1.0, 3.0); - - assert_eq!(v1.with_max_length(1.0), v1); - assert_eq!(v2.with_max_length(1.0), v2); - assert_eq!(v3.with_max_length(1.0), v3); - assert_eq!(v4.with_max_length(10.0), v4); - assert_eq!(v5.with_max_length(10.0), v5); - assert_eq!(v6.with_max_length(10.0), v6); - - let v4_clamped = v4.with_max_length(1.0); - assert!(v4_clamped.length().approx_eq(&1.0)); - assert!(v4_clamped.normalize().approx_eq(&v4.normalize())); - - let v5_clamped = v5.with_max_length(1.5); - assert!(v5_clamped.length().approx_eq(&1.5)); - assert!(v5_clamped.normalize().approx_eq(&v5.normalize())); - - let v6_clamped = v6.with_max_length(2.5); - assert!(v6_clamped.length().approx_eq(&2.5)); - assert!(v6_clamped.normalize().approx_eq(&v6.normalize())); - } - - #[test] - pub fn test_project_onto_vector() { - use crate::approxeq::ApproxEq; - - let v1: Vec2 = vec2(1.0, 2.0); - let x: Vec2 = vec2(1.0, 0.0); - let y: Vec2 = vec2(0.0, 1.0); - - assert!(v1.project_onto_vector(x).approx_eq(&vec2(1.0, 0.0))); - assert!(v1.project_onto_vector(y).approx_eq(&vec2(0.0, 2.0))); - assert!(v1.project_onto_vector(-x).approx_eq(&vec2(1.0, 0.0))); - assert!(v1.project_onto_vector(x * 10.0).approx_eq(&vec2(1.0, 0.0))); - assert!(v1.project_onto_vector(v1 * 2.0).approx_eq(&v1)); - assert!(v1.project_onto_vector(-v1).approx_eq(&v1)); - } - - #[cfg(feature = "mint")] - #[test] - pub fn test_mint() { - let v1 = Vec2::new(1.0, 3.0); - let vm: mint::Vector2<_> = v1.into(); - let v2 = Vec2::from(vm); - - assert_eq!(v1, v2); - } - - pub enum Mm {} - pub enum Cm {} - - pub type Vector2DMm = super::Vector2D; - pub type Vector2DCm = super::Vector2D; - - #[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_tpyed_scalar_mul() { - let p1 = Vector2DMm::new(1.0, 2.0); - let cm_per_mm = Scale::::new(0.1); - - let result: Vector2DCm = p1 * cm_per_mm; - - assert_eq!(result, vec2(0.1, 0.2)); - } - - #[test] - pub fn test_swizzling() { - let p: default::Vector2D = vec2(1, 2); - assert_eq!(p.yx(), vec2(2, 1)); - } - - #[test] - pub fn test_reflect() { - use crate::approxeq::ApproxEq; - let a: Vec2 = vec2(1.0, 3.0); - let n1: Vec2 = vec2(0.0, -1.0); - let n2: Vec2 = vec2(1.0, -1.0).normalize(); - - assert!(a.reflect(n1).approx_eq(&vec2(1.0, -3.0))); - assert!(a.reflect(n2).approx_eq(&vec2(3.0, 1.0))); - } -} - -#[cfg(test)] -mod vector3d { - use crate::scale::Scale; - use crate::{default, vec2, vec3}; - #[cfg(feature = "mint")] - use mint; - - type Vec3 = default::Vector3D; - - #[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() { - use std::f32; - - 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!( - p0.normalize().x.is_nan() && p0.normalize().y.is_nan() && p0.normalize().z.is_nan() - ); - 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)); - - let p3: Vec3 = vec3(::std::f32::MAX, ::std::f32::MAX, 0.0); - assert_ne!( - p3.normalize(), - vec3(1.0 / 2.0f32.sqrt(), 1.0 / 2.0f32.sqrt(), 0.0) - ); - assert_eq!( - p3.robust_normalize(), - vec3(1.0 / 2.0f32.sqrt(), 1.0 / 2.0f32.sqrt(), 0.0) - ); - - let p4: Vec3 = Vec3::zero(); - assert!(p4.try_normalize().is_none()); - let p5: Vec3 = Vec3::new(f32::MIN_POSITIVE, f32::MIN_POSITIVE, f32::MIN_POSITIVE); - assert!(p5.try_normalize().is_none()); - - let p6: Vec3 = vec3(4.0, 0.0, 3.0); - let p7: Vec3 = vec3(3.0, -4.0, 0.0); - assert_eq!(p6.try_normalize().unwrap(), vec3(0.8, 0.0, 0.6)); - assert_eq!(p7.try_normalize().unwrap(), vec3(0.6, -0.8, 0.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)); - } - - #[test] - pub fn test_clamp() { - let p1: Vec3 = vec3(1.0, -1.0, 5.0); - let p2: Vec3 = vec3(2.0, 5.0, 10.0); - let p3: Vec3 = vec3(-1.0, 2.0, 20.0); - - let result = p3.clamp(p1, p2); - - assert_eq!(result, vec3(1.0, 2.0, 10.0)); - } - - #[test] - pub fn test_typed_scalar_mul() { - enum Mm {} - enum Cm {} - - let p1 = super::Vector3D::::new(1.0, 2.0, 3.0); - let cm_per_mm = Scale::::new(0.1); - - let result: super::Vector3D = p1 * cm_per_mm; - - assert_eq!(result, vec3(0.1, 0.2, 0.3)); - } - - #[test] - pub fn test_swizzling() { - let p: Vec3 = vec3(1.0, 2.0, 3.0); - assert_eq!(p.xy(), vec2(1.0, 2.0)); - assert_eq!(p.xz(), vec2(1.0, 3.0)); - assert_eq!(p.yz(), vec2(2.0, 3.0)); - } - - #[cfg(feature = "mint")] - #[test] - pub fn test_mint() { - let v1 = Vec3::new(1.0, 3.0, 5.0); - let vm: mint::Vector3<_> = v1.into(); - let v2 = Vec3::from(vm); - - assert_eq!(v1, v2); - } - - #[test] - pub fn test_reflect() { - use crate::approxeq::ApproxEq; - let a: Vec3 = vec3(1.0, 3.0, 2.0); - let n1: Vec3 = vec3(0.0, -1.0, 0.0); - let n2: Vec3 = vec3(0.0, 1.0, 1.0).normalize(); - - assert!(a.reflect(n1).approx_eq(&vec3(1.0, -3.0, 2.0))); - assert!(a.reflect(n2).approx_eq(&vec3(1.0, -2.0, -3.0))); - } - - #[test] - pub fn test_angle_to() { - use crate::approxeq::ApproxEq; - use core::f32::consts::FRAC_PI_2; - - let right: Vec3 = vec3(10.0, 0.0, 0.0); - let right2: Vec3 = vec3(1.0, 0.0, 0.0); - let up: Vec3 = vec3(0.0, -1.0, 0.0); - let up_left: Vec3 = vec3(-1.0, -1.0, 0.0); - - assert!(right.angle_to(right2).get().approx_eq(&0.0)); - assert!(right.angle_to(up).get().approx_eq(&FRAC_PI_2)); - assert!(up.angle_to(right).get().approx_eq(&FRAC_PI_2)); - assert!(up_left - .angle_to(up) - .get() - .approx_eq_eps(&(0.5 * FRAC_PI_2), &0.0005)); - } - - #[test] - pub fn test_with_max_length() { - use crate::approxeq::ApproxEq; - - let v1: Vec3 = vec3(0.5, 0.5, 0.0); - let v2: Vec3 = vec3(1.0, 0.0, 0.0); - let v3: Vec3 = vec3(0.1, 0.2, 0.3); - let v4: Vec3 = vec3(2.0, -2.0, 2.0); - let v5: Vec3 = vec3(1.0, 2.0, -3.0); - let v6: Vec3 = vec3(-1.0, 3.0, 2.0); - - assert_eq!(v1.with_max_length(1.0), v1); - assert_eq!(v2.with_max_length(1.0), v2); - assert_eq!(v3.with_max_length(1.0), v3); - assert_eq!(v4.with_max_length(10.0), v4); - assert_eq!(v5.with_max_length(10.0), v5); - assert_eq!(v6.with_max_length(10.0), v6); - - let v4_clamped = v4.with_max_length(1.0); - assert!(v4_clamped.length().approx_eq(&1.0)); - assert!(v4_clamped.normalize().approx_eq(&v4.normalize())); - - let v5_clamped = v5.with_max_length(1.5); - assert!(v5_clamped.length().approx_eq(&1.5)); - assert!(v5_clamped.normalize().approx_eq(&v5.normalize())); - - let v6_clamped = v6.with_max_length(2.5); - assert!(v6_clamped.length().approx_eq(&2.5)); - assert!(v6_clamped.normalize().approx_eq(&v6.normalize())); - } - - #[test] - pub fn test_project_onto_vector() { - use crate::approxeq::ApproxEq; - - let v1: Vec3 = vec3(1.0, 2.0, 3.0); - let x: Vec3 = vec3(1.0, 0.0, 0.0); - let y: Vec3 = vec3(0.0, 1.0, 0.0); - let z: Vec3 = vec3(0.0, 0.0, 1.0); - - assert!(v1.project_onto_vector(x).approx_eq(&vec3(1.0, 0.0, 0.0))); - assert!(v1.project_onto_vector(y).approx_eq(&vec3(0.0, 2.0, 0.0))); - assert!(v1.project_onto_vector(z).approx_eq(&vec3(0.0, 0.0, 3.0))); - assert!(v1.project_onto_vector(-x).approx_eq(&vec3(1.0, 0.0, 0.0))); - assert!(v1 - .project_onto_vector(x * 10.0) - .approx_eq(&vec3(1.0, 0.0, 0.0))); - assert!(v1.project_onto_vector(v1 * 2.0).approx_eq(&v1)); - assert!(v1.project_onto_vector(-v1).approx_eq(&v1)); - } -} - -#[cfg(test)] -mod bool_vector { - use super::*; - use crate::default; - type Vec2 = default::Vector2D; - type Vec3 = default::Vector3D; - - #[test] - fn test_bvec2() { - assert_eq!( - Vec2::new(1.0, 2.0).greater_than(Vec2::new(2.0, 1.0)), - bvec2(false, true), - ); - - assert_eq!( - Vec2::new(1.0, 2.0).lower_than(Vec2::new(2.0, 1.0)), - bvec2(true, false), - ); - - assert_eq!( - Vec2::new(1.0, 2.0).equal(Vec2::new(1.0, 3.0)), - bvec2(true, false), - ); - - assert_eq!( - Vec2::new(1.0, 2.0).not_equal(Vec2::new(1.0, 3.0)), - bvec2(false, true), - ); - - assert!(bvec2(true, true).any()); - assert!(bvec2(false, true).any()); - assert!(bvec2(true, false).any()); - assert!(!bvec2(false, false).any()); - assert!(bvec2(false, false).none()); - assert!(bvec2(true, true).all()); - assert!(!bvec2(false, true).all()); - assert!(!bvec2(true, false).all()); - assert!(!bvec2(false, false).all()); - - assert_eq!(bvec2(true, false).not(), bvec2(false, true)); - assert_eq!( - bvec2(true, false).and(bvec2(true, true)), - bvec2(true, false) - ); - assert_eq!(bvec2(true, false).or(bvec2(true, true)), bvec2(true, true)); - - assert_eq!( - bvec2(true, false).select_vector(Vec2::new(1.0, 2.0), Vec2::new(3.0, 4.0)), - Vec2::new(1.0, 4.0), - ); - } - - #[test] - fn test_bvec3() { - assert_eq!( - Vec3::new(1.0, 2.0, 3.0).greater_than(Vec3::new(3.0, 2.0, 1.0)), - bvec3(false, false, true), - ); - - assert_eq!( - Vec3::new(1.0, 2.0, 3.0).lower_than(Vec3::new(3.0, 2.0, 1.0)), - bvec3(true, false, false), - ); - - assert_eq!( - Vec3::new(1.0, 2.0, 3.0).equal(Vec3::new(3.0, 2.0, 1.0)), - bvec3(false, true, false), - ); - - assert_eq!( - Vec3::new(1.0, 2.0, 3.0).not_equal(Vec3::new(3.0, 2.0, 1.0)), - bvec3(true, false, true), - ); - - assert!(bvec3(true, true, false).any()); - assert!(bvec3(false, true, false).any()); - assert!(bvec3(true, false, false).any()); - assert!(!bvec3(false, false, false).any()); - assert!(bvec3(false, false, false).none()); - assert!(bvec3(true, true, true).all()); - assert!(!bvec3(false, true, false).all()); - assert!(!bvec3(true, false, false).all()); - assert!(!bvec3(false, false, false).all()); - - assert_eq!(bvec3(true, false, true).not(), bvec3(false, true, false)); - assert_eq!( - bvec3(true, false, true).and(bvec3(true, true, false)), - bvec3(true, false, false) - ); - assert_eq!( - bvec3(true, false, false).or(bvec3(true, true, false)), - bvec3(true, true, false) - ); - - assert_eq!( - bvec3(true, false, true) - .select_vector(Vec3::new(1.0, 2.0, 3.0), Vec3::new(4.0, 5.0, 6.0)), - Vec3::new(1.0, 5.0, 3.0), - ); - } -}