{"id":550,"date":"2016-11-10T18:00:01","date_gmt":"2016-11-10T17:00:01","guid":{"rendered":"http:\/\/piflik.de\/?p=550"},"modified":"2016-11-09T00:11:33","modified_gmt":"2016-11-08T23:11:33","slug":"utilities-ranged-values","status":"publish","type":"post","link":"http:\/\/piflik.de\/?p=550","title":{"rendered":"Utilities: Ranged Values"},"content":{"rendered":"<p>Another day, another utility. This time: Ranged values. They were inspired from a <a href=\"https:\/\/www.youtube.com\/watch?v=VBA1QCoEAX4\">Unite Europe 2016 talk on scriptable objects<\/a> (and the Inpector code is copied nearly verbatim) by Richard Fine. The original had only a minimum and maximum float value with the fancy Inspector GUI, but I extended it with functionality nobody in their right mind would probably ever need. It started with a method to get a random value from within the interval and quickly escalated to two interpolation functions and tests to determine if an interval contains a given value or another interval, or if two intervals intersect. Finally I added operators to add, multiply or order intervals. And as if all that wasn&#8217;t already useless enough, I did the same thing again, with ints instead of floats and added a generic Range&lt;T&gt; class, that can create intervals from any orderable value-type, albeit a bit less powerfull, since adding and subtracting doesn&#8217;t necessarily have meaning outside of numbers. The inspector code also doesn&#8217;t work with the generic version.<\/p>\n<p>Anyway, here is a example of how it looks in the Inspector, and a wall of code after the break.<\/p>\n<p><a rel=\"attachment wp-att-551\" href=\"http:\/\/piflik.de\/?attachment_id=551\"><img loading=\"lazy\" class=\"aligncenter size-full wp-image-551\" title=\"RangedValues\" src=\"http:\/\/piflik.de\/wp-content\/uploads\/2016\/11\/RangedValues.png\" alt=\"\" width=\"261\" height=\"37\" \/><\/a>The editor code can be found on my <a title=\"Utilities\" href=\"https:\/\/bitbucket.org\/Piflik\/utilities\/src\">Bitbucket repository<\/a>.<\/p>\n<p><!--more--><\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">using System;\r\nusing UnityEngine;\r\nusing Random = UnityEngine.Random;\r\n\r\npublic struct Range&lt;T&gt; : IEquatable&lt;Range&lt;T&gt;&gt;, IComparable&lt;Range&lt;T&gt;&gt; where T : struct, IEquatable&lt;T&gt;, IComparable&lt;T&gt; {\r\n    public T min { get; set; }\r\n    public T max { get; set; }\r\n\r\n    public Range(T min, T max) : this() {\r\n        if (min.CompareTo(max) &lt;= 0) {\r\n            this.min = min;\r\n            this.max = max;\r\n        } else {\r\n            this.min = max;\r\n            this.max = min;\r\n        }\r\n    }\r\n\r\n    public bool valid {\r\n        get { return min.CompareTo(max) &lt;= 0; }\r\n    }\r\n\r\n    public Range&lt;T&gt; Validate() {\r\n        return valid ? this : new Range&lt;T&gt; { min = max, max = min };\r\n    }\r\n\r\n    public bool Contains(T value) {\r\n        return min.CompareTo(value) &lt;= 0 &amp;&amp; max.CompareTo(value) &gt;= 0;\r\n    }\r\n\r\n    public bool Contains(Range&lt;T&gt; range) {\r\n        return Contains(range.min) &amp;&amp; Contains(range.max);\r\n    }\r\n\r\n    public bool Intersects(Range&lt;T&gt; range) {\r\n        return Contains(range.min) &amp;&amp; max.CompareTo(range.max) &lt; 0\r\n            || Contains(range.max) &amp;&amp; min.CompareTo(range.min) &gt; 0;\r\n    }\r\n\r\n    public Range&lt;T&gt; Apply(Func&lt;T, T&gt; function) {\r\n        return new Range&lt;T&gt; {min = function(min), max = function(max)};\r\n    }\r\n\r\n    public int CompareTo(Range&lt;T&gt; range) {\r\n        if (min.CompareTo(range.min) &lt; 0 &amp;&amp; max.CompareTo(range.max) &lt; 0) return -1;\r\n        if (min.CompareTo(range.min) &gt; 0 &amp;&amp; max.CompareTo(range.max) &gt; 0) return 1;\r\n        return 0;\r\n    }\r\n\r\n    public override bool Equals(object obj) {\r\n        if (obj is Range&lt;T&gt;) {\r\n            Range&lt;T&gt; range = (Range&lt;T&gt;) obj;\r\n\r\n            return min.Equals(range.min) &amp;&amp; max.Equals(range.max);\r\n        }\r\n        return false;\r\n    }\r\n\r\n    public override int GetHashCode() {\r\n        return min.GetHashCode() ^ max.GetHashCode();\r\n    }\r\n\r\n    public bool Equals(Range&lt;T&gt; range) {\r\n        return min.Equals(range.min) &amp;&amp; max.Equals(range.max);\r\n    }\r\n}\r\n\r\n[Serializable]\r\npublic struct FloatRange : IEquatable&lt;FloatRange&gt;, IComparable&lt;FloatRange&gt; {\r\n    public float min;\r\n    public float max;\r\n\r\n    public FloatRange(float min, float max) : this() {\r\n        this.min = Mathf.Min(min, max);\r\n        this.max = Mathf.Max(min, max);\r\n    }\r\n\r\n    public float size { get { return max - min; } }\r\n    public float random { get { return Random.Range(min, max); } }\r\n    public bool valid { get { return min &lt;= max; } }\r\n\r\n    public FloatRange Validate() {\r\n        return valid ? this : new FloatRange { min = max, max = min };\r\n    }\r\n\r\n    public bool Contains(float value) {\r\n        return value &gt;= min &amp;&amp; value &lt;= max;\r\n    }\r\n\r\n    public bool Contains(FloatRange range) {\r\n        return Contains(min) &amp;&amp; Contains(max);\r\n    }\r\n\r\n    public bool Intersects(FloatRange range) {\r\n        return range.min &lt; min &amp;&amp; Contains(range.max)\r\n            || range.max &gt; max &amp;&amp; Contains(range.min);\r\n    }\r\n\r\n    public FloatRange Apply(Func&lt;float, float&gt; function) {\r\n        return new FloatRange { min = function(min), max = function(max)};\r\n    }\r\n\r\n    public float Lerp(float alpha) {\r\n        if (alpha &lt; 0) return min;\r\n        if (alpha &gt; 1) return max;\r\n\r\n        return alpha*max + (1 - alpha)*min;\r\n    }\r\n\r\n    public float SmoothstepInterpolation(float alpha) {\r\n        if(alpha &lt; 0) return min;\r\n        if(alpha &gt; 1) return max;\r\n\r\n        alpha = alpha * alpha * (3 - 2 * alpha);\r\n\r\n        return alpha * max + (1 - alpha) * min;\r\n    }\r\n\r\n    public int CompareTo(FloatRange other) {\r\n        if (this &gt; other) return 1;\r\n        if (this &lt; other) return -1;\r\n        return 0;\r\n    }\r\n\r\n    public override bool Equals(object obj) {\r\n        if (obj is FloatRange) {\r\n            FloatRange rf = (FloatRange) obj;\r\n            return min.Equals(rf.min) &amp;&amp; max.Equals(rf.max);\r\n        }\r\n        return false;\r\n    }\r\n\r\n    public override int GetHashCode() {\r\n        return min.GetHashCode() ^ max.GetHashCode();\r\n    }\r\n\r\n    public override string ToString() {\r\n        return string.Format(&quot;[{0}, {1}]&quot;, min, max);\r\n    }\r\n\r\n    public bool Equals(FloatRange other) {\r\n        return min.Equals(other.min) &amp;&amp; max.Equals(other.max);\r\n    }\r\n\r\n    public static bool operator ==(FloatRange a, FloatRange b) {\r\n        return a.min.Equals(b.min) &amp;&amp; a.max.Equals(b.max);\r\n    }\r\n\r\n    public static bool operator !=(FloatRange a, FloatRange b) {\r\n        return !a.min.Equals(b.min) || !a.max.Equals(b.max);\r\n    }\r\n\r\n    public static bool operator &lt;(FloatRange a, FloatRange b) {\r\n        return a.min &lt; b.min &amp;&amp; a.max &lt; b.max;\r\n    }\r\n\r\n    public static bool operator &lt;=(FloatRange a, FloatRange b) {\r\n        return a.min &lt;= b.min &amp;&amp; a.max &lt;= b.max;\r\n    }\r\n\r\n    public static bool operator &gt;(FloatRange a, FloatRange b) {\r\n        return a.min &gt; b.min &amp;&amp; a.max &gt; b.max;\r\n    }\r\n\r\n    public static bool operator &gt;=(FloatRange a, FloatRange b) {\r\n        return a.min &gt;= b.min &amp;&amp; a.max &gt;= b.max;\r\n    }\r\n\r\n    public static FloatRange operator +(FloatRange a, FloatRange b) {\r\n        return new FloatRange {min = a.min + b.min, max = a.max + b.max};\r\n    }\r\n\r\n    public static FloatRange operator +(FloatRange a, float b) {\r\n        return new FloatRange { min = a.min + b, max = a.max + b };\r\n    }\r\n\r\n    public static FloatRange operator +(float a, FloatRange b) {\r\n        return new FloatRange { min = b.min + a, max = b.max + a };\r\n    }\r\n\r\n    public static FloatRange operator -(FloatRange a, FloatRange b) {\r\n        return new FloatRange {min = a.min - b.min, max = a.max - b.max};\r\n    }\r\n\r\n    public static FloatRange operator -(FloatRange a, float b) {\r\n        return new FloatRange { min = a.min - b, max = a.max - b };\r\n    }\r\n\r\n    public static FloatRange operator -(float a, FloatRange b) {\r\n        return new FloatRange { min = b.min - a, max = b.max - a };\r\n    }\r\n\r\n    public static FloatRange operator -(FloatRange a) {\r\n        return new FloatRange { min = -a.max, max = -a.min };\r\n    }\r\n\r\n    public static FloatRange operator *(FloatRange a, FloatRange b) {\r\n        return new FloatRange {min = a.min*b.min, max = a.max * b.max };\r\n    }\r\n\r\n    public static FloatRange operator *(FloatRange a, float b) {\r\n        return new FloatRange { min = a.min * b, max = a.max * b };\r\n    }\r\n\r\n    public static FloatRange operator *(float a, FloatRange b) {\r\n        return new FloatRange { min = b.min * a, max = b.max * a };\r\n    }\r\n\r\n    public static FloatRange operator \/(FloatRange a, FloatRange b) {\r\n        return new FloatRange {min = a.min \/ b.min, max = a.max \/ b.max};\r\n    }\r\n\r\n    public static FloatRange operator \/(FloatRange a, float b) {\r\n        return new FloatRange { min = a.min \/ b, max = a.max \/ b };\r\n    }\r\n\r\n    public static explicit operator IntRange(FloatRange value) {\r\n        return new IntRange { min = (int)value.min, max = (int)value.max };\r\n    }\r\n}\r\n\r\n[Serializable]\r\npublic struct IntRange : IEquatable&lt;IntRange&gt;, IComparable&lt;IntRange&gt; {\r\n    public int min;\r\n    public int max;\r\n\r\n    public IntRange(int min, int max) : this() {\r\n        this.min = Mathf.Min(min, max);\r\n        this.max = Mathf.Max(min, max);\r\n    }\r\n\r\n    public float size { get { return max - min; } }\r\n    public int random { get { return Random.Range(min, max + 1); } }\r\n    public bool valid { get { return min &lt;= max; } }\r\n\r\n    public IntRange Validate() {\r\n        return valid ? this : new IntRange {min = max, max = min};\r\n    }\r\n\r\n    public bool Contains(int value) {\r\n        return value &gt;= min &amp;&amp; value &lt;= max;\r\n    }\r\n\r\n    public bool Contains(IntRange range) {\r\n        return Contains(min) &amp;&amp; Contains(max);\r\n    }\r\n\r\n    public bool Intersects(IntRange range) {\r\n        return range.min &lt; min &amp;&amp; Contains(range.max)\r\n            || range.max &gt; max &amp;&amp; Contains(range.min);\r\n    }\r\n\r\n    public IntRange Apply(Func&lt;int, int&gt; function) {\r\n        return new IntRange { min = function(min), max = function(max) };\r\n    }\r\n\r\n    public float Lerp(float alpha) {\r\n        if(alpha &lt; 0) return min;\r\n        if(alpha &gt; 1) return max;\r\n\r\n        return alpha * max + (1 - alpha) * min;\r\n    }\r\n\r\n    public int LerpToInt(float alpha) {\r\n        if(alpha &lt; 0) return min;\r\n        if(alpha &gt; 1) return max;\r\n\r\n        return Mathf.RoundToInt(alpha * max + (1 - alpha) * min);\r\n    }\r\n\r\n    public float SmoothstepInterpolation(float alpha) {\r\n        if(alpha &lt; 0) return min;\r\n        if(alpha &gt; 1) return max;\r\n\r\n        alpha = alpha * alpha * (3 - 2 * alpha);\r\n\r\n        return alpha * max + (1 - alpha) * min;\r\n    }\r\n\r\n    public float SmoothstepInterpolationToInt(float alpha) {\r\n        if(alpha &lt; 0) return min;\r\n        if(alpha &gt; 1) return max;\r\n\r\n        alpha = alpha * alpha * (3 - 2 * alpha);\r\n\r\n        return Mathf.RoundToInt(alpha * max + (1 - alpha) * min);\r\n    }\r\n\r\n    public int CompareTo(IntRange other) {\r\n        if(this &gt; other) return 1;\r\n        if(this &lt; other) return -1;\r\n        return 0;\r\n    }\r\n\r\n    public override bool Equals(object obj) {\r\n        if(obj is IntRange) {\r\n            IntRange rf = (IntRange)obj;\r\n            return min.Equals(rf.min) &amp;&amp; max.Equals(rf.max);\r\n        }\r\n        return false;\r\n    }\r\n\r\n    public override int GetHashCode() {\r\n        return min.GetHashCode() ^ max.GetHashCode();\r\n    }\r\n\r\n    public override string ToString() {\r\n        return string.Format(&quot;[{0}, {1}]&quot;, min, max);\r\n    }\r\n\r\n    public bool Equals(IntRange other) {\r\n        return min.Equals(other.min) &amp;&amp; max.Equals(other.max);\r\n    }\r\n\r\n    public static bool operator ==(IntRange a, IntRange b) {\r\n        return a.min.Equals(b.min) &amp;&amp; a.max.Equals(b.max);\r\n    }\r\n\r\n    public static bool operator !=(IntRange a, IntRange b) {\r\n        return !a.min.Equals(b.min) || !a.max.Equals(b.max);\r\n    }\r\n\r\n    public static bool operator &lt;(IntRange a, IntRange b) {\r\n        return a.min &lt; b.min &amp;&amp; a.max &lt; b.max;\r\n    }\r\n\r\n    public static bool operator &lt;=(IntRange a, IntRange b) {\r\n        return a.min &lt;= b.min &amp;&amp; a.max &lt;= b.max;\r\n    }\r\n\r\n    public static bool operator &gt;(IntRange a, IntRange b) {\r\n        return a.min &gt; b.min &amp;&amp; a.max &gt; b.max;\r\n    }\r\n\r\n    public static bool operator &gt;=(IntRange a, IntRange b) {\r\n        return a.min &gt;= b.min &amp;&amp; a.max &gt;= b.max;\r\n    }\r\n\r\n    public static IntRange operator +(IntRange a, IntRange b) {\r\n        return new IntRange { min = a.min + b.min, max = a.max + b.max };\r\n    }\r\n\r\n    public static IntRange operator +(IntRange a, int b) {\r\n        return new IntRange {min = a.min + b, max = a.max + b};\r\n    }\r\n\r\n    public static IntRange operator +(int a, IntRange b) {\r\n        return new IntRange { min = b.min + a, max = b.max + a };\r\n    }\r\n\r\n    public static IntRange operator -(IntRange a, IntRange b) {\r\n        return new IntRange { min = a.min - b.min, max = a.max - b.max };\r\n    }\r\n\r\n    public static IntRange operator -(IntRange a, int b) {\r\n        return new IntRange { min = a.min - b, max = a.max - b };\r\n    }\r\n\r\n    public static IntRange operator -(int a, IntRange b) {\r\n        return new IntRange { min = b.min - a, max = b.max - a };\r\n    }\r\n\r\n    public static IntRange operator -(IntRange a) {\r\n        return new IntRange {min = -a.max, max = -a.min};\r\n    }\r\n\r\n    public static IntRange operator *(IntRange a, IntRange b) {\r\n        return new IntRange { min = a.min * b.min, max = a.max * b.max };\r\n    }\r\n\r\n    public static IntRange operator *(IntRange a, int b) {\r\n        return new IntRange { min = a.min * b, max = a.max * b };\r\n    }\r\n\r\n    public static IntRange operator *(int a, IntRange b) {\r\n        return new IntRange { min = b.min * a, max = b.max * a };\r\n    }\r\n\r\n    public static IntRange operator \/(IntRange a, IntRange b) {\r\n        return new IntRange { min = a.min \/ b.min, max = a.max \/ b.max };\r\n    }\r\n\r\n    public static IntRange operator \/(IntRange a, int b) {\r\n        return new IntRange { min = a.min \/ b, max = a.max \/ b };\r\n    }\r\n\r\n    public static implicit operator FloatRange(IntRange value) {\r\n        return new FloatRange { min = value.min, max = value.max };\r\n    }\r\n}\r\n\r\npublic class MinMaxRangeAttribute : Attribute {\r\n    public MinMaxRangeAttribute(float min, float max) {\r\n        this.min = min;\r\n        this.max = max;\r\n    }\r\n    public float min { get; private set; }\r\n    public float max { get; private set; }\r\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Another day, another utility. This time: Ranged values. They were inspired from a Unite Europe 2016 talk on scriptable objects (and the Inpector code is copied nearly verbatim) by Richard Fine. The original had only a minimum and maximum float value with the fancy Inspector GUI, but I extended it with functionality nobody in their [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[13,12],"tags":[],"_links":{"self":[{"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts\/550"}],"collection":[{"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=550"}],"version-history":[{"count":26,"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts\/550\/revisions"}],"predecessor-version":[{"id":583,"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts\/550\/revisions\/583"}],"wp:attachment":[{"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=550"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=550"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=550"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}