Skip to content

Commit 5afcd61

Browse files
authored
Merge pull request #37 from ruby-processing/duck-type
Duck type
2 parents d901395 + 4942a9c commit 5afcd61

File tree

16 files changed

+195
-151
lines changed

16 files changed

+195
-151
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
**v1.4.5** Vec2D and Vec3D now support `copy` constructor where the original can be a duck-type. Further the only requirement is that the duck-type responds to `:x`, and `:y` by returning a `float` or `fixnum` thus Vec2D can be promoted to Vec3D (where `z = 0`), or more usually some other Vector or Point class can be used as the original. A VectorUtils library has been implemented, see examples for usage.
12

23
**v1.4.4** Bump up to JRubyComplete-9.1.15.0
34

lib/jruby_art/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22
# A wrapper for version
33
module JRubyArt
4-
VERSION = '1.4.4'.freeze
4+
VERSION = '1.4.5'.freeze
55
end
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
PHI ||= (1 + Math.sqrt(5)) / 2 # golden ratio
2+
GA = PHI * 2 * Math::PI # golden angle
3+
4+
# Useful Vector Utiliies
5+
module VectorUtil
6+
def self.rotate_vec2d(vectors: [], angle: 0)
7+
vectors.map { |vector| vector.rotate(angle) }
8+
end
9+
10+
def self.vogel_layout(number:, node_size:)
11+
(0..number).map do |i|
12+
r = Math.sqrt(i)
13+
theta = i * ((2 * Math::PI) / (PHI * PHI))
14+
x = Math.cos(theta) * r * node_size
15+
y = Math.sin(theta) * r * node_size
16+
Vec2D.new(x, y)
17+
end
18+
end
19+
20+
def self.fibonacci_sphere(number:, radius:)
21+
(0..number).map do |i|
22+
lon = GA * i
23+
lon /= 2 * Math::PI
24+
lon -= lon.floor
25+
lon *= 2 * Math::PI
26+
lon -= 2 * Math::PI if lon > Math::PI
27+
lat = Math.asin(-1 + 2 * i / number.to_f)
28+
x = radius * Math.cos(lat) * Math.cos(lon)
29+
y = radius * Math.cos(lat) * Math.sin(lon)
30+
z = radius * Math.sin(lat)
31+
Vec3D.new(x, y, z)
32+
end
33+
end
34+
35+
def self.spiral_layout(number:, radius:, resolution:, spacing:, inc:)
36+
n = 0
37+
angle = nil
38+
(0..number).map do
39+
angle = n * resolution
40+
n += inc
41+
radius -= angle * spacing
42+
x = Math.cos(angle) * radius
43+
y = Math.sin(angle) * radius
44+
Vec2D.new(x, y)
45+
end
46+
end
47+
48+
def self.cartesian_to_polar(vec:)
49+
res = Vec3D.new(vec.mag, 0, 0)
50+
return Vec3D.new unless res.x > 0
51+
res.y = -Math.atan2(vec.z, vec.x)
52+
res.z = Math.asin(vec.y / res.x)
53+
res
54+
end
55+
56+
def self.to_cartesian(lat:, long:, radius:)
57+
latitude = lat
58+
longitude = long
59+
x = radius * Math.cos(latitude) * Math.cos(longitude)
60+
y = radius * Math.cos(latitude) * Math.sin(longitude)
61+
z = radius * Math.sin(latitude)
62+
Vec3D.new(x, y, z)
63+
end
64+
65+
def self.polar_to_cartesian(vec:)
66+
return Vec3D.new if vec.mag <= 0
67+
Vec3D.new(Math.asin(vec.y / vec.mag), vec.mag, -Math.atan2(vec.z, vec.x))
68+
end
69+
end

pom.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
project 'rp5extras', 'https://github.com/ruby-processing/JRubyArt' do
33

44
model_version '4.0.0'
5-
id 'ruby-processing:rp5extras', '1.4.4'
5+
id 'ruby-processing:rp5extras', '1.4.5'
66
packaging 'jar'
77

88
description 'rp5extras for JRubyArt'

src/monkstone/vecmath/vec2/Vec2.java

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,19 @@ public Vec2(Ruby runtime, RubyClass klass) {
8888
}
8989

9090
void init(ThreadContext context, IRubyObject[] args) {
91-
if (Arity.checkArgumentCount(context.runtime, args, Arity.OPTIONAL.getValue(), 2) == 2) {
92-
jx = (args[0] instanceof RubyFloat)
93-
? ((RubyFloat) args[0]).getValue() : ((RubyFixnum) args[0]).getDoubleValue();
94-
jy = (args[1] instanceof RubyFloat)
95-
? ((RubyFloat) args[1]).getValue() : ((RubyFixnum) args[1]).getDoubleValue();
91+
int count = Arity.checkArgumentCount(context.runtime, args, Arity.OPTIONAL.getValue(), 2);
92+
if (count == 2) {
93+
jx = (args[0] instanceof RubyFloat) ? ((RubyFloat) args[0]).getValue() : ((RubyFixnum) args[0]).getDoubleValue();
94+
jy = (args[1] instanceof RubyFloat) ? ((RubyFloat) args[1]).getValue() : ((RubyFixnum) args[1]).getDoubleValue();
95+
} // allow ruby ducktyping in constructor
96+
if (count == 1) {
97+
if (!(args[0].respondsTo("x"))) {
98+
throw context.runtime.newTypeError(args[0].getType() + " doesn't respond_to :x & :y");
99+
}
100+
jx = ((args[0].callMethod(context, "x")) instanceof RubyFloat)
101+
? ((RubyFloat) args[0].callMethod(context, "x")).getValue() : ((RubyFixnum) args[0].callMethod(context, "x")).getDoubleValue();
102+
jy = ((args[0].callMethod(context, "y")) instanceof RubyFloat)
103+
? ((RubyFloat) args[0].callMethod(context, "y")).getValue() : ((RubyFixnum) args[0].callMethod(context, "y")).getDoubleValue();
96104
}
97105
}
98106

@@ -102,7 +110,6 @@ void init(ThreadContext context, IRubyObject[] args) {
102110
* @return x IRubyObject
103111
*/
104112
@JRubyMethod(name = "x")
105-
106113
public IRubyObject getX(ThreadContext context) {
107114
return context.runtime.newFloat(jx);
108115
}
@@ -113,7 +120,6 @@ public IRubyObject getX(ThreadContext context) {
113120
* @return y IRubyObject
114121
*/
115122
@JRubyMethod(name = "y")
116-
117123
public IRubyObject getY(ThreadContext context) {
118124
return context.runtime.newFloat(jy);
119125
}
@@ -148,7 +154,6 @@ public IRubyObject aref(ThreadContext context, IRubyObject key) {
148154
* @return value float
149155
*/
150156
@JRubyMethod(name = "[]=")
151-
152157
public IRubyObject aset(ThreadContext context, IRubyObject key, IRubyObject value) {
153158
Ruby runtime = context.runtime;
154159
if (key instanceof RubySymbol) {
@@ -172,7 +177,6 @@ public IRubyObject aset(ThreadContext context, IRubyObject key, IRubyObject valu
172177
* @return x IRubyObject
173178
*/
174179
@JRubyMethod(name = "x=")
175-
176180
public IRubyObject setX(ThreadContext context, IRubyObject other) {
177181
if (other instanceof RubyFloat) {
178182
jx = ((RubyFloat) other).getValue();
@@ -189,7 +193,6 @@ public IRubyObject setX(ThreadContext context, IRubyObject other) {
189193
* @return y IRubyObject
190194
*/
191195
@JRubyMethod(name = "y=")
192-
193196
public IRubyObject setY(ThreadContext context, IRubyObject other) {
194197
if (other instanceof RubyFloat) {
195198
jy = ((RubyFloat) other).getValue();
@@ -206,7 +209,6 @@ public IRubyObject setY(ThreadContext context, IRubyObject other) {
206209
* @return distance float
207210
*/
208211
@JRubyMethod(name = "dist", required = 1)
209-
210212
public IRubyObject dist(ThreadContext context, IRubyObject other) {
211213
Vec2 b = null;
212214
Ruby runtime = context.runtime;
@@ -226,7 +228,6 @@ public IRubyObject dist(ThreadContext context, IRubyObject other) {
226228
* @return cross product IRubyObject
227229
*/
228230
@JRubyMethod(name = "cross", required = 1)
229-
230231
public IRubyObject cross(ThreadContext context, IRubyObject other) {
231232
Vec2 b = null;
232233
Ruby runtime = context.runtime;
@@ -245,7 +246,6 @@ public IRubyObject cross(ThreadContext context, IRubyObject other) {
245246
* @return dot product IRubyObject
246247
*/
247248
@JRubyMethod(name = "dot", required = 1)
248-
249249
public IRubyObject dot(ThreadContext context, IRubyObject other) {
250250
Vec2 b = null;
251251
Ruby runtime = context.runtime;
@@ -264,7 +264,6 @@ public IRubyObject dot(ThreadContext context, IRubyObject other) {
264264
* @return new Vec2D object (ruby)
265265
*/
266266
@JRubyMethod(name = "+", required = 1)
267-
268267
public IRubyObject op_plus(ThreadContext context, IRubyObject other) {
269268
Vec2 b = null;
270269
Ruby runtime = context.runtime;
@@ -285,7 +284,6 @@ public IRubyObject op_plus(ThreadContext context, IRubyObject other) {
285284
* @return new Vec2D object (ruby)
286285
*/
287286
@JRubyMethod(name = "-", required = 1)
288-
289287
public IRubyObject op_minus(ThreadContext context, IRubyObject other) {
290288
Vec2 b = null;
291289
Ruby runtime = context.runtime;
@@ -306,7 +304,6 @@ public IRubyObject op_minus(ThreadContext context, IRubyObject other) {
306304
* @return new Vec2D object (ruby)
307305
*/
308306
@JRubyMethod(name = "*")
309-
310307
public IRubyObject op_mul(ThreadContext context, IRubyObject other) {
311308
Ruby runtime = context.runtime;
312309
double scalar = (other instanceof RubyFloat)
@@ -323,7 +320,6 @@ public IRubyObject op_mul(ThreadContext context, IRubyObject other) {
323320
* @return new Vec2D object (ruby)
324321
*/
325322
@JRubyMethod(name = "/", required = 1)
326-
327323
public IRubyObject op_div(ThreadContext context, IRubyObject other) {
328324
Ruby runtime = context.runtime;
329325
double scalar = (other instanceof RubyFloat)
@@ -352,7 +348,6 @@ public IRubyObject heading(ThreadContext context) {
352348
* @return magnitude IRubyObject
353349
*/
354350
@JRubyMethod(name = "mag")
355-
356351
public IRubyObject mag(ThreadContext context) {
357352
double result = 0;
358353
if (Math.abs(jx) > EPSILON && Math.abs(jy) > EPSILON) {
@@ -378,7 +373,6 @@ public IRubyObject mag(ThreadContext context) {
378373
* @return magnitude IRubyObject
379374
*/
380375
@JRubyMethod(name = "set_mag")
381-
382376
public IRubyObject set_mag(ThreadContext context, IRubyObject scalar, Block block) {
383377
double new_mag = (Double) scalar.toJava(Double.class);
384378
if (block.isGiven()) {
@@ -410,7 +404,6 @@ public IRubyObject set_mag(ThreadContext context, IRubyObject scalar, Block bloc
410404
* @return this as a ruby object
411405
*/
412406
@JRubyMethod(name = "normalize!")
413-
414407
public IRubyObject normalize_bang(ThreadContext context) {
415408
double mag = 0;
416409
if (Math.abs(jx) > EPSILON && Math.abs(jy) > EPSILON) {
@@ -436,7 +429,6 @@ public IRubyObject normalize_bang(ThreadContext context) {
436429
* @return new normalized Vec3D object (ruby)
437430
*/
438431
@JRubyMethod(name = "normalize")
439-
440432
public IRubyObject normalize(ThreadContext context) {
441433
double mag = 0;
442434
Ruby runtime = context.runtime;
@@ -573,7 +565,6 @@ public IRubyObject lerp_bang(ThreadContext context, IRubyObject[] args) {
573565
* @return angle IRubyObject in radians
574566
*/
575567
@JRubyMethod(name = "angle_between")
576-
577568
public IRubyObject angleBetween(ThreadContext context, IRubyObject other) {
578569
Vec2 vec = null;
579570
Ruby runtime = context.runtime;
@@ -591,7 +582,6 @@ public IRubyObject angleBetween(ThreadContext context, IRubyObject other) {
591582
* @return IRubyObject copy
592583
*/
593584
@JRubyMethod(name = {"copy", "dup"})
594-
595585
public IRubyObject copy(ThreadContext context) {
596586
Ruby runtime = context.runtime;
597587
return Vec2.rbNew(context, this.getMetaClass(), new IRubyObject[]{
@@ -605,7 +595,6 @@ public IRubyObject copy(ThreadContext context) {
605595
* @return IRubyObject array of float
606596
*/
607597
@JRubyMethod(name = "to_a")
608-
609598
public IRubyObject toArray(ThreadContext context) {
610599
Ruby runtime = context.runtime;
611600
return RubyArray.newArray(runtime, new IRubyObject[]{
@@ -621,7 +610,6 @@ public IRubyObject toArray(ThreadContext context) {
621610
* @param object IRubyObject vertex renderer
622611
*/
623612
@JRubyMethod(name = "to_vertex")
624-
625613
public void toVertex(ThreadContext context, IRubyObject object) {
626614
JRender renderer = (JRender) object.toJava(JRender.class);
627615
renderer.vertex(jx, jy);
@@ -635,7 +623,6 @@ public void toVertex(ThreadContext context, IRubyObject object) {
635623
* @param object IRubyObject vertex renderer
636624
*/
637625
@JRubyMethod(name = "to_curve_vertex")
638-
639626
public void toCurveVertex(ThreadContext context, IRubyObject object) {
640627
JRender renderer = (JRender) object.toJava(JRender.class);
641628
renderer.curveVertex(jx, jy);
@@ -648,7 +635,6 @@ public void toCurveVertex(ThreadContext context, IRubyObject object) {
648635
* @return IRubyObject to_s
649636
*/
650637
@JRubyMethod(name = {"to_s", "inspect"})
651-
652638
public IRubyObject to_s(ThreadContext context) {
653639
return context.runtime.newString(String.format("Vec2D(x = %4.4f, y = %4.4f)", jx, jy));
654640
}
@@ -716,7 +702,6 @@ public IRubyObject eql_p(ThreadContext context, IRubyObject other) {
716702
* @return result IRubyObject as boolean
717703
*/
718704
@JRubyMethod(name = "==", required = 1)
719-
720705
@Override
721706
public IRubyObject op_equal(ThreadContext context, IRubyObject other) {
722707
Ruby runtime = context.runtime;

0 commit comments

Comments
 (0)