Backed out 4 changesets (bug 1656236) for build bustages on a CLOSED TREE

Backed out changeset bd79e14bc5ba (bug 1656236)
Backed out changeset dc76da883823 (bug 1656236)
Backed out changeset c4883923e091 (bug 1656236)
Backed out changeset 9464c1dcb0c9 (bug 1656236)
This commit is contained in:
Cristina Coroiu 2020-08-05 12:10:43 +03:00
parent 9208b6c499
commit 2930787297
109 changed files with 1829 additions and 1291 deletions

8
Cargo.lock generated
View File

@ -1296,9 +1296,9 @@ dependencies = [
[[package]]
name = "euclid"
version = "0.22.0"
version = "0.20.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ab0e07e345fb061928646949fdf5fb888e5d75a57385e7f5856e45be289e745"
checksum = "2bb7ef65b3777a325d1eeefefab5b6d4959da54747e33bd6258e789640f307ad"
dependencies = [
"num-traits",
"serde",
@ -3688,9 +3688,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
[[package]]
name = "plane-split"
version = "0.17.0"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2211e7ccc9b6260779dd9bad59f7b10889d6361974623b9e405afd7e7e764654"
checksum = "ffe16a646a08f4b4dd74035b9ff8e378eb1a4012a74f14f5889e7001cdbece33"
dependencies = [
"binary-space-partition",
"euclid",

View File

@ -12,7 +12,7 @@ dirs = "2"
rayon = "1"
num_cpus = "1.7.0"
tracy-rs = "0.1"
euclid = { version = "0.22.0", features = ["serde"] }
euclid = { version = "0.20.14", features = ["serde"] }
app_units = "0.7"
gleam = "0.12.0"
log = "0.4"

28
gfx/wr/Cargo.lock generated
View File

@ -469,7 +469,7 @@ dependencies = [
name = "direct-composition"
version = "0.1.0"
dependencies = [
"euclid 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.12.1 (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",
@ -522,7 +522,7 @@ dependencies = [
[[package]]
name = "euclid"
version = "0.22.0"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1151,7 +1151,7 @@ dependencies = [
name = "peek-poke"
version = "0.2.0"
dependencies = [
"euclid 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
"peek-poke-derive 0.2.1",
]
@ -1178,11 +1178,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "plane-split"
version = "0.17.0"
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.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1627,7 +1627,7 @@ dependencies = [
name = "tileview"
version = "0.1.0"
dependencies = [
"euclid 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
"ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender 0.61.0",
@ -1805,7 +1805,7 @@ dependencies = [
"core-text 19.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cstr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype 0.7.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.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1817,7 +1817,7 @@ dependencies = [
"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.11 (registry+https://github.com/rust-lang/crates.io-index)",
"plane-split 0.17.0 (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.16.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1842,7 +1842,7 @@ dependencies = [
"app_units 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1861,7 +1861,7 @@ dependencies = [
"core-graphics 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-channel 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"derive_more 0.99.5 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (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.106 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1954,7 +1954,7 @@ name = "wr_malloc_size_of"
version = "0.0.1"
dependencies = [
"app_units 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1972,7 +1972,7 @@ dependencies = [
"crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)",
"font-loader 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2113,7 +2113,7 @@ dependencies = [
"checksum dwrote 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b"
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
"checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38"
"checksum euclid 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7ab0e07e345fb061928646949fdf5fb888e5d75a57385e7f5856e45be289e745"
"checksum euclid 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c6a5b0c779cd0b744c73a1d2083faf181080d696903cdad99a3b03d015d7030"
"checksum expat-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "658f19728920138342f68408b7cf7644d90d4784353d8ebc32e7e8663dbe45fa"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
"checksum font-loader 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c49d6b4c11dca1a1dd931a34a9f397e2da91abe3de4110505f3530a80e560b52"
@ -2188,7 +2188,7 @@ dependencies = [
"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
"checksum plane-split 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2211e7ccc9b6260779dd9bad59f7b10889d6361974623b9e405afd7e7e764654"
"checksum plane-split 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffe16a646a08f4b4dd74035b9ff8e378eb1a4012a74f14f5889e7001cdbece33"
"checksum png 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)" = "910f09135b1ed14bb16be445a8c23ddf0777eca485fbfc7cee00d81fecab158a"
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"

View File

@ -6,7 +6,7 @@ license = "MPL-2.0"
edition = "2018"
[target.'cfg(windows)'.dependencies]
euclid = "0.22"
euclid = "0.20"
gleam = "0.12"
mozangle = {version = "0.3.1", features = ["egl"]}
webrender = {path = "../webrender"}

View File

@ -60,7 +60,7 @@ debug = ["webrender/capture", "webrender/debugger", "webrender/profiler"]
[dependencies]
app_units = "0.7"
env_logger = "0.5"
euclid = "0.22"
euclid = "0.20"
gleam = "0.12"
glutin = "0.21"
rayon = "1"

View File

@ -165,9 +165,9 @@ impl Example for App {
self.angle0 += delta_angle * 0.1;
self.angle1 += delta_angle * 0.2;
self.angle2 -= delta_angle * 0.15;
let xf0 = LayoutTransform::rotation(0.0, 0.0, 1.0, Angle::radians(self.angle0));
let xf1 = LayoutTransform::rotation(0.0, 0.0, 1.0, Angle::radians(self.angle1));
let xf2 = LayoutTransform::rotation(0.0, 0.0, 1.0, Angle::radians(self.angle2));
let xf0 = LayoutTransform::create_rotation(0.0, 0.0, 1.0, Angle::radians(self.angle0));
let xf1 = LayoutTransform::create_rotation(0.0, 0.0, 1.0, Angle::radians(self.angle1));
let xf2 = LayoutTransform::create_rotation(0.0, 0.0, 1.0, Angle::radians(self.angle2));
let mut txn = Transaction::new();
txn.update_dynamic_properties(
DynamicProperties {

View File

@ -8,7 +8,7 @@ license = "MIT/Apache-2.0"
edition = "2018"
[dependencies]
euclid = { version = "0.22.0", optional = true }
euclid = { version = "0.20.0", optional = true }
peek-poke-derive = { version = "0.2", path = "./peek-poke-derive", optional = true }
[features]

View File

@ -12,4 +12,4 @@ ron = "0.5"
serde = {version = "1.0.88", features = ["derive"] }
webrender = {path = "../webrender", features=["capture","replay","debugger","png","profiler","no_static_freetype", "leak_checks"]}
webrender_api = {path = "../webrender_api", features=["serialize","deserialize"]}
euclid = { version = "0.22.0", features = ["serde"] }
euclid = { version = "0.20.0", features = ["serde"] }

View File

@ -73,7 +73,7 @@ fn tile_node_to_svg(node: &TileNode,
{
match &node.kind {
TileNodeKind::Leaf { .. } => {
let rect_world = transform.outer_transformed_rect(&node.rect.to_rect()).unwrap();
let rect_world = transform.transform_rect(&node.rect.to_rect()).unwrap();
format!("<rect x=\"{:.2}\" y=\"{:.2}\" width=\"{:.2}\" height=\"{:.2}\" />\n",
rect_world.origin.x * svg_settings.scale + svg_settings.x,
rect_world.origin.y * svg_settings.scale + svg_settings.y,
@ -296,7 +296,7 @@ fn tile_to_svg(key: TileOffset,
origin: tile.rect.origin,
size: PictureSize::new(1.0, 1.0)
};
let rect_visual_id_world = slice.transform.outer_transformed_rect(&rect_visual_id).unwrap();
let rect_visual_id_world = slice.transform.transform_rect(&rect_visual_id).unwrap();
svg += &format!("\n<text class=\"svg_tile_visual_id\" x=\"{}\" y=\"{}\">{},{} ({})</text>",
rect_visual_id_world.origin.x * svg_settings.scale + svg_settings.x,
(rect_visual_id_world.origin.y + 110.0) * svg_settings.scale + svg_settings.y,
@ -312,7 +312,7 @@ fn tile_to_svg(key: TileOffset,
origin: PicturePoint::new(rect.min.x, rect.min.y),
size: PictureSize::new(rect.max.x - rect.min.x, rect.max.y - rect.min.y),
};
let rect_world = slice.transform.outer_transformed_rect(&rect_pixel).unwrap();
let rect_world = slice.transform.transform_rect(&rect_pixel).unwrap();
let style =
if let Some(prev_tile) = prev_tile {

View File

@ -32,7 +32,7 @@ bitflags = "1.2"
byteorder = "1.0"
cfg-if = "0.1.2"
cstr = "0.1.2"
euclid = { version = "0.22.0", features = ["serde"] }
euclid = { version = "0.20.0", features = ["serde"] }
fxhash = "0.2.1"
gleam = "0.12.1"
image_loader = { optional = true, version = "0.23", package = "image", default-features = false, features = ["png"] }
@ -40,7 +40,7 @@ lazy_static = "1"
log = "0.4"
malloc_size_of_derive = "0.1"
num-traits = "0.2"
plane-split = "0.17"
plane-split = "0.15"
png = { optional = true, version = "0.16" }
rayon = "1"
ron = { optional = true, version = "0.5" }

View File

@ -1190,7 +1190,7 @@ impl BatchBuilder {
root_spatial_node_index,
).into_transform()
.with_destination::<WorldPixel>()
.then(&euclid::Transform3D::from_scale(ctx.global_device_pixel_scale));
.post_transform(&euclid::Transform3D::from_scale(ctx.global_device_pixel_scale));
let glyph_translation = DeviceVector2D::new(glyph_transform.m41, glyph_transform.m42);
@ -1249,7 +1249,9 @@ impl BatchBuilder {
let intersected = match pic_bounding_rect {
// The text run may have been clipped, for example if part of it is offscreen.
// So intersect our result with the original bounding rect.
Some(rect) => rect.intersection(bounding_rect).unwrap_or_else(PictureRect::zero),
Some(rect) => rect
.intersection(bounding_rect)
.unwrap_or_else(PictureRect::zero),
// If space mapping went off the rails, fall back to the old behavior.
//TODO: consider skipping the glyph run completely in this case.
None => *bounding_rect,
@ -2482,14 +2484,14 @@ impl BatchBuilder {
let specific_resource_address = cache_item.uv_rect_handle.as_int(gpu_cache);
prim_header.specific_prim_address = gpu_cache.get_address(&ctx.globals.default_image_handle);
let segment_local_clip_rect = match prim_header.local_clip_rect.intersection(&segment.local_rect) {
Some(rect) => rect,
None => { continue; }
};
let segment_local_clip_rect = prim_header.local_clip_rect.intersection(&segment.local_rect);
if segment_local_clip_rect.is_none() {
continue;
}
let segment_prim_header = PrimitiveHeader {
local_rect: segment.local_rect,
local_clip_rect: segment_local_clip_rect,
local_clip_rect: segment_local_clip_rect.unwrap(),
specific_prim_address: prim_header.specific_prim_address,
transform_id: prim_header.transform_id,
};

View File

@ -1067,12 +1067,12 @@ fn add_corner_segment(
return;
}
let segment_rect = match image_rect.intersection(&non_overlapping_rect) {
Some(rect) => rect,
None => {
return;
}
};
let segment_rect = image_rect.intersection(&non_overlapping_rect)
.unwrap_or_else(LayoutRect::zero);
if segment_rect.size.width <= 0. || segment_rect.size.height <= 0. {
return;
}
let texture_rect = segment_rect
.translate(-image_rect.origin.to_vector())

View File

@ -3,7 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{ColorF, YuvColorSpace, YuvFormat, ImageRendering, ExternalImageId};
use api::units::*;
use api::units::{DeviceRect, DeviceIntSize, DeviceIntRect, DeviceIntPoint, WorldRect};
use api::units::{DevicePixelScale, DevicePoint, PictureRect, TexelRect, DevicePixel};
use crate::batch::{resolve_image, get_buffer_kind};
use euclid::Transform3D;
use crate::gpu_cache::GpuCache;
@ -571,7 +572,7 @@ impl CompositeState {
surface_id: tile_cache.native_surface.as_ref().map(|s| s.opaque),
offset: tile_cache.device_position,
clip_rect: device_clip_rect,
transform: CompositorSurfaceTransform::translation(tile_cache.device_position.x,
transform: CompositorSurfaceTransform::create_translation(tile_cache.device_position.x,
tile_cache.device_position.y,
0.0),
image_dependencies: [ImageDependency::INVALID; 3],
@ -745,7 +746,7 @@ impl CompositeState {
surface_id: tile_cache.native_surface.as_ref().map(|s| s.alpha),
offset: tile_cache.device_position,
clip_rect: device_clip_rect,
transform: CompositorSurfaceTransform::translation(tile_cache.device_position.x,
transform: CompositorSurfaceTransform::create_translation(tile_cache.device_position.x,
tile_cache.device_position.y,
0.0),
image_dependencies: [ImageDependency::INVALID; 3],

View File

@ -2781,7 +2781,7 @@ impl Device {
debug_assert!(self.shader_is_ready);
self.gl
.uniform_matrix_4fv(program.u_transform, false, &transform.to_array());
.uniform_matrix_4fv(program.u_transform, false, &transform.to_row_major_array());
}
pub fn switch_mode(&self, mode: i32) {

View File

@ -245,7 +245,7 @@ impl<Src, Dst> From<CoordinateSpaceMapping<Src, Dst>> for TransformKey {
CoordinateSpaceMapping::Transform(ref m) => {
TransformKey::Transform {
m: MatrixKey {
m: m.to_array(),
m: m.to_row_major_array(),
},
}
}
@ -974,7 +974,7 @@ impl Tile {
/// Print debug information about this tile to a tree printer.
fn print(&self, pt: &mut dyn PrintTreePrinter) {
pt.new_level(format!("Tile {:?}", self.id));
pt.add_item(format!("local_tile_rect: {:?}", self.local_tile_rect));
pt.add_item(format!("local_tile_rect: {}", self.local_tile_rect));
pt.add_item(format!("fract_offset: {:?}", self.fract_offset));
pt.add_item(format!("background_color: {:?}", self.background_color));
pt.add_item(format!("invalidation_reason: {:?}", self.invalidation_reason));
@ -3076,7 +3076,7 @@ impl TileCacheInstance {
);
let prim_origin = Vector3D::new(local_prim_rect.origin.x, local_prim_rect.origin.y, 0.0);
let world_to_device_scale = Transform3D::from_scale(frame_context.global_device_pixel_scale);
let transform = surface_to_world_mapper.get_transform().pre_translate(prim_origin).then(&world_to_device_scale);
let transform = surface_to_world_mapper.get_transform().pre_translate(prim_origin).post_transform(&world_to_device_scale);
(local_prim_rect.cast_unit(), transform)
}
@ -3245,7 +3245,7 @@ impl TileCacheInstance {
};
// If the rect is invalid, no need to create dependencies.
if prim_rect.size.is_empty() {
if prim_rect.size.is_empty_or_negative() {
return None;
}

View File

@ -1798,7 +1798,7 @@ fn get_clipped_device_rect(
) -> Option<DeviceRect> {
let unclipped_raster_rect = {
let world_rect = *unclipped * Scale::new(1.0);
let raster_rect = world_rect * device_pixel_scale.inverse();
let raster_rect = world_rect * device_pixel_scale.inv();
raster_rect.cast_unit()
};

View File

@ -520,7 +520,7 @@ impl Document {
}
fn has_pixels(&self) -> bool {
!self.view.scene.device_rect.size.is_empty()
!self.view.scene.device_rect.size.is_empty_or_negative()
}
fn process_frame_msg(

View File

@ -258,7 +258,7 @@ impl<T: RenderTarget> RenderTargetList<T> {
}
};
if alloc_size.is_empty() && self.targets.is_empty() {
if alloc_size.is_empty_or_negative() && self.targets.is_empty() {
// push an unused target here, only if we don't have any
self.targets.push(T::new(self.screen_size, self.gpu_supports_fast_clears));
}

View File

@ -573,7 +573,7 @@ pub fn dump_render_tasks_as_svg(
let saved = if task.saved_index.is_some() { " (Saved)" } else { "" };
let label = text(tx, ty, format!("{}{}", task.kind.as_str(), saved));
let size = text(tx, ty + 12.0, format!("{:?}", task.location.size()));
let size = text(tx, ty + 12.0, format!("{}", task.location.size()));
nodes[task_index] = Some(Node { rect, label, size });

View File

@ -492,7 +492,7 @@ impl<'a> SceneBuilder<'a> {
match rotation {
Rotation::Degree0 |
Rotation::Degree180 => {
LayoutTransform::scale(
LayoutTransform::create_scale(
content_size.width / scale_from.width,
content_size.height / scale_from.height,
1.0
@ -500,7 +500,7 @@ impl<'a> SceneBuilder<'a> {
},
Rotation::Degree90 |
Rotation::Degree270 => {
LayoutTransform::scale(
LayoutTransform::create_scale(
content_size.height / scale_from.width,
content_size.width / scale_from.height,
1.0
@ -515,12 +515,12 @@ impl<'a> SceneBuilder<'a> {
if vertical_flip {
let content_size = &self.iframe_size.last().unwrap();
transform = transform
.then_translate(LayoutVector3D::new(0.0, content_size.height, 0.0))
.post_translate(LayoutVector3D::new(0.0, content_size.height, 0.0))
.pre_scale(1.0, -1.0, 1.0);
}
let rotate = rotation.to_matrix(**content_size);
let transform = transform.then(&rotate);
let transform = transform.post_transform(&rotate);
PropertyBinding::Value(transform)
},

View File

@ -410,7 +410,7 @@ impl SpatialNode {
// perspective matrix using the scroll offset.
source_transform
.pre_translate(scroll_offset)
.then_translate(-scroll_offset)
.post_translate(-scroll_offset)
}
ReferenceFrameKind::Perspective { scrolling_relative_to: None } |
ReferenceFrameKind::Transform | ReferenceFrameKind::Zoom => source_transform,
@ -425,7 +425,7 @@ impl SpatialNode {
// between our reference frame and this node. Finally, we also include
// whatever local transformation this reference frame provides.
let relative_transform = resolved_transform
.then_translate(snap_offset(state.parent_accumulated_scroll_offset, state.coordinate_system_relative_scale_offset.scale, global_device_pixel_scale))
.post_translate(snap_offset(state.parent_accumulated_scroll_offset, state.coordinate_system_relative_scale_offset.scale, global_device_pixel_scale))
.to_transform()
.with_destination::<LayoutPixel>();
@ -462,9 +462,9 @@ impl SpatialNode {
if reset_cs_id {
// If we break 2D axis alignment or have a perspective component, we need to start a
// new incompatible coordinate system with which we cannot share clips without masking.
let transform = relative_transform.then(
&state.coordinate_system_relative_scale_offset.to_transform()
);
let transform = state.coordinate_system_relative_scale_offset
.to_transform()
.pre_transform(&relative_transform);
// Push that new coordinate system and record the new id.
let coord_system = {
@ -473,7 +473,7 @@ impl SpatialNode {
if parent_system.should_flatten {
cur_transform.flatten_z_output();
}
let world_transform = cur_transform.then(&parent_system.world_transform);
let world_transform = cur_transform.post_transform(&parent_system.world_transform);
let determinant = world_transform.determinant();
info.invertible = determinant != 0.0 && !determinant.is_nan();
@ -977,7 +977,7 @@ fn test_cst_perspective_relative_scroll() {
let mut cst = SpatialTree::new();
let pipeline_id = PipelineId::dummy();
let ext_scroll_id = ExternalScrollId(1, pipeline_id);
let transform = LayoutTransform::perspective(100.0);
let transform = LayoutTransform::create_perspective(100.0);
let root = cst.add_reference_frame(
None,

View File

@ -289,16 +289,16 @@ impl SpatialTree {
let child_cs = &self.coord_systems[child.coordinate_system_id.0 as usize];
let child_transform = child.content_transform
.to_transform::<LayoutPixel, LayoutPixel>()
.then(&child_cs.world_transform);
.post_transform(&child_cs.world_transform);
let parent_cs = &self.coord_systems[parent.coordinate_system_id.0 as usize];
let parent_transform = parent.content_transform
.to_transform()
.then(&parent_cs.world_transform);
.post_transform(&parent_cs.world_transform);
let result = parent_transform
.inverse()
.unwrap_or_default()
.then(&child_transform)
.post_transform(&child_transform)
.with_source::<LayoutPixel>()
.with_destination::<LayoutPixel>();
return CoordinateSpaceMapping::Transform(result);
@ -319,10 +319,10 @@ impl SpatialTree {
}
coordinate_system_id = coord_system.parent.expect("invalid parent!");
transform = transform.then(&coord_system.transform);
transform = transform.post_transform(&coord_system.transform);
}
transform = transform.then(
transform = transform.post_transform(
&parent.content_transform
.inverse()
.to_transform(),
@ -352,7 +352,7 @@ impl SpatialTree {
};
let transform = scale_offset
.to_transform()
.then(&system.world_transform);
.post_transform(&system.world_transform);
CoordinateSpaceMapping::Transform(transform)
}
@ -827,21 +827,21 @@ fn test_cst_simple_translation() {
let child1 = add_reference_frame(
&mut cst,
Some(root),
LayoutTransform::translation(100.0, 0.0, 0.0),
LayoutTransform::create_translation(100.0, 0.0, 0.0),
LayoutVector2D::zero(),
);
let child2 = add_reference_frame(
&mut cst,
Some(child1),
LayoutTransform::translation(0.0, 50.0, 0.0),
LayoutTransform::create_translation(0.0, 50.0, 0.0),
LayoutVector2D::zero(),
);
let child3 = add_reference_frame(
&mut cst,
Some(child2),
LayoutTransform::translation(200.0, 200.0, 0.0),
LayoutTransform::create_translation(200.0, 200.0, 0.0),
LayoutVector2D::zero(),
);
@ -869,21 +869,21 @@ fn test_cst_simple_scale() {
let child1 = add_reference_frame(
&mut cst,
Some(root),
LayoutTransform::scale(4.0, 1.0, 1.0),
LayoutTransform::create_scale(4.0, 1.0, 1.0),
LayoutVector2D::zero(),
);
let child2 = add_reference_frame(
&mut cst,
Some(child1),
LayoutTransform::scale(1.0, 2.0, 1.0),
LayoutTransform::create_scale(1.0, 2.0, 1.0),
LayoutVector2D::zero(),
);
let child3 = add_reference_frame(
&mut cst,
Some(child2),
LayoutTransform::scale(2.0, 2.0, 1.0),
LayoutTransform::create_scale(2.0, 2.0, 1.0),
LayoutVector2D::zero(),
);
@ -912,28 +912,28 @@ fn test_cst_scale_translation() {
let child1 = add_reference_frame(
&mut cst,
Some(root),
LayoutTransform::translation(100.0, 50.0, 0.0),
LayoutTransform::create_translation(100.0, 50.0, 0.0),
LayoutVector2D::zero(),
);
let child2 = add_reference_frame(
&mut cst,
Some(child1),
LayoutTransform::scale(2.0, 4.0, 1.0),
LayoutTransform::create_scale(2.0, 4.0, 1.0),
LayoutVector2D::zero(),
);
let child3 = add_reference_frame(
&mut cst,
Some(child2),
LayoutTransform::translation(200.0, -100.0, 0.0),
LayoutTransform::create_translation(200.0, -100.0, 0.0),
LayoutVector2D::zero(),
);
let child4 = add_reference_frame(
&mut cst,
Some(child3),
LayoutTransform::scale(3.0, 2.0, 1.0),
LayoutTransform::create_scale(3.0, 2.0, 1.0),
LayoutVector2D::zero(),
);
@ -967,7 +967,7 @@ fn test_cst_translation_rotate() {
let child1 = add_reference_frame(
&mut cst,
Some(root),
LayoutTransform::rotation(0.0, 0.0, 1.0, Angle::degrees(-90.0)),
LayoutTransform::create_rotation(0.0, 0.0, 1.0, Angle::degrees(90.0)),
LayoutVector2D::zero(),
);

View File

@ -1206,7 +1206,7 @@ impl TextureCache {
&mut self,
params: &CacheAllocParams,
) -> CacheEntry {
assert!(!params.descriptor.size.is_empty());
assert!(!params.descriptor.size.is_empty_or_negative());
// If this image doesn't qualify to go in the shared (batching) cache,
// allocate a standalone entry.

View File

@ -284,7 +284,7 @@ impl ScaleOffset {
}
pub fn to_transform<F, T>(&self) -> Transform3D<f32, F, T> {
Transform3D::new(
Transform3D::row_major(
self.scale.x,
0.0,
0.0,
@ -387,10 +387,13 @@ impl<Src, Dst> MatrixHelpers<Src, Dst> for Transform3D<f32, Src, Dst> {
fn inverse_project(&self, target: &Point2D<f32, Dst>) -> Option<Point2D<f32, Src>> {
let m: Transform2D<f32, Src, Dst>;
m = Transform2D::new(
self.m11 - target.x * self.m14, self.m12 - target.y * self.m14,
self.m21 - target.x * self.m24, self.m22 - target.y * self.m24,
self.m41 - target.x * self.m44, self.m42 - target.y * self.m44,
m = Transform2D::column_major(
self.m11 - target.x * self.m14,
self.m21 - target.x * self.m24,
self.m41 - target.x * self.m44,
self.m12 - target.y * self.m14,
self.m22 - target.y * self.m24,
self.m42 - target.y * self.m44,
);
m.inverse().map(|inv| Point2D::new(inv.m31, inv.m32))
}
@ -473,12 +476,10 @@ impl<Src, Dst> MatrixHelpers<Src, Dst> for Transform3D<f32, Src, Dst> {
}
fn cast_unit<NewSrc, NewDst>(&self) -> Transform3D<f32, NewSrc, NewDst> {
Transform3D::new(
self.m11, self.m12, self.m13, self.m14,
self.m21, self.m22, self.m23, self.m24,
self.m31, self.m32, self.m33, self.m34,
self.m41, self.m42, self.m43, self.m44,
)
Transform3D::row_major(self.m11, self.m12, self.m13, self.m14,
self.m21, self.m22, self.m23, self.m24,
self.m31, self.m32, self.m33, self.m34,
self.m41, self.m42, self.m43, self.m44)
}
}
@ -605,9 +606,6 @@ pub fn extract_inner_rect_safe<U>(
extract_inner_rect_impl(rect, radii, 1.0)
}
#[cfg(test)]
use euclid::vec3;
#[cfg(test)]
pub mod test {
use super::*;
@ -621,7 +619,7 @@ pub mod test {
let p0 = Point2D::new(1.0, 2.0);
// an identical transform doesn't need any inverse projection
assert_eq!(m0.inverse_project(&p0), Some(p0));
let m1 = Transform3D::rotation(0.0, 1.0, 0.0, Angle::radians(-PI / 3.0));
let m1 = Transform3D::create_rotation(0.0, 1.0, 0.0, Angle::radians(PI / 3.0));
// rotation by 60 degrees would imply scaling of X component by a factor of 2
assert_eq!(m1.inverse_project(&p0), Some(Point2D::new(2.0, 2.0)));
}
@ -634,18 +632,18 @@ pub mod test {
#[test]
fn scale_offset_convert() {
let xref = LayoutTransform::translation(130.0, 200.0, 0.0);
let xref = LayoutTransform::create_translation(130.0, 200.0, 0.0);
validate_convert(&xref);
let xref = LayoutTransform::scale(13.0, 8.0, 1.0);
let xref = LayoutTransform::create_scale(13.0, 8.0, 1.0);
validate_convert(&xref);
let xref = LayoutTransform::scale(0.5, 0.5, 1.0)
let xref = LayoutTransform::create_scale(0.5, 0.5, 1.0)
.pre_translate(LayoutVector3D::new(124.0, 38.0, 0.0));
validate_convert(&xref);
let xref = LayoutTransform::scale(30.0, 11.0, 1.0)
.then_translate(vec3(50.0, 240.0, 0.0));
let xref = LayoutTransform::create_translation(50.0, 240.0, 0.0)
.pre_transform(&LayoutTransform::create_scale(30.0, 11.0, 1.0));
validate_convert(&xref);
}
@ -662,24 +660,23 @@ pub mod test {
#[test]
fn scale_offset_inverse() {
let xref = LayoutTransform::translation(130.0, 200.0, 0.0);
let xref = LayoutTransform::create_translation(130.0, 200.0, 0.0);
validate_inverse(&xref);
let xref = LayoutTransform::scale(13.0, 8.0, 1.0);
let xref = LayoutTransform::create_scale(13.0, 8.0, 1.0);
validate_inverse(&xref);
let xref = LayoutTransform::translation(124.0, 38.0, 0.0).
then_scale(0.5, 0.5, 1.0);
let xref = LayoutTransform::create_scale(0.5, 0.5, 1.0)
.pre_translate(LayoutVector3D::new(124.0, 38.0, 0.0));
validate_inverse(&xref);
let xref = LayoutTransform::scale(30.0, 11.0, 1.0)
.then_translate(vec3(50.0, 240.0, 0.0));
let xref = LayoutTransform::create_translation(50.0, 240.0, 0.0)
.pre_transform(&LayoutTransform::create_scale(30.0, 11.0, 1.0));
validate_inverse(&xref);
}
fn validate_accumulate(x0: &LayoutTransform, x1: &LayoutTransform) {
let x = x1.then(&x0);
let x = x0.pre_transform(x1);
let s0 = ScaleOffset::from_transform(x0).unwrap();
let s1 = ScaleOffset::from_transform(x1).unwrap();
@ -691,8 +688,8 @@ pub mod test {
#[test]
fn scale_offset_accumulate() {
let x0 = LayoutTransform::translation(130.0, 200.0, 0.0);
let x1 = LayoutTransform::scale(7.0, 3.0, 1.0);
let x0 = LayoutTransform::create_translation(130.0, 200.0, 0.0);
let x1 = LayoutTransform::create_scale(7.0, 3.0, 1.0);
validate_accumulate(&x0, &x1);
}
@ -801,7 +798,7 @@ impl<Src, Dst> FastTransform<Src, Dst> {
pub fn to_transform(&self) -> Cow<Transform3D<f32, Src, Dst>> {
match *self {
FastTransform::Offset(offset) => Cow::Owned(
Transform3D::translation(offset.x, offset.y, 0.0)
Transform3D::create_translation(offset.x, offset.y, 0.0)
),
FastTransform::Transform { ref transform, .. } => Cow::Borrowed(transform),
}
@ -820,7 +817,7 @@ impl<Src, Dst> FastTransform<Src, Dst> {
}
}
pub fn then<NewDst>(&self, other: &FastTransform<Dst, NewDst>) -> FastTransform<Src, NewDst> {
pub fn post_transform<NewDst>(&self, other: &FastTransform<Dst, NewDst>) -> FastTransform<Src, NewDst> {
match *self {
FastTransform::Offset(offset) => match *other {
FastTransform::Offset(other_offset) => {
@ -838,15 +835,15 @@ impl<Src, Dst> FastTransform<Src, Dst> {
FastTransform::Offset(other_offset) => {
FastTransform::with_transform(
transform
.then_translate(other_offset.to_3d())
.post_translate(other_offset.to_3d())
.with_destination::<NewDst>()
)
}
FastTransform::Transform { transform: ref other_transform, inverse: ref other_inverse, is_2d: other_is_2d } => {
FastTransform::Transform {
transform: transform.then(other_transform),
transform: transform.post_transform(other_transform),
inverse: inverse.as_ref().and_then(|self_inv|
other_inverse.as_ref().map(|other_inv| other_inv.then(self_inv))
other_inverse.as_ref().map(|other_inv| self_inv.pre_transform(other_inv))
),
is_2d: is_2d & other_is_2d,
}
@ -859,7 +856,7 @@ impl<Src, Dst> FastTransform<Src, Dst> {
&self,
other: &FastTransform<NewSrc, Src>
) -> FastTransform<NewSrc, Dst> {
other.then(self)
other.post_transform(self)
}
pub fn pre_translate(&self, other_offset: Vector2D<f32, Src>) -> Self {
@ -871,13 +868,13 @@ impl<Src, Dst> FastTransform<Src, Dst> {
}
}
pub fn then_translate(&self, other_offset: Vector2D<f32, Dst>) -> Self {
pub fn post_translate(&self, other_offset: Vector2D<f32, Dst>) -> Self {
match *self {
FastTransform::Offset(offset) => {
FastTransform::Offset(offset + other_offset * Scale::<_, _, Src>::new(1.0))
}
FastTransform::Transform { ref transform, .. } => {
let transform = transform.then_translate(other_offset.to_3d());
let transform = transform.post_translate(other_offset.to_3d());
FastTransform::with_transform(transform)
}
}

View File

@ -476,7 +476,7 @@ pub fn update_primitive_visibility(
prim_instance.clip_set.local_clip_rect
};
if combined_local_clip_rect.size.is_empty() {
if combined_local_clip_rect.size.is_empty_or_negative() {
if prim_instance.is_chased() {
println!("\tculled for zero local clip rectangle");
}

View File

@ -18,7 +18,7 @@ app_units = "0.7"
bitflags = "1.2"
byteorder = "1.2.1"
derive_more = "0.99"
euclid = { version = "0.22.0", features = ["serde"] }
euclid = { version = "0.20.0", features = ["serde"] }
malloc_size_of_derive = "0.1"
serde = { version = "1.0", features = ["rc"] }
serde_derive = "1.0"

View File

@ -740,23 +740,23 @@ impl Rotation {
) -> LayoutTransform {
let (shift_center_to_origin, angle) = match self {
Rotation::Degree0 => {
(LayoutTransform::translation(-size.width / 2., -size.height / 2., 0.), Angle::degrees(0.))
(LayoutTransform::create_translation(-size.width / 2., -size.height / 2., 0.), Angle::degrees(0.))
},
Rotation::Degree90 => {
(LayoutTransform::translation(-size.height / 2., -size.width / 2., 0.), Angle::degrees(90.))
(LayoutTransform::create_translation(-size.height / 2., -size.width / 2., 0.), Angle::degrees(90.))
},
Rotation::Degree180 => {
(LayoutTransform::translation(-size.width / 2., -size.height / 2., 0.), Angle::degrees(180.))
(LayoutTransform::create_translation(-size.width / 2., -size.height / 2., 0.), Angle::degrees(180.))
},
Rotation::Degree270 => {
(LayoutTransform::translation(-size.height / 2., -size.width / 2., 0.), Angle::degrees(270.))
(LayoutTransform::create_translation(-size.height / 2., -size.width / 2., 0.), Angle::degrees(270.))
},
};
let shift_origin_to_center = LayoutTransform::translation(size.width / 2., size.height / 2., 0.);
let shift_origin_to_center = LayoutTransform::create_translation(size.width / 2., size.height / 2., 0.);
shift_center_to_origin
.then(&LayoutTransform::rotation(0., 0., -1.0, angle))
.then(&shift_origin_to_center)
LayoutTransform::create_rotation(0., 0., -1.0, angle)
.pre_transform(&shift_center_to_origin)
.post_transform(&shift_origin_to_center)
}
}

View File

@ -516,9 +516,8 @@ where
match (*self, *other) {
(All, rect) | (rect, All) => rect,
(Partial(rect1), Partial(rect2)) => {
Partial(rect1.intersection(&rect2).unwrap_or_else(Rect::zero))
}
(Partial(rect1), Partial(rect2)) => Partial(rect1.intersection(&rect2)
.unwrap_or_else(Rect::zero))
}
}
@ -527,10 +526,9 @@ where
use crate::DirtyRect::*;
match *self {
All => *rect,
Partial(dirty_rect) => {
dirty_rect.intersection(rect).unwrap_or_else(Rect::zero)
}
All => *rect,
Partial(dirty_rect) => dirty_rect.intersection(rect)
.unwrap_or_else(Rect::zero),
}
}
}

View File

@ -592,12 +592,13 @@ pub fn compute_valid_tiles_if_bounds_change(
new_rect: &DeviceIntRect,
tile_size: u16,
) -> Option<TileRange> {
let intersection = match prev_rect.intersection(new_rect) {
Some(rect) => rect,
None => {
return Some(TileRange::zero());
}
};
let intersection = prev_rect.intersection(new_rect);
if intersection.is_none() {
return Some(TileRange::zero());
}
let intersection = intersection.unwrap_or_else(DeviceIntRect::zero);
let left = prev_rect.min_x() != new_rect.min_x();
let right = prev_rect.max_x() != new_rect.max_x();

View File

@ -291,12 +291,13 @@ fn compute_valid_tiles_if_bounds_change(
new_rect: &DeviceIntRect,
tile_size: u16,
) -> Option<TileRange> {
let intersection = match prev_rect.intersection(new_rect) {
Some(rect) => rect,
None => {
return Some(TileRange::zero());
}
};
let intersection = prev_rect.intersection(new_rect);
if intersection.is_none() {
return Some(TileRange::zero());
}
let intersection = intersection.unwrap_or_else(DeviceIntRect::zero);
let left = prev_rect.min_x() != new_rect.min_x();
let right = prev_rect.max_x() != new_rect.max_x();

View File

@ -11,4 +11,4 @@ path = "lib.rs"
[dependencies]
app_units = "0.7"
euclid = "0.22"
euclid = "0.20"

View File

@ -11,7 +11,7 @@ base64 = "0.10"
bincode = "1.0"
byteorder = "1.0"
env_logger = { version = "0.5", optional = true }
euclid = "0.22"
euclid = "0.20"
gleam = "0.12"
glutin = "0.21"
app_units = "0.7"

View File

@ -6,7 +6,7 @@
root:
items:
- type: stacking-context
transform: rotate-z(-45) rotate-x(-60)
transform: rotate-z(45) rotate-x(60)
transform-origin: 300 300
items:
- type: box-shadow

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -6,7 +6,7 @@ root:
bounds: [0, 0, 0, 0]
"clip-rect": [0, 0, 0, 0]
type: "stacking-context"
transform: rotate(-45) translate(200, 0)
transform: rotate(45) translate(200, 0)
items:
-
bounds: [0, 0, 300, 300]
@ -23,7 +23,7 @@ root:
"clip-rect": [0, 0, 0, 0]
clip-and-scroll: 5
type: "stacking-context"
transform: rotate(45) translate(-300, 0)
transform: rotate(-45) translate(-300, 0)
items:
-
bounds: [0, 0, 1598, 1200]

View File

@ -14,7 +14,7 @@ root:
-
bounds: [0, 0, 0, 0]
type: "stacking-context"
transform: rotate(-15) translate(200, 0)
transform: rotate(15) translate(200, 0)
items:
-
bounds: [0, 0, 1000, 1000]

View File

@ -30,7 +30,7 @@ root:
-
bounds: [0, 0, 200, 200]
type: stacking-context
transform: rotate(-90)
transform: rotate(90)
items:
- type: clip
id: 3

View File

@ -1,4 +1,4 @@
platform(linux,mac) == border-with-rounded-clip.yaml border-with-rounded-clip.png
platform(linux,mac) == border-with-rounded-clip.yaml border-with-rounded-clip.png
== clip-mode.yaml clip-mode.png
== clip-ellipse.yaml clip-ellipse.png
platform(linux,mac) == clip-45-degree-rotation.yaml clip-45-degree-rotation-ref.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View File

@ -14,7 +14,7 @@ root:
bounds: 0 0 256 256
- type: stacking-context
bounds: 50 50 0 0
transform: ["rotate-y(-50)", "rotate-z(-45)"]
transform: ["rotate-y(50)", "rotate-z(45)"]
items:
- type: clip
id: 2

View File

@ -8,7 +8,7 @@ root:
clip-rect: 10 0 300 300
- type: stacking-context
bounds: 30 30 0 0
transform: rotate-z(-45)
transform: rotate-z(45)
filters: drop-shadow([15, 0], 0, red)
clip-node: 2
items:

View File

@ -13,7 +13,7 @@ root:
items:
- type: stacking-context
bounds: [50, -10, 200, 100]
transform: rotate-z(-90)
transform: rotate-z(90)
items:
-
bounds: [0, 0, 500, 150]
@ -26,7 +26,7 @@ root:
- type: stacking-context
bounds: [150, 35, 200, 100]
filters: drop-shadow([200, 10], 5, red)
transform: rotate-z(-90)
transform: rotate-z(90)
items:
-
bounds: [0, 0, 500, 150]

View File

@ -3,7 +3,7 @@ root:
items:
- type: stacking-context
bounds: [0, 100, 300, 300]
transform: scale-x(0.1) rotate-z(-45)
transform: scale-x(0.1) rotate-z(45)
filter-primitives:
- type: blur
width: 10

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -8,7 +8,7 @@ root:
items:
- type: "stacking-context"
transform-origin: 0 250
transform: rotate-x(-15)
transform: rotate-x(15)
filter-primitives:
- type: drop-shadow
color: red

View File

@ -9,7 +9,7 @@ root:
items:
- type: stacking-context
bounds: [0, 0, 600, 600]
transform: rotate-x(-60.0)
transform: rotate-x(60.0)
items:
- type: rect
bounds: [000, 0, 600, 600]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -7,7 +7,7 @@ root:
items:
- type: "stacking-context"
transform-style: preserve-3d
transform: rotate-y(-30) rotate-x(-75) translate(-100, 100, 0)
transform: rotate-y(30) rotate-x(75) translate(-100, 100, 0)
items:
- type: "stacking-context"
perspective: 400
@ -25,7 +25,7 @@ root:
color: 255 0 0 1.0000
- type: stacking-context
bounds: [0, 0, 600, 600]
transform: rotate-z(-90)
transform: rotate-z(90)
items:
-
bounds: [0, 200, 150, 200]

View File

@ -10,14 +10,14 @@ root:
items:
- type: stacking-context
bounds: [0, 0, 600, 600]
transform: rotate-y(-60.0)
transform: rotate-y(60.0)
items:
- type: rect
bounds: [0, 0, 600, 600]
color: [255, 0, 0, 0.5]
- type: stacking-context
bounds: [0, 0, 600, 600]
transform: rotate-y(60.0)
transform: rotate-y(-60.0)
items:
- type: rect
bounds: [0, 0, 600, 600]

View File

@ -10,7 +10,7 @@ root:
bounds: 0 0 100 100
color: red
- type: stacking-context
transform: rotate-y(-0.1)
transform: rotate-y(0.1)
bounds: 0 0 100 100
items:
- type: rect

View File

@ -2,7 +2,7 @@ root:
items:
- type: stacking-context
bounds: [0, 0, 660, 210]
transform: scale(1.5, 2.5) rotate(-10)
transform: scale(1.5, 2.5) rotate(10)
items:
- text: "a Bcd Efgh Ijklm Nopqrs Tuvwxyz"
origin: 20 50

View File

@ -1,7 +1,7 @@
root:
items:
- type: stacking-context
transform: scale(5.0) rotate(-45)
transform: scale(5.0) rotate(45)
transform-origin: 300 300
raster-space: local(1.0)
items:
@ -10,7 +10,7 @@ root:
size: 20
font: "FreeSans.ttf"
- type: stacking-context
transform: scale(5.0) rotate(-45)
transform: scale(5.0) rotate(45)
transform-origin: 0 400
items:
- text: "Screen"
@ -18,7 +18,7 @@ root:
size: 20
font: "FreeSans.ttf"
- type: stacking-context
transform: scale(5.0) rotate(-45)
transform: scale(5.0) rotate(45)
transform-origin: -80 240
raster-space: local(5.0)
items:

View File

@ -3,7 +3,7 @@
root:
items:
- type: stacking-context
transform: rotate(-30)
transform: rotate(30)
transform-origin: 80 80
items:
-
@ -38,7 +38,7 @@ root:
items:
- type: "stacking-context"
transform-origin: 235 235
transform: rotate-x(-15)
transform: rotate-x(15)
items:
-
type: "shadow"

View File

@ -2,7 +2,7 @@ root:
items:
- type: stacking-context
bounds: [0, 0, 430, 330]
transform: rotate(-30)
transform: rotate(30)
items:
- text: "a Bcd Efgh Ijklm Nopqrs Tuvwxyz"
origin: 50 200

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -3,7 +3,7 @@ root:
items:
- type: stacking-context
bounds: [50, 50, 100, 100]
transform: rotate(-30)
transform: rotate(30)
items:
- type: border
bounds: [ 10, 10, 100, 100 ]

View File

@ -9,7 +9,7 @@ root:
items:
-
type: "stacking-context"
transform: rotate-x(-45) translate(100, 100, 0)
transform: rotate-x(45) translate(100, 100, 0)
"transform-style": "preserve-3d"
items:
-

View File

@ -6,7 +6,7 @@ root:
perspective: 20
items:
- type: stacking-context
transform: rotate-z(-45) rotate-x(-45)
transform: rotate-z(45) rotate-x(45)
filters: drop-shadow([0, 0], 10000, blue)
items:
- type: rect

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -11,7 +11,7 @@ root:
bounds: [0, 0, 0, 0]
"clip-and-scroll": 3
type: "stacking-context"
transform: rotate(-45) translate(200, 200)
transform: rotate(45) translate(200, 200)
items:
-
bounds: [0, 0, 100, 100]

View File

@ -10,7 +10,7 @@ root:
-
bounds: [0, 0, 1000, 1000]
type: "stacking-context"
transform: rotate-x(30)
transform: rotate-x(-30)
items:
-
bounds: [350, 200, 260, 300]

View File

@ -9,7 +9,7 @@ root:
-
bounds: [128, 128, 256, 256]
type: "stacking-context"
transform: rotate-x(-60) rotate-y(-120)
transform: rotate-x(60) rotate-y(120)
items:
-
bounds: [128, 128, 256, 256]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -17,7 +17,7 @@ root:
items:
-
type: "stacking-context"
transform: rotate-x(-10)
transform: rotate-x(10)
transform-origin: 300 300
filters: identity
items:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -14,7 +14,7 @@ root:
-
type: "stacking-context"
bounds: [0, 0, 250, 100]
transform: rotate-y(54)
transform: rotate-y(-54)
items:
-
bounds: [0, 0, 128, 128]

View File

@ -9,7 +9,7 @@ root:
-
bounds: [0, 0, 1000, 1000]
type: "stacking-context"
transform: rotate-x(-45)
transform: rotate-x(45)
items:
-
bounds: [350, 400, 260, 260]

View File

@ -3,7 +3,7 @@ root:
items:
- type: stacking-context
bounds: [50, 50, 100, 100]
transform: rotate(-30)
transform: rotate(30)
items:
- type: rect
bounds: [ 10, 10, 80, 80 ]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -14,4 +14,4 @@ root:
bounds: 20 20 200 200
color: blue
type: stacking-context
transform: rotate(-33)
transform: rotate(33)

View File

@ -14,4 +14,4 @@ root:
bounds: 20 20 100 100
color: blue
type: stacking-context
transform: rotate(-30)
transform: rotate(30)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@ -44,7 +44,7 @@ root:
"backface-visible": true
type: "stacking-context"
"scroll-policy": scrollable
transform: rotate-z(-1)
transform: rotate-z(1)
"transform-style": flat
items:
-

View File

@ -10,13 +10,13 @@ root:
items:
- type: "stacking-context"
transform-origin: 235 235
transform: rotate-x(-15)
transform: rotate-x(15)
items:
- image: checkerboard(2, 16, 16)
bounds: [100, 100, 260, 260]
- type: "stacking-context"
transform-origin: 635 235
transform: rotate-z(-45)
transform: rotate-z(45)
items:
- image: checkerboard(2, 16, 16)
bounds: [500, 100, 260, 260]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -9,14 +9,14 @@ root:
items:
- type: "stacking-context"
transform-origin: 235 235
transform: rotate-x(-15)
transform: rotate-x(15)
filters: identity
items:
- image: checkerboard(2, 16, 16)
bounds: [100, 100, 260, 260]
- type: "stacking-context"
transform-origin: 635 235
transform: rotate-z(-45)
transform: rotate-z(45)
items:
- image: checkerboard(2, 16, 16)
bounds: [500, 100, 260, 260]

View File

@ -6,14 +6,14 @@ root:
items:
- type: "stacking-context"
transform-origin: 235 235
transform: rotate-x(-15)
transform: rotate-x(15)
filters: blur(3, 3)
items:
- image: checkerboard(2, 16, 16)
bounds: [100, 100, 260, 260]
- type: "stacking-context"
transform-origin: 635 235
transform: rotate-z(-45)
transform: rotate-z(45)
filters: blur(3, 3)
items:
- image: checkerboard(2, 16, 16)

View File

@ -172,24 +172,24 @@ fn make_rotation(
axis_y: f32,
axis_z: f32,
) -> LayoutTransform {
let pre_transform = LayoutTransform::translation(-origin.x, -origin.y, -0.0);
let post_transform = LayoutTransform::translation(origin.x, origin.y, 0.0);
let pre_transform = LayoutTransform::create_translation(origin.x, origin.y, 0.0);
let post_transform = LayoutTransform::create_translation(-origin.x, -origin.y, -0.0);
let theta = 2.0f32 * f32::consts::PI - degrees.to_radians();
let transform =
LayoutTransform::identity().pre_rotate(axis_x, axis_y, axis_z, Angle::radians(theta));
pre_transform.then(&transform).then(&post_transform)
pre_transform.pre_transform(&transform).pre_transform(&post_transform)
}
pub fn make_perspective(
origin: LayoutPoint,
perspective: f32,
) -> LayoutTransform {
let pre_transform = LayoutTransform::translation(-origin.x, -origin.y, -0.0);
let post_transform = LayoutTransform::translation(origin.x, origin.y, 0.0);
let transform = LayoutTransform::perspective(perspective);
pre_transform.then(&transform).then(&post_transform)
let pre_transform = LayoutTransform::create_translation(origin.x, origin.y, 0.0);
let post_transform = LayoutTransform::create_translation(-origin.x, -origin.y, -0.0);
let transform = LayoutTransform::create_perspective(perspective);
pre_transform.pre_transform(&transform).pre_transform(&post_transform)
}
// Create a skew matrix, specified in degrees.
@ -199,7 +199,7 @@ fn make_skew(
) -> LayoutTransform {
let alpha = Angle::radians(skew_x.to_radians());
let beta = Angle::radians(skew_y.to_radians());
LayoutTransform::skew(alpha, beta)
LayoutTransform::create_skew(alpha, beta)
}
impl YamlHelper for Yaml {
@ -327,11 +327,23 @@ impl YamlHelper for Yaml {
fn as_matrix4d(&self) -> Option<LayoutTransform> {
if let Some(nums) = self.as_vec_f32() {
assert_eq!(nums.len(), 16, "expected 16 floats, got '{:?}'", self);
Some(LayoutTransform::new(
nums[0], nums[1], nums[2], nums[3],
nums[4], nums[5], nums[6], nums[7],
nums[8], nums[9], nums[10], nums[11],
nums[12], nums[13], nums[14], nums[15],
Some(LayoutTransform::row_major(
nums[0],
nums[1],
nums[2],
nums[3],
nums[4],
nums[5],
nums[6],
nums[7],
nums[8],
nums[9],
nums[10],
nums[11],
nums[12],
nums[13],
nums[14],
nums[15],
))
} else {
None
@ -353,7 +365,7 @@ impl YamlHelper for Yaml {
let mx = match function {
"translate" if args.len() >= 2 => {
let z = args.get(2).and_then(|a| a.parse().ok()).unwrap_or(0.);
LayoutTransform::translation(
LayoutTransform::create_translation(
args[0].parse().unwrap(),
args[1].parse().unwrap(),
z,
@ -374,16 +386,16 @@ impl YamlHelper for Yaml {
let y = args.get(1).and_then(|a| a.parse().ok()).unwrap_or(x);
// Default to no Z scale if unspecified.
let z = args.get(2).and_then(|a| a.parse().ok()).unwrap_or(1.0);
LayoutTransform::scale(x, y, z)
LayoutTransform::create_scale(x, y, z)
}
"scale-x" if args.len() == 1 => {
LayoutTransform::scale(args[0].parse().unwrap(), 1.0, 1.0)
LayoutTransform::create_scale(args[0].parse().unwrap(), 1.0, 1.0)
}
"scale-y" if args.len() == 1 => {
LayoutTransform::scale(1.0, args[0].parse().unwrap(), 1.0)
LayoutTransform::create_scale(1.0, args[0].parse().unwrap(), 1.0)
}
"scale-z" if args.len() == 1 => {
LayoutTransform::scale(1.0, 1.0, args[0].parse().unwrap())
LayoutTransform::create_scale(1.0, 1.0, args[0].parse().unwrap())
}
"skew" if args.len() >= 1 => {
// Default to no Y skew if unspecified.
@ -397,14 +409,14 @@ impl YamlHelper for Yaml {
make_skew(0.0, args[0].parse().unwrap())
}
"perspective" if args.len() == 1 => {
LayoutTransform::perspective(args[0].parse().unwrap())
LayoutTransform::create_perspective(args[0].parse().unwrap())
}
_ => {
println!("unknown function {}", function);
break;
}
};
transform = transform.then(&mx);
transform = transform.post_transform(&mx);
}
Some(transform)
}
@ -412,7 +424,7 @@ impl YamlHelper for Yaml {
let transform = array.iter().fold(
LayoutTransform::identity(),
|u, yaml| match yaml.as_transform(transform_origin) {
Some(ref transform) => transform.then(&u),
Some(ref transform) => u.pre_transform(transform),
None => u,
},
);

View File

@ -32,7 +32,7 @@ app_units = "0.7"
content-security-policy = { version = "0.4.0", features = ["serde"], optional = true }
crossbeam-channel = { version = "0.4", optional = true }
cssparser = "0.27"
euclid = "0.22"
euclid = "0.20"
hashglobe = { path = "../hashglobe" }
hyper = { version = "0.12", optional = true }
hyper_serde = { version = "0.11", optional = true }

View File

@ -37,7 +37,7 @@ cssparser = "0.27"
derive_more = "0.99"
new_debug_unreachable = "1.0"
encoding_rs = {version = "0.8", optional = true}
euclid = "0.22"
euclid = "0.20"
fallible = { path = "../fallible" }
fxhash = "0.2"
hashbrown = "0.7"

View File

@ -76,7 +76,7 @@ pub use self::GenericMatrix3D as Matrix3D;
impl<T: Into<f64>> From<Matrix<T>> for Transform3D<f64> {
#[inline]
fn from(m: Matrix<T>) -> Self {
Transform3D::new(
Transform3D::row_major(
m.a.into(), m.b.into(), 0.0, 0.0,
m.c.into(), m.d.into(), 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
@ -89,7 +89,7 @@ impl<T: Into<f64>> From<Matrix<T>> for Transform3D<f64> {
impl<T: Into<f64>> From<Matrix3D<T>> for Transform3D<f64> {
#[inline]
fn from(m: Matrix3D<T>) -> Self {
Transform3D::new(
Transform3D::row_major(
m.m11.into(), m.m12.into(), m.m13.into(), m.m14.into(),
m.m21.into(), m.m22.into(), m.m23.into(), m.m24.into(),
m.m31.into(), m.m32.into(), m.m33.into(), m.m34.into(),
@ -443,14 +443,15 @@ where
use self::TransformOperation::*;
use std::f64;
const TWO_PI: f64 = 2.0f64 * f64::consts::PI;
let reference_width = reference_box.map(|v| v.size.width);
let reference_height = reference_box.map(|v| v.size.height);
let matrix = match *self {
Rotate3D(ax, ay, az, theta) => {
let theta = theta.radians64();
let theta = TWO_PI - theta.radians64();
let (ax, ay, az, theta) =
get_normalized_vector_and_angle(ax.into(), ay.into(), az.into(), theta);
Transform3D::rotation(
Transform3D::create_rotation(
ax as f64,
ay as f64,
az as f64,
@ -458,56 +459,56 @@ where
)
},
RotateX(theta) => {
let theta = euclid::Angle::radians(theta.radians64());
Transform3D::rotation(1., 0., 0., theta)
let theta = euclid::Angle::radians(TWO_PI - theta.radians64());
Transform3D::create_rotation(1., 0., 0., theta)
},
RotateY(theta) => {
let theta = euclid::Angle::radians(theta.radians64());
Transform3D::rotation(0., 1., 0., theta)
let theta = euclid::Angle::radians(TWO_PI - theta.radians64());
Transform3D::create_rotation(0., 1., 0., theta)
},
RotateZ(theta) | Rotate(theta) => {
let theta = euclid::Angle::radians(theta.radians64());
Transform3D::rotation(0., 0., 1., theta)
let theta = euclid::Angle::radians(TWO_PI - theta.radians64());
Transform3D::create_rotation(0., 0., 1., theta)
},
Perspective(ref d) => {
let m = create_perspective_matrix(d.to_pixel_length(None)?);
m.cast()
},
Scale3D(sx, sy, sz) => Transform3D::scale(sx.into(), sy.into(), sz.into()),
Scale(sx, sy) => Transform3D::scale(sx.into(), sy.into(), 1.),
ScaleX(s) => Transform3D::scale(s.into(), 1., 1.),
ScaleY(s) => Transform3D::scale(1., s.into(), 1.),
ScaleZ(s) => Transform3D::scale(1., 1., s.into()),
Scale3D(sx, sy, sz) => Transform3D::create_scale(sx.into(), sy.into(), sz.into()),
Scale(sx, sy) => Transform3D::create_scale(sx.into(), sy.into(), 1.),
ScaleX(s) => Transform3D::create_scale(s.into(), 1., 1.),
ScaleY(s) => Transform3D::create_scale(1., s.into(), 1.),
ScaleZ(s) => Transform3D::create_scale(1., 1., s.into()),
Translate3D(ref tx, ref ty, ref tz) => {
let tx = tx.to_pixel_length(reference_width)? as f64;
let ty = ty.to_pixel_length(reference_height)? as f64;
Transform3D::translation(tx, ty, tz.to_pixel_length(None)? as f64)
Transform3D::create_translation(tx, ty, tz.to_pixel_length(None)? as f64)
},
Translate(ref tx, ref ty) => {
let tx = tx.to_pixel_length(reference_width)? as f64;
let ty = ty.to_pixel_length(reference_height)? as f64;
Transform3D::translation(tx, ty, 0.)
Transform3D::create_translation(tx, ty, 0.)
},
TranslateX(ref t) => {
let t = t.to_pixel_length(reference_width)? as f64;
Transform3D::translation(t, 0., 0.)
Transform3D::create_translation(t, 0., 0.)
},
TranslateY(ref t) => {
let t = t.to_pixel_length(reference_height)? as f64;
Transform3D::translation(0., t, 0.)
Transform3D::create_translation(0., t, 0.)
},
TranslateZ(ref z) => {
Transform3D::translation(0., 0., z.to_pixel_length(None)? as f64)
Transform3D::create_translation(0., 0., z.to_pixel_length(None)? as f64)
},
Skew(theta_x, theta_y) => Transform3D::skew(
Skew(theta_x, theta_y) => Transform3D::create_skew(
euclid::Angle::radians(theta_x.radians64()),
euclid::Angle::radians(theta_y.radians64()),
),
SkewX(theta) => Transform3D::skew(
SkewX(theta) => Transform3D::create_skew(
euclid::Angle::radians(theta.radians64()),
euclid::Angle::radians(0.),
),
SkewY(theta) => Transform3D::skew(
SkewY(theta) => Transform3D::create_skew(
euclid::Angle::radians(0.),
euclid::Angle::radians(theta.radians64()),
),
@ -546,7 +547,7 @@ impl<T: ToMatrix> Transform<T> {
let cast_3d_transform = |m: Transform3D<f64>| -> Transform3D<CSSFloat> {
use std::{f32, f64};
let cast = |v: f64| { v.min(f32::MAX as f64).max(f32::MIN as f64) as f32 };
Transform3D::new(
Transform3D::row_major(
cast(m.m11), cast(m.m12), cast(m.m13), cast(m.m14),
cast(m.m21), cast(m.m22), cast(m.m23), cast(m.m24),
cast(m.m31), cast(m.m32), cast(m.m33), cast(m.m34),
@ -564,7 +565,7 @@ impl<T: ToMatrix> Transform<T> {
reference_box: Option<&Rect<ComputedLength>>,
) -> Result<(Transform3D<f64>, bool), ()> {
// We intentionally use Transform3D<f64> during computation to avoid error propagation
// because using f32 to compute triangle functions (e.g. in rotation()) is not
// because using f32 to compute triangle functions (e.g. in create_rotation()) is not
// accurate enough. In Gecko, we also use "double" to compute the triangle functions.
// Therefore, let's use Transform3D<f64> during matrix computation and cast it into f32
// in the end.
@ -574,7 +575,7 @@ impl<T: ToMatrix> Transform<T> {
for operation in &*self.0 {
let matrix = operation.to_3d_matrix(reference_box)?;
contain_3d |= operation.is_3d();
transform = matrix.then(&transform);
transform = transform.pre_transform(&matrix);
}
Ok((transform, contain_3d))
@ -594,7 +595,7 @@ pub fn create_perspective_matrix(d: CSSFloat) -> Transform3D<CSSFloat> {
if d <= 0.0 {
Transform3D::identity()
} else {
Transform3D::perspective(d)
Transform3D::create_perspective(d)
}
}

View File

@ -17,7 +17,7 @@ gecko = []
app_units = "0.7"
bitflags = "1.0"
cssparser = "0.27"
euclid = "0.22"
euclid = "0.20"
lazy_static = "1"
malloc_size_of = { path = "../malloc_size_of" }
malloc_size_of_derive = "0.1"

View File

@ -6566,7 +6566,7 @@ pub extern "C" fn Servo_ParseTransformIntoMatrix(
Err(..) => return false,
};
*result = m.to_array();
*result = m.to_row_major_array();
*contain_3d = is_3d;
true
}

View File

@ -13,7 +13,7 @@ doctest = false
byteorder = "1.0"
app_units = "0.7"
cssparser = "0.27"
euclid = "0.22"
euclid = "0.20"
html5ever = "0.22"
parking_lot = "0.10"
rayon = "1"

View File

@ -1 +1 @@
{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"a86dfb641b12e15efe3e2b40a2061c27b9347b38a315700773d7af2c6acccc96","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/angle.rs":"b4b17c16bd135914a6e2ebad54b9cbb8ea475d5992bcb75c397b7813b6f7b8dd","src/approxeq.rs":"8ad9ab7336e1924b0543eb46f975367f4388a4dda91839b7cda7d21eec8991fb","src/approxord.rs":"f1b11ea7603b3dddb0002c7ded934816f5a8bb108e150028b49595b8e3382ac1","src/box2d.rs":"2566d13d8823c13eaab68bbeabe371fa507497d07b3638e5c501cd73cb2a5251","src/box3d.rs":"a96e6b4cbae217095fcbc997db9f7dfafe813d84856bc0a02abbbb6bc881eac7","src/homogen.rs":"57c08e6e5d0bf87c724eb074c624a6557170f9d695ef1ed1a4b2677069dbbaa4","src/length.rs":"6972f49203c0256287dbf5119124ad64e2cf001574995bfaed8cd21e4a19f17c","src/lib.rs":"ebf2023c1e1bd397a4ae135a14657d00757c9ad4094d32d65848a1d5e061df7a","src/macros.rs":"3b475e84d00cceee6c7e96e9f2c97ba15d8dc7f4094efb82c5ed10bd60d86a64","src/num.rs":"27ef5975c2149f4c1a4659ae1dd9fc86618579ec985361130ea9fdc891fcfae3","src/point.rs":"db1beb1e581261a8077669c0a69973c35100163e1b98e6b720b0af331a951345","src/rect.rs":"83ce34da75dc570d8f62700d283adfda419a98ea2d0fc691dedc4389c574dd46","src/rigid.rs":"e9b39039df2882d5b8d5a28305ddb40f7c59a9401af615b842f485a62af12217","src/rotation.rs":"6ed0b5793fdd3d557e98e9523e506786c337c98ae61a3f7773bbd934922803a9","src/scale.rs":"c26ad154ace1647196eb1a19c0c26c22c461322c643c22b9b260392443688299","src/side_offsets.rs":"b795816fe6cc027692bbb5704eebe48d8556619f837ce75de34ca6acf8502ef9","src/size.rs":"17002e23cc424c04d288f65e5f6493759ea7bfb2b0a749131c1a3561d2e3def4","src/transform2d.rs":"505f47b58a96a64804d027d21ebf28c75c80c7d2975760d6d2cadbefb7c4605c","src/transform3d.rs":"e8221391475208af1430ad3a432e972fe45cec68e10103a57af7197f11e034f8","src/translation.rs":"8500a10ed37447fbc41a4a1f554c08095f055c36b4e0a637d7c07505fe2570a2","src/trig.rs":"ab09a8503d04ac1d0d6848d074ac18a22d324184e5bb186bbd4287c977894886","src/vector.rs":"2f573f1587c8f119c45c8822c81d3fe5aa6113cad51be4d19eea73d8058b91dd"},"package":"7ab0e07e345fb061928646949fdf5fb888e5d75a57385e7f5856e45be289e745"}
{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"430f53fbae7381f12155805f713f9b9bb08a9e9ffff3a3f4c887163fb4521e7d","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/angle.rs":"b4b17c16bd135914a6e2ebad54b9cbb8ea475d5992bcb75c397b7813b6f7b8dd","src/approxeq.rs":"8ad9ab7336e1924b0543eb46f975367f4388a4dda91839b7cda7d21eec8991fb","src/approxord.rs":"f1b11ea7603b3dddb0002c7ded934816f5a8bb108e150028b49595b8e3382ac1","src/box2d.rs":"0f7ef877183e25e6b769fc91a0d814e0992b0e6d1c16df415ebbd364d2fd2cf7","src/box3d.rs":"54d6e59622957e784e611a23da9612671a530c61cd364313024d750f953a7564","src/homogen.rs":"3aa960fae9b817057013183f543cf2adc042f5867ece1ee78607e2c46bdbcfed","src/length.rs":"67ef01cfba3f70143c57afda39c8bf9990f29111a031a238de328753ccc2c8a4","src/lib.rs":"d0f1ddda70d8bf3913d9c2c49949dd21ced500cbc0c09d7d08c0aa1570f63df5","src/macros.rs":"3b475e84d00cceee6c7e96e9f2c97ba15d8dc7f4094efb82c5ed10bd60d86a64","src/nonempty.rs":"be5ac81321390d71447607de01811cc6420bcd48aa5274f7a298a99674621846","src/num.rs":"2478501dbe545a73a8b964f4713987b86df8ff0af3d1aba0571cbd00a4e9cbaa","src/point.rs":"6d07046f27dd7a18ba8db8988de82c67cfcdd1b8895a70730123338574e47d39","src/rect.rs":"1391359581ba891a35f390ec3900f1e34ce1e4dc5608fe27662655d3bf443d45","src/rigid.rs":"a9717aac4d254299dc3a60a2a32c5c5309044136702d96030533f7639adeb467","src/rotation.rs":"6cfc7f74a90236c53fa55b83eae373146f7b37a8c400f8f820ebfdbcca245245","src/scale.rs":"197d2d4ba5f6a4fe8d5f0b2b6684499a66727129ad27474b85b0d1ffecd38f05","src/side_offsets.rs":"11b84a7dc620cdf2f1877c82b534947ae337734b9075d34e61306be7f458d127","src/size.rs":"5d5703b464207ff362da650008972ca67fbbc79f7193d0d2a1c7a7873221c24c","src/transform2d.rs":"6b2ff21021d7aa1628585650cc66f18f1a5a6aff5f335ae1ec4f63616c54b3cf","src/transform3d.rs":"83ac57ab5a077127fa7eba401dae2e67f2c129a05081b5b5ed09a2166fa9703f","src/translation.rs":"7847306a3a081559f2839baff9d622e58c63fdcb3981c5ef410b6a8eb8e13ab8","src/trig.rs":"ab09a8503d04ac1d0d6848d074ac18a22d324184e5bb186bbd4287c977894886","src/vector.rs":"f895e029e273defac88b47fef4fb27f627553fb05b8d173cf8f75e28818cd580"},"package":"2bb7ef65b3777a325d1eeefefab5b6d4959da54747e33bd6258e789640f307ad"}

View File

@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "euclid"
version = "0.22.0"
version = "0.20.14"
authors = ["The Servo Project Developers"]
description = "Geometry primitives"
documentation = "https://docs.rs/euclid/"

View File

@ -9,6 +9,7 @@
use super::UnknownUnit;
use crate::approxord::{max, min};
use crate::nonempty::NonEmpty;
use crate::num::*;
use crate::point::{point2, Point2D};
use crate::rect::Rect;
@ -27,15 +28,15 @@ use core::fmt;
use core::hash::{Hash, Hasher};
use core::ops::{Add, Div, DivAssign, Mul, MulAssign, Sub};
/// A 2d axis aligned rectangle represented by its minimum and maximum coordinates.
/// An axis aligned rectangle represented by its minimum and maximum coordinates.
///
/// # Representation
///
/// This struct is similar to [`Rect`], but stores rectangle as two endpoints
/// That struct is similar to the [`Rect`] struct, but stores rectangle as two corners
/// instead of origin point and size. Such representation has several advantages over
/// [`Rect`] representation:
/// - Several operations are more efficient with `Box2D`, including [`intersection`],
/// [`union`], and point-in-rect.
/// - The representation is more symmetric, since it stores two quantities of the
/// same kind (two points) rather than a point and a dimension (width/height).
/// - The representation is less susceptible to overflow. With [`Rect`], computation
/// of second point can overflow for a large range of values of origin and size.
/// However, with `Box2D`, computation of [`size`] cannot overflow if the coordinates
@ -44,16 +45,8 @@ use core::ops::{Add, Div, DivAssign, Mul, MulAssign, Sub};
/// A known disadvantage of `Box2D` is that translating the rectangle requires translating
/// both points, whereas translating [`Rect`] only requires translating one point.
///
/// # Empty box
///
/// A box is considered empty (see [`is_empty`]) if any of the following is true:
/// - it's area is empty,
/// - it's area is negative (`min.x > max.x` or `min.y > max.y`),
/// - it contains NaNs.
///
/// [`Rect`]: struct.Rect.html
/// [`intersection`]: #method.intersection
/// [`is_empty`]: #method.is_empty
/// [`union`]: #method.union
/// [`size`]: #method.size
#[repr(C)]
@ -99,6 +92,16 @@ impl<T: fmt::Debug, U> fmt::Debug for Box2D<T, U> {
}
}
impl<T: fmt::Display, U> fmt::Display for Box2D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Box2D(")?;
fmt::Display::fmt(&self.min, f)?;
write!(f, ", ")?;
fmt::Display::fmt(&self.max, f)?;
write!(f, ")")
}
}
impl<T, U> Box2D<T, U> {
/// Constructor.
#[inline]
@ -120,9 +123,9 @@ where
self.max.x < self.min.x || self.max.y < self.min.y
}
/// Returns true if the size is zero, negative or NaN.
/// Returns true if the size is zero or negative.
#[inline]
pub fn is_empty(&self) -> bool {
pub fn is_empty_or_negative(&self) -> bool {
!(self.max.x > self.min.x && self.max.y > self.min.y)
}
@ -148,7 +151,7 @@ where
/// nonempty but this box is empty.
#[inline]
pub fn contains_box(&self, other: &Self) -> bool {
other.is_empty()
other.is_empty_or_negative()
|| (self.min.x <= other.min.x
&& other.max.x <= self.max.x
&& self.min.y <= other.min.y
@ -161,40 +164,36 @@ where
T: Copy + PartialOrd,
{
#[inline]
pub fn to_non_empty(&self) -> Option<Self> {
if self.is_empty() {
pub fn to_non_empty(&self) -> Option<NonEmpty<Self>> {
if self.is_empty_or_negative() {
return None;
}
Some(*self)
Some(NonEmpty(*self))
}
/// Computes the intersection of two boxes, returning `None` if the boxes do not intersect.
#[inline]
pub fn intersection(&self, other: &Self) -> Option<Self> {
let b = self.intersection_unchecked(other);
if b.is_empty() {
return None;
}
Some(b)
}
/// Computes the intersection of two boxes without check whether they do intersect.
/// Computes the intersection of two boxes.
///
/// The result is a negative box if the boxes do not intersect.
/// This can be useful for computing the intersection of more than two boxes, as
/// it is possible to chain multiple intersection_unchecked calls and check for
/// empty/negative result at the end.
#[inline]
pub fn intersection_unchecked(&self, other: &Self) -> Self {
pub fn intersection(&self, other: &Self) -> Self {
Box2D {
min: point2(max(self.min.x, other.min.x), max(self.min.y, other.min.y)),
max: point2(min(self.max.x, other.max.x), min(self.max.y, other.max.y)),
}
}
/// Computes the intersection of two boxes, returning `None` if the boxes do not intersect.
#[inline]
pub fn try_intersection(&self, other: &Self) -> Option<NonEmpty<Self>> {
let intersection = self.intersection(other);
if intersection.is_negative() {
return None;
}
Some(NonEmpty(intersection))
}
#[inline]
pub fn union(&self, other: &Self) -> Self {
Box2D {
@ -373,68 +372,79 @@ where
}
}
impl<T: Copy + Mul, U> Mul<T> for Box2D<T, U> {
impl<T, U> Box2D<T, U>
where
T: PartialEq,
{
/// Returns true if the size is zero.
#[inline]
pub fn is_empty(&self) -> bool {
self.min.x == self.max.x || self.min.y == self.max.y
}
}
impl<T: Clone + Mul, U> Mul<T> for Box2D<T, U> {
type Output = Box2D<T::Output, U>;
#[inline]
fn mul(self, scale: T) -> Self::Output {
Box2D::new(self.min * scale, self.max * scale)
Box2D::new(self.min * scale.clone(), self.max * scale)
}
}
impl<T: Copy + MulAssign, U> MulAssign<T> for Box2D<T, U> {
impl<T: Clone + MulAssign, U> MulAssign<T> for Box2D<T, U> {
#[inline]
fn mul_assign(&mut self, scale: T) {
*self *= Scale::new(scale);
}
}
impl<T: Copy + Div, U> Div<T> for Box2D<T, U> {
impl<T: Clone + Div, U> Div<T> for Box2D<T, U> {
type Output = Box2D<T::Output, U>;
#[inline]
fn div(self, scale: T) -> Self::Output {
Box2D::new(self.min / scale, self.max / scale)
Box2D::new(self.min / scale.clone(), self.max / scale)
}
}
impl<T: Copy + DivAssign, U> DivAssign<T> for Box2D<T, U> {
impl<T: Clone + DivAssign, U> DivAssign<T> for Box2D<T, U> {
#[inline]
fn div_assign(&mut self, scale: T) {
*self /= Scale::new(scale);
}
}
impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Box2D<T, U1> {
impl<T: Clone + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Box2D<T, U1> {
type Output = Box2D<T::Output, U2>;
#[inline]
fn mul(self, scale: Scale<T, U1, U2>) -> Self::Output {
Box2D::new(self.min * scale, self.max * scale)
Box2D::new(self.min * scale.clone(), self.max * scale)
}
}
impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Box2D<T, U> {
impl<T: Clone + MulAssign, U> MulAssign<Scale<T, U, U>> for Box2D<T, U> {
#[inline]
fn mul_assign(&mut self, scale: Scale<T, U, U>) {
self.min *= scale;
self.min *= scale.clone();
self.max *= scale;
}
}
impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Box2D<T, U2> {
impl<T: Clone + Div, U1, U2> Div<Scale<T, U1, U2>> for Box2D<T, U2> {
type Output = Box2D<T::Output, U1>;
#[inline]
fn div(self, scale: Scale<T, U1, U2>) -> Self::Output {
Box2D::new(self.min / scale, self.max / scale)
Box2D::new(self.min / scale.clone(), self.max / scale)
}
}
impl<T: Copy + DivAssign, U> DivAssign<Scale<T, U, U>> for Box2D<T, U> {
impl<T: Clone + DivAssign, U> DivAssign<Scale<T, U, U>> for Box2D<T, U> {
#[inline]
fn div_assign(&mut self, scale: Scale<T, U, U>) {
self.min /= scale;
self.min /= scale.clone();
self.max /= scale;
}
}
@ -663,7 +673,7 @@ mod tests {
#[test]
fn test_round() {
let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round();
assert_eq!(b.min.x, -25.0);
assert_eq!(b.min.x, -26.0);
assert_eq!(b.min.y, -40.0);
assert_eq!(b.max.x, 60.0);
assert_eq!(b.max.y, 37.0);
@ -732,10 +742,10 @@ mod tests {
}
#[test]
fn test_intersection_unchecked() {
fn test_intersection() {
let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]);
let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]);
let b = b1.intersection_unchecked(&b2);
let b = b1.intersection(&b2);
assert_eq!(b.max.x, 10.0);
assert_eq!(b.max.y, 20.0);
assert_eq!(b.min.x, -10.0);
@ -743,14 +753,14 @@ mod tests {
}
#[test]
fn test_intersection() {
fn test_try_intersection() {
let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]);
let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]);
assert!(b1.intersection(&b2).is_some());
assert!(b1.try_intersection(&b2).is_some());
let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(-10.0, 20.0)]);
let b2 = Box2D::from_points(&[point2(10.0, 20.0), point2(15.0, -20.0)]);
assert!(b1.intersection(&b2).is_none());
assert!(b1.try_intersection(&b2).is_none());
}
#[test]
@ -808,11 +818,11 @@ mod tests {
}
#[test]
fn test_nan_empty() {
fn test_nan_empty_or_negative() {
use std::f32::NAN;
assert!(Box2D { min: point2(NAN, 2.0), max: point2(1.0, 3.0) }.is_empty());
assert!(Box2D { min: point2(0.0, NAN), max: point2(1.0, 2.0) }.is_empty());
assert!(Box2D { min: point2(1.0, -2.0), max: point2(NAN, 2.0) }.is_empty());
assert!(Box2D { min: point2(1.0, -2.0), max: point2(0.0, NAN) }.is_empty());
assert!(Box2D { min: point2(NAN, 2.0), max: point2(1.0, 3.0) }.is_empty_or_negative());
assert!(Box2D { min: point2(0.0, NAN), max: point2(1.0, 2.0) }.is_empty_or_negative());
assert!(Box2D { min: point2(1.0, -2.0), max: point2(NAN, 2.0) }.is_empty_or_negative());
assert!(Box2D { min: point2(1.0, -2.0), max: point2(0.0, NAN) }.is_empty_or_negative());
}
}

View File

@ -9,6 +9,7 @@
use super::UnknownUnit;
use crate::approxord::{max, min};
use crate::nonempty::NonEmpty;
use crate::num::*;
use crate::point::{point3, Point3D};
use crate::scale::Scale;
@ -69,6 +70,16 @@ impl<T: fmt::Debug, U> fmt::Debug for Box3D<T, U> {
}
}
impl<T: fmt::Display, U> fmt::Display for Box3D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Box3D(")?;
fmt::Display::fmt(&self.min, f)?;
write!(f, ", ")?;
fmt::Display::fmt(&self.max, f)?;
write!(f, ")")
}
}
impl<T, U> Box3D<T, U> {
/// Constructor.
#[inline]
@ -90,9 +101,9 @@ where
self.max.x < self.min.x || self.max.y < self.min.y || self.max.z < self.min.z
}
/// Returns true if the size is zero, negative or NaN.
/// Returns true if the size is zero or negative.
#[inline]
pub fn is_empty(&self) -> bool {
pub fn is_empty_or_negative(&self) -> bool {
!(self.max.x > self.min.x && self.max.y > self.min.y && self.max.z > self.min.z)
}
@ -124,7 +135,7 @@ where
/// nonempty but this box3d is empty.
#[inline]
pub fn contains_box(&self, other: &Self) -> bool {
other.is_empty()
other.is_empty_or_negative()
|| (self.min.x <= other.min.x
&& other.max.x <= self.max.x
&& self.min.y <= other.min.y
@ -139,26 +150,24 @@ where
T: Copy + PartialOrd,
{
#[inline]
pub fn to_non_empty(&self) -> Option<Self> {
if self.is_empty() {
pub fn to_non_empty(&self) -> Option<NonEmpty<Self>> {
if self.is_empty_or_negative() {
return None;
}
Some(*self)
Some(NonEmpty(*self))
}
#[inline]
pub fn intersection(&self, other: &Self) -> Option<Self> {
let b = self.intersection_unchecked(other);
if b.is_empty() {
pub fn try_intersection(&self, other: &Self) -> Option<NonEmpty<Self>> {
if !self.intersects(other) {
return None;
}
Some(b)
Some(NonEmpty(self.intersection(other)))
}
pub fn intersection_unchecked(&self, other: &Self) -> Self {
pub fn intersection(&self, other: &Self) -> Self {
let intersection_min = Point3D::new(
max(self.min.x, other.min.x),
max(self.min.y, other.min.y),
@ -366,24 +375,35 @@ where
}
}
impl<T: Copy + Mul, U> Mul<T> for Box3D<T, U> {
impl<T, U> Box3D<T, U>
where
T: PartialEq,
{
/// Returns true if the volume is zero.
#[inline]
pub fn is_empty(&self) -> bool {
self.min.x == self.max.x || self.min.y == self.max.y || self.min.z == self.max.z
}
}
impl<T: Clone + Mul, U> Mul<T> for Box3D<T, U> {
type Output = Box3D<T::Output, U>;
#[inline]
fn mul(self, scale: T) -> Self::Output {
Box3D::new(self.min * scale, self.max * scale)
Box3D::new(self.min * scale.clone(), self.max * scale)
}
}
impl<T: Copy + MulAssign, U> MulAssign<T> for Box3D<T, U> {
impl<T: Clone + MulAssign, U> MulAssign<T> for Box3D<T, U> {
#[inline]
fn mul_assign(&mut self, scale: T) {
self.min *= scale;
self.min *= scale.clone();
self.max *= scale;
}
}
impl<T: Copy + Div, U> Div<T> for Box3D<T, U> {
impl<T: Clone + Div, U> Div<T> for Box3D<T, U> {
type Output = Box3D<T::Output, U>;
#[inline]
@ -392,15 +412,15 @@ impl<T: Copy + Div, U> Div<T> for Box3D<T, U> {
}
}
impl<T: Copy + DivAssign, U> DivAssign<T> for Box3D<T, U> {
impl<T: Clone + DivAssign, U> DivAssign<T> for Box3D<T, U> {
#[inline]
fn div_assign(&mut self, scale: T) {
self.min /= scale;
self.min /= scale.clone();
self.max /= scale;
}
}
impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Box3D<T, U1> {
impl<T: Clone + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Box3D<T, U1> {
type Output = Box3D<T::Output, U2>;
#[inline]
@ -409,7 +429,7 @@ impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Box3D<T, U1> {
}
}
impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Box3D<T, U> {
impl<T: Clone + MulAssign, U> MulAssign<Scale<T, U, U>> for Box3D<T, U> {
#[inline]
fn mul_assign(&mut self, scale: Scale<T, U, U>) {
self.min *= scale.clone();
@ -417,7 +437,7 @@ impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Box3D<T, U> {
}
}
impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Box3D<T, U2> {
impl<T: Clone + Div, U1, U2> Div<Scale<T, U1, U2>> for Box3D<T, U2> {
type Output = Box3D<T::Output, U1>;
#[inline]
@ -426,7 +446,7 @@ impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Box3D<T, U2> {
}
}
impl<T: Copy + DivAssign, U> DivAssign<Scale<T, U, U>> for Box3D<T, U> {
impl<T: Clone + DivAssign, U> DivAssign<Scale<T, U, U>> for Box3D<T, U> {
#[inline]
fn div_assign(&mut self, scale: Scale<T, U, U>) {
self.min /= scale.clone();
@ -718,7 +738,7 @@ mod tests {
fn test_round() {
let b =
Box3D::from_points(&[point3(-25.5, -40.4, -70.9), point3(60.3, 36.5, 89.8)]).round();
assert!(b.min.x == -25.0);
assert!(b.min.x == -26.0);
assert!(b.min.y == -40.0);
assert!(b.min.z == -71.0);
assert!(b.max.x == 60.0);
@ -775,10 +795,10 @@ mod tests {
}
#[test]
fn test_intersection_unchecked() {
fn test_intersection() {
let b1 = Box3D::from_points(&[point3(-15.0, -20.0, -20.0), point3(10.0, 20.0, 20.0)]);
let b2 = Box3D::from_points(&[point3(-10.0, 20.0, 20.0), point3(15.0, -20.0, -20.0)]);
let b = b1.intersection_unchecked(&b2);
let b = b1.intersection(&b2);
assert!(b.max.x == 10.0);
assert!(b.max.y == 20.0);
assert!(b.max.z == 20.0);
@ -789,14 +809,14 @@ mod tests {
}
#[test]
fn test_intersection() {
fn test_try_intersection() {
let b1 = Box3D::from_points(&[point3(-15.0, -20.0, -20.0), point3(10.0, 20.0, 20.0)]);
let b2 = Box3D::from_points(&[point3(-10.0, 20.0, 20.0), point3(15.0, -20.0, -20.0)]);
assert!(b1.intersection(&b2).is_some());
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.intersection(&b2).is_none());
assert!(b1.try_intersection(&b2).is_none());
}
#[test]
@ -871,11 +891,11 @@ mod tests {
#[test]
fn test_nan_empty_or_negative() {
use std::f32::NAN;
assert!(Box3D { min: point3(NAN, 2.0, 1.0), max: point3(1.0, 3.0, 5.0) }.is_empty());
assert!(Box3D { min: point3(0.0, NAN, 1.0), max: point3(1.0, 2.0, 5.0) }.is_empty());
assert!(Box3D { min: point3(1.0, -2.0, NAN), max: point3(3.0, 2.0, 5.0) }.is_empty());
assert!(Box3D { min: point3(1.0, -2.0, 1.0), max: point3(NAN, 2.0, 5.0) }.is_empty());
assert!(Box3D { min: point3(1.0, -2.0, 1.0), max: point3(0.0, NAN, 5.0) }.is_empty());
assert!(Box3D { min: point3(1.0, -2.0, 1.0), max: point3(0.0, 1.0, NAN) }.is_empty());
assert!(Box3D { min: point3(NAN, 2.0, 1.0), max: point3(1.0, 3.0, 5.0) }.is_empty_or_negative());
assert!(Box3D { min: point3(0.0, NAN, 1.0), max: point3(1.0, 2.0, 5.0) }.is_empty_or_negative());
assert!(Box3D { min: point3(1.0, -2.0, NAN), max: point3(3.0, 2.0, 5.0) }.is_empty_or_negative());
assert!(Box3D { min: point3(1.0, -2.0, 1.0), max: point3(NAN, 2.0, 5.0) }.is_empty_or_negative());
assert!(Box3D { min: point3(1.0, -2.0, 1.0), max: point3(0.0, NAN, 5.0) }.is_empty_or_negative());
assert!(Box3D { min: point3(1.0, -2.0, 1.0), max: point3(0.0, 1.0, NAN) }.is_empty_or_negative());
}
}

View File

@ -120,7 +120,7 @@ impl<T: Copy + Div<T, Output = T> + Zero + PartialOrd, U> HomogeneousVector<T, U
///
/// Returns None if the point is on or behind the W=0 hemisphere.
#[inline]
pub fn to_point2d(self) -> Option<Point2D<T, U>> {
pub fn to_point2d(&self) -> Option<Point2D<T, U>> {
if self.w > T::zero() {
Some(Point2D::new(self.x / self.w, self.y / self.w))
} else {
@ -132,7 +132,7 @@ impl<T: Copy + Div<T, Output = T> + Zero + PartialOrd, U> HomogeneousVector<T, U
///
/// Returns None if the point is on or behind the W=0 hemisphere.
#[inline]
pub fn to_point3d(self) -> Option<Point3D<T, U>> {
pub fn to_point3d(&self) -> Option<Point3D<T, U>> {
if self.w > T::zero() {
Some(Point3D::new(
self.x / self.w,
@ -184,6 +184,20 @@ impl<T: fmt::Debug, U> fmt::Debug for HomogeneousVector<T, U> {
}
}
impl<T: fmt::Display, U> fmt::Display for HomogeneousVector<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(")?;
fmt::Display::fmt(&self.x, f)?;
write!(f, ",")?;
fmt::Display::fmt(&self.y, f)?;
write!(f, ",")?;
fmt::Display::fmt(&self.z, f)?;
write!(f, ",")?;
fmt::Display::fmt(&self.w, f)?;
write!(f, ")")
}
}
#[cfg(test)]
mod homogeneous {
use super::HomogeneousVector;

View File

@ -11,7 +11,6 @@
use crate::approxeq::ApproxEq;
use crate::num::Zero;
use crate::scale::Scale;
use crate::approxord::{max, min};
use crate::num::One;
use core::cmp::Ordering;
@ -83,15 +82,15 @@ impl<T, U> Length<T, U> {
}
impl<T: Clone, U> Length<T, U> {
/// Unpack the underlying value from the wrapper.
pub fn get(self) -> T {
self.0
/// Unpack the underlying value from the wrapper, cloning it.
pub fn get(&self) -> T {
self.0.clone()
}
/// Cast the unit
#[inline]
pub fn cast_unit<V>(self) -> Length<T, V> {
Length::new(self.0)
pub fn cast_unit<V>(&self) -> Length<T, V> {
Length::new(self.0.clone())
}
/// Linearly interpolate between this length and another length.
@ -111,7 +110,7 @@ impl<T: Clone, U> Length<T, U> {
/// assert_eq!(from.lerp(to, 2.0), Length::new(16.0));
/// ```
#[inline]
pub fn lerp(self, other: Self, t: T) -> Self
pub fn lerp(&self, other: Self, t: T) -> Self
where
T: One + Sub<Output = T> + Mul<Output = T> + Add<Output = T>,
{
@ -120,30 +119,16 @@ impl<T: Clone, U> Length<T, U> {
}
}
impl<T: PartialOrd, U> Length<T, U> {
/// Returns minimum between this length and another length.
#[inline]
pub fn min(self, other: Self) -> Self {
min(self, other)
}
/// Returns maximum between this length and another length.
#[inline]
pub fn max(self, other: Self) -> Self {
max(self, other)
}
}
impl<T: NumCast + Clone, U> Length<T, U> {
/// Cast from one numeric representation to another, preserving the units.
#[inline]
pub fn cast<NewT: NumCast>(self) -> Length<NewT, U> {
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<NewT: NumCast>(self) -> Option<Length<NewT, U>> {
NumCast::from(self.0).map(Length::new)
pub fn try_cast<NewT: NumCast>(&self) -> Option<Length<NewT, U>> {
NumCast::from(self.get()).map(Length::new)
}
}
@ -153,6 +138,12 @@ impl<T: fmt::Debug, U> fmt::Debug for Length<T, U> {
}
}
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 {
@ -367,6 +358,19 @@ mod tests {
assert_eq!(variable_length.get(), 24.0);
}
#[test]
fn test_get_clones_length_value() {
// Calling get returns a clone of the Length's value.
// To test this, we need something clone-able - hence a vector.
let mut length: Length<Vec<i32>, Inch> = Length::new(vec![1, 2, 3]);
let value = length.get();
length.0.push(4);
assert_eq!(value, vec![1, 2, 3]);
assert_eq!(length.get(), vec![1, 2, 3, 4]);
}
#[test]
fn test_add() {
let length1: Length<u8, Mm> = Length::new(250);

View File

@ -44,6 +44,7 @@ pub use crate::angle::Angle;
pub use crate::box2d::Box2D;
pub use crate::homogen::HomogeneousVector;
pub use crate::length::Length;
pub use crate::nonempty::NonEmpty;
pub use crate::point::{point2, point3, Point2D, Point3D};
pub use crate::scale::Scale;
pub use crate::transform2d::Transform2D;
@ -70,6 +71,7 @@ mod box2d;
mod box3d;
mod homogen;
mod length;
mod nonempty;
pub mod num;
mod point;
mod rect;

250
third_party/rust/euclid/src/nonempty.rs vendored Normal file
View File

@ -0,0 +1,250 @@
use crate::{Box2D, Box3D, Rect, Vector2D, Vector3D};
use core::cmp::PartialEq;
use core::ops::Deref;
use core::ops::{Add, Sub};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct NonEmpty<T>(pub(crate) T);
impl<T> Deref for NonEmpty<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> NonEmpty<T> {
#[inline]
pub fn get(&self) -> &T {
&self.0
}
}
impl<T, U> NonEmpty<Rect<T, U>>
where
T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
{
#[inline]
pub fn union(&self, other: &Self) -> Self {
NonEmpty(self.0.to_box2d().union(&other.0.to_box2d()).to_rect())
}
#[inline]
pub fn contains_rect(&self, rect: &Self) -> bool {
self.min_x() <= rect.min_x()
&& rect.max_x() <= self.max_x()
&& self.min_y() <= rect.min_y()
&& rect.max_y() <= self.max_y()
}
#[inline]
pub fn translate(&self, by: Vector2D<T, U>) -> Self {
NonEmpty(self.0.translate(by))
}
}
impl<T, U> NonEmpty<Box2D<T, U>>
where
T: Copy + PartialOrd,
{
#[inline]
pub fn union(&self, other: &Self) -> Self {
NonEmpty(self.0.union(&other.0))
}
/// Returns true if this box contains the interior of the other box.
#[inline]
pub fn contains_box(&self, other: &Self) -> bool {
self.min.x <= other.min.x
&& other.max.x <= self.max.x
&& self.min.y <= other.min.y
&& other.max.y <= self.max.y
}
}
impl<T, U> NonEmpty<Box2D<T, U>>
where
T: Copy + Add<T, Output = T>,
{
#[inline]
pub fn translate(&self, by: Vector2D<T, U>) -> Self {
NonEmpty(self.0.translate(by))
}
}
impl<T, U> NonEmpty<Box3D<T, U>>
where
T: Copy + PartialOrd,
{
#[inline]
pub fn union(&self, other: &Self) -> Self {
NonEmpty(self.0.union(&other.0))
}
/// Returns true if this box contains the interior of the other box.
#[inline]
pub fn contains_box(&self, other: &Self) -> bool {
self.min.x <= other.min.x
&& other.max.x <= self.max.x
&& self.min.y <= other.min.y
&& other.max.y <= self.max.y
&& self.min.z <= other.min.z
&& other.max.z <= self.max.z
}
}
impl<T, U> NonEmpty<Box3D<T, U>>
where
T: Copy + Add<T, Output = T>,
{
#[inline]
pub fn translate(&self, by: Vector3D<T, U>) -> Self {
NonEmpty(self.0.translate(by))
}
}
#[test]
fn empty_nonempty() {
use crate::default;
use crate::point2;
// zero-width
let box1: default::Box2D<i32> = Box2D {
min: point2(-10, 2),
max: point2(-10, 12),
};
// zero-height
let box2: default::Box2D<i32> = Box2D {
min: point2(0, 11),
max: point2(2, 11),
};
// negative width
let box3: default::Box2D<i32> = Box2D {
min: point2(1, 11),
max: point2(0, 12),
};
// negative height
let box4: default::Box2D<i32> = Box2D {
min: point2(0, 11),
max: point2(5, 10),
};
assert!(box1.to_non_empty().is_none());
assert!(box2.to_non_empty().is_none());
assert!(box3.to_non_empty().is_none());
assert!(box4.to_non_empty().is_none());
}
#[test]
fn nonempty_union() {
use crate::default;
use crate::{point2, point3, size2};
let box1: default::Box2D<i32> = Box2D {
min: point2(-10, 2),
max: point2(15, 12),
};
let box2 = Box2D {
min: point2(-2, -5),
max: point2(10, 5),
};
assert_eq!(
box1.union(&box2),
*box1
.to_non_empty()
.unwrap()
.union(&box2.to_non_empty().unwrap())
);
let box3: default::Box3D<i32> = Box3D {
min: point3(1, -10, 2),
max: point3(6, 15, 12),
};
let box4 = Box3D {
min: point3(0, -2, -5),
max: point3(7, 10, 5),
};
assert_eq!(
box3.union(&box4),
*box3
.to_non_empty()
.unwrap()
.union(&box4.to_non_empty().unwrap())
);
let rect1: default::Rect<i32> = Rect {
origin: point2(1, 2),
size: size2(3, 4),
};
let rect2 = Rect {
origin: point2(-1, 5),
size: size2(1, 10),
};
assert_eq!(
rect1.union(&rect2),
*rect1
.to_non_empty()
.unwrap()
.union(&rect2.to_non_empty().unwrap())
);
}
#[test]
fn nonempty_contains() {
use crate::default;
use crate::{point2, point3, size2, vec2, vec3};
let r: NonEmpty<default::Rect<i32>> = Rect {
origin: point2(-20, 15),
size: size2(100, 200),
}
.to_non_empty()
.unwrap();
assert!(r.contains_rect(&r));
assert!(!r.contains_rect(&r.translate(vec2(1, 0))));
assert!(!r.contains_rect(&r.translate(vec2(-1, 0))));
assert!(!r.contains_rect(&r.translate(vec2(0, 1))));
assert!(!r.contains_rect(&r.translate(vec2(0, -1))));
let b: NonEmpty<default::Box2D<i32>> = Box2D {
min: point2(-10, 5),
max: point2(30, 100),
}
.to_non_empty()
.unwrap();
assert!(b.contains_box(&b));
assert!(!b.contains_box(&b.translate(vec2(1, 0))));
assert!(!b.contains_box(&b.translate(vec2(-1, 0))));
assert!(!b.contains_box(&b.translate(vec2(0, 1))));
assert!(!b.contains_box(&b.translate(vec2(0, -1))));
let b: NonEmpty<default::Box3D<i32>> = Box3D {
min: point3(-1, -10, 5),
max: point3(10, 30, 100),
}
.to_non_empty()
.unwrap();
assert!(b.contains_box(&b));
assert!(!b.contains_box(&b.translate(vec3(0, 1, 0))));
assert!(!b.contains_box(&b.translate(vec3(0, -1, 0))));
assert!(!b.contains_box(&b.translate(vec3(0, 0, 1))));
assert!(!b.contains_box(&b.translate(vec3(0, 0, -1))));
assert!(!b.contains_box(&b.translate(vec3(1, 1, 0))));
assert!(!b.contains_box(&b.translate(vec3(1, -1, 0))));
assert!(!b.contains_box(&b.translate(vec3(1, 0, 1))));
assert!(!b.contains_box(&b.translate(vec3(1, 0, -1))));
assert!(!b.contains_box(&b.translate(vec3(-1, 1, 0))));
assert!(!b.contains_box(&b.translate(vec3(-1, -1, 0))));
assert!(!b.contains_box(&b.translate(vec3(-1, 0, 1))));
assert!(!b.contains_box(&b.translate(vec3(-1, 0, -1))));
}

View File

@ -70,12 +70,34 @@ pub trait Ceil: Copy {
fn ceil(self) -> Self;
}
macro_rules! num_int {
($ty:ty) => {
impl Round for $ty {
#[inline]
fn round(self) -> $ty {
self
}
}
impl Floor for $ty {
#[inline]
fn floor(self) -> $ty {
self
}
}
impl Ceil for $ty {
#[inline]
fn ceil(self) -> $ty {
self
}
}
};
}
macro_rules! num_float {
($ty:ty) => {
impl Round for $ty {
#[inline]
fn round(self) -> $ty {
(self + 0.5).floor()
num_traits::Float::round(self)
}
}
impl Floor for $ty {
@ -92,5 +114,14 @@ macro_rules! num_float {
}
};
}
num_int!(i16);
num_int!(u16);
num_int!(i32);
num_int!(u32);
num_int!(i64);
num_int!(u64);
num_int!(isize);
num_int!(usize);
num_float!(f32);
num_float!(f64);

View File

@ -107,6 +107,16 @@ impl<T: fmt::Debug, U> fmt::Debug for Point2D<T, U> {
}
}
impl<T: fmt::Display, U> fmt::Display for Point2D<T, U> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "(")?;
fmt::Display::fmt(&self.x, formatter)?;
write!(formatter, ",")?;
fmt::Display::fmt(&self.y, formatter)?;
write!(formatter, ")")
}
}
impl<T: Default, U> Default for Point2D<T, U> {
fn default() -> Self {
Point2D::new(Default::default(), Default::default())
@ -158,7 +168,7 @@ impl<T, U> Point2D<T, U> {
impl<T: Copy, U> Point2D<T, U> {
/// Create a 3d point from this one, using the specified z value.
#[inline]
pub fn extend(self, z: T) -> Point3D<T, U> {
pub fn extend(&self, z: T) -> Point3D<T, U> {
point3(self.x, self.y, z)
}
@ -166,7 +176,7 @@ impl<T: Copy, U> Point2D<T, U> {
///
/// Equivalent to subtracting the origin from this point.
#[inline]
pub fn to_vector(self) -> Vector2D<T, U> {
pub fn to_vector(&self) -> Vector2D<T, U> {
Vector2D {
x: self.x,
y: self.y,
@ -187,7 +197,7 @@ impl<T: Copy, U> Point2D<T, U> {
/// assert_eq!(point.yx(), point2(-8, 1));
/// ```
#[inline]
pub fn yx(self) -> Self {
pub fn yx(&self) -> Self {
point2(self.y, self.x)
}
@ -205,7 +215,7 @@ impl<T: Copy, U> Point2D<T, U> {
/// assert_eq!(point.y, point.to_untyped().y);
/// ```
#[inline]
pub fn to_untyped(self) -> Point2D<T, UnknownUnit> {
pub fn to_untyped(&self) -> Point2D<T, UnknownUnit> {
point2(self.x, self.y)
}
@ -224,7 +234,7 @@ impl<T: Copy, U> Point2D<T, U> {
/// assert_eq!(point.y, point.cast_unit::<Cm>().y);
/// ```
#[inline]
pub fn cast_unit<V>(self) -> Point2D<T, V> {
pub fn cast_unit<V>(&self) -> Point2D<T, V> {
point2(self.x, self.y)
}
@ -241,7 +251,7 @@ impl<T: Copy, U> Point2D<T, U> {
/// assert_eq!(point.to_array(), [1, -8]);
/// ```
#[inline]
pub fn to_array(self) -> [T; 2] {
pub fn to_array(&self) -> [T; 2] {
[self.x, self.y]
}
@ -258,13 +268,13 @@ impl<T: Copy, U> Point2D<T, U> {
/// assert_eq!(point.to_tuple(), (1, -8));
/// ```
#[inline]
pub fn to_tuple(self) -> (T, T) {
pub fn to_tuple(&self) -> (T, T) {
(self.x, self.y)
}
/// Convert into a 3d point with z-coordinate equals to zero.
#[inline]
pub fn to_3d(self) -> Point3D<T, U>
pub fn to_3d(&self) -> Point3D<T, U>
where
T: Zero,
{
@ -283,7 +293,7 @@ impl<T: Copy, U> Point2D<T, U> {
/// ```
#[inline]
#[must_use]
pub fn round(self) -> Self
pub fn round(&self) -> Self
where
T: Round,
{
@ -302,7 +312,7 @@ impl<T: Copy, U> Point2D<T, U> {
/// ```
#[inline]
#[must_use]
pub fn ceil(self) -> Self
pub fn ceil(&self) -> Self
where
T: Ceil,
{
@ -321,7 +331,7 @@ impl<T: Copy, U> Point2D<T, U> {
/// ```
#[inline]
#[must_use]
pub fn floor(self) -> Self
pub fn floor(&self) -> Self
where
T: Floor,
{
@ -346,7 +356,7 @@ impl<T: Copy, U> Point2D<T, U> {
/// assert_eq!(from.lerp(to, 2.0), point2(16.0, -18.0));
/// ```
#[inline]
pub fn lerp(self, other: Self, t: T) -> Self
pub fn lerp(&self, other: Self, t: T) -> Self
where
T: One + Sub<Output = T> + Mul<Output = T> + Add<Output = T>,
{
@ -371,7 +381,7 @@ impl<T: PartialOrd, U> Point2D<T, U> {
///
/// 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,
{
@ -386,7 +396,7 @@ impl<T: NumCast + Copy, U> Point2D<T, U> {
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
#[inline]
pub fn cast<NewT: NumCast>(self) -> Point2D<NewT, U> {
pub fn cast<NewT: NumCast>(&self) -> Point2D<NewT, U> {
self.try_cast().unwrap()
}
@ -395,7 +405,7 @@ impl<T: NumCast + Copy, U> Point2D<T, U> {
/// 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>(self) -> Option<Point2D<NewT, U>> {
pub fn try_cast<NewT: NumCast>(&self) -> Option<Point2D<NewT, U>> {
match (NumCast::from(self.x), NumCast::from(self.y)) {
(Some(x), Some(y)) => Some(point2(x, y)),
_ => None,
@ -406,13 +416,13 @@ impl<T: NumCast + Copy, U> Point2D<T, U> {
/// Cast into an `f32` point.
#[inline]
pub fn to_f32(self) -> Point2D<f32, U> {
pub fn to_f32(&self) -> Point2D<f32, U> {
self.cast()
}
/// Cast into an `f64` point.
#[inline]
pub fn to_f64(self) -> Point2D<f64, U> {
pub fn to_f64(&self) -> Point2D<f64, U> {
self.cast()
}
@ -422,7 +432,7 @@ impl<T: NumCast + Copy, U> Point2D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_usize(self) -> Point2D<usize, U> {
pub fn to_usize(&self) -> Point2D<usize, U> {
self.cast()
}
@ -432,7 +442,7 @@ impl<T: NumCast + Copy, U> Point2D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_u32(self) -> Point2D<u32, U> {
pub fn to_u32(&self) -> Point2D<u32, U> {
self.cast()
}
@ -442,7 +452,7 @@ impl<T: NumCast + Copy, U> Point2D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_i32(self) -> Point2D<i32, U> {
pub fn to_i32(&self) -> Point2D<i32, U> {
self.cast()
}
@ -452,14 +462,14 @@ impl<T: NumCast + Copy, U> Point2D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_i64(self) -> Point2D<i64, U> {
pub fn to_i64(&self) -> Point2D<i64, U> {
self.cast()
}
}
impl<T: Copy + Add<T, Output = T>, U> Point2D<T, U> {
#[inline]
pub fn add_size(self, other: &Size2D<T, U>) -> Self {
pub fn add_size(&self, other: &Size2D<T, U>) -> Self {
point2(self.x + other.width, self.y + other.height)
}
}
@ -555,12 +565,12 @@ impl<T: Copy + Sub<T, Output = T>, U> SubAssign<Vector2D<T, U>> for Point2D<T, U
}
}
impl<T: Copy + Mul, U> Mul<T> for Point2D<T, U> {
impl<T: Clone + Mul, U> Mul<T> for Point2D<T, U> {
type Output = Point2D<T::Output, U>;
#[inline]
fn mul(self, scale: T) -> Self::Output {
point2(self.x * scale, self.y * scale)
point2(self.x * scale.clone(), self.y * scale)
}
}
@ -571,29 +581,29 @@ impl<T: Copy + Mul<T, Output = T>, U> MulAssign<T> for Point2D<T, U> {
}
}
impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Point2D<T, U1> {
impl<T: Clone + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Point2D<T, U1> {
type Output = Point2D<T::Output, U2>;
#[inline]
fn mul(self, scale: Scale<T, U1, U2>) -> Self::Output {
point2(self.x * scale.0, self.y * scale.0)
point2(self.x * scale.0.clone(), self.y * scale.0)
}
}
impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Point2D<T, U> {
impl<T: Clone + MulAssign, U> MulAssign<Scale<T, U, U>> for Point2D<T, U> {
#[inline]
fn mul_assign(&mut self, scale: Scale<T, U, U>) {
self.x *= scale.0;
self.x *= scale.0.clone();
self.y *= scale.0;
}
}
impl<T: Copy + Div, U> Div<T> for Point2D<T, U> {
impl<T: Clone + Div, U> Div<T> for Point2D<T, U> {
type Output = Point2D<T::Output, U>;
#[inline]
fn div(self, scale: T) -> Self::Output {
point2(self.x / scale, self.y / scale)
point2(self.x / scale.clone(), self.y / scale)
}
}
@ -604,19 +614,19 @@ impl<T: Copy + Div<T, Output = T>, U> DivAssign<T> for Point2D<T, U> {
}
}
impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Point2D<T, U2> {
impl<T: Clone + Div, U1, U2> Div<Scale<T, U1, U2>> for Point2D<T, U2> {
type Output = Point2D<T::Output, U1>;
#[inline]
fn div(self, scale: Scale<T, U1, U2>) -> Self::Output {
point2(self.x / scale.0, self.y / scale.0)
point2(self.x / scale.0.clone(), self.y / scale.0)
}
}
impl<T: Copy + DivAssign, U> DivAssign<Scale<T, U, U>> for Point2D<T, U> {
impl<T: Clone + DivAssign, U> DivAssign<Scale<T, U, U>> for Point2D<T, U> {
#[inline]
fn div_assign(&mut self, scale: Scale<T, U, U>) {
self.x /= scale.0;
self.x /= scale.0.clone();
self.y /= scale.0;
}
}
@ -632,7 +642,7 @@ impl<T: Round, U> Round for Point2D<T, U> {
/// See [Point2D::round()](#method.round)
#[inline]
fn round(self) -> Self {
self.round()
(&self).round()
}
}
@ -640,7 +650,7 @@ impl<T: Ceil, U> Ceil for Point2D<T, U> {
/// See [Point2D::ceil()](#method.ceil)
#[inline]
fn ceil(self) -> Self {
self.ceil()
(&self).ceil()
}
}
@ -648,7 +658,7 @@ impl<T: Floor, U> Floor for Point2D<T, U> {
/// See [Point2D::floor()](#method.floor)
#[inline]
fn floor(self) -> Self {
self.floor()
(&self).floor()
}
}
@ -777,6 +787,18 @@ impl<T: fmt::Debug, U> fmt::Debug for Point3D<T, U> {
}
}
impl<T: fmt::Display, U> fmt::Display for Point3D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(")?;
fmt::Display::fmt(&self.x, f)?;
write!(f, ",")?;
fmt::Display::fmt(&self.y, f)?;
write!(f, ",")?;
fmt::Display::fmt(&self.z, f)?;
write!(f, ")")
}
}
impl<T: Default, U> Default for Point3D<T, U> {
fn default() -> Self {
Point3D::new(Default::default(), Default::default(), Default::default())
@ -831,7 +853,7 @@ impl<T: Copy, U> Point3D<T, U> {
///
/// Equivalent to subtracting the origin to this point.
#[inline]
pub fn to_vector(self) -> Vector3D<T, U> {
pub fn to_vector(&self) -> Vector3D<T, U> {
Vector3D {
x: self.x,
y: self.y,
@ -842,19 +864,19 @@ impl<T: Copy, U> Point3D<T, U> {
/// Returns a 2d point using this point's x and y coordinates
#[inline]
pub fn xy(self) -> Point2D<T, U> {
pub fn xy(&self) -> Point2D<T, U> {
point2(self.x, self.y)
}
/// Returns a 2d point using this point's x and z coordinates
#[inline]
pub fn xz(self) -> Point2D<T, U> {
pub fn xz(&self) -> Point2D<T, U> {
point2(self.x, self.z)
}
/// Returns a 2d point using this point's x and z coordinates
#[inline]
pub fn yz(self) -> Point2D<T, U> {
pub fn yz(&self) -> Point2D<T, U> {
point2(self.y, self.z)
}
@ -871,12 +893,12 @@ impl<T: Copy, U> Point3D<T, U> {
/// assert_eq!(point.to_array(), [1, -8, 0]);
/// ```
#[inline]
pub fn to_array(self) -> [T; 3] {
pub fn to_array(&self) -> [T; 3] {
[self.x, self.y, self.z]
}
#[inline]
pub fn to_array_4d(self) -> [T; 4]
pub fn to_array_4d(&self) -> [T; 4]
where
T: One,
{
@ -896,12 +918,12 @@ impl<T: Copy, U> Point3D<T, U> {
/// assert_eq!(point.to_tuple(), (1, -8, 0));
/// ```
#[inline]
pub fn to_tuple(self) -> (T, T, T) {
pub fn to_tuple(&self) -> (T, T, T) {
(self.x, self.y, self.z)
}
#[inline]
pub fn to_tuple_4d(self) -> (T, T, T, T)
pub fn to_tuple_4d(&self) -> (T, T, T, T)
where
T: One,
{
@ -923,7 +945,7 @@ impl<T: Copy, U> Point3D<T, U> {
/// assert_eq!(point.z, point.to_untyped().z);
/// ```
#[inline]
pub fn to_untyped(self) -> Point3D<T, UnknownUnit> {
pub fn to_untyped(&self) -> Point3D<T, UnknownUnit> {
point3(self.x, self.y, self.z)
}
@ -943,13 +965,13 @@ impl<T: Copy, U> Point3D<T, U> {
/// assert_eq!(point.z, point.cast_unit::<Cm>().z);
/// ```
#[inline]
pub fn cast_unit<V>(self) -> Point3D<T, V> {
pub fn cast_unit<V>(&self) -> Point3D<T, V> {
point3(self.x, self.y, self.z)
}
/// Convert into a 2d point.
#[inline]
pub fn to_2d(self) -> Point2D<T, U> {
pub fn to_2d(&self) -> Point2D<T, U> {
self.xy()
}
@ -965,7 +987,7 @@ impl<T: Copy, U> Point3D<T, U> {
/// ```
#[inline]
#[must_use]
pub fn round(self) -> Self
pub fn round(&self) -> Self
where
T: Round,
{
@ -984,7 +1006,7 @@ impl<T: Copy, U> Point3D<T, U> {
/// ```
#[inline]
#[must_use]
pub fn ceil(self) -> Self
pub fn ceil(&self) -> Self
where
T: Ceil,
{
@ -1003,7 +1025,7 @@ impl<T: Copy, U> Point3D<T, U> {
/// ```
#[inline]
#[must_use]
pub fn floor(self) -> Self
pub fn floor(&self) -> Self
where
T: Floor,
{
@ -1028,7 +1050,7 @@ impl<T: Copy, U> Point3D<T, U> {
/// assert_eq!(from.lerp(to, 2.0), point3(16.0, -18.0, 1.0));
/// ```
#[inline]
pub fn lerp(self, other: Self, t: T) -> Self
pub fn lerp(&self, other: Self, t: T) -> Self
where
T: One + Sub<Output = T> + Mul<Output = T> + Add<Output = T>,
{
@ -1065,7 +1087,7 @@ impl<T: PartialOrd, U> Point3D<T, U> {
///
/// 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,
{
@ -1080,7 +1102,7 @@ impl<T: NumCast + Copy, U> Point3D<T, U> {
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
#[inline]
pub fn cast<NewT: NumCast>(self) -> Point3D<NewT, U> {
pub fn cast<NewT: NumCast>(&self) -> Point3D<NewT, U> {
self.try_cast().unwrap()
}
@ -1089,7 +1111,7 @@ impl<T: NumCast + Copy, U> Point3D<T, U> {
/// 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>(self) -> Option<Point3D<NewT, U>> {
pub fn try_cast<NewT: NumCast>(&self) -> Option<Point3D<NewT, U>> {
match (
NumCast::from(self.x),
NumCast::from(self.y),
@ -1104,13 +1126,13 @@ impl<T: NumCast + Copy, U> Point3D<T, U> {
/// Cast into an `f32` point.
#[inline]
pub fn to_f32(self) -> Point3D<f32, U> {
pub fn to_f32(&self) -> Point3D<f32, U> {
self.cast()
}
/// Cast into an `f64` point.
#[inline]
pub fn to_f64(self) -> Point3D<f64, U> {
pub fn to_f64(&self) -> Point3D<f64, U> {
self.cast()
}
@ -1120,7 +1142,7 @@ impl<T: NumCast + Copy, U> Point3D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_usize(self) -> Point3D<usize, U> {
pub fn to_usize(&self) -> Point3D<usize, U> {
self.cast()
}
@ -1130,7 +1152,7 @@ impl<T: NumCast + Copy, U> Point3D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_u32(self) -> Point3D<u32, U> {
pub fn to_u32(&self) -> Point3D<u32, U> {
self.cast()
}
@ -1140,7 +1162,7 @@ impl<T: NumCast + Copy, U> Point3D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_i32(self) -> Point3D<i32, U> {
pub fn to_i32(&self) -> Point3D<i32, U> {
self.cast()
}
@ -1150,14 +1172,14 @@ impl<T: NumCast + Copy, U> Point3D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_i64(self) -> Point3D<i64, U> {
pub fn to_i64(&self) -> Point3D<i64, U> {
self.cast()
}
}
impl<T: Copy + Add<T, Output = T>, U> Point3D<T, U> {
#[inline]
pub fn add_size(self, other: Size3D<T, U>) -> Self {
pub fn add_size(&self, other: &Size3D<T, U>) -> Self {
point3(
self.x + other.width,
self.y + other.height,
@ -1267,84 +1289,84 @@ impl<T: Copy + Sub<T, Output = T>, U> SubAssign<Vector3D<T, U>> for Point3D<T, U
}
}
impl<T: Copy + Mul, U> Mul<T> for Point3D<T, U> {
impl<T: Clone + Mul, U> Mul<T> for Point3D<T, U> {
type Output = Point3D<T::Output, U>;
#[inline]
fn mul(self, scale: T) -> Self::Output {
point3(
self.x * scale,
self.y * scale,
self.x * scale.clone(),
self.y * scale.clone(),
self.z * scale,
)
}
}
impl<T: Copy + MulAssign, U> MulAssign<T> for Point3D<T, U> {
impl<T: Clone + MulAssign, U> MulAssign<T> for Point3D<T, U> {
#[inline]
fn mul_assign(&mut self, scale: T) {
self.x *= scale;
self.y *= scale;
self.x *= scale.clone();
self.y *= scale.clone();
self.z *= scale;
}
}
impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Point3D<T, U1> {
impl<T: Clone + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Point3D<T, U1> {
type Output = Point3D<T::Output, U2>;
#[inline]
fn mul(self, scale: Scale<T, U1, U2>) -> Self::Output {
point3(
self.x * scale.0,
self.y * scale.0,
self.x * scale.0.clone(),
self.y * scale.0.clone(),
self.z * scale.0,
)
}
}
impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Point3D<T, U> {
impl<T: Clone + MulAssign, U> MulAssign<Scale<T, U, U>> for Point3D<T, U> {
#[inline]
fn mul_assign(&mut self, scale: Scale<T, U, U>) {
*self *= scale.0;
}
}
impl<T: Copy + Div, U> Div<T> for Point3D<T, U> {
impl<T: Clone + Div, U> Div<T> for Point3D<T, U> {
type Output = Point3D<T::Output, U>;
#[inline]
fn div(self, scale: T) -> Self::Output {
point3(
self.x / scale,
self.y / scale,
self.x / scale.clone(),
self.y / scale.clone(),
self.z / scale,
)
}
}
impl<T: Copy + DivAssign, U> DivAssign<T> for Point3D<T, U> {
impl<T: Clone + DivAssign, U> DivAssign<T> for Point3D<T, U> {
#[inline]
fn div_assign(&mut self, scale: T) {
self.x /= scale;
self.y /= scale;
self.x /= scale.clone();
self.y /= scale.clone();
self.z /= scale;
}
}
impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Point3D<T, U2> {
impl<T: Clone + Div, U1, U2> Div<Scale<T, U1, U2>> for Point3D<T, U2> {
type Output = Point3D<T::Output, U1>;
#[inline]
fn div(self, scale: Scale<T, U1, U2>) -> Self::Output {
point3(
self.x / scale.0,
self.y / scale.0,
self.x / scale.0.clone(),
self.y / scale.0.clone(),
self.z / scale.0,
)
}
}
impl<T: Copy + DivAssign, U> DivAssign<Scale<T, U, U>> for Point3D<T, U> {
impl<T: Clone + DivAssign, U> DivAssign<Scale<T, U, U>> for Point3D<T, U> {
#[inline]
fn div_assign(&mut self, scale: Scale<T, U, U>) {
*self /= scale.0;
@ -1362,7 +1384,7 @@ impl<T: Round, U> Round for Point3D<T, U> {
/// See [Point3D::round()](#method.round)
#[inline]
fn round(self) -> Self {
self.round()
(&self).round()
}
}
@ -1370,7 +1392,7 @@ impl<T: Ceil, U> Ceil for Point3D<T, U> {
/// See [Point3D::ceil()](#method.ceil)
#[inline]
fn ceil(self) -> Self {
self.ceil()
(&self).ceil()
}
}
@ -1378,7 +1400,7 @@ impl<T: Floor, U> Floor for Point3D<T, U> {
/// See [Point3D::floor()](#method.floor)
#[inline]
fn floor(self) -> Self {
self.floor()
(&self).floor()
}
}

View File

@ -9,6 +9,7 @@
use super::UnknownUnit;
use crate::box2d::Box2D;
use crate::nonempty::NonEmpty;
use crate::num::*;
use crate::point::Point2D;
use crate::scale::Scale;
@ -27,22 +28,6 @@ use core::hash::{Hash, Hasher};
use core::ops::{Add, Div, DivAssign, Mul, MulAssign, Range, Sub};
/// A 2d Rectangle optionally tagged with a unit.
///
/// # Representation
///
/// `Rect` is represented by an origin point and a size.
///
/// See [`Rect`] for a rectangle represented by two endpoints.
///
/// # Empty rectangle
///
/// A rectangle is considered empty (see [`is_empty`]) if any of the following is true:
/// - it's area is empty,
/// - it's area is negative (`size.x < 0` or `size.y < 0`),
/// - it contains NaNs.
///
/// [`is_empty`]: #method.is_empty
/// [`Box2D`]: struct.Box2D.html
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(
@ -87,6 +72,16 @@ impl<T: fmt::Debug, U> fmt::Debug for Rect<T, U> {
}
}
impl<T: fmt::Display, U> fmt::Display for Rect<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Rect(")?;
fmt::Display::fmt(&self.size, f)?;
write!(f, " at ")?;
fmt::Display::fmt(&self.origin, f)?;
write!(f, ")")
}
}
impl<T: Default, U> Default for Rect<T, U> {
fn default() -> Self {
Rect::new(Default::default(), Default::default())
@ -215,9 +210,8 @@ where
{
#[inline]
pub fn intersection(&self, other: &Self) -> Option<Self> {
let box2d = self.to_box2d().intersection_unchecked(&other.to_box2d());
if box2d.is_empty() {
let box2d = self.to_box2d().intersection(&other.to_box2d());
if box2d.is_empty_or_negative() {
return None;
}
@ -251,7 +245,7 @@ where
/// nonempty but this rectangle is empty.
#[inline]
pub fn contains_rect(&self, rect: &Self) -> bool {
rect.is_empty()
rect.is_empty_or_negative()
|| (self.min_x() <= rect.min_x()
&& rect.max_x() <= self.max_x()
&& self.min_y() <= rect.min_y()
@ -384,41 +378,48 @@ impl<T: Copy + Mul<T, Output = T>, U> Rect<T, U> {
}
}
impl<T: Copy + Zero + PartialOrd, U> Rect<T, U> {
#[inline]
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.is_empty()
self.size.width == Zero::zero() || self.size.height == Zero::zero()
}
}
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<Self> {
if self.is_empty() {
pub fn to_non_empty(&self) -> Option<NonEmpty<Self>> {
if self.is_empty_or_negative() {
return None;
}
Some(*self)
Some(NonEmpty(*self))
}
}
impl<T: Copy + Mul, U> Mul<T> for Rect<T, U> {
impl<T: Clone + Mul, U> Mul<T> for Rect<T, U> {
type Output = Rect<T::Output, U>;
#[inline]
fn mul(self, scale: T) -> Self::Output {
Rect::new(self.origin * scale, self.size * scale)
Rect::new(self.origin * scale.clone(), self.size * scale)
}
}
impl<T: Copy + MulAssign, U> MulAssign<T> for Rect<T, U> {
impl<T: Clone + MulAssign, U> MulAssign<T> for Rect<T, U> {
#[inline]
fn mul_assign(&mut self, scale: T) {
*self *= Scale::new(scale);
}
}
impl<T: Copy + Div, U> Div<T> for Rect<T, U> {
impl<T: Clone + Div, U> Div<T> for Rect<T, U> {
type Output = Rect<T::Output, U>;
#[inline]
@ -427,14 +428,14 @@ impl<T: Copy + Div, U> Div<T> for Rect<T, U> {
}
}
impl<T: Copy + DivAssign, U> DivAssign<T> for Rect<T, U> {
impl<T: Clone + DivAssign, U> DivAssign<T> for Rect<T, U> {
#[inline]
fn div_assign(&mut self, scale: T) {
*self /= Scale::new(scale);
}
}
impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Rect<T, U1> {
impl<T: Clone + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Rect<T, U1> {
type Output = Rect<T::Output, U2>;
#[inline]
@ -443,7 +444,7 @@ impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Rect<T, U1> {
}
}
impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Rect<T, U> {
impl<T: Clone + MulAssign, U> MulAssign<Scale<T, U, U>> for Rect<T, U> {
#[inline]
fn mul_assign(&mut self, scale: Scale<T, U, U>) {
self.origin *= scale.clone();
@ -451,7 +452,7 @@ impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Rect<T, U> {
}
}
impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Rect<T, U2> {
impl<T: Clone + Div, U1, U2> Div<Scale<T, U1, U2>> for Rect<T, U2> {
type Output = Rect<T::Output, U1>;
#[inline]
@ -460,7 +461,7 @@ impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Rect<T, U2> {
}
}
impl<T: Copy + DivAssign, U> DivAssign<Scale<T, U, U>> for Rect<T, U> {
impl<T: Clone + DivAssign, U> DivAssign<Scale<T, U, U>> for Rect<T, U> {
#[inline]
fn div_assign(&mut self, scale: Scale<T, U, U>) {
self.origin /= scale.clone();

View File

@ -114,7 +114,7 @@ impl<T: Float + ApproxEq<T>, Src, Dst> RigidTransform3D<T, Src, Dst> {
///
/// i.e., this produces `self * other` in row-vector notation
#[inline]
pub fn then<Dst2>(
pub fn post_transform<Dst2>(
&self,
other: &RigidTransform3D<T, Dst, Dst2>,
) -> RigidTransform3D<T, Src, Dst2> {
@ -131,7 +131,7 @@ impl<T: Float + ApproxEq<T>, Src, Dst> RigidTransform3D<T, Src, Dst> {
// T' * T2 = T'' = vector addition of translations T2 and T'
let t_prime = other.rotation.transform_vector3d(self.translation);
let r_prime = self.rotation.then(&other.rotation);
let r_prime = self.rotation.post_rotate(&other.rotation);
let t_prime2 = t_prime + other.translation;
RigidTransform3D {
rotation: r_prime,
@ -139,6 +139,18 @@ impl<T: Float + ApproxEq<T>, Src, Dst> RigidTransform3D<T, Src, Dst> {
}
}
/// Returns the multiplication of the two transforms such that
/// self's transformation applies after other's transformation.
///
/// i.e., this produces `other * self` in row-vector notation
#[inline]
pub fn pre_transform<Src2>(
&self,
other: &RigidTransform3D<T, Src2, Src>,
) -> RigidTransform3D<T, Src2, Dst> {
other.post_transform(&self)
}
/// Inverts the transformation
#[inline]
pub fn inverse(&self) -> RigidTransform3D<T, Dst, Src> {
@ -161,7 +173,9 @@ impl<T: Float + ApproxEq<T>, Src, Dst> RigidTransform3D<T, Src, Dst> {
where
T: Trig,
{
self.rotation.to_transform().then(&self.translation.to_transform())
self.translation
.to_transform()
.pre_transform(&self.rotation.to_transform())
}
/// Drop the units, preserving only the numeric value.
@ -209,12 +223,16 @@ mod test {
let rigid = RigidTransform3D::new(rotation, translation);
assert!(rigid.to_transform().approx_eq(
&rotation.to_transform().then(&translation.to_transform())
&translation
.to_transform()
.pre_transform(&rotation.to_transform())
));
let rigid = RigidTransform3D::new_from_reversed(translation, rotation);
assert!(rigid.to_transform().approx_eq(
&translation.to_transform().then(&rotation.to_transform())
&translation
.to_transform()
.post_transform(&rotation.to_transform())
));
}
@ -227,7 +245,7 @@ mod test {
let (t2, r2) = rigid.decompose_reversed();
assert!(rigid
.to_transform()
.approx_eq(&t2.to_transform().then(&r2.to_transform())));
.approx_eq(&t2.to_transform().post_transform(&r2.to_transform())));
}
#[test]
@ -238,7 +256,7 @@ mod test {
let rigid = RigidTransform3D::new(rotation, translation);
let inverse = rigid.inverse();
assert!(rigid
.then(&inverse)
.post_transform(&inverse)
.to_transform()
.approx_eq(&Transform3D::identity()));
assert!(inverse
@ -256,12 +274,12 @@ mod test {
let rigid2 = RigidTransform3D::new(rotation2, translation2);
assert!(rigid
.then(&rigid2)
.post_transform(&rigid2)
.to_transform()
.approx_eq(&rigid.to_transform().then(&rigid2.to_transform())));
assert!(rigid2
.then(&rigid)
.approx_eq(&rigid.to_transform().post_transform(&rigid2.to_transform())));
assert!(rigid
.pre_transform(&rigid2)
.to_transform()
.approx_eq(&rigid2.to_transform().then(&rigid.to_transform())));
.approx_eq(&rigid.to_transform().pre_transform(&rigid2.to_transform())));
}
}

View File

@ -158,11 +158,11 @@ impl<T: Copy, Src, Dst> Rotation2D<T, Src, Dst> {
impl<T, Src, Dst> Rotation2D<T, Src, Dst>
where
T: Copy,
T: Clone,
{
/// Returns self.angle as a strongly typed `Angle<T>`.
pub fn get_angle(&self) -> Angle<T> {
Angle::radians(self.angle)
Angle::radians(self.angle.clone())
}
}
@ -181,13 +181,22 @@ impl<T: Float, Src, Dst> Rotation2D<T, Src, Dst> {
/// Returns a rotation representing the other rotation followed by this rotation.
#[inline]
pub fn then<NewSrc>(
pub fn pre_rotate<NewSrc>(
&self,
other: &Rotation2D<T, NewSrc, Src>,
) -> Rotation2D<T, NewSrc, Dst> {
Rotation2D::radians(self.angle + other.angle)
}
/// Returns a rotation representing this rotation followed by the other rotation.
#[inline]
pub fn post_rotate<NewDst>(
&self,
other: &Rotation2D<T, Dst, NewDst>,
) -> Rotation2D<T, Src, NewDst> {
other.pre_rotate(self)
}
/// Returns the given 2d point transformed by this rotation.
///
/// The input point must be use the unit Src, and the returned point has the unit Dst.
@ -213,7 +222,7 @@ where
/// Returns the matrix representation of this rotation.
#[inline]
pub fn to_transform(&self) -> Transform2D<T, Src, Dst> {
Transform2D::rotation(self.get_angle())
Transform2D::create_rotation(self.get_angle())
}
}
@ -643,30 +652,38 @@ where
let m32 = jk - ri;
let m33 = one - (ii + jj);
Transform3D::new(
m11, m12, m13, zero,
m21, m22, m23, zero,
m31, m32, m33, zero,
zero, zero, zero, one,
Transform3D::row_major(
m11, m12, m13, zero, m21, m22, m23, zero, m31, m32, m33, zero, zero, zero, zero, one,
)
}
/// Returns a rotation representing the other rotation followed by this rotation.
pub fn pre_rotate<NewSrc>(
&self,
other: &Rotation3D<T, NewSrc, Src>,
) -> Rotation3D<T, NewSrc, Dst>
where
T: ApproxEq<T>,
{
debug_assert!(self.is_normalized());
Rotation3D::quaternion(
self.i * other.r + self.r * other.i + self.j * other.k - self.k * other.j,
self.j * other.r + self.r * other.j + self.k * other.i - self.i * other.k,
self.k * other.r + self.r * other.k + self.i * other.j - self.j * other.i,
self.r * other.r - self.i * other.i - self.j * other.j - self.k * other.k,
)
}
/// Returns a rotation representing this rotation followed by the other rotation.
#[inline]
pub fn then<NewDst>(
pub fn post_rotate<NewDst>(
&self,
other: &Rotation3D<T, Dst, NewDst>,
) -> Rotation3D<T, Src, NewDst>
where
T: ApproxEq<T>,
{
debug_assert!(self.is_normalized());
Rotation3D::quaternion(
other.i * self.r + other.r * self.i + other.j * self.k - other.k * self.j,
other.j * self.r + other.r * self.j + other.k * self.i - other.i * self.k,
other.k * self.r + other.r * self.k + other.i * self.j - other.j * self.i,
other.r * self.r - other.i * self.i - other.j * self.j - other.k * self.k,
)
other.pre_rotate(self)
}
// add, sub and mul are used internally for intermediate computation but aren't public
@ -713,6 +730,16 @@ impl<T: fmt::Debug, Src, Dst> fmt::Debug for Rotation3D<T, Src, Dst> {
}
}
impl<T: fmt::Display, Src, Dst> fmt::Display for Rotation3D<T, Src, Dst> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Quat({}*i + {}*j + {}*k + {})",
self.i, self.j, self.k, self.r
)
}
}
impl<T, Src, Dst> ApproxEq<T> for Rotation3D<T, Src, Dst>
where
T: Copy + Neg<Output = T> + ApproxEq<T>,
@ -810,18 +837,18 @@ fn pre_post() {
// Check that the order of transformations is correct (corresponds to what
// we do in Transform3D).
let p1 = r1.then(&r2).then(&r3).transform_point3d(p);
let p1 = r1.post_rotate(&r2).post_rotate(&r3).transform_point3d(p);
let p2 = t1
.then(&t2)
.then(&t3)
.post_transform(&t2)
.post_transform(&t3)
.transform_point3d(p);
assert!(p1.approx_eq(&p2.unwrap()));
// Check that changing the order indeed matters.
let p3 = t3
.then(&t1)
.then(&t2)
.post_transform(&t1)
.post_transform(&t2)
.transform_point3d(p);
assert!(!p1.approx_eq(&p3.unwrap()));
}
@ -991,7 +1018,7 @@ fn from_euler() {
// Now check that the yaw pitch and roll transformations when combined are applied in
// the proper order: roll -> pitch -> yaw.
let ypr_e = Rotation3D::euler(angle, angle, angle);
let ypr_q = roll_rq.then(&pitch_rq).then(&yaw_rq);
let ypr_q = roll_rq.post_rotate(&pitch_rq).post_rotate(&yaw_rq);
let ypr_pe = ypr_e.transform_point3d(p);
let ypr_pq = ypr_q.transform_point3d(p);

View File

@ -10,12 +10,12 @@
use crate::num::One;
use crate::{Point2D, Point3D, Rect, Size2D, Vector2D, Box2D, Box3D};
use crate::{Point2D, Rect, Size2D, Vector2D};
use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
use core::ops::{Add, Div, Mul, Sub};
use core::ops::{Add, Div, Mul, Neg, Sub};
use num_traits::NumCast;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
@ -56,15 +56,6 @@ impl<T, Src, Dst> Scale<T, Src, Dst> {
Scale(x, PhantomData)
}
/// Creates an identity scale (1.0).
#[inline]
pub fn identity() -> Self
where
T: One
{
Scale::new(T::one())
}
/// Returns the given point transformed by this scale.
///
/// # Example
@ -79,20 +70,11 @@ impl<T, Src, Dst> Scale<T, Src, Dst> {
/// assert_eq!(to_mm.transform_point(point2(42, -42)), point2(420, -420));
/// ```
#[inline]
pub fn transform_point(self, point: Point2D<T, Src>) -> Point2D<T::Output, Dst>
pub fn transform_point(&self, point: Point2D<T, Src>) -> Point2D<T::Output, Dst>
where
T: Copy + Mul,
T: Clone + Mul,
{
Point2D::new(point.x * self.0, point.y * self.0)
}
/// Returns the given point transformed by this scale.
#[inline]
pub fn transform_point3d(self, point: Point3D<T, Src>) -> Point3D<T::Output, Dst>
where
T: Copy + Mul,
{
Point3D::new(point.x * self.0, point.y * self.0, point.z * self.0)
Point2D::new(point.x * self.get(), point.y * self.get())
}
/// Returns the given vector transformed by this scale.
@ -109,11 +91,11 @@ impl<T, Src, Dst> Scale<T, Src, Dst> {
/// assert_eq!(to_mm.transform_vector(vec2(42, -42)), vec2(420, -420));
/// ```
#[inline]
pub fn transform_vector(self, vec: Vector2D<T, Src>) -> Vector2D<T::Output, Dst>
pub fn transform_vector(&self, vec: Vector2D<T, Src>) -> Vector2D<T::Output, Dst>
where
T: Copy + Mul,
T: Clone + Mul,
{
Vector2D::new(vec.x * self.0, vec.y * self.0)
Vector2D::new(vec.x * self.get(), vec.y * self.get())
}
/// Returns the given vector transformed by this scale.
@ -130,11 +112,11 @@ impl<T, Src, Dst> Scale<T, Src, Dst> {
/// assert_eq!(to_mm.transform_size(size2(42, -42)), size2(420, -420));
/// ```
#[inline]
pub fn transform_size(self, size: Size2D<T, Src>) -> Size2D<T::Output, Dst>
pub fn transform_size(&self, size: Size2D<T, Src>) -> Size2D<T::Output, Dst>
where
T: Copy + Mul,
T: Clone + Mul,
{
Size2D::new(size.width * self.0, size.height * self.0)
Size2D::new(size.width * self.get(), size.height * self.get())
}
/// Returns the given rect transformed by this scale.
@ -151,7 +133,7 @@ impl<T, Src, Dst> Scale<T, Src, Dst> {
/// 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::Output, Dst>
pub fn transform_rect(&self, rect: &Rect<T, Src>) -> Rect<T::Output, Dst>
where
T: Copy + Mul,
{
@ -161,28 +143,13 @@ impl<T, Src, Dst> Scale<T, Src, Dst> {
)
}
/// Returns the given box transformed by this scale.
/// Returns the inverse of this scale.
#[inline]
pub fn transform_box2d(self, b: &Box2D<T, Src>) -> Box2D<T::Output, Dst>
pub fn inverse(&self) -> Scale<T::Output, Dst, Src>
where
T: Copy + Mul,
T: Clone + Neg,
{
Box2D {
min: self.transform_point(b.min),
max: self.transform_point(b.max),
}
}
/// Returns the given box transformed by this scale.
#[inline]
pub fn transform_box3d(self, b: &Box3D<T, Src>) -> Box3D<T::Output, Dst>
where
T: Copy + Mul,
{
Box3D {
min: self.transform_point3d(b.min),
max: self.transform_point3d(b.max),
}
Scale::new(-self.get())
}
/// Returns `true` if this scale has no effect.
@ -203,17 +170,18 @@ impl<T, Src, Dst> Scale<T, Src, Dst> {
/// assert_eq!(mm_per_mm, Scale::one());
/// ```
#[inline]
pub fn is_identity(self) -> bool
pub fn is_identity(&self) -> bool
where
T: PartialEq + One,
{
self.0 == T::one()
}
}
/// Returns the underlying scalar scale factor.
impl<T: Clone, Src, Dst> Scale<T, Src, Dst> {
#[inline]
pub fn get(self) -> T {
self.0
pub fn get(&self) -> T {
self.0.clone()
}
/// The inverse Scale (1.0 / self).
@ -227,18 +195,18 @@ impl<T, Src, Dst> Scale<T, Src, Dst> {
///
/// let cm_per_mm: Scale<f32, Cm, Mm> = Scale::new(0.1);
///
/// assert_eq!(cm_per_mm.inverse(), Scale::new(10.0));
/// assert_eq!(cm_per_mm.inv(), Scale::new(10.0));
/// ```
pub fn inverse(self) -> Scale<T::Output, Dst, Src>
pub fn inv(&self) -> Scale<T::Output, Dst, Src>
where
T: One + Div,
{
let one: T = One::one();
Scale::new(one / self.0)
Scale::new(one / self.0.clone())
}
}
impl<T: NumCast, Src, Dst> Scale<T, Src, Dst> {
impl<T: NumCast + Clone, Src, Dst> Scale<T, Src, Dst> {
/// Cast from one numeric representation to another, preserving the units.
///
/// # Panics
@ -267,7 +235,7 @@ impl<T: NumCast, Src, Dst> Scale<T, Src, Dst> {
/// let to_em: Scale<i32, Mm, Em> = Scale::new(10e20).cast();
/// ```
#[inline]
pub fn cast<NewT: NumCast>(self) -> Scale<NewT, Src, Dst> {
pub fn cast<NewT: NumCast>(&self) -> Scale<NewT, Src, Dst> {
self.try_cast().unwrap()
}
@ -290,11 +258,16 @@ impl<T: NumCast, Src, Dst> Scale<T, Src, Dst> {
/// // 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.0).map(Scale::new)
pub fn try_cast<NewT: NumCast>(&self) -> Option<Scale<NewT, Src, Dst>> {
NumCast::from(self.get()).map(Scale::new)
}
}
impl<Src, Dst> Scale<f32, Src, Dst> {
/// Identity scaling, could be used to safely transit from one space to another.
pub const ONE: Self = Scale(1.0, PhantomData);
}
// scale0 * scale1
// (A,B) * (B,C) = (A,C)
impl<T: Mul, A, B, C> Mul<Scale<T, B, C>> for Scale<T, A, B> {
@ -351,7 +324,7 @@ impl<T: Ord, Src, Dst> Ord for Scale<T, Src, Dst> {
impl<T: Clone, Src, Dst> Clone for Scale<T, Src, Dst> {
fn clone(&self) -> Scale<T, Src, Dst> {
Scale::new(self.0.clone())
Scale::new(self.get())
}
}
@ -363,6 +336,12 @@ impl<T: fmt::Debug, Src, Dst> fmt::Debug for Scale<T, Src, Dst> {
}
}
impl<T: fmt::Display, Src, Dst> fmt::Display for Scale<T, Src, Dst> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T: Default, Src, Dst> Default for Scale<T, Src, Dst> {
fn default() -> Self {
Self::new(T::default())
@ -395,7 +374,7 @@ mod tests {
let mm_per_inch: Scale<f32, Inch, Mm> = Scale::new(25.4);
let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);
let mm_per_cm: Scale<f32, Cm, Mm> = cm_per_mm.inverse();
let mm_per_cm: Scale<f32, Cm, Mm> = cm_per_mm.inv();
assert_eq!(mm_per_cm.get(), 10.0);
let one: Scale<f32, Mm, Mm> = cm_per_mm * mm_per_cm;

View File

@ -165,13 +165,6 @@ impl<T, U> SideOffsets2D<T, U> {
}
}
/// Constructor, setting all sides to zero.
pub fn zero() -> Self
where T: Zero,
{
SideOffsets2D::new(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero())
}
/// Returns `true` if all side offsets are zero.
pub fn is_zero(&self) -> bool
where
@ -180,30 +173,29 @@ impl<T, U> SideOffsets2D<T, U> {
let zero = T::zero();
self.top == zero && self.right == zero && self.bottom == zero && self.left == zero
}
}
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
where T : Copy
{
pub fn new_all_same(all: T) -> Self {
SideOffsets2D::new(all, all, all, all)
}
/// Constructor setting the same value to all sides, taking a typed Length.
pub fn from_length_all_same(all: Length<T, U>) -> Self
where T : Copy
{
pub fn from_length_all_same(all: Length<T, U>) -> Self {
SideOffsets2D::new_all_same(all.0)
}
}
pub fn horizontal(&self) -> T
where T: Copy + Add<T, Output = T>
{
impl<T, U> SideOffsets2D<T, U>
where
T: Add<T, Output = T> + Copy,
{
pub fn horizontal(&self) -> T {
self.left + self.right
}
pub fn vertical(&self) -> T
where T: Copy + Add<T, Output = T>
{
pub fn vertical(&self) -> T {
self.top + self.bottom
}
}
@ -223,90 +215,97 @@ where
}
}
impl<T: Copy + Mul, U> Mul<T> for 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())
}
}
impl<T: Clone + Mul, U> Mul<T> for SideOffsets2D<T, U> {
type Output = SideOffsets2D<T::Output, U>;
#[inline]
fn mul(self, scale: T) -> Self::Output {
SideOffsets2D::new(
self.top * scale,
self.right * scale,
self.bottom * scale,
self.top * scale.clone(),
self.right * scale.clone(),
self.bottom * scale.clone(),
self.left * scale,
)
}
}
impl<T: Copy + MulAssign, U> MulAssign<T> for SideOffsets2D<T, U> {
impl<T: Clone + MulAssign, U> MulAssign<T> for SideOffsets2D<T, U> {
#[inline]
fn mul_assign(&mut self, other: T) {
self.top *= other;
self.right *= other;
self.bottom *= other;
self.top *= other.clone();
self.right *= other.clone();
self.bottom *= other.clone();
self.left *= other;
}
}
impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for SideOffsets2D<T, U1> {
impl<T: Clone + Mul, U1, U2> Mul<Scale<T, U1, U2>> for SideOffsets2D<T, U1> {
type Output = SideOffsets2D<T::Output, U2>;
#[inline]
fn mul(self, scale: Scale<T, U1, U2>) -> Self::Output {
SideOffsets2D::new(
self.top * scale.0,
self.right * scale.0,
self.bottom * scale.0,
self.top * scale.0.clone(),
self.right * scale.0.clone(),
self.bottom * scale.0.clone(),
self.left * scale.0,
)
}
}
impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for SideOffsets2D<T, U> {
impl<T: Clone + MulAssign, U> MulAssign<Scale<T, U, U>> for SideOffsets2D<T, U> {
#[inline]
fn mul_assign(&mut self, other: Scale<T, U, U>) {
*self *= other.0;
}
}
impl<T: Copy + Div, U> Div<T> for SideOffsets2D<T, U> {
impl<T: Clone + Div, U> Div<T> for SideOffsets2D<T, U> {
type Output = SideOffsets2D<T::Output, U>;
#[inline]
fn div(self, scale: T) -> Self::Output {
SideOffsets2D::new(
self.top / scale,
self.right / scale,
self.bottom / scale,
self.top / scale.clone(),
self.right / scale.clone(),
self.bottom / scale.clone(),
self.left / scale,
)
}
}
impl<T: Copy + DivAssign, U> DivAssign<T> for SideOffsets2D<T, U> {
impl<T: Clone + DivAssign, U> DivAssign<T> for SideOffsets2D<T, U> {
#[inline]
fn div_assign(&mut self, other: T) {
self.top /= other;
self.right /= other;
self.bottom /= other;
self.top /= other.clone();
self.right /= other.clone();
self.bottom /= other.clone();
self.left /= other;
}
}
impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for SideOffsets2D<T, U2> {
impl<T: Clone + Div, U1, U2> Div<Scale<T, U1, U2>> for SideOffsets2D<T, U2> {
type Output = SideOffsets2D<T::Output, U1>;
#[inline]
fn div(self, scale: Scale<T, U1, U2>) -> Self::Output {
SideOffsets2D::new(
self.top / scale.0,
self.right / scale.0,
self.bottom / scale.0,
self.top / scale.0.clone(),
self.right / scale.0.clone(),
self.bottom / scale.0.clone(),
self.left / scale.0,
)
}
}
impl<T: Copy + DivAssign, U> DivAssign<Scale<T, U, U>> for SideOffsets2D<T, U> {
impl<T: Clone + DivAssign, U> DivAssign<Scale<T, U, U>> for SideOffsets2D<T, U> {
fn div_assign(&mut self, other: Scale<T, U, U>) {
*self /= other.0;
}

View File

@ -111,6 +111,16 @@ impl<T: fmt::Debug, U> fmt::Debug for Size2D<T, U> {
}
}
impl<T: fmt::Display, U> fmt::Display for Size2D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(")?;
fmt::Display::fmt(&self.width, f)?;
write!(f, "x")?;
fmt::Display::fmt(&self.height, f)?;
write!(f, ")")
}
}
impl<T: Default, U> Default for Size2D<T, U> {
fn default() -> Self {
Size2D::new(Default::default(), Default::default())
@ -154,31 +164,31 @@ impl<T, U> Size2D<T, U> {
impl<T: Copy, U> Size2D<T, U> {
/// Return this size as an array of two elements (width, then height).
#[inline]
pub fn to_array(self) -> [T; 2] {
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) {
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> {
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> {
pub fn to_untyped(&self) -> Size2D<T, UnknownUnit> {
self.cast_unit()
}
/// Cast the unit
#[inline]
pub fn cast_unit<V>(self) -> Size2D<T, V> {
pub fn cast_unit<V>(&self) -> Size2D<T, V> {
Size2D::new(self.width, self.height)
}
@ -194,7 +204,7 @@ impl<T: Copy, U> Size2D<T, U> {
/// ```
#[inline]
#[must_use]
pub fn round(self) -> Self
pub fn round(&self) -> Self
where
T: Round,
{
@ -213,7 +223,7 @@ impl<T: Copy, U> Size2D<T, U> {
/// ```
#[inline]
#[must_use]
pub fn ceil(self) -> Self
pub fn ceil(&self) -> Self
where
T: Ceil,
{
@ -232,7 +242,7 @@ impl<T: Copy, U> Size2D<T, U> {
/// ```
#[inline]
#[must_use]
pub fn floor(self) -> Self
pub fn floor(&self) -> Self
where
T: Floor,
{
@ -240,7 +250,7 @@ impl<T: Copy, U> Size2D<T, U> {
}
/// Returns result of multiplication of both components
pub fn area(self) -> T::Output
pub fn area(&self) -> T::Output
where
T: Mul,
{
@ -265,12 +275,12 @@ impl<T: Copy, U> Size2D<T, U> {
/// assert_eq!(from.lerp(to, 2.0), size2(16.0, -18.0));
/// ```
#[inline]
pub fn lerp(self, other: Self, t: T) -> Self
pub fn lerp(&self, other: Self, t: T) -> Self
where
T: One + Sub<Output = T> + Mul<Output = T> + Add<Output = T>,
{
let one_t = T::one() - t;
self * one_t + other * t
(*self) * one_t + other * t
}
}
@ -281,7 +291,7 @@ impl<T: NumCast + Copy, U> Size2D<T, U> {
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
#[inline]
pub fn cast<NewT: NumCast>(self) -> Size2D<NewT, U> {
pub fn cast<NewT: NumCast>(&self) -> Size2D<NewT, U> {
self.try_cast().unwrap()
}
@ -290,7 +300,7 @@ impl<T: NumCast + Copy, U> Size2D<T, U> {
/// 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>(self) -> Option<Size2D<NewT, U>> {
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,
@ -301,13 +311,13 @@ impl<T: NumCast + Copy, U> Size2D<T, U> {
/// Cast into an `f32` size.
#[inline]
pub fn to_f32(self) -> Size2D<f32, U> {
pub fn to_f32(&self) -> Size2D<f32, U> {
self.cast()
}
/// Cast into an `f64` size.
#[inline]
pub fn to_f64(self) -> Size2D<f64, U> {
pub fn to_f64(&self) -> Size2D<f64, U> {
self.cast()
}
@ -317,7 +327,7 @@ impl<T: NumCast + Copy, U> Size2D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_usize(self) -> Size2D<usize, U> {
pub fn to_usize(&self) -> Size2D<usize, U> {
self.cast()
}
@ -327,7 +337,7 @@ impl<T: NumCast + Copy, U> Size2D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_u32(self) -> Size2D<u32, U> {
pub fn to_u32(&self) -> Size2D<u32, U> {
self.cast()
}
@ -337,7 +347,7 @@ impl<T: NumCast + Copy, U> Size2D<T, U> {
/// 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> {
pub fn to_u64(&self) -> Size2D<u64, U> {
self.cast()
}
@ -347,7 +357,7 @@ impl<T: NumCast + Copy, U> Size2D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_i32(self) -> Size2D<i32, U> {
pub fn to_i32(&self) -> Size2D<i32, U> {
self.cast()
}
@ -357,7 +367,7 @@ impl<T: NumCast + Copy, U> Size2D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_i64(self) -> Size2D<i64, U> {
pub fn to_i64(&self) -> Size2D<i64, U> {
self.cast()
}
}
@ -368,12 +378,12 @@ impl<T: Signed, U> Size2D<T, U> {
/// 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 {
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 {
pub fn is_positive(&self) -> bool {
self.width.is_positive() && self.height.is_positive()
}
}
@ -396,7 +406,7 @@ impl<T: PartialOrd, U> Size2D<T, U> {
///
/// 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,
{
@ -404,7 +414,7 @@ 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 {
pub fn greater_than(&self, other: Self) -> BoolVector2D {
BoolVector2D {
x: self.width > other.width,
y: self.height > other.height,
@ -412,15 +422,15 @@ 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 {
pub fn lower_than(&self, other: Self) -> BoolVector2D {
BoolVector2D {
x: self.width < other.width,
y: self.height < other.height,
}
}
/// Returns `true` if any component of size is zero, negative, or NaN.
pub fn is_empty(self) -> bool
/// Returns `true` if any component of size is zero or negative.
pub fn is_empty_or_negative(&self) -> bool
where
T: Zero,
{
@ -433,7 +443,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 {
pub fn equal(&self, other: Self) -> BoolVector2D {
BoolVector2D {
x: self.width == other.width,
y: self.height == other.height,
@ -441,7 +451,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 {
pub fn not_equal(&self, other: Self) -> BoolVector2D {
BoolVector2D {
x: self.width != other.width,
y: self.height != other.height,
@ -453,7 +463,7 @@ impl<T: Round, U> Round for Size2D<T, U> {
/// See [`Size2D::round()`](#method.round).
#[inline]
fn round(self) -> Self {
self.round()
(&self).round()
}
}
@ -461,7 +471,7 @@ impl<T: Ceil, U> Ceil for Size2D<T, U> {
/// See [`Size2D::ceil()`](#method.ceil).
#[inline]
fn ceil(self) -> Self {
self.ceil()
(&self).ceil()
}
}
@ -469,7 +479,7 @@ impl<T: Floor, U> Floor for Size2D<T, U> {
/// See [`Size2D::floor()`](#method.floor).
#[inline]
fn floor(self) -> Self {
self.floor()
(&self).floor()
}
}
@ -523,66 +533,66 @@ impl<T: SubAssign, U> SubAssign for Size2D<T, U> {
}
}
impl<T: Copy + Mul, U> Mul<T> for Size2D<T, U> {
impl<T: Clone + Mul, U> Mul<T> for Size2D<T, U> {
type Output = Size2D<T::Output, U>;
#[inline]
fn mul(self, scale: T) -> Self::Output {
Size2D::new(self.width * scale, self.height * scale)
Size2D::new(self.width * scale.clone(), self.height * scale)
}
}
impl<T: Copy + MulAssign, U> MulAssign<T> for Size2D<T, U> {
impl<T: Clone + MulAssign, U> MulAssign<T> for Size2D<T, U> {
#[inline]
fn mul_assign(&mut self, other: T) {
self.width *= other;
self.width *= other.clone();
self.height *= other;
}
}
impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Size2D<T, U1> {
impl<T: Clone + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Size2D<T, U1> {
type Output = Size2D<T::Output, U2>;
#[inline]
fn mul(self, scale: Scale<T, U1, U2>) -> Self::Output {
Size2D::new(self.width * scale.0, self.height * scale.0)
Size2D::new(self.width * scale.0.clone(), self.height * scale.0)
}
}
impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Size2D<T, U> {
impl<T: Clone + MulAssign, U> MulAssign<Scale<T, U, U>> for Size2D<T, U> {
#[inline]
fn mul_assign(&mut self, other: Scale<T, U, U>) {
*self *= other.0;
}
}
impl<T: Copy + Div, U> Div<T> for Size2D<T, U> {
impl<T: Clone + Div, U> Div<T> for Size2D<T, U> {
type Output = Size2D<T::Output, U>;
#[inline]
fn div(self, scale: T) -> Self::Output {
Size2D::new(self.width / scale, self.height / scale)
Size2D::new(self.width / scale.clone(), self.height / scale)
}
}
impl<T: Copy + DivAssign, U> DivAssign<T> for Size2D<T, U> {
impl<T: Clone + DivAssign, U> DivAssign<T> for Size2D<T, U> {
#[inline]
fn div_assign(&mut self, other: T) {
self.width /= other;
self.width /= other.clone();
self.height /= other;
}
}
impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Size2D<T, U2> {
impl<T: Clone + Div, U1, U2> Div<Scale<T, U1, U2>> for Size2D<T, U2> {
type Output = Size2D<T::Output, U1>;
#[inline]
fn div(self, scale: Scale<T, U1, U2>) -> Self::Output {
Size2D::new(self.width / scale.0, self.height / scale.0)
Size2D::new(self.width / scale.0.clone(), self.height / scale.0)
}
}
impl<T: Copy + DivAssign, U> DivAssign<Scale<T, U, U>> for Size2D<T, U> {
impl<T: Clone + DivAssign, U> DivAssign<Scale<T, U, U>> for Size2D<T, U> {
#[inline]
fn div_assign(&mut self, other: Scale<T, U, U>) {
*self /= other.0;
@ -846,9 +856,9 @@ mod size2d {
#[test]
pub fn test_nan_empty() {
use std::f32::NAN;
assert!(Size2D::new(NAN, 2.0).is_empty());
assert!(Size2D::new(0.0, NAN).is_empty());
assert!(Size2D::new(NAN, -2.0).is_empty());
assert!(Size2D::new(NAN, 2.0).is_empty_or_negative());
assert!(Size2D::new(0.0, NAN).is_empty_or_negative());
assert!(Size2D::new(NAN, -2.0).is_empty_or_negative());
}
}
}
@ -943,6 +953,18 @@ impl<T: fmt::Debug, U> fmt::Debug for Size3D<T, U> {
}
}
impl<T: fmt::Display, U> fmt::Display for Size3D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(")?;
fmt::Display::fmt(&self.width, f)?;
write!(f, "x")?;
fmt::Display::fmt(&self.height, f)?;
write!(f, "x")?;
fmt::Display::fmt(&self.depth, f)?;
write!(f, ")")
}
}
impl<T: Default, U> Default for Size3D<T, U> {
fn default() -> Self {
Size3D::new(Default::default(), Default::default(), Default::default())
@ -987,31 +1009,31 @@ impl<T, U> Size3D<T, U> {
impl<T: Copy, U> Size3D<T, U> {
/// Return this size as an array of three elements (width, then height, then depth).
#[inline]
pub fn to_array(self) -> [T; 3] {
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) {
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> {
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> {
pub fn to_untyped(&self) -> Size3D<T, UnknownUnit> {
self.cast_unit()
}
/// Cast the unit
#[inline]
pub fn cast_unit<V>(self) -> Size3D<T, V> {
pub fn cast_unit<V>(&self) -> Size3D<T, V> {
Size3D::new(self.width, self.height, self.depth)
}
@ -1027,7 +1049,7 @@ impl<T: Copy, U> Size3D<T, U> {
/// ```
#[inline]
#[must_use]
pub fn round(self) -> Self
pub fn round(&self) -> Self
where
T: Round,
{
@ -1046,7 +1068,7 @@ impl<T: Copy, U> Size3D<T, U> {
/// ```
#[inline]
#[must_use]
pub fn ceil(self) -> Self
pub fn ceil(&self) -> Self
where
T: Ceil,
{
@ -1065,7 +1087,7 @@ impl<T: Copy, U> Size3D<T, U> {
/// ```
#[inline]
#[must_use]
pub fn floor(self) -> Self
pub fn floor(&self) -> Self
where
T: Floor,
{
@ -1073,7 +1095,7 @@ impl<T: Copy, U> Size3D<T, U> {
}
/// Returns result of multiplication of all components
pub fn volume(self) -> T
pub fn volume(&self) -> T
where
T: Mul<Output = T>,
{
@ -1098,12 +1120,12 @@ impl<T: Copy, U> Size3D<T, U> {
/// assert_eq!(from.lerp(to, 2.0), size3(16.0, -18.0, 1.0));
/// ```
#[inline]
pub fn lerp(self, other: Self, t: T) -> Self
pub fn lerp(&self, other: Self, t: T) -> Self
where
T: One + Sub<Output = T> + Mul<Output = T> + Add<Output = T>,
{
let one_t = T::one() - t;
self * one_t + other * t
(*self) * one_t + other * t
}
}
@ -1114,7 +1136,7 @@ impl<T: NumCast + Copy, U> Size3D<T, U> {
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
#[inline]
pub fn cast<NewT: NumCast>(self) -> Size3D<NewT, U> {
pub fn cast<NewT: NumCast>(&self) -> Size3D<NewT, U> {
self.try_cast().unwrap()
}
@ -1123,7 +1145,7 @@ impl<T: NumCast + Copy, U> Size3D<T, U> {
/// 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>(self) -> Option<Size3D<NewT, U>> {
pub fn try_cast<NewT: NumCast>(&self) -> Option<Size3D<NewT, U>> {
match (
NumCast::from(self.width),
NumCast::from(self.height),
@ -1138,13 +1160,13 @@ impl<T: NumCast + Copy, U> Size3D<T, U> {
/// Cast into an `f32` size.
#[inline]
pub fn to_f32(self) -> Size3D<f32, U> {
pub fn to_f32(&self) -> Size3D<f32, U> {
self.cast()
}
/// Cast into an `f64` size.
#[inline]
pub fn to_f64(self) -> Size3D<f64, U> {
pub fn to_f64(&self) -> Size3D<f64, U> {
self.cast()
}
@ -1154,7 +1176,7 @@ impl<T: NumCast + Copy, U> Size3D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_usize(self) -> Size3D<usize, U> {
pub fn to_usize(&self) -> Size3D<usize, U> {
self.cast()
}
@ -1164,7 +1186,7 @@ impl<T: NumCast + Copy, U> Size3D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_u32(self) -> Size3D<u32, U> {
pub fn to_u32(&self) -> Size3D<u32, U> {
self.cast()
}
@ -1174,7 +1196,7 @@ impl<T: NumCast + Copy, U> Size3D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_i32(self) -> Size3D<i32, U> {
pub fn to_i32(&self) -> Size3D<i32, U> {
self.cast()
}
@ -1184,7 +1206,7 @@ impl<T: NumCast + Copy, U> Size3D<T, U> {
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_i64(self) -> Size3D<i64, U> {
pub fn to_i64(&self) -> Size3D<i64, U> {
self.cast()
}
}
@ -1195,12 +1217,12 @@ impl<T: Signed, U> Size3D<T, U> {
/// 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 {
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 {
pub fn is_positive(&self) -> bool {
self.width.is_positive() && self.height.is_positive() && self.depth.is_positive()
}
}
@ -1231,7 +1253,7 @@ impl<T: PartialOrd, U> Size3D<T, U> {
///
/// 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,
{
@ -1239,7 +1261,7 @@ 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 {
pub fn greater_than(&self, other: Self) -> BoolVector3D {
BoolVector3D {
x: self.width > other.width,
y: self.height > other.height,
@ -1248,7 +1270,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 {
pub fn lower_than(&self, other: Self) -> BoolVector3D {
BoolVector3D {
x: self.width < other.width,
y: self.height < other.height,
@ -1256,8 +1278,8 @@ impl<T: PartialOrd, U> Size3D<T, U> {
}
}
/// Returns `true` if any component of size is zero, negative or NaN.
pub fn is_empty(self) -> bool
/// Returns `true` if any component of size is zero or negative.
pub fn is_empty_or_negative(&self) -> bool
where
T: Zero,
{
@ -1268,7 +1290,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 {
pub fn equal(&self, other: Self) -> BoolVector3D {
BoolVector3D {
x: self.width == other.width,
y: self.height == other.height,
@ -1277,7 +1299,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 {
pub fn not_equal(&self, other: Self) -> BoolVector3D {
BoolVector3D {
x: self.width != other.width,
y: self.height != other.height,
@ -1290,7 +1312,7 @@ impl<T: Round, U> Round for Size3D<T, U> {
/// See [`Size3D::round()`](#method.round).
#[inline]
fn round(self) -> Self {
self.round()
(&self).round()
}
}
@ -1298,7 +1320,7 @@ impl<T: Ceil, U> Ceil for Size3D<T, U> {
/// See [`Size3D::ceil()`](#method.ceil).
#[inline]
fn ceil(self) -> Self {
self.ceil()
(&self).ceil()
}
}
@ -1306,7 +1328,7 @@ impl<T: Floor, U> Floor for Size3D<T, U> {
/// See [`Size3D::floor()`](#method.floor).
#[inline]
fn floor(self) -> Self {
self.floor()
(&self).floor()
}
}
@ -1370,84 +1392,84 @@ impl<T: SubAssign, U> SubAssign for Size3D<T, U> {
}
}
impl<T: Copy + Mul, U> Mul<T> for Size3D<T, U> {
impl<T: Clone + Mul, U> Mul<T> for Size3D<T, U> {
type Output = Size3D<T::Output, U>;
#[inline]
fn mul(self, scale: T) -> Self::Output {
Size3D::new(
self.width * scale,
self.height * scale,
self.width * scale.clone(),
self.height * scale.clone(),
self.depth * scale,
)
}
}
impl<T: Copy + MulAssign, U> MulAssign<T> for Size3D<T, U> {
impl<T: Clone + MulAssign, U> MulAssign<T> for Size3D<T, U> {
#[inline]
fn mul_assign(&mut self, other: T) {
self.width *= other;
self.height *= other;
self.width *= other.clone();
self.height *= other.clone();
self.depth *= other;
}
}
impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Size3D<T, U1> {
impl<T: Clone + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Size3D<T, U1> {
type Output = Size3D<T::Output, U2>;
#[inline]
fn mul(self, scale: Scale<T, U1, U2>) -> Self::Output {
Size3D::new(
self.width * scale.0,
self.height * scale.0,
self.width * scale.0.clone(),
self.height * scale.0.clone(),
self.depth * scale.0,
)
}
}
impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Size3D<T, U> {
impl<T: Clone + MulAssign, U> MulAssign<Scale<T, U, U>> for Size3D<T, U> {
#[inline]
fn mul_assign(&mut self, other: Scale<T, U, U>) {
*self *= other.0;
}
}
impl<T: Copy + Div, U> Div<T> for Size3D<T, U> {
impl<T: Clone + Div, U> Div<T> for Size3D<T, U> {
type Output = Size3D<T::Output, U>;
#[inline]
fn div(self, scale: T) -> Self::Output {
Size3D::new(
self.width / scale,
self.height / scale,
self.width / scale.clone(),
self.height / scale.clone(),
self.depth / scale,
)
}
}
impl<T: Copy + DivAssign, U> DivAssign<T> for Size3D<T, U> {
impl<T: Clone + DivAssign, U> DivAssign<T> for Size3D<T, U> {
#[inline]
fn div_assign(&mut self, other: T) {
self.width /= other;
self.height /= other;
self.width /= other.clone();
self.height /= other.clone();
self.depth /= other;
}
}
impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Size3D<T, U2> {
impl<T: Clone + Div, U1, U2> Div<Scale<T, U1, U2>> for Size3D<T, U2> {
type Output = Size3D<T::Output, U1>;
#[inline]
fn div(self, scale: Scale<T, U1, U2>) -> Self::Output {
Size3D::new(
self.width / scale.0,
self.height / scale.0,
self.width / scale.0.clone(),
self.height / scale.0.clone(),
self.depth / scale.0,
)
}
}
impl<T: Copy + DivAssign, U> DivAssign<Scale<T, U, U>> for Size3D<T, U> {
impl<T: Clone + DivAssign, U> DivAssign<Scale<T, U, U>> for Size3D<T, U> {
#[inline]
fn div_assign(&mut self, other: Scale<T, U, U>) {
*self /= other.0;
@ -1688,9 +1710,9 @@ mod size3d {
#[test]
pub fn test_nan_empty() {
use std::f32::NAN;
assert!(Size3D::new(NAN, 2.0, 3.0).is_empty());
assert!(Size3D::new(0.0, NAN, 0.0).is_empty());
assert!(Size3D::new(1.0, 2.0, NAN).is_empty());
assert!(Size3D::new(NAN, 2.0, 3.0).is_empty_or_negative());
assert!(Size3D::new(0.0, NAN, 0.0).is_empty_or_negative());
assert!(Size3D::new(1.0, 2.0, NAN).is_empty_or_negative());
}
}
}

Some files were not shown because too many files have changed in this diff Show More