-
Notifications
You must be signed in to change notification settings - Fork 279
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'PintaProject:master' into improvement7
- Loading branch information
Showing
6 changed files
with
222 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
using System; | ||
using System.Numerics; | ||
|
||
namespace Pinta.Core; | ||
|
||
/// <summary>Represents a reduced fraction</summary> | ||
/// <remarks> | ||
/// Only positive values are supported for now. | ||
/// At the time of this writing, support for negative | ||
/// numbers is not needed. | ||
/// </remarks> | ||
public readonly struct Fraction<TInt> where TInt : IBinaryInteger<TInt> | ||
{ | ||
public TInt Numerator { get; } | ||
public TInt Denominator { get; } | ||
public Fraction (TInt numerator, TInt denominator) | ||
{ | ||
if (denominator <= TInt.Zero) throw new ArgumentOutOfRangeException (nameof (denominator), "must be greater than 0(denominator = " + denominator + ")"); | ||
if (numerator < TInt.Zero) throw new ArgumentOutOfRangeException (nameof (numerator), "must be greater than 0(numerator = " + numerator + ")"); | ||
if (numerator == TInt.Zero) { | ||
Numerator = TInt.Zero; | ||
Denominator = TInt.One; | ||
} else { | ||
TInt gcd = Mathematics.EuclidGCD (numerator, denominator); | ||
TInt reducedNumerator = numerator / gcd; | ||
TInt reducedDenominator = denominator / gcd; | ||
Numerator = reducedNumerator; | ||
Denominator = reducedDenominator; | ||
} | ||
} | ||
|
||
public static bool operator == (Fraction<TInt> lhs, Fraction<TInt> rhs) | ||
=> lhs.Equals (rhs); | ||
|
||
public static bool operator != (Fraction<TInt> lhs, Fraction<TInt> rhs) | ||
=> !lhs.Equals (rhs); | ||
|
||
public static bool operator < (Fraction<TInt> lhs, Fraction<TInt> rhs) | ||
=> (lhs.Numerator * rhs.Denominator) < (rhs.Numerator * lhs.Denominator); | ||
|
||
public static bool operator > (Fraction<TInt> lhs, Fraction<TInt> rhs) | ||
=> (lhs.Numerator * rhs.Denominator) > (rhs.Numerator * lhs.Denominator); | ||
|
||
public bool Equals (Fraction<TInt> other) | ||
=> Numerator == other.Numerator && Denominator == other.Denominator; | ||
|
||
public override bool Equals (object? obj) | ||
{ | ||
if (obj is not Fraction<TInt> other) return false; | ||
return Equals (other); | ||
} | ||
|
||
public override int GetHashCode () | ||
=> Numerator.GetHashCode () ^ Denominator.GetHashCode (); | ||
} | ||
|
||
public static class FractionExtensions | ||
{ | ||
public static bool LessThan<TInt> ( | ||
this in Fraction<TInt> lhs, | ||
TInt rhsNumerator, | ||
TInt rhsDenominator | ||
) | ||
where TInt : IBinaryInteger<TInt> | ||
{ | ||
return (lhs.Numerator * rhsDenominator) < (lhs.Denominator * rhsNumerator); | ||
} | ||
|
||
public static bool GreaterThan<TInt> ( | ||
this in Fraction<TInt> lhs, | ||
TInt rhsNumerator, | ||
TInt rhsDenominator | ||
) | ||
where TInt : IBinaryInteger<TInt> | ||
{ | ||
return (lhs.Numerator * rhsDenominator) > (lhs.Denominator * rhsNumerator); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,75 +7,47 @@ | |
// Ported to Pinta by: Jonathan Pobst <[email protected]> // | ||
///////////////////////////////////////////////////////////////////////////////// | ||
|
||
using System; | ||
|
||
namespace Pinta.Core; | ||
|
||
/// <summary> | ||
/// Encapsulates functionality for zooming/scaling coordinates. | ||
/// Includes methods for Size[F]'s, Point[F]'s, Rectangle[F]'s, | ||
/// and various scalars | ||
/// </summary> | ||
public readonly struct ScaleFactor | ||
public static class ScaleFactor | ||
{ | ||
private readonly int denominator; | ||
private readonly int numerator; | ||
|
||
public double Ratio { get; } | ||
|
||
public static readonly ScaleFactor OneToOne = new (1, 1); | ||
public static readonly ScaleFactor MinValue = new (1, 100); | ||
public static readonly ScaleFactor MaxValue = new (32, 1); | ||
public static Fraction<int> OneToOne { get; } = new (1, 1); | ||
public static Fraction<int> MinValue { get; } = new (1, 100); | ||
public static Fraction<int> MaxValue { get; } = new (32, 1); | ||
|
||
public readonly int ScaleScalar (int x) => | ||
(int) (((long) x * numerator) / denominator); | ||
public static int ScaleScalar (this in Fraction<int> fraction, int x) => | ||
(int) (((long) x * fraction.Numerator) / fraction.Denominator); | ||
|
||
public readonly int UnscaleScalar (int x) => | ||
(int) (((long) x * denominator) / numerator); | ||
public static int UnscaleScalar (this in Fraction<int> fraction, int x) => | ||
(int) (((long) x * fraction.Denominator) / fraction.Numerator); | ||
|
||
public readonly double ScaleScalar (double x) => | ||
x * numerator / denominator; | ||
public static double ScaleScalar (this in Fraction<int> fraction, double x) => | ||
x * fraction.Numerator / fraction.Denominator; | ||
|
||
public readonly double UnscaleScalar (double x) => | ||
x * denominator / numerator; | ||
public static double UnscaleScalar (this in Fraction<int> fraction, double x) => | ||
x * fraction.Denominator / fraction.Numerator; | ||
|
||
public readonly PointD ScalePoint (PointD p) => | ||
new (ScaleScalar (p.X), ScaleScalar (p.Y)); | ||
public static PointD ScalePoint (this in Fraction<int> fraction, PointD p) => | ||
new (fraction.ScaleScalar (p.X), fraction.ScaleScalar (p.Y)); | ||
|
||
public readonly PointD UnscalePoint (PointD p) => | ||
new (UnscaleScalar (p.X), UnscaleScalar (p.Y)); | ||
public static PointD UnscalePoint (this in Fraction<int> fraction, PointD p) => | ||
new (fraction.UnscaleScalar (p.X), fraction.UnscaleScalar (p.Y)); | ||
|
||
public static bool operator < (ScaleFactor lhs, ScaleFactor rhs) => | ||
(lhs.numerator * rhs.denominator) < (rhs.numerator * lhs.denominator); | ||
public static double ComputeRatio (this in Fraction<int> fraction) | ||
=> fraction.Numerator / (double) fraction.Denominator; | ||
|
||
public static bool operator > (ScaleFactor lhs, ScaleFactor rhs) => | ||
(lhs.numerator * rhs.denominator) > (rhs.numerator * lhs.denominator); | ||
|
||
public ScaleFactor (int numerator, int denominator) | ||
/// <returns> | ||
/// Fraction representing the scale factor, | ||
/// clamped to <see cref="MinValue"/> and <see cref="MaxValue"/> | ||
/// </returns> | ||
public static Fraction<int> CreateClamped (int numerator, int denominator) | ||
{ | ||
if (denominator <= 0) | ||
throw new ArgumentOutOfRangeException (nameof (denominator), "must be greater than 0(denominator = " + denominator + ")"); | ||
|
||
if (numerator <= 0) | ||
throw new ArgumentOutOfRangeException (nameof (numerator), "must be greater than 0(numerator = " + numerator + ")"); | ||
|
||
// Clamp | ||
if ((numerator * MinValue.denominator) < (MinValue.numerator * denominator)) { | ||
numerator = MinValue.numerator; | ||
denominator = MinValue.denominator; | ||
} else if ((MaxValue.numerator * denominator) > (MaxValue.numerator * denominator)) { | ||
numerator = MaxValue.numerator; | ||
denominator = MaxValue.denominator; | ||
} | ||
|
||
int gcd = Mathematics.EuclidGCD (numerator, denominator); | ||
|
||
int reducedNumerator = numerator / gcd; | ||
int reducedDenominator = denominator / gcd; | ||
|
||
this.numerator = reducedNumerator; | ||
this.denominator = reducedDenominator; | ||
|
||
Ratio = reducedNumerator / (double) reducedDenominator; | ||
Fraction<int> baseFraction = new (numerator, denominator); | ||
return Mathematics.Clamp (baseFraction, MinValue, MaxValue); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.