Backed out 3 changesets (bug 1656236) for wrench failures on filter-drop-shadow-clip-3.yaml. CLOSED TREE

Backed out changeset 78205b816ac8 (bug 1656236)
Backed out changeset dc4ccb5a8ea9 (bug 1656236)
Backed out changeset dcfa644ba078 (bug 1656236)
This commit is contained in:
Csoregi Natalia 2020-08-18 20:22:57 +03:00
parent b0ffe6a42b
commit fd9ca77e37
111 changed files with 1833 additions and 1295 deletions

8
Cargo.lock generated
View File

@ -1331,9 +1331,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",
@ -3736,9 +3736,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"

View File

@ -134,7 +134,7 @@ impl SwTile {
} else {
self.valid_rect.translate(origin.to_vector())
};
let device_rect = transform.outer_transformed_rect(&bounds.to_f32().cast_unit()).unwrap().round_out().to_i32();
let device_rect = transform.transform_rect(&bounds.to_f32().cast_unit()).unwrap().round_out().to_i32();
device_rect.cast_unit().intersection(clip_rect)
}
@ -161,7 +161,7 @@ impl SwTile {
clip_rect: &DeviceIntRect,
) -> Option<(DeviceIntRect, DeviceIntRect, bool)> {
let valid = self.valid_rect.translate(self.origin(surface).to_vector());
let valid = transform.outer_transformed_rect(&valid.to_f32().cast_unit()).unwrap().round_out().to_i32();
let valid = transform.transform_rect(&valid.to_f32().cast_unit()).unwrap().round_out().to_i32();
valid.cast_unit().intersection(clip_rect).map(|r| (r.translate(-valid.origin.to_vector().cast_unit()), r, transform.m22 < 0.0))
}
}

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

@ -56,7 +56,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

@ -1191,7 +1191,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);
@ -1250,7 +1250,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,
@ -2483,14 +2485,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;
@ -572,7 +573,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],
@ -748,7 +749,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

@ -486,7 +486,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
@ -494,7 +494,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
@ -509,12 +509,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

@ -1222,7 +1222,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

@ -506,9 +506,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))
}
}
@ -517,10 +516,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
radius: 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

View File

@ -2,7 +2,7 @@ root:
items:
- type: stacking-context
bounds: [0, 0, 300, 60]
transform: rotate(-90) translate(-120, 160)
transform: rotate(90) translate(-120, 160)
items:
- text: "This is sideways-left"
origin: 0 40
@ -10,7 +10,7 @@ root:
font: "FreeSans.ttf"
- type: stacking-context
bounds: [0, 0, 300, 60]
transform: rotate(90) translate(-90, 120)
transform: rotate(-90) translate(-90, 120)
items:
- text: "This is sideways-right"
origin: 0 40

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)
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)
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

@ -6598,7 +6598,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;

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