processing 0.5.32 → 0.5.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -25,6 +25,14 @@ module Processing
25
25
  #
26
26
  TAU = PI * 2
27
27
 
28
+ # Processing mode for renderMode().
29
+ #
30
+ PROCESSING = :processing
31
+
32
+ # p5.js mode for renderMode().
33
+ #
34
+ P5JS = :p5js
35
+
28
36
  # RGBA format for createImage().
29
37
  #
30
38
  RGBA = :rgba
@@ -267,28 +275,42 @@ module Processing
267
275
 
268
276
  # @private
269
277
  def init__(image, painter)
270
- @drawing__ = false
271
- @colorMode__ = nil
272
- @hsbColor__ = false
273
- @colorMaxes__ = [1.0] * 4
274
- @angleMode__ = nil
275
- @angleScale__ = 1.0
276
- @rectMode__ = nil
277
- @ellipseMode__ = nil
278
- @imageMode__ = nil
279
- @shapeMode__ = nil
280
- @blendMode__ = nil
281
- @textAlignH__ = nil
282
- @textAlignV__ = nil
283
- @textFont__ = nil
284
- @tint__ = nil
285
- @filter__ = nil
286
- @pixels__ = nil
287
- @matrixStack__ = []
288
- @styleStack__ = []
278
+ @drawing__ = false
279
+ @renderMode__ = nil
280
+ @p5jsMode__ = false
281
+ @colorMode__ = nil
282
+ @hsbColor__ = false
283
+ @colorMaxes__ = [1.0] * 4
284
+ @angleMode__ = nil
285
+ @toRad__ = 1.0
286
+ @toDeg__ = 1.0
287
+ @fromRad__ = 1.0
288
+ @fromDeg__ = 1.0
289
+ @rectMode__ = nil
290
+ @ellipseMode__ = nil
291
+ @imageMode__ = nil
292
+ @shapeMode__ = nil
293
+ @blendMode__ = nil
294
+ @curveDetail__ = nil
295
+ @curveTightness__ = nil
296
+ @bezierDetail__ = nil
297
+ @textAlignH__ = nil
298
+ @textAlignV__ = nil
299
+ @textFont__ = nil
300
+ @tint__ = nil
301
+ @filter__ = nil
302
+ @pixels__ = nil
303
+ @random__ = nil
304
+ @nextGaussian__ = nil
305
+ @noiseSeed__ = nil
306
+ @noiseOctaves__ = nil
307
+ @noiseFallOff__ = nil
308
+ @matrixStack__ = []
309
+ @styleStack__ = []
289
310
 
290
311
  updateCanvas__ image, painter
291
312
 
313
+ renderMode PROCESSING
292
314
  colorMode RGB, 255
293
315
  angleMode RADIANS
294
316
  rectMode CORNER
@@ -303,10 +325,16 @@ module Processing
303
325
  textureMode IMAGE
304
326
  textureWrap CLAMP
305
327
 
306
- fill 255
307
- stroke 0
308
- strokeWeight 1
328
+ fill 255
329
+ stroke 0
330
+ strokeWeight 1
309
331
  noTint
332
+ curveDetail 20
333
+ curveTightness 0
334
+ bezierDetail 20
335
+ randomSeed Random.new_seed
336
+ noiseSeed Random.new_seed
337
+ noiseDetail 4, 0.5
310
338
  end
311
339
 
312
340
  # @private
@@ -322,6 +350,26 @@ module Processing
322
350
  @matrixStack__.clear
323
351
  @styleStack__.clear
324
352
  @drawing__ = true
353
+ setupMatrix__
354
+ end
355
+
356
+ # @private
357
+ def setupMatrix__()
358
+ w, h = width.to_f, height.to_f
359
+ x, y = w / 2.0, h / 2.0
360
+
361
+ fov, z = nil
362
+ if @p5jsMode__
363
+ z = 800
364
+ fov = degrees Math.atan(y / z) * 2.0
365
+ else
366
+ fov = 60
367
+ z = y / Math.tan(radians(fov) / 2.0)
368
+ end
369
+
370
+ @painter__.matrix =
371
+ Rays::Matrix.perspective(fov, w / h, z / 10.0, z * 10.0) *
372
+ Rays::Matrix.look_at(x, y, z, x, y, 0)
325
373
  end
326
374
 
327
375
  # @private
@@ -370,6 +418,20 @@ module Processing
370
418
  @painter__.pixel_density
371
419
  end
372
420
 
421
+ # Sets render mode.
422
+ #
423
+ # @param mode [PROCESSING, P5JS] compatible to Processing or p5.js
424
+ #
425
+ # @return [PROCESSING, P5JS] current mode
426
+ #
427
+ def renderMode(mode = nil)
428
+ if mode
429
+ @renderMode__ = mode
430
+ @p5jsMode__ = mode == P5JS
431
+ end
432
+ @renderMode__
433
+ end
434
+
373
435
  # Sets color mode and max color values.
374
436
  #
375
437
  # @overload colorMode(mode)
@@ -463,15 +525,48 @@ module Processing
463
525
  ((color >> 24) & 0xff) / 255.0 * @colorMaxes__[3]
464
526
  end
465
527
 
528
+ # Returns the hue value of the color.
529
+ #
530
+ # @param color [Numeric] color value
531
+ #
532
+ # @return [Numeric] the hue value
533
+ #
534
+ def hue(color)
535
+ h, = toRawColor__(color).to_hsv
536
+ h * (@hsbColor__ ? @colorMaxes__[0] : 1)
537
+ end
538
+
539
+ # Returns the saturation value of the color.
540
+ #
541
+ # @param color [Numeric] color value
542
+ #
543
+ # @return [Numeric] the saturation value
544
+ #
545
+ def saturation(color)
546
+ _, s, = toRawColor__(color).to_hsv
547
+ s * (@hsbColor__ ? @colorMaxes__[1] : 1)
548
+ end
549
+
550
+ # Returns the brightness value of the color.
551
+ #
552
+ # @param color [Numeric] color value
553
+ #
554
+ # @return [Numeric] the brightness value
555
+ #
556
+ def brightness(color)
557
+ _, _, b = toRawColor__(color).to_hsv
558
+ b * (@hsbColor__ ? @colorMaxes__[2] : 1)
559
+ end
560
+
466
561
  # @private
467
562
  private def toRGBA__(*args)
468
563
  a, b = args
469
564
  return parseColor__(a, b || alphaMax__) if a.kind_of?(String)
470
- toRaysColor__(*args).to_a
565
+ rawColor__(*args).to_a
471
566
  end
472
567
 
473
568
  # @private
474
- def toRaysColor__(*args)
569
+ def rawColor__(*args)
475
570
  a, b, c, d = args
476
571
  rgba = case args.size
477
572
  when 1, 2 then [a, a, a, b || alphaMax__]
@@ -496,6 +591,15 @@ module Processing
496
591
  @colorMaxes__[3]
497
592
  end
498
593
 
594
+ # @private
595
+ private def toRawColor__(color)
596
+ Rays::Color.new(
597
+ ((color >> 16) & 0xff) / 255.0,
598
+ ((color >> 8) & 0xff) / 255.0,
599
+ ( color & 0xff) / 255.0,
600
+ ((color >> 24) & 0xff) / 255.0)
601
+ end
602
+
499
603
  # Sets angle mode.
500
604
  #
501
605
  # @param mode [RADIANS, DEGREES] RADIANS or DEGREES
@@ -505,37 +609,34 @@ module Processing
505
609
  def angleMode(mode = nil)
506
610
  if mode != nil
507
611
  @angleMode__ = mode
508
- @angleScale__ =
612
+ @toRad__, @toDeg__, @fromRad__, @fromDeg__ =
509
613
  case mode.downcase.to_sym
510
- when RADIANS then RAD2DEG__
511
- when DEGREES then 1.0
614
+ when RADIANS then [1.0, RAD2DEG__, 1.0, DEG2RAD__]
615
+ when DEGREES then [DEG2RAD__, 1.0, RAD2DEG__, 1.0]
512
616
  else raise ArgumentError, "invalid angle mode: #{mode}"
513
617
  end
514
618
  end
515
619
  @angleMode__
516
620
  end
517
621
 
622
+ # @private
623
+ def toRadians__(angle)
624
+ angle * @toRad__
625
+ end
626
+
518
627
  # @private
519
628
  def toDegrees__(angle)
520
- angle * @angleScale__
629
+ angle * @toDeg__
521
630
  end
522
631
 
523
632
  # @private
524
633
  def fromRadians__(radians)
525
- case @angleMode__
526
- when RADIANS then radians
527
- when DEGREES then radians * RAD2DEG__
528
- else raise "invalid angle mode: #{mode}"
529
- end
634
+ radians * @fromRad__
530
635
  end
531
636
 
532
637
  # @private
533
638
  def fromDegrees__(degrees)
534
- case @angleMode__
535
- when RADIANS then degrees * DEG2RAD__
536
- when DEGREES then degrees
537
- else raise "invalid angle mode: #{mode}"
538
- end
639
+ degrees * @fromDeg__
539
640
  end
540
641
 
541
642
  # Sets rect mode. Default is CORNER.
@@ -723,6 +824,52 @@ module Processing
723
824
  nil
724
825
  end
725
826
 
827
+ # Sets the resolution at which curves display.
828
+ # The default value is 20 while the minimum value is 3.
829
+ #
830
+ # @param detail [Numeric] resolution of the curves
831
+ #
832
+ # @return [nil] nil
833
+ #
834
+ # @see https://processing.org/reference/curveDetail_.html
835
+ # @see https://p5js.org/reference/#/p5/curveDetail
836
+ #
837
+ def curveDetail(detail)
838
+ detail = 3 if detail < 3
839
+ @curveDetail__ = detail
840
+ nil
841
+ end
842
+
843
+ # Sets the quality of curve forms.
844
+ #
845
+ # @param tightness [Numeric] determines how the curve fits to the vertex points
846
+ #
847
+ # @return [nil] nil
848
+ #
849
+ # @see https://processing.org/reference/curveTightness_.html
850
+ # @see https://p5js.org/reference/#/p5/curveTightness
851
+ #
852
+ def curveTightness(tightness)
853
+ @curveTightness__ = tightness
854
+ nil
855
+ end
856
+
857
+ # Sets the resolution at which Bezier's curve is displayed.
858
+ # The default value is 20.
859
+ #
860
+ # @param detail [Numeric] resolution of the curves
861
+ #
862
+ # @return [nil] nil
863
+ #
864
+ # @see https://processing.org/reference/bezierDetail_.html
865
+ # @see https://p5js.org/reference/#/p5/bezierDetail
866
+ #
867
+ def bezierDetail(detail)
868
+ detail = 1 if detail < 1
869
+ @bezierDetail__ = detail
870
+ nil
871
+ end
872
+
726
873
  # Sets fill color for drawing images.
727
874
  #
728
875
  # @overload tint(rgb)
@@ -786,30 +933,32 @@ module Processing
786
933
  end
787
934
 
788
935
  # Sets text font.
789
- #
790
936
  # (Passing a font name as the first parameter is deprecated)
791
937
  #
938
+ # @overload textFont()
792
939
  # @overload textFont(font)
793
- # @overload textFont(name)
940
+ # @overload textFont(name) [DEPRECATED]
794
941
  # @overload textFont(font, size)
795
- # @overload textFont(name, size)
942
+ # @overload textFont(name, size) [DEPRECATED]
796
943
  #
797
944
  # @param font [Font] font
798
945
  # @param name [String] font name
799
946
  # @param size [Numeric] font size (max 256)
800
947
  #
801
- # @return [nil] nil
948
+ # @return [Font] current font
802
949
  #
803
- def textFont(font, size = nil)
804
- size = FONT_SIZE_MAX__ if size && size > FONT_SIZE_MAX__
805
- if font.nil? || font.kind_of?(String)
806
- font = createFont font, size
807
- elsif size
808
- font.setSize__ size
950
+ def textFont(font = nil, size = nil)
951
+ if font != nil || size != nil
952
+ size = FONT_SIZE_MAX__ if size && size > FONT_SIZE_MAX__
953
+ if font.nil? || font.kind_of?(String)
954
+ font = createFont font, size
955
+ elsif size
956
+ font.setSize__ size
957
+ end
958
+ @painter__.font = font.getInternal__
959
+ @textFont__ = font
809
960
  end
810
- @textFont__ = font
811
- @painter__.font = font.getInternal__
812
- nil
961
+ @textFont__
813
962
  end
814
963
 
815
964
  # Sets text size.
@@ -839,6 +988,20 @@ module Processing
839
988
  @textAlignV__ = vertical
840
989
  end
841
990
 
991
+ # Sets the spacing between lines of text in units of pixels.
992
+ #
993
+ # @overload textLeading()
994
+ # @overload textLeading(leading)
995
+ #
996
+ # @param leading [Numeric] the size in pixels for spacing between lines
997
+ #
998
+ # @return [Numeric] current spacing
999
+ #
1000
+ def textLeading(leading = nil)
1001
+ @painter__.line_height = leading if leading
1002
+ @painter__.line_height
1003
+ end
1004
+
842
1005
  def texture(image)
843
1006
  @painter__.texture image&.getInternal__
844
1007
  nil
@@ -961,7 +1124,7 @@ module Processing
961
1124
  #
962
1125
  def point(x, y)
963
1126
  assertDrawing__
964
- @painter__.line x, y, x, y
1127
+ @painter__.point x, y
965
1128
  nil
966
1129
  end
967
1130
 
@@ -1144,7 +1307,9 @@ module Processing
1144
1307
  #
1145
1308
  def curve(cx1, cy1, x1, y1, x2, y2, cx2, cy2)
1146
1309
  assertDrawing__
1310
+ @painter__.nsegment = @curveDetail__
1147
1311
  @painter__.curve cx1, cy1, x1, y1, x2, y2, cx2, cy2
1312
+ @painter__.nsegment = 0
1148
1313
  nil
1149
1314
  end
1150
1315
 
@@ -1165,7 +1330,9 @@ module Processing
1165
1330
  #
1166
1331
  def bezier(x1, y1, cx1, cy1, cx2, cy2, x2, y2)
1167
1332
  assertDrawing__
1333
+ @painter__.nsegment = @bezierDetail__
1168
1334
  @painter__.bezier x1, y1, cx1, cy1, cx2, cy2, x2, y2
1335
+ @painter__.nsegment = 0
1169
1336
  nil
1170
1337
  end
1171
1338
 
@@ -1478,9 +1645,16 @@ module Processing
1478
1645
  #
1479
1646
  # @return [nil] nil
1480
1647
  #
1481
- def updatePixels()
1482
- return unless @pixels__
1483
- getInternal__.pixels = @pixels__
1648
+ def updatePixels(&block)
1649
+ return if !block && !@pixels__
1650
+ if block
1651
+ loadPixels
1652
+ block.call pixels
1653
+ end
1654
+ getInternal__.tap do |img|
1655
+ img.pixels = @pixels__
1656
+ img.paint {} # update texture and set modifiied
1657
+ end
1484
1658
  @pixels__ = nil
1485
1659
  end
1486
1660
 
@@ -1548,6 +1722,42 @@ module Processing
1548
1722
  nil
1549
1723
  end
1550
1724
 
1725
+ def rotateX(angle)
1726
+ assertDrawing__
1727
+ @painter__.rotate toDegrees__(angle), 1, 0, 0
1728
+ nil
1729
+ end
1730
+
1731
+ def rotateY(angle)
1732
+ assertDrawing__
1733
+ @painter__.rotate toDegrees__(angle), 0, 1, 0
1734
+ nil
1735
+ end
1736
+
1737
+ def rotateZ(angle)
1738
+ assertDrawing__
1739
+ @painter__.rotate toDegrees__(angle), 0, 0, 1
1740
+ nil
1741
+ end
1742
+
1743
+ def shearX(angle)
1744
+ t = Math.tan toRadians__(angle)
1745
+ @painter__.matrix *= Rays::Matrix.new(
1746
+ 1, t, 0, 0,
1747
+ 0, 1, 0, 0,
1748
+ 0, 0, 1, 0,
1749
+ 0, 0, 0, 1)
1750
+ end
1751
+
1752
+ def shearY(angle)
1753
+ t = Math.tan toRadians__(angle)
1754
+ @painter__.matrix *= Rays::Matrix.new(
1755
+ 1, 0, 0, 0,
1756
+ t, 1, 0, 0,
1757
+ 0, 0, 1, 0,
1758
+ 0, 0, 0, 1)
1759
+ end
1760
+
1551
1761
  # Pushes the current transformation matrix to stack.
1552
1762
  #
1553
1763
  # @return [Object] result of the expression at the end of the block
@@ -1571,6 +1781,51 @@ module Processing
1571
1781
  nil
1572
1782
  end
1573
1783
 
1784
+ # Reset current transformation matrix with 2x3, or 4x4 matrix.
1785
+ #
1786
+ # @overload applyMatrix(array)
1787
+ # @overload applyMatrix(a, b, c, d, e, f)
1788
+ # @overload applyMatrix(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
1789
+ #
1790
+ # @param array [Array] 6 or 16 numbers which define the matrix
1791
+ # @param a [Numeric] number which defines the matrix
1792
+ # @param b [Numeric] number which defines the matrix
1793
+ # @param c [Numeric] number which defines the matrix
1794
+ # @param d [Numeric] number which defines the matrix
1795
+ # @param e [Numeric] number which defines the matrix
1796
+ # @param f [Numeric] number which defines the matrix
1797
+ # @param g [Numeric] number which defines the matrix
1798
+ # @param h [Numeric] number which defines the matrix
1799
+ # @param i [Numeric] number which defines the matrix
1800
+ # @param j [Numeric] number which defines the matrix
1801
+ # @param k [Numeric] number which defines the matrix
1802
+ # @param l [Numeric] number which defines the matrix
1803
+ # @param m [Numeric] number which defines the matrix
1804
+ # @param n [Numeric] number which defines the matrix
1805
+ # @param o [Numeric] number which defines the matrix
1806
+ # @param p [Numeric] number which defines the matrix
1807
+ #
1808
+ # @return [nil] nil
1809
+ #
1810
+ def applyMatrix(*args)
1811
+ assertDrawing__
1812
+ args = args.first if args.first.kind_of?(Array)
1813
+ if args.size == 6
1814
+ a, b, c, d, e, f = args
1815
+ args = [
1816
+ a, b, 0, 0,
1817
+ c, d, 0, 0,
1818
+ 0, 0, 1, 0,
1819
+ e, f, 0, 1
1820
+ ]
1821
+ end
1822
+ raise ArgumentError unless args.size == 16
1823
+ m = Rays::Matrix.new(*args)
1824
+ m.transpose! if @p5jsMode__
1825
+ @painter__.matrix *= m
1826
+ nil
1827
+ end
1828
+
1574
1829
  # Reset current transformation matrix with identity matrix.
1575
1830
  #
1576
1831
  # @return [nil] nil
@@ -1581,6 +1836,17 @@ module Processing
1581
1836
  nil
1582
1837
  end
1583
1838
 
1839
+ # Prints matrix elements to console.
1840
+ #
1841
+ # @return [nil] nil
1842
+ #
1843
+ def printMatrix()
1844
+ m = @painter__.matrix
1845
+ m.transpose! if @p5jsMode__
1846
+ print "%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n" % m.to_a
1847
+ nil
1848
+ end
1849
+
1584
1850
  # Save current style values to the style stack.
1585
1851
  #
1586
1852
  # @return [Object] result of the expression at the end of the block
@@ -1593,6 +1859,8 @@ module Processing
1593
1859
  @painter__.stroke_width,
1594
1860
  @painter__.stroke_cap,
1595
1861
  @painter__.stroke_join,
1862
+ @painter__.miter_limit,
1863
+ @painter__.line_height!,
1596
1864
  @painter__.clip,
1597
1865
  @painter__.blend_mode,
1598
1866
  @painter__.font,
@@ -1600,13 +1868,22 @@ module Processing
1600
1868
  @painter__.texcoord_mode,
1601
1869
  @painter__.texcoord_wrap,
1602
1870
  @painter__.shader,
1871
+ @colorMode__,
1603
1872
  @hsbColor__,
1604
1873
  @colorMaxes__,
1605
- @angleScale__,
1874
+ @angleMode__,
1875
+ @toRad__,
1876
+ @toDeg__,
1877
+ @fromRad__,
1878
+ @fromDeg__,
1606
1879
  @rectMode__,
1607
1880
  @ellipseMode__,
1608
1881
  @imageMode__,
1609
1882
  @shapeMode__,
1883
+ @blendMode__,
1884
+ @curveDetail__,
1885
+ @curveTightness__,
1886
+ @bezierDetail__,
1610
1887
  @textAlignH__,
1611
1888
  @textAlignV__,
1612
1889
  @textFont__,
@@ -1629,6 +1906,8 @@ module Processing
1629
1906
  @painter__.stroke_width,
1630
1907
  @painter__.stroke_cap,
1631
1908
  @painter__.stroke_join,
1909
+ @painter__.miter_limit,
1910
+ @painter__.line_height,
1632
1911
  @painter__.clip,
1633
1912
  @painter__.blend_mode,
1634
1913
  @painter__.font,
@@ -1636,13 +1915,22 @@ module Processing
1636
1915
  @painter__.texcoord_mode,
1637
1916
  @painter__.texcoord_wrap,
1638
1917
  @painter__.shader,
1918
+ @colorMode__,
1639
1919
  @hsbColor__,
1640
1920
  @colorMaxes__,
1641
- @angleScale__,
1921
+ @angleMode__,
1922
+ @toRad__,
1923
+ @toDeg__,
1924
+ @fromRad__,
1925
+ @fromDeg__,
1642
1926
  @rectMode__,
1643
1927
  @ellipseMode__,
1644
1928
  @imageMode__,
1645
1929
  @shapeMode__,
1930
+ @blendMode__,
1931
+ @curveDetail__,
1932
+ @curveTightness__,
1933
+ @bezierDetail__,
1646
1934
  @textAlignH__,
1647
1935
  @textAlignV__,
1648
1936
  @textFont__,
@@ -1678,10 +1966,10 @@ module Processing
1678
1966
  end
1679
1967
 
1680
1968
  # @private
1681
- def drawImage__(painter, *args, **states)
1969
+ def drawImage__(painter, *args, image__: getInternal__, **states)
1682
1970
  shader = painter.shader || @filter__&.getInternal__
1683
1971
  painter.push shader: shader, **states do |_|
1684
- painter.image getInternal__, *args
1972
+ painter.image image__, *args
1685
1973
  end
1686
1974
  end
1687
1975
 
@@ -2024,6 +2312,98 @@ module Processing
2024
2312
  Math.atan2 y, x
2025
2313
  end
2026
2314
 
2315
+ # Evaluates the curve at point t for points a, b, c, d.
2316
+ #
2317
+ # @param a [Numeric] coordinate of first control point
2318
+ # @param b [Numeric] coordinate of first point on the curve
2319
+ # @param c [Numeric] coordinate of second point on the curve
2320
+ # @param d [Numeric] coordinate of second control point
2321
+ # @param t [Numeric] value between 0.0 and 1.0
2322
+ #
2323
+ # @return [Numeric] interpolated value
2324
+ #
2325
+ # @see https://processing.org/reference/curvePoint_.html
2326
+ # @see https://p5js.org/reference/#/p5/curvePoint
2327
+ #
2328
+ def curvePoint(a, b, c, d, t)
2329
+ s = @curveTightness__
2330
+ t3 = t * t * t
2331
+ t2 = t * t
2332
+ f1 = ( s - 1.0) / 2.0 * t3 + ( 1.0 - s) * t2 + (s - 1.0) / 2.0 * t
2333
+ f2 = ( s + 3.0) / 2.0 * t3 + (-5.0 - s) / 2.0 * t2 + 1.0
2334
+ f3 = (-3.0 - s) / 2.0 * t3 + ( s + 2.0) * t2 + (1.0 - s) / 2.0 * t
2335
+ f4 = ( 1.0 - s) / 2.0 * t3 + ( s - 1.0) / 2.0 * t2
2336
+ a * f1 + b * f2 + c * f3 + d * f4
2337
+ end
2338
+
2339
+ # Calculates the tangent of a point on a curve.
2340
+ #
2341
+ # @param a [Numeric] coordinate of first control point
2342
+ # @param b [Numeric] coordinate of first point on the curve
2343
+ # @param c [Numeric] coordinate of second point on the curve
2344
+ # @param d [Numeric] coordinate of second control point
2345
+ # @param t [Numeric] value between 0.0 and 1.0
2346
+ #
2347
+ # @return [Numeric] tangent value
2348
+ #
2349
+ # @see https://processing.org/reference/curveTangent_.html
2350
+ # @see https://p5js.org/reference/#/p5/curveTangent
2351
+ #
2352
+ def curveTangent(a, b, c, d, t)
2353
+ s = @curveTightness__
2354
+ tt3 = t * t * 3.0
2355
+ t2 = t * 2.0
2356
+ f1 = ( s - 1.0) / 2.0 * tt3 + ( 1.0 - s) * t2 + (s - 1.0) / 2.0
2357
+ f2 = ( s + 3.0) / 2.0 * tt3 + (-5.0 - s) / 2.0 * t2
2358
+ f3 = (-3.0 - s) / 2.0 * tt3 + ( s + 2.0) * t2 + (1.0 - s) / 2.0
2359
+ f4 = ( 1.0 - s) / 2.0 * tt3 + ( s - 1.0) / 2.0 * t2
2360
+ a * f1 + b * f2 + c * f3 + d * f4
2361
+ end
2362
+
2363
+ # Evaluates the Bezier at point t for points a, b, c, d.
2364
+ #
2365
+ # @param a [Numeric] coordinate of first point on the curve
2366
+ # @param b [Numeric] coordinate of first control point
2367
+ # @param c [Numeric] coordinate of second control point
2368
+ # @param d [Numeric] coordinate of second point on the curve
2369
+ # @param t [Numeric] value between 0.0 and 1.0
2370
+ #
2371
+ # @return [Numeric] interpolated value
2372
+ #
2373
+ # @see https://processing.org/reference/bezierPoint_.html
2374
+ # @see https://p5js.org/reference/#/p5/bezierPoint
2375
+ #
2376
+ def bezierPoint(a, b, c, d, t)
2377
+ tt = 1.0 - t
2378
+ tt ** 3.0 * a +
2379
+ tt ** 2.0 * b * 3.0 * t +
2380
+ t ** 2.0 * c * 3.0 * tt +
2381
+ t ** 3.0 * d
2382
+ end
2383
+
2384
+ # Calculates the tangent of a point on a Bezier curve.
2385
+ #
2386
+ # @param a [Numeric] coordinate of first point on the curve
2387
+ # @param b [Numeric] coordinate of first control point
2388
+ # @param c [Numeric] coordinate of second control point
2389
+ # @param d [Numeric] coordinate of second point on the curve
2390
+ # @param t [Numeric] value between 0.0 and 1.0
2391
+ #
2392
+ # @return [Numeric] tangent value
2393
+ #
2394
+ # @see https://processing.org/reference/bezierTangent_.html
2395
+ # @see https://p5js.org/reference/#/p5/bezierTangent
2396
+ #
2397
+ def bezierTangent(a, b, c, d, t)
2398
+ tt = 1.0 - t
2399
+ 3.0 * d * t ** 2.0 -
2400
+ 3.0 * c * t ** 2.0 +
2401
+ 6.0 * c * tt * t -
2402
+ 6.0 * b * tt * t +
2403
+ 3.0 * b * tt ** 2.0 -
2404
+ 3.0 * a * tt ** 2.0
2405
+ end
2406
+
2027
2407
  # Returns the perlin noise value.
2028
2408
  #
2029
2409
  # @overload noise(x)
@@ -2036,13 +2416,52 @@ module Processing
2036
2416
  #
2037
2417
  # @return [Numeric] noise value (0.0..1.0)
2038
2418
  #
2419
+ # @see https://processing.org/reference/noise_.html
2420
+ # @see https://p5js.org/reference/#/p5/noise
2421
+ #
2039
2422
  def noise(x, y = 0, z = 0)
2040
- Rays.perlin(x, y, z) / 2.0 + 0.5
2423
+ seed, falloff = @noiseSeed__, @noiseFallOff__
2424
+ amp = 0.5
2425
+ @noiseOctaves__.times.reduce(0) do |sum|
2426
+ value = (Rays.perlin(x, y, z, seed) / 2.0 + 0.5) * amp
2427
+ x *= 2
2428
+ y *= 2
2429
+ z *= 2
2430
+ amp *= falloff
2431
+ sum + value
2432
+ end
2433
+ end
2434
+
2435
+ # Sets the seed value for noise()
2436
+ #
2437
+ # @param seed [Numeric] seed value
2438
+ #
2439
+ # @return [nil] nil
2440
+ #
2441
+ # @see https://processing.org/reference/noiseSeed_.html
2442
+ # @see https://p5js.org/reference/#/p5/noiseSeed
2443
+ #
2444
+ def noiseSeed(seed)
2445
+ @noiseSeed__ = Random.new(seed).rand 0.0..1.0
2446
+ end
2447
+
2448
+ # Adjusts the character and level of detail produced by the Perlin noise function.
2449
+ #
2450
+ # @param lod [Numeric] number of octaves to be used by the noise
2451
+ # @param falloff [Numeric] falloff factor for each octave
2452
+ #
2453
+ # @return [nil] nil
2454
+ #
2455
+ # @see https://processing.org/reference/noiseDetail_.html
2456
+ # @see https://p5js.org/reference/#/p5/noiseDetail
2457
+ #
2458
+ def noiseDetail(lod, falloff = nil)
2459
+ @noiseOctaves__ = lod if lod && lod > 0
2460
+ @noiseFallOff__ = falloff if falloff && falloff > 0
2041
2461
  end
2042
2462
 
2043
2463
  # Returns a random number in range low...high
2044
2464
  #
2045
- # @overload random()
2046
2465
  # @overload random(high)
2047
2466
  # @overload random(low, high)
2048
2467
  # @overload random(choices)
@@ -2053,10 +2472,60 @@ module Processing
2053
2472
  #
2054
2473
  # @return [Float] random number
2055
2474
  #
2475
+ # @see https://processing.org/reference/random_.html
2476
+ # @see https://p5js.org/reference/#/p5/random
2477
+ #
2056
2478
  def random(*args)
2057
- return args.first.sample if args.first.kind_of? Array
2058
- high, low = args.reverse
2059
- rand (low || 0).to_f...(high || 1).to_f
2479
+ if args.first.kind_of? Array
2480
+ a = args.first
2481
+ a.empty? ? nil : a[@random__.rand a.size]
2482
+ else
2483
+ high, low = args.reverse
2484
+ @random__.rand (low || 0).to_f...(high || 1).to_f
2485
+ end
2486
+ end
2487
+
2488
+ # Sets the seed value for random()
2489
+ #
2490
+ # @param seed [Numeric] seed value
2491
+ #
2492
+ # @return [nil] nil
2493
+ #
2494
+ # @see https://processing.org/reference/randomSeed_.html
2495
+ # @see https://p5js.org/reference/#/p5/randomSeed
2496
+ #
2497
+ def randomSeed(seed)
2498
+ @random__ = Random.new seed
2499
+ @nextGaussian__ = nil
2500
+ end
2501
+
2502
+ # Returns a random number fitting a Gaussian, or normal, distribution.
2503
+ #
2504
+ # @param mean [Numeric] mean
2505
+ # @param sd [Numeric] standard deviation
2506
+ #
2507
+ # @return [Float] random number
2508
+ #
2509
+ # @see https://processing.org/reference/randomGaussian_.html
2510
+ # @see https://p5js.org/reference/#/p5/randomGaussian
2511
+ #
2512
+ def randomGaussian(mean = 0, sd = 1)
2513
+ value =
2514
+ if @nextGaussian__
2515
+ x, @nextGaussian__ = @nextGaussian__, nil
2516
+ x
2517
+ else
2518
+ a, b, w = 0, 0, 1
2519
+ until w < 1
2520
+ a = random(2) - 1
2521
+ b = random(2) - 1
2522
+ w = a ** 2 + b ** 2
2523
+ end
2524
+ w = Math.sqrt(-2 * Math.log(w) / w)
2525
+ @randomGaussian__ = a * w
2526
+ b * w
2527
+ end
2528
+ value * sd + mean
2060
2529
  end
2061
2530
 
2062
2531
  # Creates a new vector object.
@@ -2235,7 +2704,7 @@ module Processing
2235
2704
  raise "unsupported font type -- '#{ext}'" unless ext =~ /^\.?(ttf|otf)$/i
2236
2705
 
2237
2706
  filename = httpGet__ filename, ext if filename =~ %r|^https?://|
2238
- Font.new Rays::Font.load p filename
2707
+ Font.new Rays::Font.load filename
2239
2708
  end
2240
2709
 
2241
2710
  # Loads image.
@@ -2299,15 +2768,10 @@ module Processing
2299
2768
  path = path.sub_ext ext
2300
2769
 
2301
2770
  unless path.file?
2302
- URI.open uri do |input|
2303
- input.set_encoding nil# disable default_internal
2771
+ Net::HTTP.get_response URI.parse(uri) do |res|
2772
+ res.value # raise an error unless successful
2304
2773
  tmpdir.mkdir unless tmpdir.directory?
2305
- path.open('w') do |output|
2306
- output.set_encoding Encoding::ASCII_8BIT
2307
- while buf = input.read(2 ** 16)
2308
- output.write buf
2309
- end
2310
- end
2774
+ path.open('wb') {|file| res.read_body {|body| file.write body}}
2311
2775
  end
2312
2776
  end
2313
2777
  path.to_s