Bug 1625220 - Use euclid 0.20.8. r=gw

Differential Revision: https://phabricator.services.mozilla.com/D68469

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nicolas Silva 2020-03-31 12:41:52 +00:00
parent ee5c428fbf
commit 430e8ef7b4
28 changed files with 3313 additions and 1314 deletions

4
Cargo.lock generated
View File

@ -1197,9 +1197,9 @@ checksum = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
[[package]]
name = "euclid"
version = "0.20.0"
version = "0.20.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c4786521fec183792e755bf32cd0188e4e7628c6d0fcfd51426435b9081a106"
checksum = "57d9ae79e19d69ffb5b47b0a744c4215c115dfed4039314c9ca1b8ddc6c333be"
dependencies = [
"num-traits",
"serde",

View File

@ -11,7 +11,7 @@ webrender_debugger = ["webrender/debugger"]
rayon = "1"
num_cpus = "1.7.0"
tracy-rs = "0.1"
euclid = { version = "0.20.0", features = ["serde"] }
euclid = { version = "0.20.8", features = ["serde"] }
app_units = "0.7"
gleam = "0.10.0"
log = "0.4"

59
gfx/wr/Cargo.lock generated
View File

@ -44,7 +44,7 @@ name = "app_units"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -53,7 +53,7 @@ name = "approx"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -79,6 +79,11 @@ name = "autocfg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "autocfg"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "backtrace"
version = "0.3.12"
@ -428,7 +433,7 @@ dependencies = [
name = "direct-composition"
version = "0.1.0"
dependencies = [
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.8 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"mozangle 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender 0.61.0",
@ -485,10 +490,10 @@ dependencies = [
[[package]]
name = "euclid"
version = "0.20.0"
version = "0.20.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -745,7 +750,7 @@ dependencies = [
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"png 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -822,7 +827,7 @@ name = "line_drawing"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -988,7 +993,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -996,7 +1001,7 @@ name = "num-integer"
version = "0.1.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1005,7 +1010,7 @@ version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1014,13 +1019,16 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.4"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num_cpus"
@ -1048,7 +1056,7 @@ name = "ordered-float"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1097,7 +1105,7 @@ dependencies = [
name = "peek-poke"
version = "0.2.0"
dependencies = [
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.8 (registry+https://github.com/rust-lang/crates.io-index)",
"peek-poke-derive 0.2.1",
]
@ -1133,9 +1141,9 @@ version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1633,7 +1641,7 @@ dependencies = [
name = "tileview"
version = "0.1.0"
dependencies = [
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender 0.61.0",
@ -1821,7 +1829,7 @@ dependencies = [
"core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cstr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.8 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1831,7 +1839,7 @@ dependencies = [
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"malloc_size_of_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"mozangle 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"plane-split 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
"png 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1856,7 +1864,7 @@ dependencies = [
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.8 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1874,7 +1882,7 @@ dependencies = [
"core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
"derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.8 (registry+https://github.com/rust-lang/crates.io-index)",
"malloc_size_of_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"peek-poke 0.2.0",
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1965,7 +1973,7 @@ name = "wr_malloc_size_of"
version = "0.0.1"
dependencies = [
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1983,7 +1991,7 @@ dependencies = [
"crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.8 (registry+https://github.com/rust-lang/crates.io-index)",
"font-loader 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2074,6 +2082,7 @@ dependencies = [
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1"
"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
"checksum backtrace 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "a2eff3830839471718ef8522b9025b399bfb713e25bc220da721364efb660d7d"
"checksum backtrace-sys 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5b3a000b9c543553af61bc01cbfc403b04b5caa9e421033866f2e98061eb3e61"
"checksum base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "621fc7ecb8008f86d7fb9b95356cd692ce9514b80a86d85b397f32a22da7b9e2"
@ -2118,7 +2127,7 @@ dependencies = [
"checksum dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0bd1369e02db5e9b842a9b67bce8a2fcc043beafb2ae8a799dd482d46ea1ff0d"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
"checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a"
"checksum euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4786521fec183792e755bf32cd0188e4e7628c6d0fcfd51426435b9081a106"
"checksum euclid 0.20.8 (registry+https://github.com/rust-lang/crates.io-index)" = "57d9ae79e19d69ffb5b47b0a744c4215c115dfed4039314c9ca1b8ddc6c333be"
"checksum expat-sys 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c470ccb972f2088549b023db8029ed9da9426f5affbf9b62efff7009ab8ed5b1"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
"checksum font-loader 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd330f40acb3016432cbfa4c54b3d6e6e893a538df79d8df8fd8c26e21c36aaa"
@ -2180,7 +2189,7 @@ dependencies = [
"checksum num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac0ea58d64a89d9d6b7688031b3be9358d6c919badcf7fbb0527ccfd891ee45"
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
"checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10"
"checksum num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28"
"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
"checksum objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d"
"checksum opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "51ecbcb821e1bd256d456fe858aaa7f380b63863eab2eb86eee1bd9f33dd6682"

View File

@ -4590,15 +4590,10 @@ impl PicturePrimitive {
let world_min = map_raster_to_world.map_vector(raster_min);
let world_max = map_raster_to_world.map_vector(raster_max);
let top_left = -world_max.max(vec2(0.0, 0.0));
let bottom_right = -world_min.min(vec2(0.0, 0.0));
// Grow the clip in the opposite direction of the shadow's offset.
SideOffsets2D::new(
-top_left.y,
bottom_right.x,
bottom_right.y,
-top_left.x,
SideOffsets2D::from_vectors_outer(
-world_max.max(vec2(0.0, 0.0)),
-world_min.min(vec2(0.0, 0.0)),
)
}
_ => SideOffsets2D::zero(),

View File

@ -1 +1 @@
{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"7ae5531c88ac476361c06e6ee5531839eff3b301c66ba05619570b3ab7926467","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/approxeq.rs":"6594377e8f6c20f88f628520d8de9b9a59c5892a0ee9a6ccd13c8400c1499911","src/approxord.rs":"087e0a8d24b8a9bed4c1cc571eec5e50cc7afa184c6ac4961c7409a69456ec7b","src/box2d.rs":"0dc013b9bfe088e62df8675674a5430580ecfaff202d0966ba5d316e7ff0165e","src/box3d.rs":"f15962fa34ef4dec099ca7403651ac92d5be55eba7aee0300b1a2837643dcb86","src/homogen.rs":"5c14355182b4fb7c148fc65c1f63b25607019ae8d763e187d659925e2ca210a3","src/length.rs":"b1f44beb961b193bea814f5a15aee713cab97d076de13e51e294891fd7153f27","src/lib.rs":"d58eecf5847b37f68ac6604c5b5a16962756faf04f9af1f5293228486b120378","src/macros.rs":"3b475e84d00cceee6c7e96e9f2c97ba15d8dc7f4094efb82c5ed10bd60d86a64","src/nonempty.rs":"865d51dc1ae785ee2e6e94eb2ee935f29a86b9efa8daa322bca7992fa9ae70fc","src/num.rs":"4439479fad5729073e0bfe0b96b547672a237430d48e564519759b9550baa033","src/point.rs":"b0eeed9f99cdd81525dd32b4d76caff862447e129b29bf55d003a35425e93ab6","src/rect.rs":"8298e2b67c7aadd255a53d42a6e5b19968aa47fcff05f8c60f4073da0a808dfc","src/rigid.rs":"aab59591562938695e63487230504b2d94df6e3a7b7740069166c8499d4fa930","src/rotation.rs":"307b22df279f30e4ac4aa35a0d69fb7f9196bd553c06b7f519692655e1e353d3","src/scale.rs":"6a4c3da9444c72e967d5217bbe5442a8517448857cb32472f883d6da58b8f846","src/side_offsets.rs":"eaa52aa64f0fa041fbd5c1c9165a01614db6c37d4746a56c3294a388bd5e0616","src/size.rs":"b3478be99f4409d3083e7553f5906c8ac314beddb83cc87492415c02785b8311","src/transform2d.rs":"8a0b4f097c8e98408dfe709b3ef0e8530562a6e1b68f62d6cd86c906cc0bb7eb","src/transform3d.rs":"6a6d56b67fdb1b6d4bfd725959d6b95cf4fa5ffbc272ae9f1508a400a3a4b30e","src/translation.rs":"67afb126179e3cb5a2c1bd462a8f5c87630233a68f63ff6a2194dbd3b229d734","src/trig.rs":"97a263c4f178b0332501659ca8143f9f637a0755aca189dd31ac551bcd4cb73c","src/vector.rs":"ca39c30729f781dd5e64b5fea1516e676b6ab4fc57788895fa2ca5309ad73ec3"},"package":"2c4786521fec183792e755bf32cd0188e4e7628c6d0fcfd51426435b9081a106"}
{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"c4a674cb74720c00564b769ece718e999df001023762356400c943b89424a578","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/angle.rs":"e16bf0419d8dcfac421c097ce744d0b1ca0887c479e779124388d9da9b009c1c","src/approxeq.rs":"8ad9ab7336e1924b0543eb46f975367f4388a4dda91839b7cda7d21eec8991fb","src/approxord.rs":"f1b11ea7603b3dddb0002c7ded934816f5a8bb108e150028b49595b8e3382ac1","src/box2d.rs":"232dea6d2684851f190e7eca97a9ef956f2813ae1f1d18e500e036cf2d7fb0d4","src/box3d.rs":"1372dc7a0e610d07696ec275682b49a3b2b1c97bed50de6532862317793690d2","src/homogen.rs":"37c9bc61e557b155b4f7e0a002078f0d2fa6ed5b498cefb4742affb521f6ceb4","src/length.rs":"fadb8c272acbbd34fa4c531450f6aee5450408a186cc3ccdf2d1102ee9430545","src/lib.rs":"4a7eac719427b4a907c81da2d2294f1904421b7fd440cf9a211e1eb7b1918c8a","src/macros.rs":"3b475e84d00cceee6c7e96e9f2c97ba15d8dc7f4094efb82c5ed10bd60d86a64","src/nonempty.rs":"69d62da24751efe2e8af2bb26713633c7445dbbd02e82b8146bad602002792df","src/num.rs":"189286d1dc06df5d31430e161fe45fd4da4fc2b3df5059d88044b7b30b87f2b2","src/point.rs":"4c94c1265f5629753f0e5a4040aeb617583ca81d4c9e2652bfc6c22019b57458","src/rect.rs":"018c3d4f82c07257e1b369f6c877dcfe19a9a105577d88ba39b6f713978d4328","src/rigid.rs":"b2b9c17fb75cb2b748ee8c78fab85a30961cc1fa7c4cc794244284b1aaf9bd08","src/rotation.rs":"2f2e92febee5e76c4fe94bda560b2b31cdaaaf068d35cae0e4ec3831901a2f6c","src/scale.rs":"b1a26dbcce145149c13bd8541838fb33a5e1c919717153adc716857d3acf49c2","src/side_offsets.rs":"e0d95daf9dd4e4ceb709a369dcdea10aa0dbde17e059b6a3c6d05a256f134838","src/size.rs":"3c76c1e35163bdd9ba45847154ce3e0f8fd5c1bb8ac5686bb4e239e328766447","src/transform2d.rs":"505fb0380353bd11d718228822d46a71f6c8b02f7fc360ab14168e6a87604b60","src/transform3d.rs":"b4d4e427ce047c9dc8055ed0d8be2411a4eeb0874627bf5ca004d3aae8b2e752","src/translation.rs":"d01894715e99c314a475b9e6b94a60062cf13a75428932012360d11ab6b0fa8e","src/trig.rs":"ab09a8503d04ac1d0d6848d074ac18a22d324184e5bb186bbd4287c977894886","src/vector.rs":"94ad9104a0a540d3441105d7b2a37ec1eb368273f0b68534dec19ffaf313c4d7"},"package":"57d9ae79e19d69ffb5b47b0a744c4215c115dfed4039314c9ca1b8ddc6c333be"}

View File

@ -12,7 +12,7 @@
[package]
name = "euclid"
version = "0.20.0"
version = "0.20.8"
authors = ["The Servo Project Developers"]
description = "Geometry primitives"
documentation = "https://docs.rs/euclid/"
@ -25,14 +25,19 @@ version = "0.5.1"
optional = true
[dependencies.num-traits]
version = "0.2"
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 = []

244
third_party/rust/euclid/src/angle.rs vendored Normal file
View File

@ -0,0 +1,244 @@
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use num_traits::{Float, FloatConst, Zero};
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign};
use core::cmp::{Eq, PartialEq};
use core::hash::{Hash};
use trig::Trig;
#[cfg(feature = "serde")]
use serde;
/// An angle in radians
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Angle<T> {
pub radians: T,
}
impl<T> Angle<T> {
#[inline]
pub fn radians(radians: T) -> Self {
Angle { radians }
}
#[inline]
pub fn get(self) -> T {
self.radians
}
}
impl<T> Angle<T>
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<T> Angle<T>
where
T: Rem<Output = T> + Sub<Output = T> + Add<Output = T> + 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<T> Angle<T>
where
T: Float,
{
/// Returns (sin(self), cos(self)).
pub fn sin_cos(self) -> (T, T) {
self.radians.sin_cos()
}
}
impl<T> Angle<T>
where
T: Zero,
{
pub fn zero() -> Self {
Angle::radians(T::zero())
}
}
impl<T> Angle<T>
where
T: FloatConst + Add<Output = T>,
{
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<T: Add<T, Output = T>> Add for Angle<T> {
type Output = Angle<T>;
fn add(self, other: Angle<T>) -> Angle<T> {
Angle::radians(self.radians + other.radians)
}
}
impl<T: AddAssign<T>> AddAssign for Angle<T> {
fn add_assign(&mut self, other: Angle<T>) {
self.radians += other.radians;
}
}
impl<T: Sub<T, Output = T>> Sub<Angle<T>> for Angle<T> {
type Output = Angle<T>;
fn sub(self, other: Angle<T>) -> <Self as Sub>::Output {
Angle::radians(self.radians - other.radians)
}
}
impl<T: SubAssign<T>> SubAssign for Angle<T> {
fn sub_assign(&mut self, other: Angle<T>) {
self.radians -= other.radians;
}
}
impl<T: Div<T, Output = T>> Div<Angle<T>> for Angle<T> {
type Output = T;
#[inline]
fn div(self, other: Angle<T>) -> T {
self.radians / other.radians
}
}
impl<T: Div<T, Output = T>> Div<T> for Angle<T> {
type Output = Angle<T>;
#[inline]
fn div(self, factor: T) -> Angle<T> {
Angle::radians(self.radians / factor)
}
}
impl<T: DivAssign<T>> DivAssign<T> for Angle<T> {
fn div_assign(&mut self, factor: T) {
self.radians /= factor;
}
}
impl<T: Mul<T, Output = T>> Mul<T> for Angle<T> {
type Output = Angle<T>;
#[inline]
fn mul(self, factor: T) -> Angle<T> {
Angle::radians(self.radians * factor)
}
}
impl<T: MulAssign<T>> MulAssign<T> for Angle<T> {
fn mul_assign(&mut self, factor: T) {
self.radians *= factor;
}
}
impl<T: Neg<Output = T>> Neg for Angle<T> {
type Output = Self;
fn neg(self) -> Self {
Angle::radians(-self.radians)
}
}
#[test]
fn wrap_angles() {
use approxeq::ApproxEq;
use core::f32::consts::{FRAC_PI_2, PI};
assert!(Angle::radians(0.0).positive().radians.approx_eq(&0.0));
assert!(
Angle::radians(FRAC_PI_2)
.positive()
.radians
.approx_eq(&FRAC_PI_2)
);
assert!(
Angle::radians(-FRAC_PI_2)
.positive()
.radians
.approx_eq(&(3.0 * FRAC_PI_2))
);
assert!(
Angle::radians(3.0 * FRAC_PI_2)
.positive()
.radians
.approx_eq(&(3.0 * FRAC_PI_2))
);
assert!(
Angle::radians(5.0 * FRAC_PI_2)
.positive()
.radians
.approx_eq(&FRAC_PI_2)
);
assert!(Angle::radians(2.0 * PI).positive().radians.approx_eq(&0.0));
assert!(Angle::radians(-2.0 * PI).positive().radians.approx_eq(&0.0));
assert!(Angle::radians(PI).positive().radians.approx_eq(&PI));
assert!(Angle::radians(-PI).positive().radians.approx_eq(&PI));
assert!(
Angle::radians(FRAC_PI_2)
.signed()
.radians
.approx_eq(&FRAC_PI_2)
);
assert!(
Angle::radians(3.0 * FRAC_PI_2)
.signed()
.radians
.approx_eq(&-FRAC_PI_2)
);
assert!(
Angle::radians(5.0 * FRAC_PI_2)
.signed()
.radians
.approx_eq(&FRAC_PI_2)
);
assert!(Angle::radians(2.0 * PI).signed().radians.approx_eq(&0.0));
assert!(Angle::radians(-2.0 * PI).signed().radians.approx_eq(&0.0));
assert!(Angle::radians(-PI).signed().radians.approx_eq(&PI));
assert!(Angle::radians(PI).signed().radians.approx_eq(&PI));
}

View File

@ -9,26 +9,33 @@
/// Trait for testing approximate equality
pub trait ApproxEq<Eps> {
/// Default epsilon value
fn approx_epsilon() -> Eps;
fn approx_eq(&self, other: &Self) -> bool;
/// 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) => (
($ty:ty, $eps:expr) => {
impl ApproxEq<$ty> for $ty {
#[inline]
fn approx_epsilon() -> $ty { $eps }
#[inline]
fn approx_eq(&self, other: &$ty) -> bool {
self.approx_eq_eps(other, &$eps)
fn approx_epsilon() -> $ty {
$eps
}
#[inline]
fn approx_eq_eps(&self, other: &$ty, approx_epsilon: &$ty) -> bool {
(*self - *other).abs() < *approx_epsilon
num_traits::Float::abs(*self - *other) < *approx_epsilon
}
}
)
};
}
approx_eq!(f32, 1.0e-6);

View File

@ -7,8 +7,9 @@
// 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.
//! Utilities for testing approximate ordering - especially true for
//! floating point types, where NaN's cannot be ordered.
pub fn min<T: PartialOrd>(x: T, y: T) -> T {
if x <= y {
x

View File

@ -47,9 +47,9 @@ impl<T: Hash, U> Hash for Box2D<T, U> {
impl<T: Copy, U> Copy for Box2D<T, U> {}
impl<T: Copy, U> Clone for Box2D<T, U> {
impl<T: Clone, U> Clone for Box2D<T, U> {
fn clone(&self) -> Self {
*self
Self::new(self.min.clone(), self.max.clone())
}
}
@ -75,7 +75,8 @@ impl<T: fmt::Display, U> fmt::Display for Box2D<T, U> {
impl<T, U> Box2D<T, U> {
/// Constructor.
pub fn new(min: Point2D<T, U>, max: Point2D<T, U>) -> Self {
#[inline]
pub const fn new(min: Point2D<T, U>, max: Point2D<T, U>) -> Self {
Box2D {
min,
max,
@ -98,7 +99,7 @@ where
impl<T, U> Box2D<T, U>
where
T: Copy + PartialOrd,
T: PartialOrd,
{
/// Returns true if the box has a negative area.
///
@ -115,16 +116,7 @@ where
self.max.x <= self.min.x || self.max.y <= self.min.y
}
#[inline]
pub fn to_non_empty(&self) -> Option<NonEmpty<Self>> {
if self.is_empty_or_negative() {
return None;
}
Some(NonEmpty(*self))
}
/// Returns true if the two boxes intersect.
/// Returns `true` if the two boxes intersect.
#[inline]
pub fn intersects(&self, other: &Self) -> bool {
self.min.x < other.max.x
@ -133,6 +125,38 @@ where
&& 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<T, U>) -> 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<T, U> Box2D<T, U>
where
T: Copy + PartialOrd,
{
#[inline]
pub fn to_non_empty(&self) -> Option<NonEmpty<Self>> {
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.
@ -177,35 +201,6 @@ where
}
}
impl<T, U> Box2D<T, U>
where
T: Copy + PartialOrd + Zero,
{
/// 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<T, U>) -> bool {
self.min.x <= p.x && p.x < self.max.x
&& self.min.y <= p.y && p.y < self.max.y
}
}
impl<T, U> Box2D<T, U>
where
T: Copy + PartialOrd + Zero + Sub<T, Output = T>,
{
/// 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<T, U> Box2D<T, U>
where
T: Copy + Sub<T, Output = T>,
@ -215,6 +210,16 @@ where
(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<T, U> {
Rect {
@ -278,37 +283,25 @@ where
{
let mut points = points.into_iter();
// Need at least 2 different points for a valid box (ie: volume > 0).
let (mut min_x, mut min_y) = match points.next() {
Some(first) => (first.borrow().x, first.borrow().y),
None => return Box2D::zero(),
};
let (mut max_x, mut max_y) = (min_x, min_y);
{
let mut assign_min_max = |point: I::Item| {
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
}
};
match points.next() {
Some(second) => assign_min_max(second),
None => return Box2D::zero(),
for point in points {
let p = point.borrow();
if p.x < min_x {
min_x = p.x
}
for point in points {
assign_min_max(point);
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
}
}
@ -325,7 +318,8 @@ where
{
/// Linearly interpolate between this box and another box.
///
/// `t` is expected to be between zero and one.
/// When `t` is `One::one()`, returned value equals to `other`,
/// otherwise equals to `self`.
#[inline]
pub fn lerp(&self, other: Self, t: T) -> Self {
Self::new(
@ -393,7 +387,7 @@ where
impl<T, U> Box2D<T, U>
where
T: Copy + Zero,
T: Zero,
{
/// Constructor, setting all sides to zero.
pub fn zero() -> Self {
@ -456,34 +450,43 @@ where
}
}
impl<T, Unit> Box2D<T, Unit>
impl<T, U> Box2D<T, U>
where
T: Copy,
{
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> Box2D<T, UnknownUnit> {
Box2D::new(self.min.to_untyped(), self.max.to_untyped())
}
/// Tag a unitless value with units.
pub fn from_untyped(c: &Box2D<T, UnknownUnit>) -> Box2D<T, Unit> {
#[inline]
pub fn from_untyped(c: &Box2D<T, UnknownUnit>) -> Box2D<T, U> {
Box2D::new(
Point2D::from_untyped(c.min),
Point2D::from_untyped(c.max),
)
}
/// Cast the unit
#[inline]
pub fn cast_unit<V>(&self) -> Box2D<T, V> {
Box2D::new(self.min.cast_unit(), self.max.cast_unit())
}
}
impl<T0, Unit> Box2D<T0, Unit>
impl<T, U> Box2D<T, U>
where
T0: NumCast + Copy,
T: NumCast + Copy,
{
/// Cast from one numeric representation to another, preserving the units.
///
/// When casting from floating point to integer coordinates, the decimals are truncated
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using round(), round_in or round_out() before casting.
pub fn cast<T1: NumCast + Copy>(&self) -> Box2D<T1, Unit> {
#[inline]
pub fn cast<NewT: NumCast>(&self) -> Box2D<NewT, U> {
Box2D::new(
self.min.cast(),
self.max.cast(),
@ -495,7 +498,7 @@ where
/// 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<T1: NumCast + Copy>(&self) -> Option<Box2D<T1, Unit>> {
pub fn try_cast<NewT: NumCast>(&self) -> Option<Box2D<NewT, U>> {
match (self.min.try_cast(), self.max.try_cast()) {
(Some(a), Some(b)) => Some(Box2D::new(a, b)),
_ => None,
@ -546,14 +549,16 @@ where
}
// Convenience functions for common casts
impl<T: NumCast + Copy, Unit> Box2D<T, Unit> {
impl<T: NumCast + Copy, U> Box2D<T, U> {
/// Cast into an `f32` box.
pub fn to_f32(&self) -> Box2D<f32, Unit> {
#[inline]
pub fn to_f32(&self) -> Box2D<f32, U> {
self.cast()
}
/// Cast into an `f64` box.
pub fn to_f64(&self) -> Box2D<f64, Unit> {
#[inline]
pub fn to_f64(&self) -> Box2D<f64, U> {
self.cast()
}
@ -562,7 +567,8 @@ impl<T: NumCast + Copy, Unit> Box2D<T, Unit> {
/// 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.
pub fn to_usize(&self) -> Box2D<usize, Unit> {
#[inline]
pub fn to_usize(&self) -> Box2D<usize, U> {
self.cast()
}
@ -571,7 +577,8 @@ impl<T: NumCast + Copy, Unit> Box2D<T, Unit> {
/// 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.
pub fn to_u32(&self) -> Box2D<u32, Unit> {
#[inline]
pub fn to_u32(&self) -> Box2D<u32, U> {
self.cast()
}
@ -580,7 +587,8 @@ impl<T: NumCast + Copy, Unit> Box2D<T, Unit> {
/// 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.
pub fn to_i32(&self) -> Box2D<i32, Unit> {
#[inline]
pub fn to_i32(&self) -> Box2D<i32, U> {
self.cast()
}
@ -589,7 +597,8 @@ impl<T: NumCast + Copy, Unit> Box2D<T, Unit> {
/// 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.
pub fn to_i64(&self) -> Box2D<i64, Unit> {
#[inline]
pub fn to_i64(&self) -> Box2D<i64, U> {
self.cast()
}
}
@ -617,6 +626,13 @@ mod tests {
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));

View File

@ -10,7 +10,7 @@
use super::UnknownUnit;
use scale::Scale;
use num::*;
use point::Point3D;
use point::{Point3D, point3};
use vector::Vector3D;
use size::Size3D;
use approxord::{min, max};
@ -32,7 +32,7 @@ use core::ops::{Add, Div, Mul, Sub};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>")))]
pub struct Box3D<T, U> {
pub min: Point3D<T, U>,
pub min: Point3D<T, U>,
pub max: Point3D<T, U>,
}
@ -45,9 +45,9 @@ impl<T: Hash, U> Hash for Box3D<T, U> {
impl<T: Copy, U> Copy for Box3D<T, U> {}
impl<T: Copy, U> Clone for Box3D<T, U> {
impl<T: Clone, U> Clone for Box3D<T, U> {
fn clone(&self) -> Self {
*self
Self::new(self.min.clone(), self.max.clone())
}
}
@ -73,7 +73,8 @@ impl<T: fmt::Display, U> fmt::Display for Box3D<T, U> {
impl<T, U> Box3D<T, U> {
/// Constructor.
pub fn new(min: Point3D<T, U>, max: Point3D<T, U>) -> Self {
#[inline]
pub const fn new(min: Point3D<T, U>, max: Point3D<T, U>) -> Self {
Box3D {
min,
max,
@ -96,7 +97,7 @@ where
impl<T, U> Box3D<T, U>
where
T: Copy + PartialOrd,
T: PartialOrd,
{
/// Returns true if the box has a negative volume.
///
@ -113,15 +114,6 @@ where
self.max.x <= self.min.x || self.max.y <= self.min.y || self.max.z <= self.min.z
}
#[inline]
pub fn to_non_empty(&self) -> Option<NonEmpty<Self>> {
if self.is_empty_or_negative() {
return None;
}
Some(NonEmpty(*self))
}
#[inline]
pub fn intersects(&self, other: &Self) -> bool {
self.min.x < other.max.x
@ -132,6 +124,41 @@ where
&& 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<T, U>) -> 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<T, U> Box3D<T, U>
where
T: Copy + PartialOrd,
{
#[inline]
pub fn to_non_empty(&self) -> Option<NonEmpty<Self>> {
if self.is_empty_or_negative() {
return None;
}
Some(NonEmpty(*self))
}
#[inline]
pub fn try_intersection(&self, other: &Self) -> Option<NonEmpty<Self>> {
if !self.intersects(other) {
@ -155,7 +182,7 @@ where
);
Box3D::new(
intersection_min,
intersection_min,
intersection_max,
)
}
@ -176,37 +203,6 @@ where
}
}
impl<T, U> Box3D<T, U>
where
T: Copy + PartialOrd + Zero,
{
/// 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<T, U>) -> 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
}
}
impl<T, U> Box3D<T, U>
where
T: Copy + PartialOrd + Zero + Sub<T, Output = T>,
{
/// 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<T, U> Box3D<T, U>
where
T: Copy + Sub<T, Output = T>,
@ -219,6 +215,21 @@ where
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<T, U> Box3D<T, U>
@ -248,47 +259,38 @@ where
{
let mut points = points.into_iter();
// Need at least 2 different points for a valid box3d (ie: volume > 0).
let (mut min_x, mut min_y, mut min_z) = match points.next() {
Some(first) => (first.borrow().x, first.borrow().y, first.borrow().z),
None => return Box3D::zero(),
};
let (mut max_x, mut max_y, mut max_z) = (min_x, min_y, min_z);
{
let mut assign_min_max = |point: I::Item| {
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
}
};
match points.next() {
Some(second) => assign_min_max(second),
None => return Box3D::zero(),
for point in points {
let p = point.borrow();
if p.x < min_x {
min_x = p.x
}
for point in points {
assign_min_max(point);
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
}
}
Self::new(Point3D::new(min_x, min_y, min_z), Point3D::new(max_x, max_y, max_z))
Box3D {
min: point3(min_x, min_y, min_z),
max: point3(max_x, max_y, max_z),
}
}
}
@ -298,7 +300,8 @@ where
{
/// Linearly interpolate between this box3d and another box3d.
///
/// `t` is expected to be between zero and one.
/// When `t` is `One::one()`, returned value equals to `other`,
/// otherwise equals to `self`.
#[inline]
pub fn lerp(&self, other: Self, t: T) -> Self {
Self::new(
@ -320,7 +323,7 @@ where
impl<T, U> Box3D<T, U>
where
T: Copy + Clone + PartialOrd + Add<T, Output = T> + Sub<T, Output = T> + Zero,
T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T> + Zero,
{
#[inline]
pub fn union(&self, other: &Self) -> Self {
@ -384,9 +387,9 @@ where
}
}
impl<T, U> Box3D<T, U>
impl<T, U> Box3D<T, U>
where
T: Copy + Zero,
T: Zero,
{
/// Constructor, setting all sides to zero.
pub fn zero() -> Self {
@ -449,7 +452,7 @@ where
}
}
impl<T, Unit> Box3D<T, Unit>
impl<T, U> Box3D<T, U>
where
T: Copy,
{
@ -464,24 +467,31 @@ where
/// Tag a unitless value with units.
#[inline]
pub fn from_untyped(c: &Box3D<T, UnknownUnit>) -> Box3D<T, Unit> {
pub fn from_untyped(c: &Box3D<T, UnknownUnit>) -> Box3D<T, U> {
Box3D {
min: Point3D::from_untyped(c.min),
max: Point3D::from_untyped(c.max),
}
}
/// Cast the unit
#[inline]
pub fn cast_unit<V>(&self) -> Box3D<T, V> {
Box3D::new(self.min.cast_unit(), self.max.cast_unit())
}
}
impl<T0, Unit> Box3D<T0, Unit>
impl<T, U> Box3D<T, U>
where
T0: NumCast + Copy,
T: NumCast + Copy,
{
/// Cast from one numeric representation to another, preserving the units.
///
/// When casting from floating point to integer coordinates, the decimals are truncated
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using round(), round_in or round_out() before casting.
pub fn cast<T1: NumCast + Copy>(&self) -> Box3D<T1, Unit> {
#[inline]
pub fn cast<NewT: NumCast>(&self) -> Box3D<NewT, U> {
Box3D::new(
self.min.cast(),
self.max.cast(),
@ -493,7 +503,7 @@ where
/// 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<T1: NumCast + Copy>(&self) -> Option<Box3D<T1, Unit>> {
pub fn try_cast<NewT: NumCast>(&self) -> Option<Box3D<NewT, U>> {
match (self.min.try_cast(), self.max.try_cast()) {
(Some(a), Some(b)) => Some(Box3D::new(a, b)),
_ => None,
@ -546,14 +556,16 @@ where
}
// Convenience functions for common casts
impl<T: NumCast + Copy, Unit> Box3D<T, Unit> {
impl<T: NumCast + Copy, U> Box3D<T, U> {
/// Cast into an `f32` box3d.
pub fn to_f32(&self) -> Box3D<f32, Unit> {
#[inline]
pub fn to_f32(&self) -> Box3D<f32, U> {
self.cast()
}
/// Cast into an `f64` box3d.
pub fn to_f64(&self) -> Box3D<f64, Unit> {
#[inline]
pub fn to_f64(&self) -> Box3D<f64, U> {
self.cast()
}
@ -562,7 +574,8 @@ impl<T: NumCast + Copy, Unit> Box3D<T, Unit> {
/// 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.
pub fn to_usize(&self) -> Box3D<usize, Unit> {
#[inline]
pub fn to_usize(&self) -> Box3D<usize, U> {
self.cast()
}
@ -571,7 +584,8 @@ impl<T: NumCast + Copy, Unit> Box3D<T, Unit> {
/// 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.
pub fn to_u32(&self) -> Box3D<u32, Unit> {
#[inline]
pub fn to_u32(&self) -> Box3D<u32, U> {
self.cast()
}
@ -580,7 +594,8 @@ impl<T: NumCast + Copy, Unit> Box3D<T, Unit> {
/// 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.
pub fn to_i32(&self) -> Box3D<i32, Unit> {
#[inline]
pub fn to_i32(&self) -> Box3D<i32, U> {
self.cast()
}
@ -589,13 +604,14 @@ impl<T: NumCast + Copy, Unit> Box3D<T, Unit> {
/// 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.
pub fn to_i64(&self) -> Box3D<i64, Unit> {
#[inline]
pub fn to_i64(&self) -> Box3D<i64, U> {
self.cast()
}
}
impl<T, U> From<Size3D<T, U>> for Box3D<T, U>
where
where
T: Copy + Zero + PartialOrd,
{
fn from(b: Size3D<T, U>) -> Self {
@ -632,6 +648,14 @@ mod tests {
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));
@ -770,7 +794,7 @@ mod tests {
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());

View File

@ -53,7 +53,7 @@ impl<'de, T, U> serde::Deserialize<'de> for HomogeneousVector<T, U>
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: serde::Deserializer<'de>
{
let (x, y, z, w) = try!(serde::Deserialize::deserialize(deserializer));
let (x, y, z, w) = serde::Deserialize::deserialize(deserializer)?;
Ok(HomogeneousVector { x, y, z, w, _unit: PhantomData })
}
}
@ -93,7 +93,7 @@ impl<T, U> Hash for HomogeneousVector<T, U>
impl<T, U> HomogeneousVector<T, U> {
/// Constructor taking scalar values directly.
#[inline]
pub fn new(x: T, y: T, z: T, w: T) -> Self {
pub const fn new(x: T, y: T, z: T, w: T) -> Self {
HomogeneousVector { x, y, z, w, _unit: PhantomData }
}
}

View File

@ -18,6 +18,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
use core::cmp::Ordering;
use core::ops::{Add, Div, Mul, Neg, Sub};
use core::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
use core::fmt;
@ -37,16 +38,16 @@ use core::fmt;
#[repr(C)]
pub struct Length<T, Unit>(pub T, #[doc(hidden)] pub PhantomData<Unit>);
impl<T: Clone, Unit> Clone for Length<T, Unit> {
impl<T: Clone, U> Clone for Length<T, U> {
fn clone(&self) -> Self {
Length(self.0.clone(), PhantomData)
}
}
impl<T: Copy, Unit> Copy for Length<T, Unit> {}
impl<T: Copy, U> Copy for Length<T, U> {}
#[cfg(feature = "serde")]
impl<'de, Unit, T> Deserialize<'de> for Length<T, Unit>
impl<'de, T, U> Deserialize<'de> for Length<T, U>
where
T: Deserialize<'de>,
{
@ -55,14 +56,14 @@ where
D: Deserializer<'de>,
{
Ok(Length(
try!(Deserialize::deserialize(deserializer)),
Deserialize::deserialize(deserializer)?,
PhantomData,
))
}
}
#[cfg(feature = "serde")]
impl<T, Unit> Serialize for Length<T, Unit>
impl<T, U> Serialize for Length<T, U>
where
T: Serialize,
{
@ -74,86 +75,108 @@ where
}
}
impl<T, Unit> Length<T, Unit> {
pub fn new(x: T) -> Self {
impl<T, U> Length<T, U> {
#[inline]
pub const fn new(x: T) -> Self {
Length(x, PhantomData)
}
}
impl<Unit, T: Clone> Length<T, Unit> {
impl<T: Clone, U> Length<T, U> {
pub fn get(&self) -> T {
self.0.clone()
}
}
impl<T: fmt::Debug + Clone, U> fmt::Debug for Length<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.get().fmt(f)
/// Cast the unit
#[inline]
pub fn cast_unit<V>(&self) -> Length<T, V> {
Length::new(self.0.clone())
}
}
impl<T: fmt::Display + Clone, U> fmt::Display for Length<T, U> {
impl<T: fmt::Debug, U> fmt::Debug for Length<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.get().fmt(f)
self.0.fmt(f)
}
}
impl<T: fmt::Display, U> fmt::Display for Length<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T: Default, U> Default for Length<T, U> {
#[inline]
fn default() -> Self {
Length::new(Default::default())
}
}
impl<T, U> Hash for Length<T, U>
where T: Hash
{
fn hash<H: Hasher>(&self, h: &mut H) {
self.0.hash(h);
}
}
// length + length
impl<U, T: Clone + Add<T, Output = T>> Add for Length<T, U> {
impl<U, T: Add<T, Output = T>> Add for Length<T, U> {
type Output = Length<T, U>;
fn add(self, other: Length<T, U>) -> Length<T, U> {
Length::new(self.get() + other.get())
Length::new(self.0 + other.0)
}
}
// length += length
impl<U, T: Clone + AddAssign<T>> AddAssign for Length<T, U> {
impl<U, T: AddAssign<T>> AddAssign for Length<T, U> {
fn add_assign(&mut self, other: Length<T, U>) {
self.0 += other.get();
self.0 += other.0;
}
}
// length - length
impl<U, T: Clone + Sub<T, Output = T>> Sub<Length<T, U>> for Length<T, U> {
impl<U, T: Sub<T, Output = T>> Sub<Length<T, U>> for Length<T, U> {
type Output = Length<T, U>;
fn sub(self, other: Length<T, U>) -> <Self as Sub>::Output {
Length::new(self.get() - other.get())
Length::new(self.0 - other.0)
}
}
// length -= length
impl<U, T: Clone + SubAssign<T>> SubAssign for Length<T, U> {
impl<U, T: SubAssign<T>> SubAssign for Length<T, U> {
fn sub_assign(&mut self, other: Length<T, U>) {
self.0 -= other.get();
self.0 -= other.0;
}
}
// Saturating length + length and length - length.
impl<U, T: Clone + Saturating> Saturating for Length<T, U> {
impl<U, T: Saturating> Saturating for Length<T, U> {
fn saturating_add(self, other: Length<T, U>) -> Length<T, U> {
Length::new(self.get().saturating_add(other.get()))
Length::new(self.0.saturating_add(other.0))
}
fn saturating_sub(self, other: Length<T, U>) -> Length<T, U> {
Length::new(self.get().saturating_sub(other.get()))
Length::new(self.0.saturating_sub(other.0))
}
}
// length / length
impl<Src, Dst, T: Clone + Div<T, Output = T>> Div<Length<T, Src>> for Length<T, Dst> {
impl<Src, Dst, T: Div<T, Output = T>> Div<Length<T, Src>> for Length<T, Dst> {
type Output = Scale<T, Src, Dst>;
#[inline]
fn div(self, other: Length<T, Src>) -> Scale<T, Src, Dst> {
Scale::new(self.get() / other.get())
Scale::new(self.0 / other.0)
}
}
// length * scalar
impl<T: Copy + Mul<T, Output = T>, U> Mul<T> for Length<T, U> {
impl<T: Mul<T, Output = T>, U> Mul<T> for Length<T, U> {
type Output = Self;
#[inline]
fn mul(self, scale: T) -> Self {
Length::new(self.get() * scale)
Length::new(self.0 * scale)
}
}
@ -166,11 +189,11 @@ impl<T: Copy + Mul<T, Output = T>, U> MulAssign<T> for Length<T, U> {
}
// length / scalar
impl<T: Copy + Div<T, Output = T>, U> Div<T> for Length<T, U> {
impl<T: Div<T, Output = T>, U> Div<T> for Length<T, U> {
type Output = Self;
#[inline]
fn div(self, scale: T) -> Self {
Length::new(self.get() / scale)
Length::new(self.0 / scale)
}
}
@ -183,65 +206,67 @@ impl<T: Copy + Div<T, Output = T>, U> DivAssign<T> for Length<T, U> {
}
// length * scaleFactor
impl<Src, Dst, T: Clone + Mul<T, Output = T>> Mul<Scale<T, Src, Dst>> for Length<T, Src> {
impl<Src, Dst, T: Mul<T, Output = T>> Mul<Scale<T, Src, Dst>> for Length<T, Src> {
type Output = Length<T, Dst>;
#[inline]
fn mul(self, scale: Scale<T, Src, Dst>) -> Length<T, Dst> {
Length::new(self.get() * scale.get())
Length::new(self.0 * scale.0)
}
}
// length / scaleFactor
impl<Src, Dst, T: Clone + Div<T, Output = T>> Div<Scale<T, Src, Dst>> for Length<T, Dst> {
impl<Src, Dst, T: Div<T, Output = T>> Div<Scale<T, Src, Dst>> for Length<T, Dst> {
type Output = Length<T, Src>;
#[inline]
fn div(self, scale: Scale<T, Src, Dst>) -> Length<T, Src> {
Length::new(self.get() / scale.get())
Length::new(self.0 / scale.0)
}
}
// -length
impl<U, T: Clone + Neg<Output = T>> Neg for Length<T, U> {
impl<U, T: Neg<Output = T>> Neg for Length<T, U> {
type Output = Length<T, U>;
#[inline]
fn neg(self) -> Length<T, U> {
Length::new(-self.get())
Length::new(-self.0)
}
}
impl<Unit, T0: NumCast + Clone> Length<T0, Unit> {
impl<T: NumCast + Clone, U> Length<T, U> {
/// Cast from one numeric representation to another, preserving the units.
pub fn cast<T1: NumCast + Clone>(&self) -> Length<T1, Unit> {
#[inline]
pub fn cast<NewT: NumCast>(&self) -> Length<NewT, U> {
self.try_cast().unwrap()
}
/// Fallible cast from one numeric representation to another, preserving the units.
pub fn try_cast<T1: NumCast + Clone>(&self) -> Option<Length<T1, Unit>> {
pub fn try_cast<NewT: NumCast>(&self) -> Option<Length<NewT, U>> {
NumCast::from(self.get()).map(Length::new)
}
}
impl<Unit, T: Clone + PartialEq> PartialEq for Length<T, Unit> {
impl<T: PartialEq, U> PartialEq for Length<T, U> {
fn eq(&self, other: &Self) -> bool {
self.get().eq(&other.get())
self.0.eq(&other.0)
}
}
impl<Unit, T: Clone + PartialOrd> PartialOrd for Length<T, Unit> {
impl<T: PartialOrd, U> PartialOrd for Length<T, U> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.get().partial_cmp(&other.get())
self.0.partial_cmp(&other.0)
}
}
impl<Unit, T: Clone + Eq> Eq for Length<T, Unit> {}
impl<T: Eq, U> Eq for Length<T, U> {}
impl<Unit, T: Clone + Ord> Ord for Length<T, Unit> {
impl<T: Ord, U> Ord for Length<T, U> {
fn cmp(&self, other: &Self) -> Ordering {
self.get().cmp(&other.get())
self.0.cmp(&other.0)
}
}
impl<Unit, T: Zero> Zero for Length<T, Unit> {
impl<T: Zero, U> Zero for Length<T, U> {
#[inline]
fn zero() -> Self {
Length::new(Zero::zero())
}
@ -253,7 +278,8 @@ where
{
/// Linearly interpolate between this length and another length.
///
/// `t` is expected to be between zero and one.
/// When `t` is `One::one()`, returned value equals to `other`,
/// otherwise equals to `self`.
#[inline]
pub fn lerp(&self, other: Self, t: T) -> Self {
let one_t = T::one() - t;

View File

@ -18,9 +18,9 @@
//! 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
//! This unit system is not mandatory and all structures have an alias
//! with the default unit: `UnknownUnit`.
//! for example ```Point2D<T>``` is equivalent to ```Point2D<T, UnknownUnit>```.
//! for example ```default::Point2D<T>``` is equivalent to ```Point2D<T, UnknownUnit>```.
//! Client code typically creates a set of aliases for each type and doesn't need
//! to deal with the specifics of typed units further. For example:
//!
@ -38,6 +38,7 @@
//! 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)]
#[cfg(feature = "serde")]
#[macro_use]
@ -49,6 +50,7 @@ extern crate num_traits;
#[cfg(test)]
use std as core;
pub use angle::Angle;
pub use box2d::Box2D;
pub use length::Length;
pub use scale::Scale;
@ -64,7 +66,7 @@ pub use rect::{rect, Rect};
pub use rigid::{RigidTransform3D};
pub use box3d::{box3d, Box3D};
pub use translation::{Translation2D, Translation3D};
pub use rotation::{Angle, Rotation2D, Rotation3D};
pub use rotation::{Rotation2D, Rotation3D};
pub use side_offsets::SideOffsets2D;
pub use size::{Size2D, Size3D, size2, size3};
pub use trig::Trig;
@ -72,6 +74,7 @@ pub use trig::Trig;
#[macro_use]
mod macros;
mod angle;
pub mod approxeq;
pub mod approxord;
mod box2d;
@ -98,7 +101,10 @@ mod nonempty;
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<T> = super::Length<T, UnknownUnit>;
pub type Point2D<T> = super::Point2D<T, UnknownUnit>;
pub type Point3D<T> = super::Point3D<T, UnknownUnit>;
pub type Vector2D<T> = super::Vector2D<T, UnknownUnit>;
@ -114,6 +120,7 @@ pub mod default {
pub type Transform3D<T> = super::Transform3D<T, UnknownUnit, UnknownUnit>;
pub type Rotation2D<T> = super::Rotation2D<T, UnknownUnit, UnknownUnit>;
pub type Rotation3D<T> = super::Rotation3D<T, UnknownUnit, UnknownUnit>;
pub type Translation2D<T> = super::Translation2D<T, UnknownUnit, UnknownUnit>;
pub type Translation3D<T> = super::Translation3D<T, UnknownUnit, UnknownUnit>;
pub type Scale<T> = super::Scale<T, UnknownUnit, UnknownUnit>;
pub type RigidTransform3D<T> = super::RigidTransform3D<T, UnknownUnit, UnknownUnit>;

View File

@ -1,6 +1,5 @@
use {Rect, Box2D, Box3D, Vector2D, Vector3D, size2, point2, point3};
use approxord::{min, max};
use num::Zero;
use core::ops::Deref;
use core::ops::{Add, Sub};
use core::cmp::{PartialEq};
@ -27,7 +26,7 @@ impl<T> NonEmpty<T> {
impl<T, U> NonEmpty<Rect<T, U>>
where
T: Copy + Clone + Zero + PartialOrd + PartialEq + Add<T, Output = T> + Sub<T, Output = T>,
T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
{
#[inline]
pub fn union(&self, other: &NonEmpty<Rect<T, U>>) -> NonEmpty<Rect<T, U>> {

View File

@ -30,47 +30,74 @@ impl<T: num_traits::One> One for T {
}
}
/// 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) => (
($ty:ty) => {
impl Round for $ty {
#[inline]
fn round(self) -> $ty { self }
fn round(self) -> $ty {
self
}
}
impl Floor for $ty {
#[inline]
fn floor(self) -> $ty { self }
fn floor(self) -> $ty {
self
}
}
impl Ceil for $ty {
#[inline]
fn ceil(self) -> $ty { self }
fn ceil(self) -> $ty {
self
}
}
)
};
}
macro_rules! num_float {
($ty:ty) => (
($ty:ty) => {
impl Round for $ty {
#[inline]
fn round(self) -> $ty { self.round() }
fn round(self) -> $ty {
num_traits::Float::round(self)
}
}
impl Floor for $ty {
#[inline]
fn floor(self) -> $ty { self.floor() }
fn floor(self) -> $ty {
num_traits::Float::floor(self)
}
}
impl Ceil for $ty {
#[inline]
fn ceil(self) -> $ty { self.ceil() }
fn ceil(self) -> $ty {
num_traits::Float::ceil(self)
}
}
)
};
}
num_int!(i16);

File diff suppressed because it is too large Load Diff

View File

@ -47,9 +47,9 @@ impl<T: Hash, U> Hash for Rect<T, U> {
impl<T: Copy, U> Copy for Rect<T, U> {}
impl<T: Copy, U> Clone for Rect<T, U> {
impl<T: Clone, U> Clone for Rect<T, U> {
fn clone(&self) -> Self {
*self
Self::new(self.origin.clone(), self.size.clone())
}
}
@ -81,7 +81,8 @@ impl<T: Default, U> Default for Rect<T, U> {
impl<T, U> Rect<T, U> {
/// Constructor.
pub fn new(origin: Point2D<T, U>, size: Size2D<T, U>) -> Self {
#[inline]
pub const fn new(origin: Point2D<T, U>, size: Size2D<T, U>) -> Self {
Rect {
origin,
size,
@ -91,9 +92,16 @@ impl<T, U> Rect<T, U> {
impl<T, U> Rect<T, U>
where
T: Copy + Zero
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<T, U>) -> Self {
Rect {
origin: Point2D::zero(),
@ -104,7 +112,7 @@ where
impl<T, U> Rect<T, U>
where
T: Copy + Clone + Zero + PartialOrd + PartialEq + Add<T, Output = T> + Sub<T, Output = T>,
T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
{
#[inline]
pub fn intersects(&self, other: &Self) -> bool {
@ -144,6 +152,16 @@ where
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<T> {
self.min_x()..self.max_x()
@ -189,16 +207,6 @@ where
&& self.origin.y <= other.y && other.y < self.origin.y + self.size.height
}
/// Returns true if this rectangle contains the interior of rect. Always
/// returns true if rect is empty, and always returns false if rect is
/// nonempty but this rectangle is empty.
#[inline]
pub fn contains_rect(&self, rect: &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())
}
#[inline]
#[must_use]
pub fn inflate(&self, width: T, height: T) -> Self {
@ -218,6 +226,21 @@ where
max: self.max(),
}
}
}
impl<T, U> Rect<T, U>
where
T: Copy + Zero + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
{
/// 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())
}
/// Calculate the size and position of an inner rectangle.
///
@ -307,7 +330,8 @@ where
{
/// Linearly interpolate between this rectangle and another rectangle.
///
/// `t` is expected to be between zero and one.
/// When `t` is `One::one()`, returned value equals to `other`,
/// otherwise equals to `self`.
#[inline]
pub fn lerp(&self, other: Self, t: T) -> Self {
Self::new(
@ -329,7 +353,7 @@ where
impl<T, U> Rect<T, U>
where
T: Copy + Clone + PartialOrd + Add<T, Output = T> + Sub<T, Output = T> + Zero,
T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T> + Zero,
{
#[inline]
pub fn union(&self, other: &Self) -> Self {
@ -359,7 +383,7 @@ impl<T, U> Rect<T, U> {
#[inline]
pub fn scale<S: Copy>(&self, x: S, y: S) -> Self
where
T: Copy + Clone + Mul<S, Output = T>,
T: Copy + Mul<S, Output = T>,
{
Rect::new(
Point2D::new(self.origin.x * x, self.origin.y * y),
@ -368,32 +392,29 @@ impl<T, U> Rect<T, U> {
}
}
impl<T: Copy + Clone + Mul<T, Output = T>, U> Rect<T, U> {
impl<T: Copy + Mul<T, Output = T>, U> Rect<T, U> {
#[inline]
pub fn area(&self) -> T {
self.size.area()
}
}
impl<T: Copy + PartialEq + Zero, U> Rect<T, U> {
/// Constructor, setting all sides to zero.
pub fn zero() -> Self {
Rect::new(Point2D::origin(), Size2D::zero())
}
impl<T: Zero + PartialEq, U> Rect<T, U> {
/// 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<T: Copy + Zero + PartialOrd, U> Rect<T, U> {
impl<T: Zero + PartialOrd, U> Rect<T, U> {
#[inline]
pub fn is_empty_or_negative(&self) -> bool {
self.size.is_empty_or_negative()
}
}
impl<T: Copy + Zero + PartialOrd, U> Rect<T, U> {
#[inline]
pub fn to_non_empty(&self) -> Option<NonEmpty<Self>> {
if self.is_empty_or_negative() {
@ -436,7 +457,7 @@ impl<T: Copy + Div<T, Output = T>, U1, U2> Div<Scale<T, U1, U2>> for Rect<T, U2>
}
}
impl<T: Copy, Unit> Rect<T, Unit> {
impl<T: Copy, U> Rect<T, U> {
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> Rect<T, UnknownUnit> {
@ -445,21 +466,28 @@ impl<T: Copy, Unit> Rect<T, Unit> {
/// Tag a unitless value with units.
#[inline]
pub fn from_untyped(r: &Rect<T, UnknownUnit>) -> Rect<T, Unit> {
pub fn from_untyped(r: &Rect<T, UnknownUnit>) -> Rect<T, U> {
Rect::new(
Point2D::from_untyped(r.origin),
Size2D::from_untyped(r.size),
)
}
/// Cast the unit
#[inline]
pub fn cast_unit<V>(&self) -> Rect<T, V> {
Rect::new(self.origin.cast_unit(), self.size.cast_unit())
}
}
impl<T0: NumCast + Copy, Unit> Rect<T0, Unit> {
impl<T: NumCast + Copy, U> Rect<T, U> {
/// Cast from one numeric representation to another, preserving the units.
///
/// When casting from floating point to integer coordinates, the decimals are truncated
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using round(), round_in or round_out() before casting.
pub fn cast<T1: NumCast + Copy>(&self) -> Rect<T1, Unit> {
#[inline]
pub fn cast<NewT: NumCast>(&self) -> Rect<NewT, U> {
Rect::new(
self.origin.cast(),
self.size.cast(),
@ -471,7 +499,7 @@ impl<T0: NumCast + Copy, Unit> Rect<T0, Unit> {
/// 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<T1: NumCast + Copy>(&self) -> Option<Rect<T1, Unit>> {
pub fn try_cast<NewT: NumCast>(&self) -> Option<Rect<NewT, U>> {
match (self.origin.try_cast(), self.size.try_cast()) {
(Some(origin), Some(size)) => Some(Rect::new(origin, size)),
_ => None,
@ -492,7 +520,7 @@ impl<T: Floor + Ceil + Round + Add<T, Output = T> + Sub<T, Output = T>, U> Rect<
#[must_use]
pub fn round(&self) -> Self {
let origin = self.origin.round();
let size = self.origin.add_size(&self.size).round() - origin;
let size = (self.origin + self.size).round() - origin;
Rect::new(origin, Size2D::new(size.x, size.y))
}
@ -501,7 +529,7 @@ impl<T: Floor + Ceil + Round + Add<T, Output = T> + Sub<T, Output = T>, U> Rect<
#[must_use]
pub fn round_in(&self) -> Self {
let origin = self.origin.ceil();
let size = self.origin.add_size(&self.size).floor() - origin;
let size = (self.origin + self.size).floor() - origin;
Rect::new(origin, Size2D::new(size.x, size.y))
}
@ -510,20 +538,22 @@ impl<T: Floor + Ceil + Round + Add<T, Output = T> + Sub<T, Output = T>, U> Rect<
#[must_use]
pub fn round_out(&self) -> Self {
let origin = self.origin.floor();
let size = self.origin.add_size(&self.size).ceil() - origin;
let size = (self.origin + self.size).ceil() - origin;
Rect::new(origin, Size2D::new(size.x, size.y))
}
}
// Convenience functions for common casts
impl<T: NumCast + Copy, Unit> Rect<T, Unit> {
impl<T: NumCast + Copy, U> Rect<T, U> {
/// Cast into an `f32` rectangle.
pub fn to_f32(&self) -> Rect<f32, Unit> {
#[inline]
pub fn to_f32(&self) -> Rect<f32, U> {
self.cast()
}
/// Cast into an `f64` rectangle.
pub fn to_f64(&self) -> Rect<f64, Unit> {
#[inline]
pub fn to_f64(&self) -> Rect<f64, U> {
self.cast()
}
@ -532,7 +562,8 @@ impl<T: NumCast + Copy, Unit> Rect<T, Unit> {
/// When casting from floating point rectangles, it is worth considering whether
/// to `round()`, `round_in()` or `round_out()` before the cast in order to
/// obtain the desired conversion behavior.
pub fn to_usize(&self) -> Rect<usize, Unit> {
#[inline]
pub fn to_usize(&self) -> Rect<usize, U> {
self.cast()
}
@ -541,7 +572,18 @@ impl<T: NumCast + Copy, Unit> Rect<T, Unit> {
/// When casting from floating point rectangles, it is worth considering whether
/// to `round()`, `round_in()` or `round_out()` before the cast in order to
/// obtain the desired conversion behavior.
pub fn to_u32(&self) -> Rect<u32, Unit> {
#[inline]
pub fn to_u32(&self) -> Rect<u32, U> {
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<u64, U> {
self.cast()
}
@ -550,7 +592,8 @@ impl<T: NumCast + Copy, Unit> Rect<T, Unit> {
/// When casting from floating point rectangles, it is worth considering whether
/// to `round()`, `round_in()` or `round_out()` before the cast in order to
/// obtain the desired conversion behavior.
pub fn to_i32(&self) -> Rect<i32, Unit> {
#[inline]
pub fn to_i32(&self) -> Rect<i32, U> {
self.cast()
}
@ -559,13 +602,14 @@ impl<T: NumCast + Copy, Unit> Rect<T, Unit> {
/// When casting from floating point rectangles, it is worth considering whether
/// to `round()`, `round_in()` or `round_out()` before the cast in order to
/// obtain the desired conversion behavior.
pub fn to_i64(&self) -> Rect<i64, Unit> {
#[inline]
pub fn to_i64(&self) -> Rect<i64, U> {
self.cast()
}
}
impl<T, U> From<Size2D<T, U>> for Rect<T, U>
where T: Copy + Zero
where T: Zero
{
fn from(size: Size2D<T, U>) -> Self {
Self::from_size(size)
@ -573,7 +617,7 @@ where T: Copy + Zero
}
/// Shorthand for `Rect::new(Point2D::new(x, y), Size2D::new(w, h))`.
pub fn rect<T: Copy, U>(x: T, y: T, w: T, h: T) -> Rect<T, U> {
pub const fn rect<T, U>(x: T, y: T, w: T, h: T) -> Rect<T, U> {
Rect::new(Point2D::new(x, y), Size2D::new(w, h))
}
@ -644,6 +688,22 @@ mod tests {
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));
@ -752,6 +812,13 @@ mod tests {
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());

View File

@ -1,7 +1,11 @@
//! 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 approxeq::ApproxEq;
use num_traits::Float;
use trig::Trig;
use {Rotation3D, Transform3D, Vector3D};
use {Rotation3D, Transform3D, Vector3D, UnknownUnit};
/// A rigid transformation. All lengths are preserved under such a transformation.
///
@ -19,20 +23,18 @@ pub struct RigidTransform3D<T, Src, Dst> {
pub translation: Vector3D<T, Dst>,
}
// All matrix multiplication in this file 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`
impl<T: Float + ApproxEq<T>, Src, Dst> RigidTransform3D<T, Src, Dst> {
impl<T, Src, Dst> RigidTransform3D<T, Src, Dst> {
/// Construct a new rigid transformation, where the `rotation` applies first
#[inline]
pub fn new(rotation: Rotation3D<T, Src, Dst>, translation: Vector3D<T, Dst>) -> Self {
pub const fn new(rotation: Rotation3D<T, Src, Dst>, translation: Vector3D<T, Dst>) -> Self {
Self {
rotation,
translation,
}
}
}
impl<T: Float + ApproxEq<T>, Src, Dst> RigidTransform3D<T, Src, Dst> {
/// Construct an identity transform
#[inline]
pub fn identity() -> Self {
@ -169,6 +171,24 @@ impl<T: Float + ApproxEq<T>, Src, Dst> RigidTransform3D<T, Src, Dst> {
.to_transform()
.pre_transform(&self.rotation.to_transform())
}
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> RigidTransform3D<T, UnknownUnit, UnknownUnit> {
RigidTransform3D {
rotation: self.rotation.to_untyped(),
translation: self.translation.to_untyped(),
}
}
/// Tag a unitless value with units.
#[inline]
pub fn from_untyped(transform: &RigidTransform3D<T, UnknownUnit, UnknownUnit>) -> Self {
RigidTransform3D {
rotation: Rotation3D::from_untyped(&transform.rotation),
translation: Vector3D::from_untyped(transform.translation),
}
}
}
impl<T: Float + ApproxEq<T>, Src, Dst> From<Rotation3D<T, Src, Dst>>

View File

@ -8,187 +8,18 @@
// except according to those terms.
use approxeq::ApproxEq;
use num_traits::{Float, FloatConst, One, Zero, NumCast};
use num_traits::{Float, One, Zero, NumCast};
use core::fmt;
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign};
use core::ops::{Add, Div, Mul, Neg, Sub};
use core::marker::PhantomData;
use core::cmp::{Eq, PartialEq};
use core::hash::{Hash};
use trig::Trig;
use {Point2D, Point3D, Vector2D, Vector3D, point2, point3, vec3};
use {Angle, Point2D, Point3D, Vector2D, Vector3D, point2, point3, vec3};
use {Transform2D, Transform3D, UnknownUnit};
#[cfg(feature = "serde")]
use serde;
/// An angle in radians
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Angle<T> {
pub radians: T,
}
impl<T> Angle<T> {
#[inline]
pub fn radians(radians: T) -> Self {
Angle { radians }
}
#[inline]
pub fn get(self) -> T {
self.radians
}
}
impl<T> Angle<T>
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<T> Angle<T>
where
T: Rem<Output = T> + Sub<Output = T> + Add<Output = T> + 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<T> Angle<T>
where
T: Float,
{
/// Returns (sin(self), cos(self)).
pub fn sin_cos(self) -> (T, T) {
self.radians.sin_cos()
}
}
impl<T> Angle<T>
where
T: Zero,
{
pub fn zero() -> Self {
Angle::radians(T::zero())
}
}
impl<T> Angle<T>
where
T: FloatConst + Add<Output = T>,
{
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<T: Clone + Add<T, Output = T>> Add for Angle<T> {
type Output = Angle<T>;
fn add(self, other: Angle<T>) -> Angle<T> {
Angle::radians(self.radians + other.radians)
}
}
impl<T: Clone + AddAssign<T>> AddAssign for Angle<T> {
fn add_assign(&mut self, other: Angle<T>) {
self.radians += other.radians;
}
}
impl<T: Clone + Sub<T, Output = T>> Sub<Angle<T>> for Angle<T> {
type Output = Angle<T>;
fn sub(self, other: Angle<T>) -> <Self as Sub>::Output {
Angle::radians(self.radians - other.radians)
}
}
impl<T: Clone + SubAssign<T>> SubAssign for Angle<T> {
fn sub_assign(&mut self, other: Angle<T>) {
self.radians -= other.radians;
}
}
impl<T: Clone + Div<T, Output = T>> Div<Angle<T>> for Angle<T> {
type Output = T;
#[inline]
fn div(self, other: Angle<T>) -> T {
self.radians / other.radians
}
}
impl<T: Clone + Div<T, Output = T>> Div<T> for Angle<T> {
type Output = Angle<T>;
#[inline]
fn div(self, factor: T) -> Angle<T> {
Angle::radians(self.radians / factor)
}
}
impl<T: Clone + DivAssign<T>> DivAssign<T> for Angle<T> {
fn div_assign(&mut self, factor: T) {
self.radians /= factor;
}
}
impl<T: Clone + Mul<T, Output = T>> Mul<T> for Angle<T> {
type Output = Angle<T>;
#[inline]
fn mul(self, factor: T) -> Angle<T> {
Angle::radians(self.radians * factor)
}
}
impl<T: Clone + MulAssign<T>> MulAssign<T> for Angle<T> {
fn mul_assign(&mut self, factor: T) {
self.radians *= factor;
}
}
impl<T: Neg<Output = T>> Neg for Angle<T> {
type Output = Self;
fn neg(self) -> Self {
Angle::radians(-self.radians)
}
}
/// A transform that can represent rotations in 2d, represented as an angle in radians.
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@ -264,9 +95,7 @@ where
impl<T, Src, Dst> Rotation2D<T, Src, Dst>
where
T: Copy
+ Clone
+ Add<T, Output = T>
T: Add<T, Output = T>
+ Sub<T, Output = T>
+ Mul<T, Output = T>
+ Div<T, Output = T>
@ -322,12 +151,29 @@ where
pub fn transform_vector(&self, vector: Vector2D<T, Src>) -> Vector2D<T, Dst> {
self.transform_point(vector.to_point()).to_vector()
}
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> Rotation2D<T, UnknownUnit, UnknownUnit> {
Rotation2D {
angle: self.angle,
_unit: PhantomData,
}
}
/// Tag a unitless value with units.
#[inline]
pub fn from_untyped(r: &Rotation2D<T, UnknownUnit, UnknownUnit>) -> Self {
Rotation2D {
angle: r.angle,
_unit: PhantomData,
}
}
}
impl<T, Src, Dst> Rotation2D<T, Src, Dst>
where
T: Copy
+ Clone
+ Add<T, Output = T>
+ Mul<T, Output = T>
+ Div<T, Output = T>
@ -590,7 +436,8 @@ where
/// Basic Linear interpolation between this rotation and another rotation.
///
/// `t` is expected to be between zero and one.
/// When `t` is `One::one()`, returned value equals to `other`,
/// otherwise equals to `self`.
#[inline]
pub fn lerp(&self, other: &Self, t: T) -> Self {
let one_t = T::one() - t;
@ -766,6 +613,30 @@ where
self.r * factor,
)
}
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> Rotation3D<T, UnknownUnit, UnknownUnit> {
Rotation3D {
i: self.i,
j: self.j,
k: self.k,
r: self.r,
_unit: PhantomData,
}
}
/// Tag a unitless value with units.
#[inline]
pub fn from_untyped(r: &Rotation3D<T, UnknownUnit, UnknownUnit>) -> Self {
Rotation3D {
i: r.i,
j: r.j,
k: r.k,
r: r.r,
_unit: PhantomData,
}
}
}
impl<T: fmt::Debug, Src, Dst> fmt::Debug for Rotation3D<T, Src, Dst> {
@ -796,10 +667,6 @@ where
T::approx_epsilon()
}
fn approx_eq(&self, other: &Self) -> bool {
self.approx_eq_eps(other, &Self::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))
@ -1081,61 +948,3 @@ fn from_euler() {
assert!(ypr_pe.approx_eq(&ypr_pq));
}
#[test]
fn wrap_angles() {
use core::f32::consts::{FRAC_PI_2, PI};
assert!(Angle::radians(0.0).positive().radians.approx_eq(&0.0));
assert!(
Angle::radians(FRAC_PI_2)
.positive()
.radians
.approx_eq(&FRAC_PI_2)
);
assert!(
Angle::radians(-FRAC_PI_2)
.positive()
.radians
.approx_eq(&(3.0 * FRAC_PI_2))
);
assert!(
Angle::radians(3.0 * FRAC_PI_2)
.positive()
.radians
.approx_eq(&(3.0 * FRAC_PI_2))
);
assert!(
Angle::radians(5.0 * FRAC_PI_2)
.positive()
.radians
.approx_eq(&FRAC_PI_2)
);
assert!(Angle::radians(2.0 * PI).positive().radians.approx_eq(&0.0));
assert!(Angle::radians(-2.0 * PI).positive().radians.approx_eq(&0.0));
assert!(Angle::radians(PI).positive().radians.approx_eq(&PI));
assert!(Angle::radians(-PI).positive().radians.approx_eq(&PI));
assert!(
Angle::radians(FRAC_PI_2)
.signed()
.radians
.approx_eq(&FRAC_PI_2)
);
assert!(
Angle::radians(3.0 * FRAC_PI_2)
.signed()
.radians
.approx_eq(&-FRAC_PI_2)
);
assert!(
Angle::radians(5.0 * FRAC_PI_2)
.signed()
.radians
.approx_eq(&FRAC_PI_2)
);
assert!(Angle::radians(2.0 * PI).signed().radians.approx_eq(&0.0));
assert!(Angle::radians(-2.0 * PI).signed().radians.approx_eq(&0.0));
assert!(Angle::radians(-PI).signed().radians.approx_eq(&PI));
assert!(Angle::radians(PI).signed().radians.approx_eq(&PI));
}

View File

@ -43,12 +43,14 @@ use {Point2D, Rect, Size2D, Vector2D};
pub struct Scale<T, Src, Dst>(pub T, #[doc(hidden)] pub PhantomData<(Src, Dst)>);
impl<T, Src, Dst> Scale<T, Src, Dst> {
pub fn new(x: T) -> Self {
#[inline]
pub const fn new(x: T) -> Self {
Scale(x, PhantomData)
}
}
impl<T: Clone, Src, Dst> Scale<T, Src, Dst> {
#[inline]
pub fn get(&self) -> T {
self.0.clone()
}
@ -61,6 +63,18 @@ impl<Src, Dst> Scale<f32, Src, Dst> {
impl<T: Clone + One + Div<T, Output = T>, Src, Dst> Scale<T, Src, Dst> {
/// The inverse Scale (1.0 / self).
///
/// # Example
///
/// ```rust
/// use euclid::Scale;
/// enum Mm {};
/// enum Cm {};
///
/// let cm_per_mm: Scale<f32, Cm, Mm> = Scale::new(0.1);
///
/// assert_eq!(cm_per_mm.inv(), Scale::new(10.0));
/// ```
pub fn inv(&self) -> Scale<T, Dst, Src> {
let one: T = One::one();
Scale::new(one / self.get())
@ -68,67 +82,160 @@ impl<T: Clone + One + Div<T, Output = T>, Src, Dst> Scale<T, Src, Dst> {
}
// scale0 * scale1
impl<T: Clone + Mul<T, Output = T>, A, B, C> Mul<Scale<T, B, C>> for Scale<T, A, B> {
impl<T: Mul<T, Output = T>, A, B, C> Mul<Scale<T, B, C>> for Scale<T, A, B> {
type Output = Scale<T, A, C>;
#[inline]
fn mul(self, other: Scale<T, B, C>) -> Scale<T, A, C> {
Scale::new(self.get() * other.get())
Scale::new(self.0 * other.0)
}
}
// scale0 + scale1
impl<T: Clone + Add<T, Output = T>, Src, Dst> Add for Scale<T, Src, Dst> {
impl<T: Add<T, Output = T>, Src, Dst> Add for Scale<T, Src, Dst> {
type Output = Scale<T, Src, Dst>;
#[inline]
fn add(self, other: Scale<T, Src, Dst>) -> Scale<T, Src, Dst> {
Scale::new(self.get() + other.get())
Scale::new(self.0 + other.0)
}
}
// scale0 - scale1
impl<T: Clone + Sub<T, Output = T>, Src, Dst> Sub for Scale<T, Src, Dst> {
impl<T: Sub<T, Output = T>, Src, Dst> Sub for Scale<T, Src, Dst> {
type Output = Scale<T, Src, Dst>;
#[inline]
fn sub(self, other: Scale<T, Src, Dst>) -> Scale<T, Src, Dst> {
Scale::new(self.get() - other.get())
Scale::new(self.0 - other.0)
}
}
impl<T: NumCast + Clone, Src, Dst0> Scale<T, Src, Dst0> {
impl<T: NumCast + Clone, Src, Dst> Scale<T, Src, Dst> {
/// Cast from one numeric representation to another, preserving the units.
pub fn cast<T1: NumCast + Clone>(&self) -> Scale<T1, Src, Dst0> {
///
/// # 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<i32, Cm, Mm> = Scale::new(10);
///
/// assert_eq!(to_mm.cast::<f32>(), 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<i32, Mm, Em> = Scale::new(10e20).cast();
/// ```
#[inline]
pub fn cast<NewT: NumCast>(&self) -> Scale<NewT, Src, Dst> {
self.try_cast().unwrap()
}
/// Fallible cast from one numeric representation to another, preserving the units.
pub fn try_cast<T1: NumCast + Clone>(&self) -> Option<Scale<T1, Src, Dst0>> {
/// 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<i32, Cm, Mm> = Scale::new(10);
/// let to_em: Scale<f32, Mm, Em> = Scale::new(10e20);
///
/// assert_eq!(to_mm.try_cast::<f32>(), Some(Scale::new(10.0)));
/// // Integer to small to store that number
/// assert_eq!(to_em.try_cast::<i32>(), None);
/// ```
pub fn try_cast<NewT: NumCast>(&self) -> Option<Scale<NewT, Src, Dst>> {
NumCast::from(self.get()).map(Scale::new)
}
}
impl<T, Src, Dst> Scale<T, Src, Dst>
where
T: Copy + Clone + Mul<T, Output = T> + Neg<Output = T> + PartialEq + One,
T: Copy + Mul<T, Output = T> + Neg<Output = T> + PartialEq + One,
{
/// Returns the given point transformed by this scale.
///
/// # Example
///
/// ```rust
/// use euclid::{Scale, point2};
/// enum Mm {};
/// enum Cm {};
///
/// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
///
/// assert_eq!(to_mm.transform_point(point2(42, -42)), point2(420, -420));
/// ```
#[inline]
pub fn transform_point(&self, point: Point2D<T, Src>) -> Point2D<T, Dst> {
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<i32, Cm, Mm> = Scale::new(10);
///
/// assert_eq!(to_mm.transform_vector(vec2(42, -42)), vec2(420, -420));
/// ```
#[inline]
pub fn transform_vector(&self, vec: Vector2D<T, Src>) -> Vector2D<T, Dst> {
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<i32, Cm, Mm> = Scale::new(10);
///
/// assert_eq!(to_mm.transform_size(size2(42, -42)), size2(420, -420));
/// ```
#[inline]
pub fn transform_size(&self, size: Size2D<T, Src>) -> Size2D<T, Dst> {
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<i32, Cm, Mm> = 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<T, Src>) -> Rect<T, Dst> {
Rect::new(
@ -143,15 +250,30 @@ where
Scale::new(-self.get())
}
/// Returns true if this scale has no effect.
/// 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<f32, Mm, Cm> = Scale::new(0.1);
/// let mm_per_mm: Scale<f32, Mm, Mm> = Scale::new(1.0);
///
/// assert_eq!(cm_per_mm.is_identity(), false);
/// assert_eq!(mm_per_mm.is_identity(), true);
/// ```
#[inline]
pub fn is_identity(&self) -> bool {
self.get() == T::one()
self.0 == T::one()
}
}
// FIXME: Switch to `derive(PartialEq, Clone)` after this Rust issue is fixed:
// https://github.com/mozilla/rust/issues/7671
// https://github.com/rust-lang/rust/issues/26925
impl<T: PartialEq, Src, Dst> PartialEq for Scale<T, Src, Dst> {
fn eq(&self, other: &Scale<T, Src, Dst>) -> bool {

View File

@ -13,14 +13,15 @@
use length::Length;
use num::Zero;
use core::fmt;
use core::ops::Add;
use core::ops::{Add, Neg};
use core::marker::PhantomData;
use core::cmp::{Eq, PartialEq};
use core::hash::{Hash};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::Vector2D;
/// A group of 2D side offsets, which correspond to top/left/bottom/right for borders, padding,
/// 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))]
@ -94,9 +95,12 @@ impl<T: Default, U> Default for SideOffsets2D<T, U> {
}
}
impl<T: Copy, U> SideOffsets2D<T, U> {
impl<T, U> SideOffsets2D<T, U> {
/// Constructor taking a scalar for each side.
pub fn new(top: T, right: T, bottom: T, left: T) -> Self {
///
/// 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,
@ -107,6 +111,9 @@ impl<T: Copy, U> SideOffsets2D<T, U> {
}
/// 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<T, U>,
right: Length<T, U>,
@ -116,6 +123,44 @@ impl<T: Copy, U> SideOffsets2D<T, U> {
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<T, U>, max: Vector2D<T,U>) -> Self
where
T: Neg<Output = T>
{
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<T, U>, max: Vector2D<T,U>) -> Self
where
T: Neg<Output = T>
{
SideOffsets2D {
left: min.x,
top: min.y,
right: -max.x,
bottom: -max.y,
_unit: PhantomData,
}
}
}
impl<T: Copy, U> SideOffsets2D<T, U> {
/// 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)
@ -142,7 +187,7 @@ where
impl<T, U> Add for SideOffsets2D<T, U>
where
T: Copy + Add<T, Output = T>,
T: Add<T, Output = T>,
{
type Output = Self;
fn add(self, other: Self) -> Self {
@ -155,9 +200,26 @@ where
}
}
impl<T: Copy + Zero, U> SideOffsets2D<T, U> {
impl<T: Zero, U> SideOffsets2D<T, U> {
/// Constructor, setting all sides to zero.
pub fn zero() -> Self {
SideOffsets2D::new(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero())
}
}
#[test]
fn from_vectors() {
use crate::{vec2, point2};
type Box2D = crate::default::Box2D<i32>;
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) });
}

View File

@ -8,6 +8,7 @@
// except according to those terms.
use super::UnknownUnit;
use approxord::{max, min};
#[cfg(feature = "mint")]
use mint;
use length::Length;
@ -16,7 +17,7 @@ use vector::{Vector2D, vec2, BoolVector2D};
use vector::{Vector3D, vec3, BoolVector3D};
use num::*;
use num_traits::{Float, NumCast, Signed};
use num_traits::{NumCast, Signed};
use core::fmt;
use core::ops::{Add, Div, Mul, Sub};
use core::marker::PhantomData;
@ -28,7 +29,9 @@ use serde;
/// A 2d size tagged with a unit.
#[repr(C)]
pub struct Size2D<T, U> {
/// 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<U>,
@ -50,10 +53,11 @@ impl<T: Clone, U> Clone for Size2D<T, U> {
impl<'de, T, U> serde::Deserialize<'de> for Size2D<T, U>
where T: serde::Deserialize<'de>
{
/// Deserializes 2d size from tuple of width and height.
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: serde::Deserializer<'de>
{
let (width, height) = try!(serde::Deserialize::deserialize(deserializer));
let (width, height) = serde::Deserialize::deserialize(deserializer)?;
Ok(Size2D { width, height, _unit: PhantomData })
}
}
@ -62,6 +66,7 @@ impl<'de, T, U> serde::Deserialize<'de> for Size2D<T, U>
impl<T, U> serde::Serialize for Size2D<T, U>
where T: serde::Serialize
{
/// Serializes 2d size to tuple of width and height.
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer
{
@ -108,19 +113,24 @@ impl<T: Default, U> Default for Size2D<T, U> {
impl<T, U> Size2D<T, U> {
/// Constructor taking scalar values.
pub fn new(width: T, height: T) -> Self {
#[inline]
pub const fn new(width: T, height: T) -> Self {
Size2D {
width,
height,
_unit: PhantomData,
}
}
}
impl<T: Clone, U> Size2D<T, U> {
/// Constructor taking scalar strongly typed lengths.
#[inline]
pub fn from_lengths(width: Length<T, U>, height: Length<T, U>) -> Self {
Size2D::new(width.get(), height.get())
Size2D::new(width.0, height.0)
}
/// Tag a unitless value with units.
#[inline]
pub fn from_untyped(p: Size2D<T, UnknownUnit>) -> Self {
Size2D::new(p.width, p.height)
}
}
@ -128,6 +138,7 @@ impl<T: Round, U> Size2D<T, U> {
/// Rounds each component to the nearest integer value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
#[inline]
pub fn round(&self) -> Self {
Size2D::new(self.width.round(), self.height.round())
}
@ -137,6 +148,7 @@ impl<T: Ceil, U> Size2D<T, U> {
/// Rounds each component to the smallest integer equal or greater than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
#[inline]
pub fn ceil(&self) -> Self {
Size2D::new(self.width.ceil(), self.height.ceil())
}
@ -146,26 +158,28 @@ impl<T: Floor, U> Size2D<T, U> {
/// Rounds each component to the biggest integer equal or lower than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
#[inline]
pub fn floor(&self) -> Self {
Size2D::new(self.width.floor(), self.height.floor())
}
}
impl<T: Copy + Add<T, Output = T>, U> Add for Size2D<T, U> {
impl<T: Add<T, Output = T>, U> Add for Size2D<T, U> {
type Output = Self;
fn add(self, other: Self) -> Self {
Size2D::new(self.width + other.width, self.height + other.height)
}
}
impl<T: Copy + Sub<T, Output = T>, U> Sub for Size2D<T, U> {
impl<T: Sub<T, Output = T>, U> Sub for Size2D<T, U> {
type Output = Self;
fn sub(self, other: Self) -> Self {
Size2D::new(self.width - other.width, self.height - other.height)
}
}
impl<T: Copy + Clone + Mul<T>, U> Size2D<T, U> {
impl<T: Copy + Mul<T>, U> Size2D<T, U> {
/// Returns result of multiplication of both components
pub fn area(&self) -> T::Output {
self.width * self.height
}
@ -175,9 +189,26 @@ impl<T, U> Size2D<T, U>
where
T: Copy + One + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
{
/// Linearly interpolate between this size and another size.
/// Linearly interpolate each component between this size and another size.
///
/// `t` is expected to be between zero and one.
/// When `t` is `One::one()`, returned value equals to `other`,
/// otherwise equals to `self`.
///
/// # Example
///
/// ```rust
/// use euclid::size2;
/// use euclid::default::Size2D;
///
/// let first: Size2D<_> = size2(0.0, 10.0);
/// let last: Size2D<_> = size2(8.0, -4.0);
///
/// assert_eq!(first.lerp(last, -1.0), size2(-8.0, 24.0));
/// assert_eq!(first.lerp(last, 0.0), size2( 0.0, 10.0));
/// assert_eq!(first.lerp(last, 0.5), size2( 4.0, 3.0));
/// assert_eq!(first.lerp(last, 1.0), size2( 8.0, -4.0));
/// assert_eq!(first.lerp(last, 2.0), size2(16.0, -18.0));
/// ```
#[inline]
pub fn lerp(&self, other: Self, t: T) -> Self {
let one_t = T::one() - t;
@ -189,6 +220,7 @@ where
}
impl<T: Zero + PartialOrd, U> Size2D<T, U> {
/// Returns `true` if any component of size is zero or negative.
pub fn is_empty_or_negative(&self) -> bool {
let zero = T::zero();
self.width <= zero || self.height <= zero
@ -196,12 +228,17 @@ impl<T: Zero + PartialOrd, U> Size2D<T, U> {
}
impl<T: Zero, U> Size2D<T, U> {
/// The same as [`Zero::zero()`] but available without importing trait.
///
/// [`Zero::zero()`]: ./num/trait.Zero.html#tymethod.zero
#[inline]
pub fn zero() -> Self {
Size2D::new(Zero::zero(), Zero::zero())
}
}
impl<T: Zero, U> Zero for Size2D<T, U> {
#[inline]
fn zero() -> Self {
Size2D::new(Zero::zero(), Zero::zero())
}
@ -240,40 +277,45 @@ impl<T: Copy + Div<T, Output = T>, U1, U2> Div<Scale<T, U1, U2>> for Size2D<T, U
}
impl<T: Copy, U> Size2D<T, U> {
/// Returns self.width as a Length carrying the unit.
/// 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<T, U> {
vec2(self.width, self.height)
}
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> Size2D<T, UnknownUnit> {
Size2D::new(self.width, self.height)
}
/// Tag a unitless value with units.
pub fn from_untyped(p: Size2D<T, UnknownUnit>) -> Self {
Size2D::new(p.width, p.height)
/// Cast the unit
#[inline]
pub fn cast_unit<V>(&self) -> Size2D<T, V> {
Size2D::new(self.width, self.height)
}
}
impl<T: NumCast + Copy, Unit> Size2D<T, Unit> {
impl<T: NumCast + Copy, U> Size2D<T, U> {
/// Cast from one numeric representation to another, preserving the units.
///
/// When casting from floating point to integer coordinates, the decimals are truncated
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
pub fn cast<NewT: NumCast + Copy>(&self) -> Size2D<NewT, Unit> {
#[inline]
pub fn cast<NewT: NumCast>(&self) -> Size2D<NewT, U> {
self.try_cast().unwrap()
}
@ -282,7 +324,7 @@ impl<T: NumCast + Copy, Unit> Size2D<T, Unit> {
/// 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<NewT: NumCast + Copy>(&self) -> Option<Size2D<NewT, Unit>> {
pub fn try_cast<NewT: NumCast>(&self) -> Option<Size2D<NewT, U>> {
match (NumCast::from(self.width), NumCast::from(self.height)) {
(Some(w), Some(h)) => Some(Size2D::new(w, h)),
_ => None,
@ -292,12 +334,14 @@ impl<T: NumCast + Copy, Unit> Size2D<T, Unit> {
// Convenience functions for common casts
/// Cast into an `f32` size.
pub fn to_f32(&self) -> Size2D<f32, Unit> {
#[inline]
pub fn to_f32(&self) -> Size2D<f32, U> {
self.cast()
}
/// Cast into an `f64` size.
pub fn to_f64(&self) -> Size2D<f64, Unit> {
#[inline]
pub fn to_f64(&self) -> Size2D<f64, U> {
self.cast()
}
@ -306,7 +350,8 @@ impl<T: NumCast + Copy, Unit> Size2D<T, Unit> {
/// When casting from floating point sizes, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_usize(&self) -> Size2D<usize, Unit> {
#[inline]
pub fn to_usize(&self) -> Size2D<usize, U> {
self.cast()
}
@ -315,7 +360,18 @@ impl<T: NumCast + Copy, Unit> Size2D<T, Unit> {
/// When casting from floating point sizes, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_u32(&self) -> Size2D<u32, Unit> {
#[inline]
pub fn to_u32(&self) -> Size2D<u32, U> {
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<u64, U> {
self.cast()
}
@ -324,7 +380,8 @@ impl<T: NumCast + Copy, Unit> Size2D<T, Unit> {
/// When casting from floating point sizes, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_i32(&self) -> Size2D<i32, Unit> {
#[inline]
pub fn to_i32(&self) -> Size2D<i32, U> {
self.cast()
}
@ -333,7 +390,8 @@ impl<T: NumCast + Copy, Unit> Size2D<T, Unit> {
/// When casting from floating point sizes, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_i64(&self) -> Size2D<i64, Unit> {
#[inline]
pub fn to_i64(&self) -> Size2D<i64, U> {
self.cast()
}
}
@ -342,16 +400,23 @@ impl<T, U> Size2D<T, U>
where
T: Signed,
{
/// 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<T: PartialOrd, U> Size2D<T, U> {
/// 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,
@ -359,6 +424,7 @@ impl<T: PartialOrd, U> Size2D<T, U> {
}
}
/// 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,
@ -369,6 +435,7 @@ impl<T: PartialOrd, U> Size2D<T, U> {
impl<T: PartialEq, U> Size2D<T, U> {
/// Returns vector with results of "equal" operation on each component.
pub fn equal(&self, other: Self) -> BoolVector2D {
BoolVector2D {
x: self.width == other.width,
@ -376,6 +443,7 @@ impl<T: PartialEq, U> Size2D<T, U> {
}
}
/// 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,
@ -384,37 +452,48 @@ impl<T: PartialEq, U> Size2D<T, U> {
}
}
impl<T: Float, U> Size2D<T, U> {
impl<T: PartialOrd, U> Size2D<T, U> {
/// Returns the size each component of which are minimum of this size and another.
#[inline]
pub fn min(self, other: Self) -> Self {
size2(
self.width.min(other.width),
self.height.min(other.height),
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(
self.width.max(other.width),
self.height.max(other.height),
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 {
pub fn clamp(&self, start: Self, end: Self) -> Self
where
T: Copy,
{
self.max(start).min(end)
}
}
/// Shorthand for `Size2D::new(w, h)`.
pub fn size2<T, U>(w: T, h: T) -> Size2D<T, U> {
#[inline]
pub const fn size2<T, U>(w: T, h: T) -> Size2D<T, U> {
Size2D::new(w, h)
}
#[cfg(feature = "mint")]
impl<T, U> From<mint::Vector2<T>> for Size2D<T, U> {
#[inline]
fn from(v: mint::Vector2<T>) -> Self {
Size2D {
width: v.x,
@ -425,6 +504,7 @@ impl<T, U> From<mint::Vector2<T>> for Size2D<T, U> {
}
#[cfg(feature = "mint")]
impl<T, U> Into<mint::Vector2<T>> for Size2D<T, U> {
#[inline]
fn into(self) -> mint::Vector2<T> {
mint::Vector2 {
x: self.width,
@ -434,6 +514,7 @@ impl<T, U> Into<mint::Vector2<T>> for Size2D<T, U> {
}
impl<T, U> From<Vector2D<T, U>> for Size2D<T, U> {
#[inline]
fn from(v: Vector2D<T, U>) -> Self {
Size2D {
width: v.x,
@ -443,25 +524,29 @@ impl<T, U> From<Vector2D<T, U>> for Size2D<T, U> {
}
}
impl<T: Copy, U> Into<[T; 2]> for Size2D<T, U> {
impl<T, U> Into<[T; 2]> for Size2D<T, U> {
#[inline]
fn into(self) -> [T; 2] {
self.to_array()
[self.width, self.height]
}
}
impl<T: Copy, U> From<[T; 2]> for Size2D<T, U> {
fn from(array: [T; 2]) -> Self {
size2(array[0], array[1])
impl<T, U> From<[T; 2]> for Size2D<T, U> {
#[inline]
fn from([w, h]: [T; 2]) -> Self {
size2(w, h)
}
}
impl<T: Copy, U> Into<(T, T)> for Size2D<T, U> {
impl<T, U> Into<(T, T)> for Size2D<T, U> {
#[inline]
fn into(self) -> (T, T) {
self.to_tuple()
(self.width, self.height)
}
}
impl<T: Copy, U> From<(T, T)> for Size2D<T, U> {
impl<T, U> From<(T, T)> for Size2D<T, U> {
#[inline]
fn from(tuple: (T, T)) -> Self {
size2(tuple.0, tuple.1)
}
@ -531,8 +616,11 @@ mod size2d {
/// A 3d size tagged with a unit.
#[repr(C)]
pub struct Size3D<T, U> {
/// 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<U>,
@ -558,7 +646,7 @@ impl<'de, T, U> serde::Deserialize<'de> for Size3D<T, U>
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: serde::Deserializer<'de>
{
let (width, height, depth) = try!(serde::Deserialize::deserialize(deserializer));
let (width, height, depth) = serde::Deserialize::deserialize(deserializer)?;
Ok(Size3D { width, height, depth, _unit: PhantomData })
}
}
@ -614,7 +702,8 @@ impl<T: Default, U> Default for Size3D<T, U> {
impl<T, U> Size3D<T, U> {
/// Constructor taking scalar values.
pub fn new(width: T, height: T, depth: T) -> Self {
#[inline]
pub const fn new(width: T, height: T, depth: T) -> Self {
Size3D {
width,
height,
@ -624,10 +713,11 @@ impl<T, U> Size3D<T, U> {
}
}
impl<T: Clone, U> Size3D<T, U> {
impl<T, U> Size3D<T, U> {
/// Constructor taking scalar strongly typed lengths.
#[inline]
pub fn from_lengths(width: Length<T, U>, height: Length<T, U>, depth: Length<T, U>) -> Self {
Size3D::new(width.get(), height.get(), depth.get())
Size3D::new(width.0, height.0, depth.0)
}
}
@ -635,6 +725,7 @@ impl<T: Round, U> Size3D<T, U> {
/// Rounds each component to the nearest integer value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
#[inline]
pub fn round(&self) -> Self {
Size3D::new(self.width.round(), self.height.round(), self.depth.round())
}
@ -644,6 +735,7 @@ impl<T: Ceil, U> Size3D<T, U> {
/// Rounds each component to the smallest integer equal or greater than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
#[inline]
pub fn ceil(&self) -> Self {
Size3D::new(self.width.ceil(), self.height.ceil(), self.depth.ceil())
}
@ -653,26 +745,30 @@ impl<T: Floor, U> Size3D<T, U> {
/// Rounds each component to the biggest integer equal or lower than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
#[inline]
pub fn floor(&self) -> Self {
Size3D::new(self.width.floor(), self.height.floor(), self.depth.floor())
}
}
impl<T: Copy + Add<T, Output = T>, U> Add for Size3D<T, U> {
impl<T: Add<T, Output = T>, U> Add for Size3D<T, U> {
type Output = Self;
#[inline]
fn add(self, other: Self) -> Self {
Size3D::new(self.width + other.width, self.height + other.height, self.depth + other.depth)
}
}
impl<T: Copy + Sub<T, Output = T>, U> Sub for Size3D<T, U> {
impl<T: Sub<T, Output = T>, U> Sub for Size3D<T, U> {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self {
Size3D::new(self.width - other.width, self.height - other.height, self.depth - other.depth)
}
}
impl<T: Copy + Clone + Mul<T, Output=T>, U> Size3D<T, U> {
impl<T: Copy + Mul<T, Output=T>, U> Size3D<T, U> {
/// Returns result of multiplication of all components
pub fn volume(&self) -> T {
self.width * self.height * self.depth
}
@ -684,7 +780,24 @@ where
{
/// Linearly interpolate between this size and another size.
///
/// `t` is expected to be between zero and one.
/// When `t` is `One::one()`, returned value equals to `other`,
/// otherwise equals to `self`.
///
/// # Example
///
/// ```rust
/// use euclid::size3;
/// use euclid::default::Size3D;
///
/// let first: Size3D<_> = size3(0.0, 10.0, -1.0);
/// let last: Size3D<_> = size3(8.0, -4.0, 0.0);
///
/// assert_eq!(first.lerp(last, -1.0), size3(-8.0, 24.0, -2.0));
/// assert_eq!(first.lerp(last, 0.0), size3( 0.0, 10.0, -1.0));
/// assert_eq!(first.lerp(last, 0.5), size3( 4.0, 3.0, -0.5));
/// assert_eq!(first.lerp(last, 1.0), size3( 8.0, -4.0, 0.0));
/// assert_eq!(first.lerp(last, 2.0), size3(16.0, -18.0, 1.0));
/// ```
#[inline]
pub fn lerp(&self, other: Self, t: T) -> Self {
let one_t = T::one() - t;
@ -697,6 +810,7 @@ where
}
impl<T: Zero + PartialOrd, U> Size3D<T, U> {
/// Returns `true` if any component of size is zero or negative.
pub fn is_empty_or_negative(&self) -> bool {
let zero = T::zero();
self.width <= zero || self.height <= zero || self.depth <= zero
@ -704,12 +818,17 @@ impl<T: Zero + PartialOrd, U> Size3D<T, U> {
}
impl<T: Zero, U> Size3D<T, U> {
/// The same as [`Zero::zero()`] but available without importing trait.
///
/// [`Zero::zero()`]: ./num/trait.Zero.html#tymethod.zero
#[inline]
pub fn zero() -> Self {
Size3D::new(Zero::zero(), Zero::zero(), Zero::zero())
}
}
impl<T: Zero, U> Zero for Size3D<T, U> {
#[inline]
fn zero() -> Self {
Size3D::new(Zero::zero(), Zero::zero(), Zero::zero())
}
@ -748,35 +867,51 @@ impl<T: Copy + Div<T, Output = T>, U1, U2> Div<Scale<T, U1, U2>> for Size3D<T, U
}
impl<T: Copy, U> Size3D<T, U> {
/// Returns self.width as a Length carrying the unit.
/// 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<T, U> {
vec3(self.width, self.height, self.depth)
}
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> Size3D<T, UnknownUnit> {
Size3D::new(self.width, self.height, self.depth)
}
/// Tag a unitless value with units.
#[inline]
pub fn from_untyped(p: Size3D<T, UnknownUnit>) -> Self {
Size3D::new(p.width, p.height, p.depth)
}
/// Cast the unit
#[inline]
pub fn cast_unit<V>(&self) -> Size3D<T, V> {
Size3D::new(self.width, self.height, self.depth)
}
}
impl<T: NumCast + Copy, Unit> Size3D<T, Unit> {
impl<T: NumCast + Copy, U> Size3D<T, U> {
/// Cast from one numeric representation to another, preserving the units.
///
/// When casting from floating point to integer coordinates, the decimals are truncated
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
pub fn cast<NewT: NumCast + Copy>(&self) -> Size3D<NewT, Unit> {
#[inline]
pub fn cast<NewT: NumCast + Copy>(&self) -> Size3D<NewT, U> {
self.try_cast().unwrap()
}
@ -785,7 +920,7 @@ impl<T: NumCast + Copy, Unit> Size3D<T, Unit> {
/// 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<NewT: NumCast + Copy>(&self) -> Option<Size3D<NewT, Unit>> {
pub fn try_cast<NewT: NumCast + Copy>(&self) -> Option<Size3D<NewT, U>> {
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,
@ -795,12 +930,14 @@ impl<T: NumCast + Copy, Unit> Size3D<T, Unit> {
// Convenience functions for common casts
/// Cast into an `f32` size.
pub fn to_f32(&self) -> Size3D<f32, Unit> {
#[inline]
pub fn to_f32(&self) -> Size3D<f32, U> {
self.cast()
}
/// Cast into an `f64` size.
pub fn to_f64(&self) -> Size3D<f64, Unit> {
#[inline]
pub fn to_f64(&self) -> Size3D<f64, U> {
self.cast()
}
@ -809,7 +946,8 @@ impl<T: NumCast + Copy, Unit> Size3D<T, Unit> {
/// When casting from floating point sizes, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_usize(&self) -> Size3D<usize, Unit> {
#[inline]
pub fn to_usize(&self) -> Size3D<usize, U> {
self.cast()
}
@ -818,7 +956,8 @@ impl<T: NumCast + Copy, Unit> Size3D<T, Unit> {
/// When casting from floating point sizes, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_u32(&self) -> Size3D<u32, Unit> {
#[inline]
pub fn to_u32(&self) -> Size3D<u32, U> {
self.cast()
}
@ -827,7 +966,8 @@ impl<T: NumCast + Copy, Unit> Size3D<T, Unit> {
/// When casting from floating point sizes, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_i32(&self) -> Size3D<i32, Unit> {
#[inline]
pub fn to_i32(&self) -> Size3D<i32, U> {
self.cast()
}
@ -836,7 +976,8 @@ impl<T: NumCast + Copy, Unit> Size3D<T, Unit> {
/// When casting from floating point sizes, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_i64(&self) -> Size3D<i64, Unit> {
#[inline]
pub fn to_i64(&self) -> Size3D<i64, U> {
self.cast()
}
}
@ -845,16 +986,23 @@ impl<T, U> Size3D<T, U>
where
T: Signed,
{
/// 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<T: PartialOrd, U> Size3D<T, U> {
/// 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,
@ -863,6 +1011,7 @@ impl<T: PartialOrd, U> Size3D<T, U> {
}
}
/// 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,
@ -874,6 +1023,7 @@ impl<T: PartialOrd, U> Size3D<T, U> {
impl<T: PartialEq, U> Size3D<T, U> {
/// Returns vector with results of "equal" operation on each component.
pub fn equal(&self, other: Self) -> BoolVector3D {
BoolVector3D {
x: self.width == other.width,
@ -882,6 +1032,7 @@ impl<T: PartialEq, U> Size3D<T, U> {
}
}
/// 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,
@ -891,39 +1042,50 @@ impl<T: PartialEq, U> Size3D<T, U> {
}
}
impl<T: Float, U> Size3D<T, U> {
impl<T: PartialOrd, U> Size3D<T, U> {
/// Returns the size each component of which are minimum of this size and another.
#[inline]
pub fn min(self, other: Self) -> Self {
size3(
self.width.min(other.width),
self.height.min(other.height),
self.depth.min(other.depth),
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(
self.width.max(other.width),
self.height.max(other.height),
self.depth.max(other.depth),
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 {
pub fn clamp(&self, start: Self, end: Self) -> Self
where
T: Copy,
{
self.max(start).min(end)
}
}
/// Shorthand for `Size3D::new(w, h, d)`.
pub fn size3<T, U>(w: T, h: T, d: T) -> Size3D<T, U> {
#[inline]
pub const fn size3<T, U>(w: T, h: T, d: T) -> Size3D<T, U> {
Size3D::new(w, h, d)
}
#[cfg(feature = "mint")]
impl<T, U> From<mint::Vector3<T>> for Size3D<T, U> {
#[inline]
fn from(v: mint::Vector3<T>) -> Self {
Size3D {
width: v.x,
@ -935,6 +1097,7 @@ impl<T, U> From<mint::Vector3<T>> for Size3D<T, U> {
}
#[cfg(feature = "mint")]
impl<T, U> Into<mint::Vector3<T>> for Size3D<T, U> {
#[inline]
fn into(self) -> mint::Vector3<T> {
mint::Vector3 {
x: self.width,

View File

@ -79,7 +79,7 @@ impl<'de, T, Src, Dst> serde::Deserialize<'de> for Transform2D<T, Src, Dst>
m11, m12,
m21, m22,
m31, m32,
) = try!(serde::Deserialize::deserialize(deserializer));
) = serde::Deserialize::deserialize(deserializer)?;
Ok(Transform2D {
m11, m12,
m21, m22,
@ -132,13 +132,13 @@ impl<T, Src, Dst> Hash for Transform2D<T, Src, Dst>
}
}
impl<T: Copy, Src, Dst> Transform2D<T, Src, Dst> {
impl<T, Src, Dst> Transform2D<T, Src, Dst> {
/// 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 fn row_major(m11: T, m12: T, m21: T, m22: T, m31: T, m32: T) -> Self {
pub const fn row_major(m11: T, m12: T, m21: T, m22: T, m31: T, m32: T) -> Self {
Transform2D {
m11, m12,
m21, m22,
@ -152,7 +152,7 @@ impl<T: Copy, Src, Dst> Transform2D<T, Src, Dst> {
/// 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 fn column_major(m11: T, m21: T, m31: T, m12: T, m22: T, m32: T) -> Self {
pub const fn column_major(m11: T, m21: T, m31: T, m12: T, m22: T, m32: T) -> Self {
Transform2D {
m11, m12,
m21, m22,
@ -161,12 +161,40 @@ impl<T: Copy, Src, Dst> Transform2D<T, Src, Dst> {
}
}
/// 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<T> {
<Self as ApproxEq<T>>::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<T> {
<Self as ApproxEq<T>>::approx_eq_eps(&self, &other, &eps)
}
}
impl<T: Copy, Src, Dst> Transform2D<T, Src, Dst> {
/// Returns an array containing this transform's terms in row-major order (the order
/// in which the transform is actually laid out in memory).
///
/// 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,
@ -180,6 +208,7 @@ impl<T: Copy, Src, Dst> Transform2D<T, Src, Dst> {
/// 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,
@ -195,6 +224,7 @@ impl<T: Copy, Src, Dst> Transform2D<T, Src, Dst> {
/// 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],
@ -208,6 +238,7 @@ impl<T: Copy, Src, Dst> Transform2D<T, Src, Dst> {
/// 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],
@ -221,6 +252,7 @@ impl<T: Copy, Src, Dst> Transform2D<T, Src, Dst> {
/// 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],
@ -230,6 +262,7 @@ impl<T: Copy, Src, Dst> Transform2D<T, Src, Dst> {
}
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> Transform2D<T, UnknownUnit, UnknownUnit> {
Transform2D::row_major(
self.m11, self.m12,
@ -239,6 +272,7 @@ impl<T: Copy, Src, Dst> Transform2D<T, Src, Dst> {
}
/// Tag a unitless value with units.
#[inline]
pub fn from_untyped(p: &Transform2D<T, UnknownUnit, UnknownUnit>) -> Self {
Transform2D::row_major(
p.m11, p.m12,
@ -248,14 +282,15 @@ impl<T: Copy, Src, Dst> Transform2D<T, Src, Dst> {
}
}
impl<T0: NumCast + Copy, Src, Dst> Transform2D<T0, Src, Dst> {
impl<T: NumCast + Copy, Src, Dst> Transform2D<T, Src, Dst> {
/// Cast from one numeric representation to another, preserving the units.
pub fn cast<T1: NumCast + Copy>(&self) -> Transform2D<T1, Src, Dst> {
#[inline]
pub fn cast<NewT: NumCast>(&self) -> Transform2D<NewT, Src, Dst> {
self.try_cast().unwrap()
}
/// Fallible cast from one numeric representation to another, preserving the units.
pub fn try_cast<T1: NumCast + Copy>(&self) -> Option<Transform2D<T1, Src, Dst>> {
pub fn try_cast<NewT: NumCast>(&self) -> Option<Transform2D<NewT, Src, Dst>> {
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)) {
@ -295,12 +330,11 @@ where T: Copy +
}
impl<T, Src, Dst> Transform2D<T, Src, Dst>
where T: Copy + Clone +
where T: Copy +
Add<T, Output=T> +
Mul<T, Output=T> +
Div<T, Output=T> +
Sub<T, Output=T> +
Trig +
PartialOrd +
One + Zero {
@ -377,39 +411,12 @@ where T: Copy + Clone +
#[must_use]
pub fn pre_scale(&self, x: T, y: T) -> Self {
Transform2D::row_major(
self.m11 * x, self.m12,
self.m21, self.m22 * y,
self.m11 * x, self.m12 * x,
self.m21 * y, self.m22 * y,
self.m31, self.m32
)
}
/// Returns a rotation transform.
#[inline]
pub fn create_rotation(theta: Angle<T>) -> 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<T>) -> 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<T>) -> Self {
self.pre_transform(&Transform2D::create_rotation(theta))
}
/// Returns the given point transformed by this transform.
///
/// Assuming row vectors, this is equivalent to `p * self`
@ -452,6 +459,12 @@ where T: Copy + Clone +
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<Transform2D<T, Dst, Src>> {
@ -496,8 +509,45 @@ where T: Copy + Clone +
}
}
impl<T, Src, Dst> Transform2D<T, Src, Dst>
where T: Copy +
Add<T, Output=T> +
Mul<T, Output=T> +
Div<T, Output=T> +
Sub<T, Output=T> +
Trig +
PartialOrd +
One + Zero {
/// Returns a rotation transform.
#[inline]
pub fn create_rotation(theta: Angle<T>) -> 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<T>) -> 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<T>) -> Self {
self.pre_transform(&Transform2D::create_rotation(theta))
}
}
impl <T, Src, Dst> Transform2D<T, Src, Dst>
where T: Copy + Clone +
where T: Copy +
Add<T, Output=T> +
Sub<T, Output=T> +
Mul<T, Output=T> +
@ -521,15 +571,20 @@ impl <T, Src, Dst> Default for Transform2D<T, Src, Dst>
}
}
impl<T: ApproxEq<T>, Src, Dst> Transform2D<T, Src, Dst> {
pub fn approx_eq(&self, other: &Self) -> bool {
self.m11.approx_eq(&other.m11) && self.m12.approx_eq(&other.m12) &&
self.m21.approx_eq(&other.m21) && self.m22.approx_eq(&other.m22) &&
self.m31.approx_eq(&other.m31) && self.m32.approx_eq(&other.m32)
impl<T: ApproxEq<T>, Src, Dst> ApproxEq<T> for Transform2D<T, Src, Dst> {
#[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<T: Copy + fmt::Debug, Src, Dst> fmt::Debug for Transform2D<T, Src, Dst>
impl<T, Src, Dst> fmt::Debug for Transform2D<T, Src, Dst>
where T: Copy + fmt::Debug +
PartialEq +
One + Zero {
@ -616,6 +671,15 @@ mod test {
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!(

View File

@ -93,7 +93,7 @@ impl<'de, T, Src, Dst> serde::Deserialize<'de> for Transform3D<T, Src, Dst>
m21, m22, m23, m24,
m31, m32, m33, m34,
m41, m42, m43, m44,
) = try!(serde::Deserialize::deserialize(deserializer));
) = serde::Deserialize::deserialize(deserializer)?;
Ok(Transform3D {
m11, m12, m13, m14,
m21, m22, m23, m24,
@ -179,7 +179,7 @@ impl<T, Src, Dst> Transform3D<T, Src, Dst> {
/// is `T * v`), then please use `column_major`
#[inline]
#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
pub fn row_major(
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,
@ -204,7 +204,7 @@ impl<T, Src, Dst> Transform3D<T, Src, Dst> {
/// is `T * v`), then please use `row_major`
#[inline]
#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
pub fn column_major(
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,
@ -221,7 +221,7 @@ impl<T, Src, Dst> Transform3D<T, Src, Dst> {
}
impl <T, Src, Dst> Transform3D<T, Src, Dst>
where T: Copy + Clone +
where T: Copy +
PartialEq +
One + Zero {
#[inline]
@ -245,7 +245,7 @@ where T: Copy + Clone +
}
impl <T, Src, Dst> Transform3D<T, Src, Dst>
where T: Copy + Clone +
where T: Copy +
Add<T, Output=T> +
Sub<T, Output=T> +
Mul<T, Output=T> +
@ -323,16 +323,28 @@ where T: Copy + Clone +
(m33 * det) < _0
}
/// 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<T> {
self.m11.approx_eq(&other.m11) && self.m12.approx_eq(&other.m12) &&
self.m13.approx_eq(&other.m13) && self.m14.approx_eq(&other.m14) &&
self.m21.approx_eq(&other.m21) && self.m22.approx_eq(&other.m22) &&
self.m23.approx_eq(&other.m23) && self.m24.approx_eq(&other.m24) &&
self.m31.approx_eq(&other.m31) && self.m32.approx_eq(&other.m32) &&
self.m33.approx_eq(&other.m33) && self.m34.approx_eq(&other.m34) &&
self.m41.approx_eq(&other.m41) && self.m42.approx_eq(&other.m42) &&
self.m43.approx_eq(&other.m43) && self.m44.approx_eq(&other.m44)
<Self as ApproxEq<T>>::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<T> {
<Self as ApproxEq<T>>::approx_eq_eps(&self, &other, &eps)
}
/// Returns the same transform with a different destination unit.
@ -415,6 +427,12 @@ where T: Copy + Clone +
mat.post_transform(self)
}
/// 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<Transform3D<T, Dst, Src>> {
let det = self.determinant();
@ -718,9 +736,9 @@ where T: Copy + Clone +
#[must_use]
pub fn pre_scale(&self, x: T, y: T, z: T) -> Self {
Transform3D::row_major(
self.m11 * x, self.m12, self.m13, self.m14,
self.m21 , self.m22 * y, self.m23, self.m24,
self.m31 , self.m32, self.m33 * z, self.m34,
self.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
)
}
@ -813,6 +831,7 @@ impl<T: Copy, Src, Dst> Transform3D<T, Src, Dst> {
/// 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,
@ -827,6 +846,7 @@ impl<T: Copy, Src, Dst> Transform3D<T, Src, Dst> {
/// 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,
@ -844,6 +864,7 @@ impl<T: Copy, Src, Dst> Transform3D<T, Src, Dst> {
/// 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],
@ -861,6 +882,7 @@ impl<T: Copy, Src, Dst> Transform3D<T, Src, Dst> {
/// 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],
@ -875,6 +897,7 @@ impl<T: Copy, Src, Dst> Transform3D<T, Src, Dst> {
/// 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],
@ -889,6 +912,7 @@ impl<T: Copy, Src, Dst> Transform3D<T, Src, Dst> {
/// 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],
@ -899,14 +923,15 @@ impl<T: Copy, Src, Dst> Transform3D<T, Src, Dst> {
}
}
impl<T0: NumCast + Copy, Src, Dst> Transform3D<T0, Src, Dst> {
impl<T: NumCast + Copy, Src, Dst> Transform3D<T, Src, Dst> {
/// Cast from one numeric representation to another, preserving the units.
pub fn cast<T1: NumCast + Copy>(&self) -> Transform3D<T1, Src, Dst> {
#[inline]
pub fn cast<NewT: NumCast>(&self) -> Transform3D<NewT, Src, Dst> {
self.try_cast().unwrap()
}
/// Fallible cast from one numeric representation to another, preserving the units.
pub fn try_cast<T1: NumCast + Copy>(&self) -> Option<Transform3D<T1, Src, Dst>> {
pub fn try_cast<NewT: NumCast>(&self) -> Option<Transform3D<NewT, Src, Dst>> {
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),
@ -929,6 +954,22 @@ impl<T0: NumCast + Copy, Src, Dst> Transform3D<T0, Src, Dst> {
}
}
impl<T: ApproxEq<T>, Src, Dst> ApproxEq<T> for Transform3D<T, Src, Dst> {
#[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 <T, Src, Dst> Default for Transform3D<T, Src, Dst>
where T: Copy + PartialEq + One + Zero
{
@ -1040,6 +1081,16 @@ mod tests {
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);

View File

@ -9,6 +9,7 @@
use {Vector2D, Point2D, Vector3D, Point3D, Transform2D, Transform3D};
use {Size2D, Rect, vec2, point2, vec3, point3};
use UnknownUnit;
use num::*;
use trig::Trig;
use core::ops::{Add, Sub, Neg, Mul, Div};
@ -82,38 +83,71 @@ impl<T, Src, Dst> Hash for Translation2D<T, Src, Dst>
impl<T, Src, Dst> Translation2D<T, Src, Dst> {
#[inline]
pub fn new(x: T, y: T) -> Self {
pub const fn new(x: T, y: T) -> Self {
Translation2D {
x,
y,
_unit: PhantomData,
}
}
/// No-op, just cast the unit.
#[inline]
pub fn transform_size(&self, s: Size2D<T, Src>) -> Size2D<T, Dst> {
Size2D::new(s.width, s.height)
}
}
impl<T, Src, Dst> Translation2D<T, Src, Dst>
where
T : Copy
{
/// Cast into a 2D vector.
#[inline]
pub fn to_vector(&self) -> Vector2D<T, Src> {
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<T, UnknownUnit, UnknownUnit> {
Translation2D {
x: self.x,
y: self.y,
_unit: PhantomData,
}
}
/// Tag a unitless value with units.
#[inline]
pub fn from_untyped(t: &Translation2D<T, UnknownUnit, UnknownUnit>) -> Self {
Translation2D {
x: t.x,
y: t.y,
_unit: PhantomData,
}
}
}
impl<T, Src, Dst> Translation2D<T, Src, Dst>
where
T : Copy + Zero
T: Zero
{
#[inline]
pub fn identity() -> Self {
let _0 = T::zero();
Translation2D::new(_0, _0)
Translation2D::new(T::zero(), T::zero())
}
}
@ -123,7 +157,8 @@ where
{
#[inline]
pub fn is_identity(&self) -> bool {
self.x == T::zero() && self.y == T::zero()
let _0 = T::zero();
self.x == _0 && self.y == _0
}
}
@ -145,17 +180,6 @@ where
size: self.transform_size(r.size),
}
}
/// No-op, just cast the unit.
#[inline]
pub fn transform_size(&self, s: Size2D<T, Src>) -> Size2D<T, Dst> {
Size2D::new(s.width, s.height)
}
/// Cast into a 2D vector.
pub fn to_vector(&self) -> Vector2D<T, Src> {
vec2(self.x, self.y)
}
}
impl<T, Src, Dst> Translation2D<T, Src, Dst>
@ -172,7 +196,7 @@ where
impl<T, Src, Dst1, Dst2> Add<Translation2D<T, Dst1, Dst2>>
for Translation2D<T, Src, Dst1>
where
T: Copy + Add<T, Output = T>
T: Add<T, Output = T>
{
type Output = Translation2D<T, Src, Dst2>;
fn add(self, other: Translation2D<T, Dst1, Dst2>) -> Translation2D<T, Src, Dst2> {
@ -187,7 +211,7 @@ impl<T, Src, Dst1, Dst2>
Sub<Translation2D<T, Dst1, Dst2>>
for Translation2D<T, Src, Dst2>
where
T: Copy + Sub<T, Output = T>
T: Sub<T, Output = T>
{
type Output = Translation2D<T, Src, Dst1>;
fn sub(self, other: Translation2D<T, Dst1, Dst2>) -> Translation2D<T, Src, Dst1> {
@ -201,7 +225,6 @@ where
impl<T, Src, Dst> Translation2D<T, Src, Dst>
where
T: Copy
+ Clone
+ Add<T, Output = T>
+ Mul<T, Output = T>
+ Div<T, Output = T>
@ -219,8 +242,6 @@ where
}
impl<T, Src, Dst> From<Vector2D<T, Src>> for Translation2D<T, Src, Dst>
where
T: Copy
{
fn from(v: Vector2D<T, Src>) -> Self {
Translation2D::new(v.x, v.y)
@ -228,8 +249,6 @@ where
}
impl<T, Src, Dst> Into<Vector2D<T, Src>> for Translation2D<T, Src, Dst>
where
T: Copy
{
fn into(self) -> Vector2D<T, Src> {
vec2(self.x, self.y)
@ -239,7 +258,6 @@ where
impl<T, Src, Dst> Into<Transform2D<T, Src, Dst>> for Translation2D<T, Src, Dst>
where
T: Copy
+ Clone
+ Add<T, Output = T>
+ Mul<T, Output = T>
+ Div<T, Output = T>
@ -255,20 +273,24 @@ where
}
impl <T, Src, Dst> Default for Translation2D<T, Src, Dst>
where T: Copy + Zero
where T: Zero
{
fn default() -> Self {
Self::identity()
}
}
impl<T, Src, Dst> fmt::Debug for Translation2D<T, Src, Dst>
where T: Copy + fmt::Debug {
impl<T: fmt::Debug, Src, Dst> fmt::Debug for Translation2D<T, Src, Dst> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_array().fmt(f)
write!(f, "Translation({:?},{:?})", self.x, self.y)
}
}
impl<T: fmt::Display, Src, Dst> fmt::Display for Translation2D<T, Src, Dst> {
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.
@ -304,7 +326,7 @@ impl<'de, T, Src, Dst> serde::Deserialize<'de> for Translation3D<T, Src, Dst>
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: serde::Deserializer<'de>
{
let (x, y, z) = try!(serde::Deserialize::deserialize(deserializer));
let (x, y, z) = serde::Deserialize::deserialize(deserializer)?;
Ok(Translation3D { x, y, z, _unit: PhantomData })
}
}
@ -342,7 +364,7 @@ impl<T, Src, Dst> Hash for Translation3D<T, Src, Dst>
impl<T, Src, Dst> Translation3D<T, Src, Dst> {
#[inline]
pub fn new(x: T, y: T, z: T) -> Self {
pub const fn new(x: T, y: T, z: T) -> Self {
Translation3D {
x,
y,
@ -350,31 +372,66 @@ impl<T, Src, Dst> Translation3D<T, Src, Dst> {
_unit: PhantomData,
}
}
/// No-op, just cast the unit.
#[inline]
pub fn transform_size(self, s: Size2D<T, Src>) -> Size2D<T, Dst> {
Size2D::new(s.width, s.height)
}
}
impl<T, Src, Dst> Translation3D<T, Src, Dst>
where
T: Copy
{
/// Cast into a 3D vector.
#[inline]
pub fn to_vector(&self) -> Vector3D<T, Src> {
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<T, UnknownUnit, UnknownUnit> {
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<T, UnknownUnit, UnknownUnit>) -> Self {
Translation3D {
x: t.x,
y: t.y,
z: t.z,
_unit: PhantomData,
}
}
}
impl<T, Src, Dst> Translation3D<T, Src, Dst>
where
T: Copy + Zero
T: Zero
{
#[inline]
pub fn identity() -> Self {
let _0 = T::zero();
Translation3D::new(_0, _0, _0)
Translation3D::new(T::zero(), T::zero(), T::zero())
}
}
@ -384,7 +441,8 @@ where
{
#[inline]
pub fn is_identity(&self) -> bool {
self.x == T::zero() && self.y == T::zero() && self.z == T::zero()
let _0 = T::zero();
self.x == _0 && self.y == _0 && self.z == _0
}
}
@ -412,17 +470,6 @@ where
size: self.transform_size(r.size),
}
}
/// No-op, just cast the unit.
#[inline]
pub fn transform_size(self, s: Size2D<T, Src>) -> Size2D<T, Dst> {
Size2D::new(s.width, s.height)
}
/// Cast into a 3D vector.
pub fn to_vector(&self) -> Vector3D<T, Src> {
vec3(self.x, self.y, self.z)
}
}
impl<T, Src, Dst> Translation3D<T, Src, Dst>
@ -439,7 +486,7 @@ where
impl<T, Src, Dst1, Dst2> Add<Translation3D<T, Dst1, Dst2>>
for Translation3D<T, Src, Dst1>
where
T: Copy + Add<T, Output = T>
T: Add<T, Output = T>
{
type Output = Translation3D<T, Src, Dst2>;
fn add(self, other: Translation3D<T, Dst1, Dst2>) -> Translation3D<T, Src, Dst2> {
@ -455,7 +502,7 @@ impl<T, Src, Dst1, Dst2>
Sub<Translation3D<T, Dst1, Dst2>>
for Translation3D<T, Src, Dst2>
where
T: Copy + Sub<T, Output = T>
T: Sub<T, Output = T>
{
type Output = Translation3D<T, Src, Dst1>;
fn sub(self, other: Translation3D<T, Dst1, Dst2>) -> Translation3D<T, Src, Dst1> {
@ -469,7 +516,7 @@ where
impl<T, Src, Dst> Translation3D<T, Src, Dst>
where
T: Copy + Clone +
T: Copy +
Add<T, Output=T> +
Sub<T, Output=T> +
Mul<T, Output=T> +
@ -487,8 +534,6 @@ where
}
impl<T, Src, Dst> From<Vector3D<T, Src>> for Translation3D<T, Src, Dst>
where
T: Copy
{
fn from(v: Vector3D<T, Src>) -> Self {
Translation3D::new(v.x, v.y, v.z)
@ -496,8 +541,6 @@ where
}
impl<T, Src, Dst> Into<Vector3D<T, Src>> for Translation3D<T, Src, Dst>
where
T: Copy
{
fn into(self) -> Vector3D<T, Src> {
vec3(self.x, self.y, self.z)
@ -506,7 +549,7 @@ where
impl<T, Src, Dst> Into<Transform3D<T, Src, Dst>> for Translation3D<T, Src, Dst>
where
T: Copy + Clone +
T: Copy +
Add<T, Output=T> +
Sub<T, Output=T> +
Mul<T, Output=T> +
@ -522,17 +565,22 @@ where
}
impl <T, Src, Dst> Default for Translation3D<T, Src, Dst>
where T: Copy + Zero
where T: Zero
{
fn default() -> Self {
Self::identity()
}
}
impl<T, Src, Dst> fmt::Debug for Translation3D<T, Src, Dst>
where T: Copy + fmt::Debug {
impl<T: fmt::Debug, Src, Dst> fmt::Debug for Translation3D<T, Src, Dst> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_array().fmt(f)
write!(f, "Translation({:?},{:?},{:?})", self.x, self.y, self.z)
}
}
impl<T: fmt::Display, Src, Dst> fmt::Display for Translation3D<T, Src, Dst> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({},{},{})", self.x, self.y, self.z)
}
}

View File

@ -18,14 +18,20 @@ pub trait Trig {
}
macro_rules! trig {
($ty:ident) => (
($ty:ident) => {
impl Trig for $ty {
#[inline]
fn sin(self) -> $ty { self.sin() }
fn sin(self) -> $ty {
num_traits::Float::sin(self)
}
#[inline]
fn cos(self) -> $ty { self.cos() }
fn cos(self) -> $ty {
num_traits::Float::cos(self)
}
#[inline]
fn tan(self) -> $ty { self.tan() }
fn tan(self) -> $ty {
num_traits::Float::tan(self)
}
/// A slightly faster approximation of `atan2`.
///
@ -38,11 +44,12 @@ macro_rules! trig {
// See https://math.stackexchange.com/questions/1098487/atan2-faster-approximation#1105038
use core::$ty::consts;
let x_abs = x.abs();
let y_abs = y.abs();
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;
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;
}
@ -66,7 +73,7 @@ macro_rules! trig {
rad.to_degrees()
}
}
)
};
}
trig!(f32);

File diff suppressed because it is too large Load Diff