Skip to content

Commit 7e943a4

Browse files
committed
Finished gradients
1 parent 5f43377 commit 7e943a4

File tree

3 files changed

+153
-17
lines changed

3 files changed

+153
-17
lines changed

src/main/scala/io/github/scalamath/colorlib/Gradient.scala

+24-7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import scala.collection.immutable.TreeMap
88
* Created from a set of points made of a color and an offset.
99
* A color can be sampled from the gradient and the result will be an interpolation between the colors of the gradient.
1010
*
11+
* The offsets are usually numbers between `0.0` and `1.0`, but other values are also allowed.
12+
*
1113
* @example {{{
1214
* // Scala
1315
* val gradient = Gradient(
@@ -16,7 +18,7 @@ import scala.collection.immutable.TreeMap
1618
* 1.0f -> Col4f(0.0f, 1.0f, 0.0f) // Green
1719
* )
1820
* // Java
19-
* var gradient = new Gradient()
21+
* Gradient gradient = new Gradient()
2022
* .addPoint(0.0f, new Col4f(1.0f, 0.0f, 0.0f))
2123
* .addPoint(0.5f, new Col4f(1.0f, 1.0f, 0.0f))
2224
* .addPoint(1.0f, new Col4f(0.0f, 1.0f, 0.0f));
@@ -33,7 +35,7 @@ class Gradient private(private val points: TreeMap[Float, Color]) {
3335
def this() = this(new TreeMap())
3436

3537
/**
36-
* Creates a new gradient obtained by updating this gradient with the given color and offset.
38+
* Creates a new gradient obtained by updating this one with the given color and offset.
3739
*
3840
* @param color The color to add to the gradient.
3941
* @param offset The offset of the color.
@@ -42,7 +44,7 @@ class Gradient private(private val points: TreeMap[Float, Color]) {
4244
def addPoint(color: Color, offset: Float): Gradient = new Gradient(this.points.updated(offset, color))
4345

4446
/**
45-
* Creates a new gradient obtained by updating this gradient with the given color and offset.
47+
* Creates a new gradient obtained by updating this one with the given color and offset.
4648
*
4749
* @param offset The offset of the color.
4850
* @param color The color to add to the gradient.
@@ -51,7 +53,7 @@ class Gradient private(private val points: TreeMap[Float, Color]) {
5153
def addPoint(offset: Float, color: Color): Gradient = this.addPoint(color, offset)
5254

5355
/**
54-
* Creates a new gradient obtained by updating this gradient with the given color and offset.
56+
* Creates a new gradient obtained by updating this one with the given color and offset.
5557
*
5658
* This method is an alias for `addPoint`.
5759
*
@@ -62,7 +64,7 @@ class Gradient private(private val points: TreeMap[Float, Color]) {
6264
def +(color: Color, offset: Float): Gradient = this.addPoint(color, offset)
6365

6466
/**
65-
* Creates a new gradient obtained by updating this gradient with the given color and offset.
67+
* Creates a new gradient obtained by updating this one with the given color and offset.
6668
*
6769
* This method is an alias for `addPoint`.
6870
*
@@ -73,7 +75,8 @@ class Gradient private(private val points: TreeMap[Float, Color]) {
7375
def +(offset: Float, color: Color): Gradient = this + (color, offset)
7476

7577
/**
76-
* Returns the number of colors in the gradient.
78+
* Returns the number of points in the gradient.
79+
* Each pair of color and offset is a point.
7780
*
7881
* @return The number of colors in the gradient.
7982
*/
@@ -83,6 +86,11 @@ class Gradient private(private val points: TreeMap[Float, Color]) {
8386
* Returns the interpolated color specified by the given offset.
8487
* Colors are interpolated linearly.
8588
*
89+
* Returns black if this gradient is empty.
90+
*
91+
* Returns the first color in the gradient if the given offset is lower than the offset of the first point.
92+
* Returns the last color in the gradient if the given offset is higher than the offset of the last point.
93+
*
8694
* @param offset The offset of the color.
8795
* @return The result of linearly interpolating the color of this gradient at the given offset.
8896
*/
@@ -109,7 +117,13 @@ class Gradient private(private val points: TreeMap[Float, Color]) {
109117
* @param offset The offset of the color.
110118
* @return The color at the given offset.
111119
*/
112-
def getColor(offset: Float): Color = this.points.maxBefore(offset).map(entry => entry._2).getOrElse(this.points(this.points.firstKey))
120+
def getColor(offset: Float): Color = {
121+
if(this.points.contains(offset)) {
122+
this.points(offset)
123+
} else {
124+
this.points.maxBefore(offset).map(entry => entry._2).getOrElse(this.points(this.points.firstKey))
125+
}
126+
}
113127

114128
/**
115129
* Creates a new gradient obtained by removing the color at the given offset from this gradient.
@@ -133,6 +147,8 @@ class Gradient private(private val points: TreeMap[Float, Color]) {
133147
case gradient: Gradient => this.points.equals(gradient.points)
134148
case _ => super.equals(obj)
135149
}
150+
151+
override def hashCode(): Int = 31 + this.points.hashCode()
136152
}
137153

138154
/**
@@ -151,6 +167,7 @@ object Gradient {
151167

152168
/**
153169
* Creates a gradient from the given points.
170+
* Every point is a pair made of an offset and a color.
154171
*
155172
* @example {{{
156173
* val gradient = Gradient(
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
package io.github.scalamath.colorlib;
22

3+
import org.junit.Assert;
34
import org.junit.Test;
45

56
public class TestGradient {
67

78
@Test
8-
public void testGradient() {
9-
var gradient = new Gradient()
9+
public void testAddPoint() {
10+
var g1 = new Gradient()
1011
.addPoint(new Col3f(1.0f, 0.0f, 0.0f), 0.0f)
12+
.addPoint(new Col3f(1.0f, 1.0f, 0.0f), 0.5f)
1113
.addPoint(new Col3f(0.0f, 1.0f, 0.0f), 1.0f);
12-
System.out.println(gradient.sample(0.5f));
14+
var g2 = new Gradient()
15+
.addPoint(new Col3f(1.0f, 0.0f, 0.0f), 0.0f)
16+
.addPoint(new Col3f(1.0f, 0.0f, 1.0f), 0.25f)
17+
.addPoint(new Col3f(1.0f, 1.0f, 0.0f), 0.5f)
18+
.addPoint(new Col3f(0.0f, 0.0f, 1.0f), 0.75f)
19+
.addPoint(new Col3f(0.0f, 1.0f, 0.0f), 1.0f);
20+
var res = g1
21+
.addPoint(new Col3f(0.0f, 0.0f, 1.0f), 0.75f)
22+
.addPoint(0.25f, new Col3f(1.0f, 0.0f, 1.0f));
23+
Assert.assertEquals(g2, res);
1324
}
1425
}

src/test/scala/io/github/scalamath/colorlib/GradientSuite.scala

+115-7
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,123 @@ import org.scalatest.funsuite.AnyFunSuite
44

55
class GradientSuite extends AnyFunSuite {
66

7-
test("Thing") {
7+
test("Sample color from gradient") {
88
val gradient = Gradient(
99
0.0f -> Col3f(1.0f, 0.0f, 0.0f),
10-
0.5f -> Col3f(0.0f, 1.0f, 0.0f)
10+
0.5f -> Col3f(1.0f, 1.0f, 0.0f),
11+
1.0f -> Col3f(0.0f, 1.0f, 0.0f)
1112
)
12-
println(gradient.sample(0.5f))
13-
println(gradient.sample(0.25f))
14-
println(gradient.sample(0.1f))
15-
println(gradient.sample(0.75f))
16-
println(gradient.sample(1.0f))
13+
assert(gradient.sample(0.25f) == Col3f(1.0f, 0.5f, 0.0f))
14+
assert(gradient.sample(0.5f) == Col3f(1.0f, 1.0f, 0.0f))
15+
assert(gradient.sample(0.375f) == Col3f(1.0f, 0.75f, 0.0f))
16+
assert(gradient.sample(-0.1f) == Col3f(1.0f, 0.0f, 0.0f))
17+
assert(gradient.sample(0.75f) == Col3f(0.5f, 1.0f, 0.0f))
18+
assert(gradient.sample(0.625f) == Col3f(0.75f, 1.0f, 0.0f))
19+
assert(gradient.sample(1.0f) == Col3f(0.0f, 1.0f, 0.0f))
20+
}
21+
22+
test("Add points to gradient") {
23+
val g1 = Gradient(
24+
0.0f -> Col3f(1.0f, 0.0f, 0.0f),
25+
0.5f -> Col3f(1.0f, 1.0f, 0.0f),
26+
1.0f -> Col3f(0.0f, 1.0f, 0.0f)
27+
)
28+
val g2 = Gradient(
29+
0.0f -> Col3f(1.0f, 0.0f, 0.0f),
30+
0.25f -> Col3f(1.0f, 0.0f, 1.0f),
31+
0.5f -> Col3f(1.0f, 1.0f, 0.0f),
32+
0.75f -> Col3f(0.0f, 0.0f, 1.0f),
33+
1.0f -> Col3f(0.0f, 1.0f, 0.0f)
34+
)
35+
val res = g1
36+
.addPoint(Col3f(0.0f, 0.0f, 1.0f), 0.75f)
37+
.addPoint(0.25f, Col3f(1.0f, 0.0f, 1.0f))
38+
assert(g2 == res)
39+
}
40+
41+
test("Add points using the + operator") {
42+
val g1 = Gradient(
43+
0.0f -> Col3f(1.0f, 0.0f, 0.0f),
44+
0.5f -> Col3f(1.0f, 1.0f, 0.0f),
45+
1.0f -> Col3f(0.0f, 1.0f, 0.0f)
46+
)
47+
val g2 = Gradient(
48+
0.0f -> Col3f(1.0f, 0.0f, 0.0f),
49+
0.25f -> Col3f(1.0f, 0.0f, 1.0f),
50+
0.5f -> Col3f(1.0f, 1.0f, 0.0f),
51+
0.75f -> Col3f(0.0f, 0.0f, 1.0f),
52+
1.0f -> Col3f(0.0f, 1.0f, 0.0f)
53+
)
54+
val res = g1 + (Col3f(0.0f, 0.0f, 1.0f), 0.75f) + (0.25f, Col3f(1.0f, 0.0f, 1.0f))
55+
assert(g2 == res)
56+
}
57+
58+
test("Get the number of points in a gradient") {
59+
val gradient = Gradient(
60+
0.0f -> Col3f(1.0f, 0.0f, 0.0f),
61+
1.0f / 6.0f -> Col3f(1.0f, 0.5f, 0.0f),
62+
2.0f / 6.0f -> Col3f(1.0f, 1.0f, 0.0f),
63+
3.0f / 6.0f -> Col3f(0.0f, 1.0f, 0.0f),
64+
4.0f / 6.0f -> Col3f(0.0f, 0.0f, 1.0f),
65+
5.0f / 6.0f -> Col3f(0.5f, 0.0f, 1.0f),
66+
1.0f -> Col3f(1.0f, 1.0f, 1.0f)
67+
)
68+
assert(gradient.pointCount == 7)
69+
assert(Gradient().pointCount == 0)
70+
}
71+
72+
test("Get color without interpolating") {
73+
val gradient = Gradient(
74+
0.0f -> Col3f(1.0f, 0.0f, 0.0f),
75+
0.5f -> Col3f(1.0f, 1.0f, 0.0f),
76+
1.0f -> Col3f(0.0f, 1.0f, 0.0f)
77+
)
78+
assert(gradient.getColor(0.0f) == Col3f(1.0f, 0.0f, 0.0f))
79+
assert(gradient.getColor(0.25f) == Col3f(1.0f, 0.0f, 0.0f))
80+
assert(gradient.getColor(0.5f) == Col3f(1.0f, 1.0f, 0.0f))
81+
assert(gradient.getColor(0.75f) == Col3f(1.0f, 1.0f, 0.0f))
82+
assert(gradient.getColor(1.0f) == Col3f(0.0f, 1.0f, 0.0f))
83+
assert(gradient.getColor(1.2f) == Col3f(0.0f, 1.0f, 0.0f))
84+
assert(gradient.getColor(-0.2f) == Col3f(1.0f, 0.0f, 0.0f))
85+
}
86+
87+
test("Remove points from gradient") {
88+
val g1 = Gradient(
89+
0.0f -> Col3f(1.0f, 0.0f, 0.0f),
90+
0.5f -> Col3f(1.0f, 1.0f, 0.0f),
91+
1.0f -> Col3f(0.0f, 1.0f, 0.0f)
92+
)
93+
val g2 = Gradient(
94+
0.0f -> Col3f(1.0f, 0.0f, 0.0f),
95+
0.25f -> Col3f(1.0f, 0.0f, 1.0f),
96+
0.5f -> Col3f(1.0f, 1.0f, 0.0f),
97+
0.75f -> Col3f(0.0f, 0.0f, 1.0f),
98+
1.0f -> Col3f(0.0f, 1.0f, 0.0f)
99+
)
100+
val res = g2.removePoint(0.25f).removePoint(0.75f)
101+
assert(g1 == res)
102+
}
103+
104+
test("Remove points using the - operator") {
105+
val g1 = Gradient(
106+
0.0f -> Col3f(1.0f, 0.0f, 0.0f),
107+
0.5f -> Col3f(1.0f, 1.0f, 0.0f),
108+
1.0f -> Col3f(0.0f, 1.0f, 0.0f)
109+
)
110+
val g2 = Gradient(
111+
0.0f -> Col3f(1.0f, 0.0f, 0.0f),
112+
0.25f -> Col3f(1.0f, 0.0f, 1.0f),
113+
0.5f -> Col3f(1.0f, 1.0f, 0.0f),
114+
0.75f -> Col3f(0.0f, 0.0f, 1.0f),
115+
1.0f -> Col3f(0.0f, 1.0f, 0.0f)
116+
)
117+
val res = g2 - 0.25f - 0.75f
118+
assert(g1 == res)
119+
}
120+
121+
test("Create gradient between two colors") {
122+
val g1 = Gradient(0.0f -> Col3f(1.0f, 0.0f, 0.0f), 1.0f -> Col3f(0.0f, 1.0f, 0.0f))
123+
val g2 = Gradient.between(Col3f(1.0f, 0.0f, 0.0f), Col3f(0.0f, 1.0f, 0.0f))
124+
assert(g1 == g2)
17125
}
18126
}

0 commit comments

Comments
 (0)