mirror of https://github.com/SixLabors/ImageSharp
committed by
GitHub
364 changed files with 5112 additions and 617 deletions
@ -0,0 +1,34 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors |
|||
{ |
|||
/// <summary>
|
|||
/// Utility class for common geometric functions.
|
|||
/// </summary>
|
|||
public static class GeometryUtilities |
|||
{ |
|||
/// <summary>
|
|||
/// Converts a degree (360-periodic) angle to a radian (2*Pi-periodic) angle.
|
|||
/// </summary>
|
|||
/// <param name="degree">The angle in degrees.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="float"/> representing the degree as radians.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static float DegreeToRadian(float degree) => degree * (MathF.PI / 180F); |
|||
|
|||
/// <summary>
|
|||
/// Converts a radian (2*Pi-periodic) angle to a degree (360-periodic) angle.
|
|||
/// </summary>
|
|||
/// <param name="radian">The angle in radians.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="float"/> representing the degree as radians.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static float RadianToDegree(float radian) => radian / (MathF.PI / 180F); |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Memory |
|||
{ |
|||
/// <summary>
|
|||
/// Options for allocating buffers.
|
|||
/// </summary>
|
|||
public enum AllocationOptions |
|||
{ |
|||
/// <summary>
|
|||
/// Indicates that the buffer should just be allocated.
|
|||
/// </summary>
|
|||
None, |
|||
|
|||
/// <summary>
|
|||
/// Indicates that the allocated buffer should be cleaned following allocation.
|
|||
/// </summary>
|
|||
Clean |
|||
} |
|||
} |
|||
@ -0,0 +1,85 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using System.Runtime.InteropServices; |
|||
using SixLabors.ImageSharp.Memory.Internals; |
|||
|
|||
namespace SixLabors.ImageSharp.Memory |
|||
{ |
|||
/// <summary>
|
|||
/// Contains <see cref="Buffer{T}"/> and <see cref="ManagedByteBuffer"/>.
|
|||
/// </summary>
|
|||
public partial class ArrayPoolMemoryAllocator |
|||
{ |
|||
/// <summary>
|
|||
/// The buffer implementation of <see cref="ArrayPoolMemoryAllocator"/>.
|
|||
/// </summary>
|
|||
private class Buffer<T> : ManagedBufferBase<T> |
|||
where T : struct |
|||
{ |
|||
/// <summary>
|
|||
/// The length of the buffer.
|
|||
/// </summary>
|
|||
private readonly int length; |
|||
|
|||
/// <summary>
|
|||
/// A weak reference to the source pool.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// By using a weak reference here, we are making sure that array pools and their retained arrays are always GC-ed
|
|||
/// after a call to <see cref="ArrayPoolMemoryAllocator.ReleaseRetainedResources"/>, regardless of having buffer instances still being in use.
|
|||
/// </remarks>
|
|||
private WeakReference<ArrayPool<byte>> sourcePoolReference; |
|||
|
|||
public Buffer(byte[] data, int length, ArrayPool<byte> sourcePool) |
|||
{ |
|||
this.Data = data; |
|||
this.length = length; |
|||
this.sourcePoolReference = new WeakReference<ArrayPool<byte>>(sourcePool); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the buffer as a byte array.
|
|||
/// </summary>
|
|||
protected byte[] Data { get; private set; } |
|||
|
|||
/// <inheritdoc />
|
|||
public override Span<T> GetSpan() => MemoryMarshal.Cast<byte, T>(this.Data.AsSpan()).Slice(0, this.length); |
|||
|
|||
/// <inheritdoc />
|
|||
protected override void Dispose(bool disposing) |
|||
{ |
|||
if (!disposing || this.Data is null || this.sourcePoolReference is null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (this.sourcePoolReference.TryGetTarget(out ArrayPool<byte> pool)) |
|||
{ |
|||
pool.Return(this.Data); |
|||
} |
|||
|
|||
this.sourcePoolReference = null; |
|||
this.Data = null; |
|||
} |
|||
|
|||
protected override object GetPinnableObject() => this.Data; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The <see cref="IManagedByteBuffer"/> implementation of <see cref="ArrayPoolMemoryAllocator"/>.
|
|||
/// </summary>
|
|||
private sealed class ManagedByteBuffer : Buffer<byte>, IManagedByteBuffer |
|||
{ |
|||
public ManagedByteBuffer(byte[] data, int length, ArrayPool<byte> sourcePool) |
|||
: base(data, length, sourcePool) |
|||
{ |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public byte[] Array => this.Data; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,72 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Memory |
|||
{ |
|||
/// <summary>
|
|||
/// Contains common factory methods and configuration constants.
|
|||
/// </summary>
|
|||
public partial class ArrayPoolMemoryAllocator |
|||
{ |
|||
/// <summary>
|
|||
/// The default value for: maximum size of pooled arrays in bytes.
|
|||
/// Currently set to 24MB, which is equivalent to 8 megapixels of raw RGBA32 data.
|
|||
/// </summary>
|
|||
internal const int DefaultMaxPooledBufferSizeInBytes = 24 * 1024 * 1024; |
|||
|
|||
/// <summary>
|
|||
/// The value for: The threshold to pool arrays in <see cref="largeArrayPool"/> which has less buckets for memory safety.
|
|||
/// </summary>
|
|||
private const int DefaultBufferSelectorThresholdInBytes = 8 * 1024 * 1024; |
|||
|
|||
/// <summary>
|
|||
/// The default bucket count for <see cref="largeArrayPool"/>.
|
|||
/// </summary>
|
|||
private const int DefaultLargePoolBucketCount = 6; |
|||
|
|||
/// <summary>
|
|||
/// The default bucket count for <see cref="normalArrayPool"/>.
|
|||
/// </summary>
|
|||
private const int DefaultNormalPoolBucketCount = 16; |
|||
|
|||
/// <summary>
|
|||
/// This is the default. Should be good for most use cases.
|
|||
/// </summary>
|
|||
/// <returns>The memory manager.</returns>
|
|||
public static ArrayPoolMemoryAllocator CreateDefault() |
|||
{ |
|||
return new ArrayPoolMemoryAllocator( |
|||
DefaultMaxPooledBufferSizeInBytes, |
|||
DefaultBufferSelectorThresholdInBytes, |
|||
DefaultLargePoolBucketCount, |
|||
DefaultNormalPoolBucketCount); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// For environments with very limited memory capabilities, only small buffers like image rows are pooled.
|
|||
/// </summary>
|
|||
/// <returns>The memory manager.</returns>
|
|||
public static ArrayPoolMemoryAllocator CreateWithMinimalPooling() |
|||
{ |
|||
return new ArrayPoolMemoryAllocator(64 * 1024, 32 * 1024, 8, 24); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// For environments with limited memory capabilities, only small array requests are pooled, which can result in reduced throughput.
|
|||
/// </summary>
|
|||
/// <returns>The memory manager.</returns>
|
|||
public static ArrayPoolMemoryAllocator CreateWithModeratePooling() |
|||
{ |
|||
return new ArrayPoolMemoryAllocator(1024 * 1024, 32 * 1024, 16, 24); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// For environments where memory capabilities are not an issue, the maximum amount of array requests are pooled which results in optimal throughput.
|
|||
/// </summary>
|
|||
/// <returns>The memory manager.</returns>
|
|||
public static ArrayPoolMemoryAllocator CreateWithAggressivePooling() |
|||
{ |
|||
return new ArrayPoolMemoryAllocator(128 * 1024 * 1024, 32 * 1024 * 1024, 16, 32); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,150 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.Memory |
|||
{ |
|||
/// <summary>
|
|||
/// Implements <see cref="MemoryAllocator"/> by allocating memory from <see cref="ArrayPool{T}"/>.
|
|||
/// </summary>
|
|||
public sealed partial class ArrayPoolMemoryAllocator : MemoryAllocator |
|||
{ |
|||
private readonly int maxArraysPerBucketNormalPool; |
|||
|
|||
private readonly int maxArraysPerBucketLargePool; |
|||
|
|||
/// <summary>
|
|||
/// The <see cref="ArrayPool{T}"/> for small-to-medium buffers which is not kept clean.
|
|||
/// </summary>
|
|||
private ArrayPool<byte> normalArrayPool; |
|||
|
|||
/// <summary>
|
|||
/// The <see cref="ArrayPool{T}"/> for huge buffers, which is not kept clean.
|
|||
/// </summary>
|
|||
private ArrayPool<byte> largeArrayPool; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ArrayPoolMemoryAllocator"/> class.
|
|||
/// </summary>
|
|||
public ArrayPoolMemoryAllocator() |
|||
: this(DefaultMaxPooledBufferSizeInBytes, DefaultBufferSelectorThresholdInBytes) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ArrayPoolMemoryAllocator"/> class.
|
|||
/// </summary>
|
|||
/// <param name="maxPoolSizeInBytes">The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.</param>
|
|||
public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes) |
|||
: this(maxPoolSizeInBytes, GetLargeBufferThresholdInBytes(maxPoolSizeInBytes)) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ArrayPoolMemoryAllocator"/> class.
|
|||
/// </summary>
|
|||
/// <param name="maxPoolSizeInBytes">The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.</param>
|
|||
/// <param name="poolSelectorThresholdInBytes">Arrays over this threshold will be pooled in <see cref="largeArrayPool"/> which has less buckets for memory safety.</param>
|
|||
public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes) |
|||
: this(maxPoolSizeInBytes, poolSelectorThresholdInBytes, DefaultLargePoolBucketCount, DefaultNormalPoolBucketCount) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ArrayPoolMemoryAllocator"/> class.
|
|||
/// </summary>
|
|||
/// <param name="maxPoolSizeInBytes">The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.</param>
|
|||
/// <param name="poolSelectorThresholdInBytes">The threshold to pool arrays in <see cref="largeArrayPool"/> which has less buckets for memory safety.</param>
|
|||
/// <param name="maxArraysPerBucketLargePool">Max arrays per bucket for the large array pool.</param>
|
|||
/// <param name="maxArraysPerBucketNormalPool">Max arrays per bucket for the normal array pool.</param>
|
|||
public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes, int maxArraysPerBucketLargePool, int maxArraysPerBucketNormalPool) |
|||
{ |
|||
Guard.MustBeGreaterThan(maxPoolSizeInBytes, 0, nameof(maxPoolSizeInBytes)); |
|||
Guard.MustBeLessThanOrEqualTo(poolSelectorThresholdInBytes, maxPoolSizeInBytes, nameof(poolSelectorThresholdInBytes)); |
|||
|
|||
this.MaxPoolSizeInBytes = maxPoolSizeInBytes; |
|||
this.PoolSelectorThresholdInBytes = poolSelectorThresholdInBytes; |
|||
this.maxArraysPerBucketLargePool = maxArraysPerBucketLargePool; |
|||
this.maxArraysPerBucketNormalPool = maxArraysPerBucketNormalPool; |
|||
|
|||
this.InitArrayPools(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the maximum size of pooled arrays in bytes.
|
|||
/// </summary>
|
|||
public int MaxPoolSizeInBytes { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the threshold to pool arrays in <see cref="largeArrayPool"/> which has less buckets for memory safety.
|
|||
/// </summary>
|
|||
public int PoolSelectorThresholdInBytes { get; } |
|||
|
|||
/// <inheritdoc />
|
|||
public override void ReleaseRetainedResources() |
|||
{ |
|||
this.InitArrayPools(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override IMemoryOwner<T> Allocate<T>(int length, AllocationOptions options = AllocationOptions.None) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length)); |
|||
int itemSizeBytes = Unsafe.SizeOf<T>(); |
|||
int bufferSizeInBytes = length * itemSizeBytes; |
|||
if (bufferSizeInBytes < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException( |
|||
nameof(length), |
|||
$"{nameof(ArrayPoolMemoryAllocator)} can not allocate {length} elements of {typeof(T).Name}."); |
|||
} |
|||
|
|||
ArrayPool<byte> pool = this.GetArrayPool(bufferSizeInBytes); |
|||
byte[] byteArray = pool.Rent(bufferSizeInBytes); |
|||
|
|||
var buffer = new Buffer<T>(byteArray, length, pool); |
|||
if (options == AllocationOptions.Clean) |
|||
{ |
|||
buffer.GetSpan().Clear(); |
|||
} |
|||
|
|||
return buffer; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length)); |
|||
|
|||
ArrayPool<byte> pool = this.GetArrayPool(length); |
|||
byte[] byteArray = pool.Rent(length); |
|||
|
|||
var buffer = new ManagedByteBuffer(byteArray, length, pool); |
|||
if (options == AllocationOptions.Clean) |
|||
{ |
|||
buffer.GetSpan().Clear(); |
|||
} |
|||
|
|||
return buffer; |
|||
} |
|||
|
|||
private static int GetLargeBufferThresholdInBytes(int maxPoolSizeInBytes) |
|||
{ |
|||
return maxPoolSizeInBytes / 4; |
|||
} |
|||
|
|||
private ArrayPool<byte> GetArrayPool(int bufferSizeInBytes) |
|||
{ |
|||
return bufferSizeInBytes <= this.PoolSelectorThresholdInBytes ? this.normalArrayPool : this.largeArrayPool; |
|||
} |
|||
|
|||
private void InitArrayPools() |
|||
{ |
|||
this.largeArrayPool = ArrayPool<byte>.Create(this.MaxPoolSizeInBytes, this.maxArraysPerBucketLargePool); |
|||
this.normalArrayPool = ArrayPool<byte>.Create(this.PoolSelectorThresholdInBytes, this.maxArraysPerBucketNormalPool); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Buffers; |
|||
|
|||
namespace SixLabors.ImageSharp.Memory |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a byte buffer backed by a managed array. Useful for interop with classic .NET API-s.
|
|||
/// </summary>
|
|||
public interface IManagedByteBuffer : IMemoryOwner<byte> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the managed array backing this buffer instance.
|
|||
/// </summary>
|
|||
byte[] Array { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
|
|||
namespace SixLabors.ImageSharp.Memory.Internals |
|||
{ |
|||
/// <summary>
|
|||
/// Wraps an array as an <see cref="IManagedByteBuffer"/> instance.
|
|||
/// </summary>
|
|||
/// <inheritdoc />
|
|||
internal class BasicArrayBuffer<T> : ManagedBufferBase<T> |
|||
where T : struct |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BasicArrayBuffer{T}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="array">The array.</param>
|
|||
/// <param name="length">The length of the buffer.</param>
|
|||
public BasicArrayBuffer(T[] array, int length) |
|||
{ |
|||
DebugGuard.MustBeLessThanOrEqualTo(length, array.Length, nameof(length)); |
|||
this.Array = array; |
|||
this.Length = length; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BasicArrayBuffer{T}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="array">The array.</param>
|
|||
public BasicArrayBuffer(T[] array) |
|||
: this(array, array.Length) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the array.
|
|||
/// </summary>
|
|||
public T[] Array { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the length.
|
|||
/// </summary>
|
|||
public int Length { get; } |
|||
|
|||
/// <inheritdoc />
|
|||
public override Span<T> GetSpan() => this.Array.AsSpan(0, this.Length); |
|||
|
|||
/// <inheritdoc />
|
|||
protected override void Dispose(bool disposing) |
|||
{ |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
protected override object GetPinnableObject() |
|||
{ |
|||
return this.Array; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Memory.Internals |
|||
{ |
|||
/// <summary>
|
|||
/// Provides an <see cref="IManagedByteBuffer"/> based on <see cref="BasicArrayBuffer{T}"/>.
|
|||
/// </summary>
|
|||
internal sealed class BasicByteBuffer : BasicArrayBuffer<byte>, IManagedByteBuffer |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BasicByteBuffer"/> class.
|
|||
/// </summary>
|
|||
/// <param name="array">The byte array.</param>
|
|||
internal BasicByteBuffer(byte[] array) |
|||
: base(array) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Buffers; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace SixLabors.ImageSharp.Memory.Internals |
|||
{ |
|||
/// <summary>
|
|||
/// Provides a base class for <see cref="IMemoryOwner{T}"/> implementations by implementing pinning logic for <see cref="MemoryManager{T}"/> adaption.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The element type.</typeparam>
|
|||
internal abstract class ManagedBufferBase<T> : MemoryManager<T> |
|||
where T : struct |
|||
{ |
|||
private GCHandle pinHandle; |
|||
|
|||
/// <inheritdoc />
|
|||
public override unsafe MemoryHandle Pin(int elementIndex = 0) |
|||
{ |
|||
if (!this.pinHandle.IsAllocated) |
|||
{ |
|||
this.pinHandle = GCHandle.Alloc(this.GetPinnableObject(), GCHandleType.Pinned); |
|||
} |
|||
|
|||
void* ptr = (void*)this.pinHandle.AddrOfPinnedObject(); |
|||
return new MemoryHandle(ptr, this.pinHandle); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Unpin() |
|||
{ |
|||
if (this.pinHandle.IsAllocated) |
|||
{ |
|||
this.pinHandle.Free(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the object that should be pinned.
|
|||
/// </summary>
|
|||
/// <returns>The pinnable <see cref="object"/>.</returns>
|
|||
protected abstract object GetPinnableObject(); |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Buffers; |
|||
|
|||
namespace SixLabors.ImageSharp.Memory |
|||
{ |
|||
/// <summary>
|
|||
/// Memory managers are used to allocate memory for image processing operations.
|
|||
/// </summary>
|
|||
public abstract class MemoryAllocator |
|||
{ |
|||
/// <summary>
|
|||
/// Allocates an <see cref="IMemoryOwner{T}" />, holding a <see cref="System.Memory{T}"/> of length <paramref name="length"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">Type of the data stored in the buffer.</typeparam>
|
|||
/// <param name="length">Size of the buffer to allocate.</param>
|
|||
/// <param name="options">The allocation options.</param>
|
|||
/// <returns>A buffer of values of type <typeparamref name="T"/>.</returns>
|
|||
public abstract IMemoryOwner<T> Allocate<T>(int length, AllocationOptions options = AllocationOptions.None) |
|||
where T : struct; |
|||
|
|||
/// <summary>
|
|||
/// Allocates an <see cref="IManagedByteBuffer"/>.
|
|||
/// </summary>
|
|||
/// <param name="length">The requested buffer length.</param>
|
|||
/// <param name="options">The allocation options.</param>
|
|||
/// <returns>The <see cref="IManagedByteBuffer"/>.</returns>
|
|||
public abstract IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None); |
|||
|
|||
/// <summary>
|
|||
/// Releases all retained resources not being in use.
|
|||
/// Eg: by resetting array pools and letting GC to free the arrays.
|
|||
/// </summary>
|
|||
public virtual void ReleaseRetainedResources() |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Buffers; |
|||
using SixLabors.ImageSharp.Memory.Internals; |
|||
|
|||
namespace SixLabors.ImageSharp.Memory |
|||
{ |
|||
/// <summary>
|
|||
/// Implements <see cref="MemoryAllocator"/> by newing up arrays by the GC on every allocation requests.
|
|||
/// </summary>
|
|||
public sealed class SimpleGcMemoryAllocator : MemoryAllocator |
|||
{ |
|||
/// <inheritdoc />
|
|||
public override IMemoryOwner<T> Allocate<T>(int length, AllocationOptions options = AllocationOptions.None) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length)); |
|||
|
|||
return new BasicArrayBuffer<T>(new T[length]); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length)); |
|||
|
|||
return new BasicByteBuffer(new byte[length]); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,101 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Numerics; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Extension methods for the <see cref="Matrix3x2"/> struct.
|
|||
/// </summary>
|
|||
public static class Matrix3x2Extensions |
|||
{ |
|||
/// <summary>
|
|||
/// Creates a translation matrix from the given vector.
|
|||
/// </summary>
|
|||
/// <param name="position">The translation position.</param>
|
|||
/// <returns>A translation matrix.</returns>
|
|||
public static Matrix3x2 CreateTranslation(PointF position) => Matrix3x2.CreateTranslation(position); |
|||
|
|||
/// <summary>
|
|||
/// Creates a scale matrix that is offset by a given center point.
|
|||
/// </summary>
|
|||
/// <param name="xScale">Value to scale by on the X-axis.</param>
|
|||
/// <param name="yScale">Value to scale by on the Y-axis.</param>
|
|||
/// <param name="centerPoint">The center point.</param>
|
|||
/// <returns>A scaling matrix.</returns>
|
|||
public static Matrix3x2 CreateScale(float xScale, float yScale, PointF centerPoint) => Matrix3x2.CreateScale(xScale, yScale, centerPoint); |
|||
|
|||
/// <summary>
|
|||
/// Creates a scale matrix from the given vector scale.
|
|||
/// </summary>
|
|||
/// <param name="scales">The scale to use.</param>
|
|||
/// <returns>A scaling matrix.</returns>
|
|||
public static Matrix3x2 CreateScale(SizeF scales) => Matrix3x2.CreateScale(scales); |
|||
|
|||
/// <summary>
|
|||
/// Creates a scale matrix from the given vector scale with an offset from the given center point.
|
|||
/// </summary>
|
|||
/// <param name="scales">The scale to use.</param>
|
|||
/// <param name="centerPoint">The center offset.</param>
|
|||
/// <returns>A scaling matrix.</returns>
|
|||
public static Matrix3x2 CreateScale(SizeF scales, PointF centerPoint) => Matrix3x2.CreateScale(scales, centerPoint); |
|||
|
|||
/// <summary>
|
|||
/// Creates a scale matrix that scales uniformly with the given scale with an offset from the given center.
|
|||
/// </summary>
|
|||
/// <param name="scale">The uniform scale to use.</param>
|
|||
/// <param name="centerPoint">The center offset.</param>
|
|||
/// <returns>A scaling matrix.</returns>
|
|||
public static Matrix3x2 CreateScale(float scale, PointF centerPoint) => Matrix3x2.CreateScale(scale, centerPoint); |
|||
|
|||
/// <summary>
|
|||
/// Creates a skew matrix from the given angles in degrees.
|
|||
/// </summary>
|
|||
/// <param name="degreesX">The X angle, in degrees.</param>
|
|||
/// <param name="degreesY">The Y angle, in degrees.</param>
|
|||
/// <returns>A skew matrix.</returns>
|
|||
public static Matrix3x2 CreateSkewDegrees(float degreesX, float degreesY) => Matrix3x2.CreateSkew(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY)); |
|||
|
|||
/// <summary>
|
|||
/// Creates a skew matrix from the given angles in radians and a center point.
|
|||
/// </summary>
|
|||
/// <param name="radiansX">The X angle, in radians.</param>
|
|||
/// <param name="radiansY">The Y angle, in radians.</param>
|
|||
/// <param name="centerPoint">The center point.</param>
|
|||
/// <returns>A skew matrix.</returns>
|
|||
public static Matrix3x2 CreateSkew(float radiansX, float radiansY, PointF centerPoint) => Matrix3x2.CreateSkew(radiansX, radiansY, centerPoint); |
|||
|
|||
/// <summary>
|
|||
/// Creates a skew matrix from the given angles in degrees and a center point.
|
|||
/// </summary>
|
|||
/// <param name="degreesX">The X angle, in degrees.</param>
|
|||
/// <param name="degreesY">The Y angle, in degrees.</param>
|
|||
/// <param name="centerPoint">The center point.</param>
|
|||
/// <returns>A skew matrix.</returns>
|
|||
public static Matrix3x2 CreateSkewDegrees(float degreesX, float degreesY, PointF centerPoint) => Matrix3x2.CreateSkew(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), centerPoint); |
|||
|
|||
/// <summary>
|
|||
/// Creates a rotation matrix using the given rotation in degrees.
|
|||
/// </summary>
|
|||
/// <param name="degrees">The amount of rotation, in degrees.</param>
|
|||
/// <returns>A rotation matrix.</returns>
|
|||
public static Matrix3x2 CreateRotationDegrees(float degrees) => Matrix3x2.CreateRotation(GeometryUtilities.DegreeToRadian(degrees)); |
|||
|
|||
/// <summary>
|
|||
/// Creates a rotation matrix using the given rotation in radians and a center point.
|
|||
/// </summary>
|
|||
/// <param name="radians">The amount of rotation, in radians.</param>
|
|||
/// <param name="centerPoint">The center point.</param>
|
|||
/// <returns>A rotation matrix.</returns>
|
|||
public static Matrix3x2 CreateRotation(float radians, PointF centerPoint) => Matrix3x2.CreateRotation(radians, centerPoint); |
|||
|
|||
/// <summary>
|
|||
/// Creates a rotation matrix using the given rotation in degrees and a center point.
|
|||
/// </summary>
|
|||
/// <param name="degrees">The amount of rotation, in degrees.</param>
|
|||
/// <param name="centerPoint">The center point.</param>
|
|||
/// <returns>A rotation matrix.</returns>
|
|||
public static Matrix3x2 CreateRotationDegrees(float degrees, PointF centerPoint) => Matrix3x2.CreateRotation(GeometryUtilities.DegreeToRadian(degrees), centerPoint); |
|||
} |
|||
} |
|||
@ -0,0 +1,288 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Represents an ordered pair of integer x- and y-coordinates that defines a point in
|
|||
/// a two-dimensional plane.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|||
/// as it avoids the need to create new values for modification operations.
|
|||
/// </remarks>
|
|||
public struct Point : IEquatable<Point> |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a <see cref="Point"/> that has X and Y values set to zero.
|
|||
/// </summary>
|
|||
public static readonly Point Empty = default; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Point"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="value">The horizontal and vertical position of the point.</param>
|
|||
public Point(int value) |
|||
: this() |
|||
{ |
|||
this.X = LowInt16(value); |
|||
this.Y = HighInt16(value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Point"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The horizontal position of the point.</param>
|
|||
/// <param name="y">The vertical position of the point.</param>
|
|||
public Point(int x, int y) |
|||
: this() |
|||
{ |
|||
this.X = x; |
|||
this.Y = y; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Point"/> struct from the given <see cref="Size"/>.
|
|||
/// </summary>
|
|||
/// <param name="size">The size.</param>
|
|||
public Point(Size size) |
|||
{ |
|||
this.X = size.Width; |
|||
this.Y = size.Height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the x-coordinate of this <see cref="Point"/>.
|
|||
/// </summary>
|
|||
public int X { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the y-coordinate of this <see cref="Point"/>.
|
|||
/// </summary>
|
|||
public int Y { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this <see cref="Point"/> is empty.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public bool IsEmpty => this.Equals(Empty); |
|||
|
|||
/// <summary>
|
|||
/// Creates a <see cref="PointF"/> with the coordinates of the specified <see cref="Point"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static implicit operator PointF(Point point) => new PointF(point.X, point.Y); |
|||
|
|||
/// <summary>
|
|||
/// Creates a <see cref="Vector2"/> with the coordinates of the specified <see cref="Point"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static implicit operator Vector2(Point point) => new Vector2(point.X, point.Y); |
|||
|
|||
/// <summary>
|
|||
/// Creates a <see cref="Size"/> with the coordinates of the specified <see cref="Point"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static explicit operator Size(Point point) => new Size(point.X, point.Y); |
|||
|
|||
/// <summary>
|
|||
/// Negates the given point by multiplying all values by -1.
|
|||
/// </summary>
|
|||
/// <param name="value">The source point.</param>
|
|||
/// <returns>The negated point.</returns>
|
|||
public static Point operator -(Point value) => new Point(-value.X, -value.Y); |
|||
|
|||
/// <summary>
|
|||
/// Translates a <see cref="Point"/> by a given <see cref="Size"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point on the left hand of the operand.</param>
|
|||
/// <param name="size">The size on the right hand of the operand.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Point"/>.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Point operator +(Point point, Size size) => Add(point, size); |
|||
|
|||
/// <summary>
|
|||
/// Translates a <see cref="Point"/> by the negative of a given <see cref="Size"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point on the left hand of the operand.</param>
|
|||
/// <param name="size">The size on the right hand of the operand.</param>
|
|||
/// <returns>The <see cref="Point"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Point operator -(Point point, Size size) => Subtract(point, size); |
|||
|
|||
/// <summary>
|
|||
/// Multiplies <see cref="Point"/> by a <see cref="int"/> producing <see cref="Point"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">Multiplier of type <see cref="int"/>.</param>
|
|||
/// <param name="right">Multiplicand of type <see cref="Point"/>.</param>
|
|||
/// <returns>Product of type <see cref="Point"/>.</returns>
|
|||
public static Point operator *(int left, Point right) => Multiply(right, left); |
|||
|
|||
/// <summary>
|
|||
/// Multiplies <see cref="Point"/> by a <see cref="int"/> producing <see cref="Point"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">Multiplicand of type <see cref="Point"/>.</param>
|
|||
/// <param name="right">Multiplier of type <see cref="int"/>.</param>
|
|||
/// <returns>Product of type <see cref="Point"/>.</returns>
|
|||
public static Point operator *(Point left, int right) => Multiply(left, right); |
|||
|
|||
/// <summary>
|
|||
/// Divides <see cref="Point"/> by a <see cref="int"/> producing <see cref="Point"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">Dividend of type <see cref="Point"/>.</param>
|
|||
/// <param name="right">Divisor of type <see cref="int"/>.</param>
|
|||
/// <returns>Result of type <see cref="Point"/>.</returns>
|
|||
public static Point operator /(Point left, int right) |
|||
=> new Point(left.X / right, left.Y / right); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Point"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Point"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Point"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator ==(Point left, Point right) => left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Point"/> objects for inequality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Point"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Point"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator !=(Point left, Point right) => !left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Translates a <see cref="Point"/> by the negative of a given <see cref="Size"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point on the left hand of the operand.</param>
|
|||
/// <param name="size">The size on the right hand of the operand.</param>
|
|||
/// <returns>The <see cref="Point"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Point Add(Point point, Size size) => new Point(unchecked(point.X + size.Width), unchecked(point.Y + size.Height)); |
|||
|
|||
/// <summary>
|
|||
/// Translates a <see cref="Point"/> by the negative of a given value.
|
|||
/// </summary>
|
|||
/// <param name="point">The point on the left hand of the operand.</param>
|
|||
/// <param name="value">The value on the right hand of the operand.</param>
|
|||
/// <returns>The <see cref="Point"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Point Multiply(Point point, int value) => new Point(unchecked(point.X * value), unchecked(point.Y * value)); |
|||
|
|||
/// <summary>
|
|||
/// Translates a <see cref="Point"/> by the negative of a given <see cref="Size"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point on the left hand of the operand.</param>
|
|||
/// <param name="size">The size on the right hand of the operand.</param>
|
|||
/// <returns>The <see cref="Point"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Point Subtract(Point point, Size size) => new Point(unchecked(point.X - size.Width), unchecked(point.Y - size.Height)); |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="PointF"/> to a <see cref="Point"/> by performing a ceiling operation on all the coordinates.
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
/// <returns>The <see cref="Point"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Point Ceiling(PointF point) => new Point(unchecked((int)MathF.Ceiling(point.X)), unchecked((int)MathF.Ceiling(point.Y))); |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="PointF"/> to a <see cref="Point"/> by performing a round operation on all the coordinates.
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
/// <returns>The <see cref="Point"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Point Round(PointF point) => new Point(unchecked((int)MathF.Round(point.X)), unchecked((int)MathF.Round(point.Y))); |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="Vector2"/> to a <see cref="Point"/> by performing a round operation on all the coordinates.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector.</param>
|
|||
/// <returns>The <see cref="Point"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Point Round(Vector2 vector) => new Point(unchecked((int)MathF.Round(vector.X)), unchecked((int)MathF.Round(vector.Y))); |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="PointF"/> to a <see cref="Point"/> by performing a truncate operation on all the coordinates.
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
/// <returns>The <see cref="Point"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Point Truncate(PointF point) => new Point(unchecked((int)point.X), unchecked((int)point.Y)); |
|||
|
|||
/// <summary>
|
|||
/// Transforms a point by a specified 3x2 matrix.
|
|||
/// </summary>
|
|||
/// <param name="point">The point to transform.</param>
|
|||
/// <param name="matrix">The transformation matrix used.</param>
|
|||
/// <returns>The transformed <see cref="PointF"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Point Transform(Point point, Matrix3x2 matrix) => Round(Vector2.Transform(new Vector2(point.X, point.Y), matrix)); |
|||
|
|||
/// <summary>
|
|||
/// Deconstructs this point into two integers.
|
|||
/// </summary>
|
|||
/// <param name="x">The out value for X.</param>
|
|||
/// <param name="y">The out value for Y.</param>
|
|||
public void Deconstruct(out int x, out int y) |
|||
{ |
|||
x = this.X; |
|||
y = this.Y; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Translates this <see cref="Point"/> by the specified amount.
|
|||
/// </summary>
|
|||
/// <param name="dx">The amount to offset the x-coordinate.</param>
|
|||
/// <param name="dy">The amount to offset the y-coordinate.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Offset(int dx, int dy) |
|||
{ |
|||
unchecked |
|||
{ |
|||
this.X += dx; |
|||
this.Y += dy; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Translates this <see cref="Point"/> by the specified amount.
|
|||
/// </summary>
|
|||
/// <param name="point">The <see cref="Point"/> used offset this <see cref="Point"/>.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Offset(Point point) => this.Offset(point.X, point.Y); |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() => HashCode.Combine(this.X, this.Y); |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() => $"Point [ X={this.X}, Y={this.Y} ]"; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) => obj is Point other && this.Equals(other); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Equals(Point other) => this.X.Equals(other.X) && this.Y.Equals(other.Y); |
|||
|
|||
private static short HighInt16(int n) => unchecked((short)((n >> 16) & 0xffff)); |
|||
|
|||
private static short LowInt16(int n) => unchecked((short)(n & 0xffff)); |
|||
} |
|||
} |
|||
@ -0,0 +1,293 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Represents an ordered pair of single precision floating point x- and y-coordinates that defines a point in
|
|||
/// a two-dimensional plane.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|||
/// as it avoids the need to create new values for modification operations.
|
|||
/// </remarks>
|
|||
public struct PointF : IEquatable<PointF> |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a <see cref="PointF"/> that has X and Y values set to zero.
|
|||
/// </summary>
|
|||
public static readonly PointF Empty = default; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PointF"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The horizontal position of the point.</param>
|
|||
/// <param name="y">The vertical position of the point.</param>
|
|||
public PointF(float x, float y) |
|||
: this() |
|||
{ |
|||
this.X = x; |
|||
this.Y = y; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PointF"/> struct from the given <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="size">The size.</param>
|
|||
public PointF(SizeF size) |
|||
{ |
|||
this.X = size.Width; |
|||
this.Y = size.Height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the x-coordinate of this <see cref="PointF"/>.
|
|||
/// </summary>
|
|||
public float X { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the y-coordinate of this <see cref="PointF"/>.
|
|||
/// </summary>
|
|||
public float Y { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this <see cref="PointF"/> is empty.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public bool IsEmpty => this.Equals(Empty); |
|||
|
|||
/// <summary>
|
|||
/// Creates a <see cref="Vector2"/> with the coordinates of the specified <see cref="PointF"/>.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Vector2"/>.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static implicit operator PointF(Vector2 vector) => new PointF(vector.X, vector.Y); |
|||
|
|||
/// <summary>
|
|||
/// Creates a <see cref="Vector2"/> with the coordinates of the specified <see cref="PointF"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Vector2"/>.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static implicit operator Vector2(PointF point) => new Vector2(point.X, point.Y); |
|||
|
|||
/// <summary>
|
|||
/// Creates a <see cref="Point"/> with the coordinates of the specified <see cref="PointF"/> by truncating each of the coordinates.
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Point"/>.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static explicit operator Point(PointF point) => Point.Truncate(point); |
|||
|
|||
/// <summary>
|
|||
/// Negates the given point by multiplying all values by -1.
|
|||
/// </summary>
|
|||
/// <param name="value">The source point.</param>
|
|||
/// <returns>The negated point.</returns>
|
|||
public static PointF operator -(PointF value) => new PointF(-value.X, -value.Y); |
|||
|
|||
/// <summary>
|
|||
/// Translates a <see cref="PointF"/> by a given <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point on the left hand of the operand.</param>
|
|||
/// <param name="size">The size on the right hand of the operand.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="PointF"/>.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static PointF operator +(PointF point, SizeF size) => Add(point, size); |
|||
|
|||
/// <summary>
|
|||
/// Translates a <see cref="PointF"/> by the negative of a given <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point on the left hand of the operand.</param>
|
|||
/// <param name="size">The size on the right hand of the operand.</param>
|
|||
/// <returns>The <see cref="PointF"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static PointF operator -(PointF point, PointF size) => Subtract(point, size); |
|||
|
|||
/// <summary>
|
|||
/// Translates a <see cref="PointF"/> by a given <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point on the left hand of the operand.</param>
|
|||
/// <param name="size">The size on the right hand of the operand.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="PointF"/>.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static PointF operator +(PointF point, PointF size) => Add(point, size); |
|||
|
|||
/// <summary>
|
|||
/// Translates a <see cref="PointF"/> by the negative of a given <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point on the left hand of the operand.</param>
|
|||
/// <param name="size">The size on the right hand of the operand.</param>
|
|||
/// <returns>The <see cref="PointF"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static PointF operator -(PointF point, SizeF size) => Subtract(point, size); |
|||
|
|||
/// <summary>
|
|||
/// Multiplies <see cref="PointF"/> by a <see cref="float"/> producing <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">Multiplier of type <see cref="float"/>.</param>
|
|||
/// <param name="right">Multiplicand of type <see cref="SizeF"/>.</param>
|
|||
/// <returns>Product of type <see cref="SizeF"/>.</returns>
|
|||
public static PointF operator *(float left, PointF right) => Multiply(right, left); |
|||
|
|||
/// <summary>
|
|||
/// Multiplies <see cref="PointF"/> by a <see cref="float"/> producing <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">Multiplicand of type <see cref="PointF"/>.</param>
|
|||
/// <param name="right">Multiplier of type <see cref="float"/>.</param>
|
|||
/// <returns>Product of type <see cref="SizeF"/>.</returns>
|
|||
public static PointF operator *(PointF left, float right) => Multiply(left, right); |
|||
|
|||
/// <summary>
|
|||
/// Divides <see cref="PointF"/> by a <see cref="float"/> producing <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">Dividend of type <see cref="PointF"/>.</param>
|
|||
/// <param name="right">Divisor of type <see cref="int"/>.</param>
|
|||
/// <returns>Result of type <see cref="PointF"/>.</returns>
|
|||
public static PointF operator /(PointF left, float right) |
|||
=> new PointF(left.X / right, left.Y / right); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="PointF"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="PointF"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="PointF"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator ==(PointF left, PointF right) => left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="PointF"/> objects for inequality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="PointF"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="PointF"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator !=(PointF left, PointF right) => !left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Translates a <see cref="PointF"/> by the given <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point on the left hand of the operand.</param>
|
|||
/// <param name="size">The size on the right hand of the operand.</param>
|
|||
/// <returns>The <see cref="PointF"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static PointF Add(PointF point, SizeF size) => new PointF(point.X + size.Width, point.Y + size.Height); |
|||
|
|||
/// <summary>
|
|||
/// Translates a <see cref="PointF"/> by the given <see cref="PointF"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point on the left hand of the operand.</param>
|
|||
/// <param name="pointb">The point on the right hand of the operand.</param>
|
|||
/// <returns>The <see cref="PointF"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static PointF Add(PointF point, PointF pointb) => new PointF(point.X + pointb.X, point.Y + pointb.Y); |
|||
|
|||
/// <summary>
|
|||
/// Translates a <see cref="PointF"/> by the negative of a given <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point on the left hand of the operand.</param>
|
|||
/// <param name="size">The size on the right hand of the operand.</param>
|
|||
/// <returns>The <see cref="PointF"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static PointF Subtract(PointF point, SizeF size) => new PointF(point.X - size.Width, point.Y - size.Height); |
|||
|
|||
/// <summary>
|
|||
/// Translates a <see cref="PointF"/> by the negative of a given <see cref="PointF"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point on the left hand of the operand.</param>
|
|||
/// <param name="pointb">The point on the right hand of the operand.</param>
|
|||
/// <returns>The <see cref="PointF"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static PointF Subtract(PointF point, PointF pointb) => new PointF(point.X - pointb.X, point.Y - pointb.Y); |
|||
|
|||
/// <summary>
|
|||
/// Translates a <see cref="PointF"/> by the multiplying the X and Y by the given value.
|
|||
/// </summary>
|
|||
/// <param name="point">The point on the left hand of the operand.</param>
|
|||
/// <param name="right">The value on the right hand of the operand.</param>
|
|||
/// <returns>The <see cref="PointF"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static PointF Multiply(PointF point, float right) => new PointF(point.X * right, point.Y * right); |
|||
|
|||
/// <summary>
|
|||
/// Transforms a point by a specified 3x2 matrix.
|
|||
/// </summary>
|
|||
/// <param name="point">The point to transform.</param>
|
|||
/// <param name="matrix">The transformation matrix used.</param>
|
|||
/// <returns>The transformed <see cref="PointF"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static PointF Transform(PointF point, Matrix3x2 matrix) => Vector2.Transform(point, matrix); |
|||
|
|||
/// <summary>
|
|||
/// Deconstructs this point into two floats.
|
|||
/// </summary>
|
|||
/// <param name="x">The out value for X.</param>
|
|||
/// <param name="y">The out value for Y.</param>
|
|||
public void Deconstruct(out float x, out float y) |
|||
{ |
|||
x = this.X; |
|||
y = this.Y; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Translates this <see cref="PointF"/> by the specified amount.
|
|||
/// </summary>
|
|||
/// <param name="dx">The amount to offset the x-coordinate.</param>
|
|||
/// <param name="dy">The amount to offset the y-coordinate.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Offset(float dx, float dy) |
|||
{ |
|||
this.X += dx; |
|||
this.Y += dy; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Translates this <see cref="PointF"/> by the specified amount.
|
|||
/// </summary>
|
|||
/// <param name="point">The <see cref="PointF"/> used offset this <see cref="PointF"/>.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Offset(PointF point) => this.Offset(point.X, point.Y); |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() => HashCode.Combine(this.X, this.Y); |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() => $"PointF [ X={this.X}, Y={this.Y} ]"; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) => obj is PointF && this.Equals((PointF)obj); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Equals(PointF other) => this.X.Equals(other.X) && this.Y.Equals(other.Y); |
|||
} |
|||
} |
|||
@ -0,0 +1,463 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Stores a set of four integers that represent the location and size of a rectangle.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|||
/// as it avoids the need to create new values for modification operations.
|
|||
/// </remarks>
|
|||
public struct Rectangle : IEquatable<Rectangle> |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a <see cref="Rectangle"/> that has X, Y, Width, and Height values set to zero.
|
|||
/// </summary>
|
|||
public static readonly Rectangle Empty = default; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rectangle"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The horizontal position of the rectangle.</param>
|
|||
/// <param name="y">The vertical position of the rectangle.</param>
|
|||
/// <param name="width">The width of the rectangle.</param>
|
|||
/// <param name="height">The height of the rectangle.</param>
|
|||
public Rectangle(int x, int y, int width, int height) |
|||
{ |
|||
this.X = x; |
|||
this.Y = y; |
|||
this.Width = width; |
|||
this.Height = height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rectangle"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="point">
|
|||
/// The <see cref="Point"/> which specifies the rectangles point in a two-dimensional plane.
|
|||
/// </param>
|
|||
/// <param name="size">
|
|||
/// The <see cref="Size"/> which specifies the rectangles height and width.
|
|||
/// </param>
|
|||
public Rectangle(Point point, Size size) |
|||
{ |
|||
this.X = point.X; |
|||
this.Y = point.Y; |
|||
this.Width = size.Width; |
|||
this.Height = size.Height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the x-coordinate of this <see cref="Rectangle"/>.
|
|||
/// </summary>
|
|||
public int X { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the y-coordinate of this <see cref="Rectangle"/>.
|
|||
/// </summary>
|
|||
public int Y { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the width of this <see cref="Rectangle"/>.
|
|||
/// </summary>
|
|||
public int Width { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the height of this <see cref="Rectangle"/>.
|
|||
/// </summary>
|
|||
public int Height { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the coordinates of the upper-left corner of the rectangular region represented by this <see cref="Rectangle"/>.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public Point Location |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => new Point(this.X, this.Y); |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
set |
|||
{ |
|||
this.X = value.X; |
|||
this.Y = value.Y; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the size of this <see cref="Rectangle"/>.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public Size Size |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => new Size(this.Width, this.Height); |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
set |
|||
{ |
|||
this.Width = value.Width; |
|||
this.Height = value.Height; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this <see cref="Rectangle"/> is empty.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public bool IsEmpty => this.Equals(Empty); |
|||
|
|||
/// <summary>
|
|||
/// Gets the y-coordinate of the top edge of this <see cref="Rectangle"/>.
|
|||
/// </summary>
|
|||
public int Top => this.Y; |
|||
|
|||
/// <summary>
|
|||
/// Gets the x-coordinate of the right edge of this <see cref="Rectangle"/>.
|
|||
/// </summary>
|
|||
public int Right |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => unchecked(this.X + this.Width); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the y-coordinate of the bottom edge of this <see cref="Rectangle"/>.
|
|||
/// </summary>
|
|||
public int Bottom |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => unchecked(this.Y + this.Height); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the x-coordinate of the left edge of this <see cref="Rectangle"/>.
|
|||
/// </summary>
|
|||
public int Left => this.X; |
|||
|
|||
/// <summary>
|
|||
/// Creates a <see cref="RectangleF"/> with the coordinates of the specified <see cref="Rectangle"/>.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The rectangle.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static implicit operator RectangleF(Rectangle rectangle) => new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); |
|||
|
|||
/// <summary>
|
|||
/// Creates a <see cref="Vector4"/> with the coordinates of the specified <see cref="Rectangle"/>.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The rectangle.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static implicit operator Vector4(Rectangle rectangle) => new Vector4(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Rectangle"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Rectangle"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Rectangle"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator ==(Rectangle left, Rectangle right) => left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Rectangle"/> objects for inequality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Rectangle"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Rectangle"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator !=(Rectangle left, Rectangle right) => !left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Creates a new <see cref="Rectangle"/> with the specified location and size. </summary>
|
|||
/// <param name="left">The left coordinate of the rectangle.</param>
|
|||
/// <param name="top">The top coordinate of the rectangle.</param>
|
|||
/// <param name="right">The right coordinate of the rectangle.</param>
|
|||
/// <param name="bottom">The bottom coordinate of the rectangle.</param>
|
|||
/// <returns>The <see cref="Rectangle"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
|
|||
// ReSharper disable once InconsistentNaming
|
|||
public static Rectangle FromLTRB(int left, int top, int right, int bottom) => new Rectangle(left, top, unchecked(right - left), unchecked(bottom - top)); |
|||
|
|||
/// <summary>
|
|||
/// Returns the center point of the given <see cref="Rectangle"/>.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The rectangle.</param>
|
|||
/// <returns>The <see cref="Point"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Point Center(Rectangle rectangle) => new Point(rectangle.Left + (rectangle.Width / 2), rectangle.Top + (rectangle.Height / 2)); |
|||
|
|||
/// <summary>
|
|||
/// Creates a rectangle that represents the intersection between <paramref name="a"/> and
|
|||
/// <paramref name="b"/>. If there is no intersection, an empty rectangle is returned.
|
|||
/// </summary>
|
|||
/// <param name="a">The first rectangle.</param>
|
|||
/// <param name="b">The second rectangle.</param>
|
|||
/// <returns>The <see cref="Rectangle"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Rectangle Intersect(Rectangle a, Rectangle b) |
|||
{ |
|||
int x1 = Math.Max(a.X, b.X); |
|||
int x2 = Math.Min(a.Right, b.Right); |
|||
int y1 = Math.Max(a.Y, b.Y); |
|||
int y2 = Math.Min(a.Bottom, b.Bottom); |
|||
|
|||
if (x2 >= x1 && y2 >= y1) |
|||
{ |
|||
return new Rectangle(x1, y1, x2 - x1, y2 - y1); |
|||
} |
|||
|
|||
return Empty; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a <see cref="Rectangle"/> that is inflated by the specified amount.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The rectangle.</param>
|
|||
/// <param name="x">The amount to inflate the width by.</param>
|
|||
/// <param name="y">The amount to inflate the height by.</param>
|
|||
/// <returns>A new <see cref="Rectangle"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Rectangle Inflate(Rectangle rectangle, int x, int y) |
|||
{ |
|||
Rectangle r = rectangle; |
|||
r.Inflate(x, y); |
|||
return r; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="RectangleF"/> to a <see cref="Rectangle"/> by performing a ceiling operation on all the coordinates.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The rectangle.</param>
|
|||
/// <returns>The <see cref="Rectangle"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Rectangle Ceiling(RectangleF rectangle) |
|||
{ |
|||
unchecked |
|||
{ |
|||
return new Rectangle( |
|||
(int)MathF.Ceiling(rectangle.X), |
|||
(int)MathF.Ceiling(rectangle.Y), |
|||
(int)MathF.Ceiling(rectangle.Width), |
|||
(int)MathF.Ceiling(rectangle.Height)); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Transforms a rectangle by the given matrix.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The source rectangle.</param>
|
|||
/// <param name="matrix">The transformation matrix.</param>
|
|||
/// <returns>A transformed rectangle.</returns>
|
|||
public static RectangleF Transform(Rectangle rectangle, Matrix3x2 matrix) |
|||
{ |
|||
PointF bottomRight = Point.Transform(new Point(rectangle.Right, rectangle.Bottom), matrix); |
|||
PointF topLeft = Point.Transform(rectangle.Location, matrix); |
|||
return new RectangleF(topLeft, new SizeF(bottomRight - topLeft)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="RectangleF"/> to a <see cref="Rectangle"/> by performing a truncate operation on all the coordinates.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The rectangle.</param>
|
|||
/// <returns>The <see cref="Rectangle"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Rectangle Truncate(RectangleF rectangle) |
|||
{ |
|||
unchecked |
|||
{ |
|||
return new Rectangle( |
|||
(int)rectangle.X, |
|||
(int)rectangle.Y, |
|||
(int)rectangle.Width, |
|||
(int)rectangle.Height); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="RectangleF"/> to a <see cref="Rectangle"/> by performing a round operation on all the coordinates.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The rectangle.</param>
|
|||
/// <returns>The <see cref="Rectangle"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Rectangle Round(RectangleF rectangle) |
|||
{ |
|||
unchecked |
|||
{ |
|||
return new Rectangle( |
|||
(int)MathF.Round(rectangle.X), |
|||
(int)MathF.Round(rectangle.Y), |
|||
(int)MathF.Round(rectangle.Width), |
|||
(int)MathF.Round(rectangle.Height)); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a rectangle that represents the union between <paramref name="a"/> and <paramref name="b"/>.
|
|||
/// </summary>
|
|||
/// <param name="a">The first rectangle.</param>
|
|||
/// <param name="b">The second rectangle.</param>
|
|||
/// <returns>The <see cref="Rectangle"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Rectangle Union(Rectangle a, Rectangle b) |
|||
{ |
|||
int x1 = Math.Min(a.X, b.X); |
|||
int x2 = Math.Max(a.Right, b.Right); |
|||
int y1 = Math.Min(a.Y, b.Y); |
|||
int y2 = Math.Max(a.Bottom, b.Bottom); |
|||
|
|||
return new Rectangle(x1, y1, x2 - x1, y2 - y1); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Deconstructs this rectangle into four integers.
|
|||
/// </summary>
|
|||
/// <param name="x">The out value for X.</param>
|
|||
/// <param name="y">The out value for Y.</param>
|
|||
/// <param name="width">The out value for the width.</param>
|
|||
/// <param name="height">The out value for the height.</param>
|
|||
public void Deconstruct(out int x, out int y, out int width, out int height) |
|||
{ |
|||
x = this.X; |
|||
y = this.Y; |
|||
width = this.Width; |
|||
height = this.Height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a Rectangle that represents the intersection between this Rectangle and the <paramref name="rectangle"/>.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The rectangle.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Intersect(Rectangle rectangle) |
|||
{ |
|||
Rectangle result = Intersect(rectangle, this); |
|||
|
|||
this.X = result.X; |
|||
this.Y = result.Y; |
|||
this.Width = result.Width; |
|||
this.Height = result.Height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Inflates this <see cref="Rectangle"/> by the specified amount.
|
|||
/// </summary>
|
|||
/// <param name="width">The width.</param>
|
|||
/// <param name="height">The height.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Inflate(int width, int height) |
|||
{ |
|||
unchecked |
|||
{ |
|||
this.X -= width; |
|||
this.Y -= height; |
|||
|
|||
this.Width += 2 * width; |
|||
this.Height += 2 * height; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Inflates this <see cref="Rectangle"/> by the specified amount.
|
|||
/// </summary>
|
|||
/// <param name="size">The size.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Inflate(Size size) => this.Inflate(size.Width, size.Height); |
|||
|
|||
/// <summary>
|
|||
/// Determines if the specfied point is contained within the rectangular region defined by
|
|||
/// this <see cref="Rectangle"/>.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-coordinate of the given point.</param>
|
|||
/// <param name="y">The y-coordinate of the given point.</param>
|
|||
/// <returns>The <see cref="bool"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Contains(int x, int y) => this.X <= x && x < this.Right && this.Y <= y && y < this.Bottom; |
|||
|
|||
/// <summary>
|
|||
/// Determines if the specified point is contained within the rectangular region defined by this <see cref="Rectangle"/> .
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
/// <returns>The <see cref="bool"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Contains(Point point) => this.Contains(point.X, point.Y); |
|||
|
|||
/// <summary>
|
|||
/// Determines if the rectangular region represented by <paramref name="rectangle"/> is entirely contained
|
|||
/// within the rectangular region represented by this <see cref="Rectangle"/> .
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The rectangle.</param>
|
|||
/// <returns>The <see cref="bool"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Contains(Rectangle rectangle) => |
|||
(this.X <= rectangle.X) && (rectangle.Right <= this.Right) && |
|||
(this.Y <= rectangle.Y) && (rectangle.Bottom <= this.Bottom); |
|||
|
|||
/// <summary>
|
|||
/// Determines if the specfied <see cref="Rectangle"/> intersects the rectangular region defined by
|
|||
/// this <see cref="Rectangle"/>.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The other Rectange. </param>
|
|||
/// <returns>The <see cref="bool"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool IntersectsWith(Rectangle rectangle) => |
|||
(rectangle.X < this.Right) && (this.X < rectangle.Right) && |
|||
(rectangle.Y < this.Bottom) && (this.Y < rectangle.Bottom); |
|||
|
|||
/// <summary>
|
|||
/// Adjusts the location of this rectangle by the specified amount.
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Offset(Point point) => this.Offset(point.X, point.Y); |
|||
|
|||
/// <summary>
|
|||
/// Adjusts the location of this rectangle by the specified amount.
|
|||
/// </summary>
|
|||
/// <param name="dx">The amount to offset the x-coordinate.</param>
|
|||
/// <param name="dy">The amount to offset the y-coordinate.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Offset(int dx, int dy) |
|||
{ |
|||
unchecked |
|||
{ |
|||
this.X += dx; |
|||
this.Y += dy; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() |
|||
{ |
|||
return HashCode.Combine(this.X, this.Y, this.Width, this.Height); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() |
|||
{ |
|||
return $"Rectangle [ X={this.X}, Y={this.Y}, Width={this.Width}, Height={this.Height} ]"; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) => obj is Rectangle other && this.Equals(other); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Equals(Rectangle other) => |
|||
this.X.Equals(other.X) && |
|||
this.Y.Equals(other.Y) && |
|||
this.Width.Equals(other.Width) && |
|||
this.Height.Equals(other.Height); |
|||
} |
|||
} |
|||
@ -0,0 +1,396 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Stores a set of four single precision floating points that represent the location and size of a rectangle.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|||
/// as it avoids the need to create new values for modification operations.
|
|||
/// </remarks>
|
|||
public struct RectangleF : IEquatable<RectangleF> |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a <see cref="RectangleF"/> that has X, Y, Width, and Height values set to zero.
|
|||
/// </summary>
|
|||
public static readonly RectangleF Empty = default; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="RectangleF"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="x">The horizontal position of the rectangle.</param>
|
|||
/// <param name="y">The vertical position of the rectangle.</param>
|
|||
/// <param name="width">The width of the rectangle.</param>
|
|||
/// <param name="height">The height of the rectangle.</param>
|
|||
public RectangleF(float x, float y, float width, float height) |
|||
{ |
|||
this.X = x; |
|||
this.Y = y; |
|||
this.Width = width; |
|||
this.Height = height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="RectangleF"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="point">
|
|||
/// The <see cref="Point"/> which specifies the rectangles point in a two-dimensional plane.
|
|||
/// </param>
|
|||
/// <param name="size">
|
|||
/// The <see cref="Size"/> which specifies the rectangles height and width.
|
|||
/// </param>
|
|||
public RectangleF(PointF point, SizeF size) |
|||
{ |
|||
this.X = point.X; |
|||
this.Y = point.Y; |
|||
this.Width = size.Width; |
|||
this.Height = size.Height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the x-coordinate of this <see cref="RectangleF"/>.
|
|||
/// </summary>
|
|||
public float X { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the y-coordinate of this <see cref="RectangleF"/>.
|
|||
/// </summary>
|
|||
public float Y { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the width of this <see cref="RectangleF"/>.
|
|||
/// </summary>
|
|||
public float Width { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the height of this <see cref="RectangleF"/>.
|
|||
/// </summary>
|
|||
public float Height { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the coordinates of the upper-left corner of the rectangular region represented by this <see cref="RectangleF"/>.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public PointF Location |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => new PointF(this.X, this.Y); |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
set |
|||
{ |
|||
this.X = value.X; |
|||
this.Y = value.Y; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the size of this <see cref="RectangleF"/>.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public SizeF Size |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => new SizeF(this.Width, this.Height); |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
set |
|||
{ |
|||
this.Width = value.Width; |
|||
this.Height = value.Height; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this <see cref="RectangleF"/> is empty.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public bool IsEmpty => (this.Width <= 0) || (this.Height <= 0); |
|||
|
|||
/// <summary>
|
|||
/// Gets the y-coordinate of the top edge of this <see cref="RectangleF"/>.
|
|||
/// </summary>
|
|||
public float Top => this.Y; |
|||
|
|||
/// <summary>
|
|||
/// Gets the x-coordinate of the right edge of this <see cref="RectangleF"/>.
|
|||
/// </summary>
|
|||
public float Right |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => this.X + this.Width; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the y-coordinate of the bottom edge of this <see cref="RectangleF"/>.
|
|||
/// </summary>
|
|||
public float Bottom |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => this.Y + this.Height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the x-coordinate of the left edge of this <see cref="RectangleF"/>.
|
|||
/// </summary>
|
|||
public float Left => this.X; |
|||
|
|||
/// <summary>
|
|||
/// Creates a <see cref="Rectangle"/> with the coordinates of the specified <see cref="RectangleF"/> by truncating each coordinate.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The rectangle.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static explicit operator Rectangle(RectangleF rectangle) => Rectangle.Truncate(rectangle); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="RectangleF"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="RectangleF"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="RectangleF"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator ==(RectangleF left, RectangleF right) => left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="RectangleF"/> objects for inequality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="RectangleF"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="RectangleF"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator !=(RectangleF left, RectangleF right) => !left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Creates a new <see cref="RectangleF"/> with the specified location and size. </summary>
|
|||
/// <param name="left">The left coordinate of the rectangle.</param>
|
|||
/// <param name="top">The top coordinate of the rectangle.</param>
|
|||
/// <param name="right">The right coordinate of the rectangle.</param>
|
|||
/// <param name="bottom">The bottom coordinate of the rectangle.</param>
|
|||
/// <returns>The <see cref="RectangleF"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
|
|||
// ReSharper disable once InconsistentNaming
|
|||
public static RectangleF FromLTRB(float left, float top, float right, float bottom) => new RectangleF(left, top, right - left, bottom - top); |
|||
|
|||
/// <summary>
|
|||
/// Returns the center point of the given <see cref="RectangleF"/>.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The rectangle.</param>
|
|||
/// <returns>The <see cref="Point"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static PointF Center(RectangleF rectangle) => new PointF(rectangle.Left + (rectangle.Width / 2), rectangle.Top + (rectangle.Height / 2)); |
|||
|
|||
/// <summary>
|
|||
/// Creates a rectangle that represents the intersection between <paramref name="a"/> and
|
|||
/// <paramref name="b"/>. If there is no intersection, an empty rectangle is returned.
|
|||
/// </summary>
|
|||
/// <param name="a">The first rectangle.</param>
|
|||
/// <param name="b">The second rectangle.</param>
|
|||
/// <returns>The <see cref="RectangleF"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static RectangleF Intersect(RectangleF a, RectangleF b) |
|||
{ |
|||
float x1 = MathF.Max(a.X, b.X); |
|||
float x2 = MathF.Min(a.Right, b.Right); |
|||
float y1 = MathF.Max(a.Y, b.Y); |
|||
float y2 = MathF.Min(a.Bottom, b.Bottom); |
|||
|
|||
if (x2 >= x1 && y2 >= y1) |
|||
{ |
|||
return new RectangleF(x1, y1, x2 - x1, y2 - y1); |
|||
} |
|||
|
|||
return Empty; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a <see cref="RectangleF"/> that is inflated by the specified amount.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The rectangle.</param>
|
|||
/// <param name="x">The amount to inflate the width by.</param>
|
|||
/// <param name="y">The amount to inflate the height by.</param>
|
|||
/// <returns>A new <see cref="RectangleF"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static RectangleF Inflate(RectangleF rectangle, float x, float y) |
|||
{ |
|||
RectangleF r = rectangle; |
|||
r.Inflate(x, y); |
|||
return r; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Transforms a rectangle by the given matrix.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The source rectangle.</param>
|
|||
/// <param name="matrix">The transformation matrix.</param>
|
|||
/// <returns>A transformed <see cref="RectangleF"/>.</returns>
|
|||
public static RectangleF Transform(RectangleF rectangle, Matrix3x2 matrix) |
|||
{ |
|||
PointF bottomRight = PointF.Transform(new PointF(rectangle.Right, rectangle.Bottom), matrix); |
|||
PointF topLeft = PointF.Transform(rectangle.Location, matrix); |
|||
return new RectangleF(topLeft, new SizeF(bottomRight - topLeft)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a rectangle that represents the union between <paramref name="a"/> and <paramref name="b"/>.
|
|||
/// </summary>
|
|||
/// <param name="a">The first rectangle.</param>
|
|||
/// <param name="b">The second rectangle.</param>
|
|||
/// <returns>The <see cref="RectangleF"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static RectangleF Union(RectangleF a, RectangleF b) |
|||
{ |
|||
float x1 = MathF.Min(a.X, b.X); |
|||
float x2 = MathF.Max(a.Right, b.Right); |
|||
float y1 = MathF.Min(a.Y, b.Y); |
|||
float y2 = MathF.Max(a.Bottom, b.Bottom); |
|||
|
|||
return new RectangleF(x1, y1, x2 - x1, y2 - y1); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Deconstructs this rectangle into four floats.
|
|||
/// </summary>
|
|||
/// <param name="x">The out value for X.</param>
|
|||
/// <param name="y">The out value for Y.</param>
|
|||
/// <param name="width">The out value for the width.</param>
|
|||
/// <param name="height">The out value for the height.</param>
|
|||
public void Deconstruct(out float x, out float y, out float width, out float height) |
|||
{ |
|||
x = this.X; |
|||
y = this.Y; |
|||
width = this.Width; |
|||
height = this.Height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a RectangleF that represents the intersection between this RectangleF and the <paramref name="rectangle"/>.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The rectangle.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Intersect(RectangleF rectangle) |
|||
{ |
|||
RectangleF result = Intersect(rectangle, this); |
|||
|
|||
this.X = result.X; |
|||
this.Y = result.Y; |
|||
this.Width = result.Width; |
|||
this.Height = result.Height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Inflates this <see cref="RectangleF"/> by the specified amount.
|
|||
/// </summary>
|
|||
/// <param name="width">The width.</param>
|
|||
/// <param name="height">The height.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Inflate(float width, float height) |
|||
{ |
|||
this.X -= width; |
|||
this.Y -= height; |
|||
|
|||
this.Width += 2 * width; |
|||
this.Height += 2 * height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Inflates this <see cref="RectangleF"/> by the specified amount.
|
|||
/// </summary>
|
|||
/// <param name="size">The size.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Inflate(SizeF size) => this.Inflate(size.Width, size.Height); |
|||
|
|||
/// <summary>
|
|||
/// Determines if the specfied point is contained within the rectangular region defined by
|
|||
/// this <see cref="RectangleF"/>.
|
|||
/// </summary>
|
|||
/// <param name="x">The x-coordinate of the given point.</param>
|
|||
/// <param name="y">The y-coordinate of the given point.</param>
|
|||
/// <returns>The <see cref="bool"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Contains(float x, float y) => this.X <= x && x < this.Right && this.Y <= y && y < this.Bottom; |
|||
|
|||
/// <summary>
|
|||
/// Determines if the specified point is contained within the rectangular region defined by this <see cref="RectangleF"/> .
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
/// <returns>The <see cref="bool"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Contains(PointF point) => this.Contains(point.X, point.Y); |
|||
|
|||
/// <summary>
|
|||
/// Determines if the rectangular region represented by <paramref name="rectangle"/> is entirely contained
|
|||
/// within the rectangular region represented by this <see cref="RectangleF"/> .
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The rectangle.</param>
|
|||
/// <returns>The <see cref="bool"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Contains(RectangleF rectangle) => |
|||
(this.X <= rectangle.X) && (rectangle.Right <= this.Right) && |
|||
(this.Y <= rectangle.Y) && (rectangle.Bottom <= this.Bottom); |
|||
|
|||
/// <summary>
|
|||
/// Determines if the specfied <see cref="RectangleF"/> intersects the rectangular region defined by
|
|||
/// this <see cref="RectangleF"/>.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The other Rectange. </param>
|
|||
/// <returns>The <see cref="bool"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool IntersectsWith(RectangleF rectangle) => |
|||
(rectangle.X < this.Right) && (this.X < rectangle.Right) && |
|||
(rectangle.Y < this.Bottom) && (this.Y < rectangle.Bottom); |
|||
|
|||
/// <summary>
|
|||
/// Adjusts the location of this rectangle by the specified amount.
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Offset(PointF point) => this.Offset(point.X, point.Y); |
|||
|
|||
/// <summary>
|
|||
/// Adjusts the location of this rectangle by the specified amount.
|
|||
/// </summary>
|
|||
/// <param name="dx">The amount to offset the x-coordinate.</param>
|
|||
/// <param name="dy">The amount to offset the y-coordinate.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Offset(float dx, float dy) |
|||
{ |
|||
this.X += dx; |
|||
this.Y += dy; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() |
|||
{ |
|||
return HashCode.Combine(this.X, this.Y, this.Width, this.Height); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() |
|||
{ |
|||
return $"RectangleF [ X={this.X}, Y={this.Y}, Width={this.Width}, Height={this.Height} ]"; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) => obj is RectangleF other && this.Equals(other); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Equals(RectangleF other) => |
|||
this.X.Equals(other.X) && |
|||
this.Y.Equals(other.Y) && |
|||
this.Width.Equals(other.Width) && |
|||
this.Height.Equals(other.Height); |
|||
} |
|||
} |
|||
@ -0,0 +1,296 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Stores an ordered pair of integers, which specify a height and width.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|||
/// as it avoids the need to create new values for modification operations.
|
|||
/// </remarks>
|
|||
public struct Size : IEquatable<Size> |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a <see cref="Size"/> that has Width and Height values set to zero.
|
|||
/// </summary>
|
|||
public static readonly Size Empty = default; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Size"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="value">The width and height of the size.</param>
|
|||
public Size(int value) |
|||
: this() |
|||
{ |
|||
this.Width = value; |
|||
this.Height = value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Size"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="width">The width of the size.</param>
|
|||
/// <param name="height">The height of the size.</param>
|
|||
public Size(int width, int height) |
|||
{ |
|||
this.Width = width; |
|||
this.Height = height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Size"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="size">The size.</param>
|
|||
public Size(Size size) |
|||
: this() |
|||
{ |
|||
this.Width = size.Width; |
|||
this.Height = size.Height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Size"/> struct from the given <see cref="Point"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
public Size(Point point) |
|||
{ |
|||
this.Width = point.X; |
|||
this.Height = point.Y; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the width of this <see cref="Size"/>.
|
|||
/// </summary>
|
|||
public int Width { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the height of this <see cref="Size"/>.
|
|||
/// </summary>
|
|||
public int Height { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this <see cref="Size"/> is empty.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public bool IsEmpty => this.Equals(Empty); |
|||
|
|||
/// <summary>
|
|||
/// Creates a <see cref="SizeF"/> with the dimensions of the specified <see cref="Size"/>.
|
|||
/// </summary>
|
|||
/// <param name="size">The point.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static implicit operator SizeF(Size size) => new SizeF(size.Width, size.Height); |
|||
|
|||
/// <summary>
|
|||
/// Converts the given <see cref="Size"/> into a <see cref="Point"/>.
|
|||
/// </summary>
|
|||
/// <param name="size">The size.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static explicit operator Point(Size size) => new Point(size.Width, size.Height); |
|||
|
|||
/// <summary>
|
|||
/// Computes the sum of adding two sizes.
|
|||
/// </summary>
|
|||
/// <param name="left">The size on the left hand of the operand.</param>
|
|||
/// <param name="right">The size on the right hand of the operand.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Size"/>.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Size operator +(Size left, Size right) => Add(left, right); |
|||
|
|||
/// <summary>
|
|||
/// Computes the difference left by subtracting one size from another.
|
|||
/// </summary>
|
|||
/// <param name="left">The size on the left hand of the operand.</param>
|
|||
/// <param name="right">The size on the right hand of the operand.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Size"/>.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Size operator -(Size left, Size right) => Subtract(left, right); |
|||
|
|||
/// <summary>
|
|||
/// Multiplies a <see cref="Size"/> by an <see cref="int"/> producing <see cref="Size"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">Multiplier of type <see cref="int"/>.</param>
|
|||
/// <param name="right">Multiplicand of type <see cref="Size"/>.</param>
|
|||
/// <returns>Product of type <see cref="Size"/>.</returns>
|
|||
public static Size operator *(int left, Size right) => Multiply(right, left); |
|||
|
|||
/// <summary>
|
|||
/// Multiplies <see cref="Size"/> by an <see cref="int"/> producing <see cref="Size"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">Multiplicand of type <see cref="Size"/>.</param>
|
|||
/// <param name="right">Multiplier of type <see cref="int"/>.</param>
|
|||
/// <returns>Product of type <see cref="Size"/>.</returns>
|
|||
public static Size operator *(Size left, int right) => Multiply(left, right); |
|||
|
|||
/// <summary>
|
|||
/// Divides <see cref="Size"/> by an <see cref="int"/> producing <see cref="Size"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">Dividend of type <see cref="Size"/>.</param>
|
|||
/// <param name="right">Divisor of type <see cref="int"/>.</param>
|
|||
/// <returns>Result of type <see cref="Size"/>.</returns>
|
|||
public static Size operator /(Size left, int right) => new Size(unchecked(left.Width / right), unchecked(left.Height / right)); |
|||
|
|||
/// <summary>
|
|||
/// Multiplies <see cref="Size"/> by a <see cref="float"/> producing <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">Multiplier of type <see cref="float"/>.</param>
|
|||
/// <param name="right">Multiplicand of type <see cref="Size"/>.</param>
|
|||
/// <returns>Product of type <see cref="SizeF"/>.</returns>
|
|||
public static SizeF operator *(float left, Size right) => Multiply(right, left); |
|||
|
|||
/// <summary>
|
|||
/// Multiplies <see cref="Size"/> by a <see cref="float"/> producing <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">Multiplicand of type <see cref="Size"/>.</param>
|
|||
/// <param name="right">Multiplier of type <see cref="float"/>.</param>
|
|||
/// <returns>Product of type <see cref="SizeF"/>.</returns>
|
|||
public static SizeF operator *(Size left, float right) => Multiply(left, right); |
|||
|
|||
/// <summary>
|
|||
/// Divides <see cref="Size"/> by a <see cref="float"/> producing <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">Dividend of type <see cref="Size"/>.</param>
|
|||
/// <param name="right">Divisor of type <see cref="int"/>.</param>
|
|||
/// <returns>Result of type <see cref="SizeF"/>.</returns>
|
|||
public static SizeF operator /(Size left, float right) |
|||
=> new SizeF(left.Width / right, left.Height / right); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Size"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Size"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Size"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator ==(Size left, Size right) => left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Size"/> objects for inequality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="Size"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="Size"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator !=(Size left, Size right) => !left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Performs vector addition of two <see cref="Size"/> objects.
|
|||
/// </summary>
|
|||
/// <param name="left">The size on the left hand of the operand.</param>
|
|||
/// <param name="right">The size on the right hand of the operand.</param>
|
|||
/// <returns>The <see cref="Size"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Size Add(Size left, Size right) => new Size(unchecked(left.Width + right.Width), unchecked(left.Height + right.Height)); |
|||
|
|||
/// <summary>
|
|||
/// Contracts a <see cref="Size"/> by another <see cref="Size"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">The size on the left hand of the operand.</param>
|
|||
/// <param name="right">The size on the right hand of the operand.</param>
|
|||
/// <returns>The <see cref="Size"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Size Subtract(Size left, Size right) => new Size(unchecked(left.Width - right.Width), unchecked(left.Height - right.Height)); |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="SizeF"/> to a <see cref="Size"/> by performing a ceiling operation on all the dimensions.
|
|||
/// </summary>
|
|||
/// <param name="size">The size.</param>
|
|||
/// <returns>The <see cref="Size"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Size Ceiling(SizeF size) => new Size(unchecked((int)MathF.Ceiling(size.Width)), unchecked((int)MathF.Ceiling(size.Height))); |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="SizeF"/> to a <see cref="Size"/> by performing a round operation on all the dimensions.
|
|||
/// </summary>
|
|||
/// <param name="size">The size.</param>
|
|||
/// <returns>The <see cref="Size"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Size Round(SizeF size) => new Size(unchecked((int)MathF.Round(size.Width)), unchecked((int)MathF.Round(size.Height))); |
|||
|
|||
/// <summary>
|
|||
/// Transforms a size by the given matrix.
|
|||
/// </summary>
|
|||
/// <param name="size">The source size.</param>
|
|||
/// <param name="matrix">The transformation matrix.</param>
|
|||
/// <returns>A transformed size.</returns>
|
|||
public static SizeF Transform(Size size, Matrix3x2 matrix) |
|||
{ |
|||
var v = Vector2.Transform(new Vector2(size.Width, size.Height), matrix); |
|||
|
|||
return new SizeF(v.X, v.Y); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="SizeF"/> to a <see cref="Size"/> by performing a round operation on all the dimensions.
|
|||
/// </summary>
|
|||
/// <param name="size">The size.</param>
|
|||
/// <returns>The <see cref="Size"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Size Truncate(SizeF size) => new Size(unchecked((int)size.Width), unchecked((int)size.Height)); |
|||
|
|||
/// <summary>
|
|||
/// Deconstructs this size into two integers.
|
|||
/// </summary>
|
|||
/// <param name="width">The out value for the width.</param>
|
|||
/// <param name="height">The out value for the height.</param>
|
|||
public void Deconstruct(out int width, out int height) |
|||
{ |
|||
width = this.Width; |
|||
height = this.Height; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() => HashCode.Combine(this.Width, this.Height); |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() => $"Size [ Width={this.Width}, Height={this.Height} ]"; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) => obj is Size other && this.Equals(other); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Equals(Size other) => this.Width.Equals(other.Width) && this.Height.Equals(other.Height); |
|||
|
|||
/// <summary>
|
|||
/// Multiplies <see cref="Size"/> by an <see cref="int"/> producing <see cref="Size"/>.
|
|||
/// </summary>
|
|||
/// <param name="size">Multiplicand of type <see cref="Size"/>.</param>
|
|||
/// <param name="multiplier">Multiplier of type <see cref="int"/>.</param>
|
|||
/// <returns>Product of type <see cref="Size"/>.</returns>
|
|||
private static Size Multiply(Size size, int multiplier) => |
|||
new Size(unchecked(size.Width * multiplier), unchecked(size.Height * multiplier)); |
|||
|
|||
/// <summary>
|
|||
/// Multiplies <see cref="Size"/> by a <see cref="float"/> producing <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="size">Multiplicand of type <see cref="Size"/>.</param>
|
|||
/// <param name="multiplier">Multiplier of type <see cref="float"/>.</param>
|
|||
/// <returns>Product of type SizeF.</returns>
|
|||
private static SizeF Multiply(Size size, float multiplier) => |
|||
new SizeF(size.Width * multiplier, size.Height * multiplier); |
|||
} |
|||
} |
|||
@ -0,0 +1,233 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Stores an ordered pair of single precision floating points, which specify a height and width.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|||
/// as it avoids the need to create new values for modification operations.
|
|||
/// </remarks>
|
|||
public struct SizeF : IEquatable<SizeF> |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a <see cref="SizeF"/> that has Width and Height values set to zero.
|
|||
/// </summary>
|
|||
public static readonly SizeF Empty = default; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="SizeF"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="width">The width of the size.</param>
|
|||
/// <param name="height">The height of the size.</param>
|
|||
public SizeF(float width, float height) |
|||
{ |
|||
this.Width = width; |
|||
this.Height = height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="SizeF"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="size">The size.</param>
|
|||
public SizeF(SizeF size) |
|||
: this() |
|||
{ |
|||
this.Width = size.Width; |
|||
this.Height = size.Height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="SizeF"/> struct from the given <see cref="PointF"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
public SizeF(PointF point) |
|||
{ |
|||
this.Width = point.X; |
|||
this.Height = point.Y; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the width of this <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
public float Width { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the height of this <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
public float Height { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this <see cref="SizeF"/> is empty.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public bool IsEmpty => this.Equals(Empty); |
|||
|
|||
/// <summary>
|
|||
/// Creates a <see cref="Vector2"/> with the coordinates of the specified <see cref="PointF"/>.
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Vector2"/>.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static implicit operator Vector2(SizeF point) => new Vector2(point.Width, point.Height); |
|||
|
|||
/// <summary>
|
|||
/// Creates a <see cref="Size"/> with the dimensions of the specified <see cref="SizeF"/> by truncating each of the dimensions.
|
|||
/// </summary>
|
|||
/// <param name="size">The size.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Size"/>.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static explicit operator Size(SizeF size) => new Size(unchecked((int)size.Width), unchecked((int)size.Height)); |
|||
|
|||
/// <summary>
|
|||
/// Converts the given <see cref="SizeF"/> into a <see cref="PointF"/>.
|
|||
/// </summary>
|
|||
/// <param name="size">The size.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static explicit operator PointF(SizeF size) => new PointF(size.Width, size.Height); |
|||
|
|||
/// <summary>
|
|||
/// Computes the sum of adding two sizes.
|
|||
/// </summary>
|
|||
/// <param name="left">The size on the left hand of the operand.</param>
|
|||
/// <param name="right">The size on the right hand of the operand.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="SizeF"/>.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static SizeF operator +(SizeF left, SizeF right) => Add(left, right); |
|||
|
|||
/// <summary>
|
|||
/// Computes the difference left by subtracting one size from another.
|
|||
/// </summary>
|
|||
/// <param name="left">The size on the left hand of the operand.</param>
|
|||
/// <param name="right">The size on the right hand of the operand.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="SizeF"/>.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static SizeF operator -(SizeF left, SizeF right) => Subtract(left, right); |
|||
|
|||
/// <summary>
|
|||
/// Multiplies <see cref="SizeF"/> by a <see cref="float"/> producing <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">Multiplier of type <see cref="float"/>.</param>
|
|||
/// <param name="right">Multiplicand of type <see cref="SizeF"/>.</param>
|
|||
/// <returns>Product of type <see cref="SizeF"/>.</returns>
|
|||
public static SizeF operator *(float left, SizeF right) => Multiply(right, left); |
|||
|
|||
/// <summary>
|
|||
/// Multiplies <see cref="SizeF"/> by a <see cref="float"/> producing <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">Multiplicand of type <see cref="SizeF"/>.</param>
|
|||
/// <param name="right">Multiplier of type <see cref="float"/>.</param>
|
|||
/// <returns>Product of type <see cref="SizeF"/>.</returns>
|
|||
public static SizeF operator *(SizeF left, float right) => Multiply(left, right); |
|||
|
|||
/// <summary>
|
|||
/// Divides <see cref="SizeF"/> by a <see cref="float"/> producing <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">Dividend of type <see cref="SizeF"/>.</param>
|
|||
/// <param name="right">Divisor of type <see cref="int"/>.</param>
|
|||
/// <returns>Result of type <see cref="SizeF"/>.</returns>
|
|||
public static SizeF operator /(SizeF left, float right) |
|||
=> new SizeF(left.Width / right, left.Height / right); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="SizeF"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The size on the left hand of the operand.</param>
|
|||
/// <param name="right">The size on the right hand of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator ==(SizeF left, SizeF right) => left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="SizeF"/> objects for inequality.
|
|||
/// </summary>
|
|||
/// <param name="left">The size on the left hand of the operand.</param>
|
|||
/// <param name="right">The size on the right hand of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator !=(SizeF left, SizeF right) => !left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Performs vector addition of two <see cref="SizeF"/> objects.
|
|||
/// </summary>
|
|||
/// <param name="left">The size on the left hand of the operand.</param>
|
|||
/// <param name="right">The size on the right hand of the operand.</param>
|
|||
/// <returns>The <see cref="SizeF"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static SizeF Add(SizeF left, SizeF right) => new SizeF(left.Width + right.Width, left.Height + right.Height); |
|||
|
|||
/// <summary>
|
|||
/// Contracts a <see cref="SizeF"/> by another <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="left">The size on the left hand of the operand.</param>
|
|||
/// <param name="right">The size on the right hand of the operand.</param>
|
|||
/// <returns>The <see cref="SizeF"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static SizeF Subtract(SizeF left, SizeF right) => new SizeF(left.Width - right.Width, left.Height - right.Height); |
|||
|
|||
/// <summary>
|
|||
/// Transforms a size by the given matrix.
|
|||
/// </summary>
|
|||
/// <param name="size">The source size.</param>
|
|||
/// <param name="matrix">The transformation matrix.</param>
|
|||
/// <returns>A transformed size.</returns>
|
|||
public static SizeF Transform(SizeF size, Matrix3x2 matrix) |
|||
{ |
|||
var v = Vector2.Transform(new Vector2(size.Width, size.Height), matrix); |
|||
|
|||
return new SizeF(v.X, v.Y); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Deconstructs this size into two floats.
|
|||
/// </summary>
|
|||
/// <param name="width">The out value for the width.</param>
|
|||
/// <param name="height">The out value for the height.</param>
|
|||
public void Deconstruct(out float width, out float height) |
|||
{ |
|||
width = this.Width; |
|||
height = this.Height; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() => HashCode.Combine(this.Width, this.Height); |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() => $"SizeF [ Width={this.Width}, Height={this.Height} ]"; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) => obj is SizeF && this.Equals((SizeF)obj); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Equals(SizeF other) => this.Width.Equals(other.Width) && this.Height.Equals(other.Height); |
|||
|
|||
/// <summary>
|
|||
/// Multiplies <see cref="SizeF"/> by a <see cref="float"/> producing <see cref="SizeF"/>.
|
|||
/// </summary>
|
|||
/// <param name="size">Multiplicand of type <see cref="SizeF"/>.</param>
|
|||
/// <param name="multiplier">Multiplier of type <see cref="float"/>.</param>
|
|||
/// <returns>Product of type SizeF.</returns>
|
|||
private static SizeF Multiply(SizeF size, float multiplier) => |
|||
new SizeF(size.Width * multiplier, size.Height * multiplier); |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue