wicket 0.0.2 → 0.1.0

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.
@@ -1,36 +1,51 @@
1
1
  module Wicket
2
2
  class SVGPath
3
- attr_reader :text
4
- def initialize(text)
3
+ attr_reader :text, :subpaths
4
+ def initialize(text,opts={})
5
5
  @text = text
6
+ @opts = Wicket.configuration.merge(opts)
6
7
  @subpaths = []
7
8
  parse
8
9
  end
9
10
 
10
- def to_polygon
11
- poly = @subpaths.first.to_polygon
11
+ def to_polygon(opts={})
12
+ poly = @subpaths.first.to_polygon(opts)
12
13
  "POLYGON#{poly}"
13
14
  end
14
15
 
15
- def to_multipolygon
16
- polys = @subpaths.map(&:to_polygon).join(",")
16
+ def to_multipolygon(opts={})
17
+ polys = @subpaths.map{|s| s.to_polygon(opts) }.join(",")
17
18
  "MULTIPOLYGON(#{polys})"
18
19
  end
19
20
 
21
+ def to_svg(opts={},style="fill:none;stroke:lawngreen")
22
+ o = @opts.merge(opts)
23
+ paths = @subpaths.map{|s| s.to_svg(o) }.join(" ")
24
+ <<-SVG
25
+ <svg>
26
+ <path d="#{@text}" style="fill: slateblue; opacity:0.2"/>
27
+ <path d="#{paths}" style="#{style}" stroke-weight="2"/>
28
+ </svg>
29
+ SVG
30
+ end
31
+
20
32
  private
21
33
 
22
34
  def parse
23
35
  commands = @text.scan(/(?:([MmLlHhVvQqCcTtSsAaZz])([\d\.\,\-\s]+)*)/)
24
- commands.each_with_index.inject(new_subpath) do |subpath,((code,arg_string),index)|
36
+ commands.inject(new_subpath) do |subpath,(code,arg_string)|
37
+ subpath = new_subpath if subpath.closed?
25
38
  # pass the code and arguments for parsing into individual commands and add them to the subpath
26
- subpath.add_command( *Command.from_code(code,arg_string,subpath) )
27
- # if the path closes, provision a new subpath for future commands unless done
28
- (subpath.closed? && (index + 1) < commands.length) ? new_subpath : subpath
39
+ subpath.add_command( *Command.from_code(code,arg_string,subpath,@opts) )
29
40
  end
30
41
  end
31
42
 
32
43
  def new_subpath
33
44
  Subpath.new.tap {|s| @subpaths << s }
34
45
  end
46
+
47
+ def default_opts
48
+ Wicket.configuration.to_h
49
+ end
35
50
  end
36
51
  end
@@ -0,0 +1,60 @@
1
+ module Wicket
2
+ module Utilities
3
+ class << self
4
+ def radians_tolerance(opts={})
5
+ t = opts[:min_angle]
6
+ case opts[:min_angle_unit] || determine_tolerance(t)
7
+ when nil,:radians
8
+ check_range(Math::PI,t)
9
+ t
10
+ when :degrees
11
+ check_range(180,t)
12
+ (t / 180.0) * Math::PI
13
+ when :percentage
14
+ check_range(100,t)
15
+ (t / 100.0) * Math::PI
16
+ when :decimal_percentage
17
+ check_range(1,t)
18
+ t * Math::PI
19
+ end
20
+ end
21
+
22
+ def format(n,opts={})
23
+ s = scale(opts)
24
+ if s == 0
25
+ n.to_i.to_s
26
+ else
27
+ n.round(s).to_s("F")
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def determine_tolerance(t)
34
+ if t > 0 && t < 1
35
+ :decimal_percentage
36
+ elsif t >= 1 && t < Math::PI
37
+ :radians
38
+ elsif t >= Math::PI && t < 100
39
+ :percentage
40
+ elsif t >= 100 && t < 180
41
+ :degrees
42
+ else
43
+ raise_error(0,180)
44
+ end
45
+ end
46
+
47
+ def check_range(upper,val)
48
+ raise_error(0,upper) unless val < upper
49
+ end
50
+
51
+ def raise_error(lower,upper)
52
+ raise ArgumentError.new("Tolerance must be greater than #{lower} and less than #{upper}")
53
+ end
54
+
55
+ def scale(o={})
56
+ o[:scale] || o[:_scale]
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,3 +1,3 @@
1
1
  module Wicket
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ module Wicket
4
+ describe Coordinate do
5
+ let(:coord){ Coordinate.new(3,4) }
6
+ let(:remote){ Coordinate.new(0,0) }
7
+
8
+ it "calculates distance" do
9
+ expect(coord.distance_to(remote)).to eq(5)
10
+ end
11
+
12
+ it "absolutizes" do
13
+ ab = coord.absolutize(2,-4)
14
+ expect(ab.x).to eq(5)
15
+ expect(ab.y).to eq(0)
16
+ end
17
+
18
+ it "relativizes" do
19
+ expect(coord.relativize(remote)).to eq([-3,-4])
20
+ end
21
+
22
+ it "reflects" do
23
+ reflection = coord.reflect(remote)
24
+ expect(reflection.x).to eq(6)
25
+ expect(reflection.y).to eq(8)
26
+ end
27
+ end
28
+ end
@@ -1,126 +1,45 @@
1
1
  require 'spec_helper'
2
+ require 'yaml'
2
3
 
3
4
  module Wicket
4
5
  describe SVGPath do
5
- let(:path){ SVGPath.new("M10 10 20 20") }
6
6
 
7
- it "knows its text" do
8
- expect(path.text).to eq("M10 10 20 20")
9
- end
10
-
11
- context "absolute h shortcuts" do
12
- let(:path){ SVGPath.new("M10 10H20l10 10H10z") }
13
- it "parses to polygon" do
14
- expect(path.to_polygon).to eq("POLYGON((10.0 -10.0,20.0 -10.0,30.0 -20.0,10.0 -20.0,10.0 -10.0))")
15
- end
16
-
17
- it "parses to a multipolygon" do
18
- expect(path.to_multipolygon).to eq("MULTIPOLYGON(((10.0 -10.0,20.0 -10.0,30.0 -20.0,10.0 -20.0,10.0 -10.0)))")
19
- end
20
- end
21
-
22
- context "relative h shortcuts" do
23
- let(:path){ SVGPath.new("M10 10h20h10l10 10h-10z") }
24
- it "parses to polygon" do
25
- expect(path.to_polygon).to eq("POLYGON((10.0 -10.0,30.0 -10.0,40.0 -10.0,50.0 -20.0,40.0 -20.0,10.0 -10.0))")
26
- end
27
-
28
- it "parses to a multipolygon" do
29
- expect(path.to_multipolygon).to eq("MULTIPOLYGON(((10.0 -10.0,30.0 -10.0,40.0 -10.0,50.0 -20.0,40.0 -20.0,10.0 -10.0)))")
30
- end
31
- end
32
-
33
- context "absolute h shortcuts" do
34
- let(:path){ SVGPath.new("M10 10l20 20V50V80z") }
35
- it "parses to polygon" do
36
- expect(path.to_polygon).to eq("POLYGON((10.0 -10.0,30.0 -30.0,30.0 -50.0,30.0 -80.0,10.0 -10.0))")
37
- end
38
-
39
- it "parses to a multipolygon" do
40
- expect(path.to_multipolygon).to eq("MULTIPOLYGON(((10.0 -10.0,30.0 -30.0,30.0 -50.0,30.0 -80.0,10.0 -10.0)))")
41
- end
42
- end
43
-
44
- context "relative h shortcuts" do
45
- let(:path){ SVGPath.new("M10 10h20h10l10 10h-10z") }
46
- it "parses to polygon" do
47
- expect(path.to_polygon).to eq("POLYGON((10.0 -10.0,30.0 -10.0,40.0 -10.0,50.0 -20.0,40.0 -20.0,10.0 -10.0))")
48
- end
49
-
50
- it "parses to a multipolygon" do
51
- expect(path.to_multipolygon).to eq("MULTIPOLYGON(((10.0 -10.0,30.0 -10.0,40.0 -10.0,50.0 -20.0,40.0 -20.0,10.0 -10.0)))")
52
- end
53
- end
54
-
55
- context "single subpath, manually closed, no explicit commands" do
56
- let(:path){ SVGPath.new("M197.5977 356.0957 227.0786 325.3271 229.667 328.4067 200.8188 358.5156 197.5977 356.0957") }
7
+ # examples from test_cases.yml
8
+ YAML.load(File.open("spec/test_cases.yml","r")).each do |title,data|
9
+ wkts = data["wkt"].map{|w| "((#{w}))" }
10
+ context(title) do
11
+ let(:path){ SVGPath.new(data["path"]) }
12
+ it "parses to polygon" do
13
+ expect(path.to_polygon(:min_angle => 165)).to eq("POLYGON#{wkts.first}")
14
+ end
57
15
 
58
- it "parses to polygon" do
59
- expect(path.to_polygon).to eq("POLYGON((197.5977 -356.0957,227.0786 -325.3271,229.667 -328.4067,200.8188 -358.5156,197.5977 -356.0957))")
60
- end
61
-
62
- it "parses to a multipolygon" do
63
- expect(path.to_multipolygon).to eq("MULTIPOLYGON(((197.5977 -356.0957,227.0786 -325.3271,229.667 -328.4067,200.8188 -358.5156,197.5977 -356.0957)))")
64
- end
65
- end
66
-
67
- context "single subpath, z closed, no explicit commands" do
68
- let(:path){ SVGPath.new("M227.1177 371.5405 247.7852 349.9634 250.373 353.0425 230.2959 374.0044 z") }
69
-
70
- it "parses to polygon" do
71
- expect(path.to_polygon).to eq("POLYGON((227.1177 -371.5405,247.7852 -349.9634,250.373 -353.0425,230.2959 -374.0044,227.1177 -371.5405))")
72
- end
73
-
74
- it "parses to a multipolygon" do
75
- expect(path.to_multipolygon).to eq("MULTIPOLYGON(((227.1177 -371.5405,247.7852 -349.9634,250.373 -353.0425,230.2959 -374.0044,227.1177 -371.5405)))")
76
- end
77
- end
78
-
79
-
80
- context "single subpath, z closed, no explicit commands" do
81
- let(:path){ SVGPath.new("M227.1177 371.5405 247.7852 349.9634 250.373 353.0425 230.2959 374.0044 z") }
82
-
83
- it "parses to polygon" do
84
- expect(path.to_polygon).to eq("POLYGON((227.1177 -371.5405,247.7852 -349.9634,250.373 -353.0425,230.2959 -374.0044,227.1177 -371.5405))")
85
- end
86
-
87
- it "parses to a multipolygon" do
88
- expect(path.to_multipolygon).to eq("MULTIPOLYGON(((227.1177 -371.5405,247.7852 -349.9634,250.373 -353.0425,230.2959 -374.0044,227.1177 -371.5405)))")
16
+ it "parses to a multipolygon" do
17
+ expect(path.to_multipolygon(:min_angle => 165)).to eq("MULTIPOLYGON(#{wkts.join(",")})")
18
+ end
89
19
  end
90
20
  end
91
21
 
92
- context "single subpath, z closed, relative and absolute commands" do
93
- let(:path){ SVGPath.new("M722.3984,688.502L710,693.5693l-1.8115-3.5811l12.3096-5.0313L732.3984,688.502z") }
94
-
95
- it "parses to polygon" do
96
- expect(path.to_polygon).to eq("POLYGON((722.3984 -688.502,710.0 -693.5693,708.1885 -689.9882,720.4981 -684.9569,732.3984 -688.502,722.3984 -688.502))")
97
- end
98
-
99
- it "parses to a multipolygon" do
100
- expect(path.to_multipolygon).to eq("MULTIPOLYGON(((722.3984 -688.502,710.0 -693.5693,708.1885 -689.9882,720.4981 -684.9569,732.3984 -688.502,722.3984 -688.502)))")
101
- end
22
+ it "knows its text" do
23
+ path = SVGPath.new("M10 10 20 20")
24
+ expect(path.text).to eq("M10 10 20 20")
102
25
  end
103
26
 
104
- context "two subpaths, z closed, no explicit commands" do
105
- let(:path){ SVGPath.new("M227.1177 371.5405 247.7852 349.9634 250.373 353.0425 230.2959 374.0044 z M197.5977 356.0957 227.0786 325.3271 229.667 328.4067 200.8188 358.5156 197.5977 356.0957") }
27
+ context "curved paths" do
28
+ let(:path){ SVGPath.new("M0 0,C0 200,200 200,200 0z") }
29
+ let(:wkt){ path.to_polygon(:min_angle => 160) }
106
30
 
107
- it "parses the first subpath to polygon" do
108
- expect(path.to_polygon).to eq("POLYGON((227.1177 -371.5405,247.7852 -349.9634,250.373 -353.0425,230.2959 -374.0044,227.1177 -371.5405))")
31
+ it "contains the vertices" do
32
+ ["0 0","200 0"].each do |vertex|
33
+ expect(path.to_multipolygon).to include(vertex)
34
+ end
109
35
  end
110
36
 
111
- it "parses both to a multipolygon" do
112
- expect(path.to_multipolygon).to eq("MULTIPOLYGON(((227.1177 -371.5405,247.7852 -349.9634,250.373 -353.0425,230.2959 -374.0044,227.1177 -371.5405)),((197.5977 -356.0957,227.0786 -325.3271,229.667 -328.4067,200.8188 -358.5156,197.5977 -356.0957)))")
113
- end
114
- end
115
-
116
- context "the kitchen sink" do
117
- let(:path){ SVGPath.new("M293.9214,533.9287l-6.3857-18.1475l3.9316-0.8857l6.0811,17.29L293.9214,533.9287z M287.5356,515.7813V496.5h3.9316v18.3955 L287.5356,515.7813z") }
118
- it "parses the first subpath to polygon" do
119
- expect(path.to_polygon).to eq("POLYGON((293.9214 -533.9287,287.5357 -515.7812,291.4673 -514.8955,297.5484 -532.1855,293.9214 -533.9287,293.9214 -533.9287))")
37
+ it "allows you to make a lower resolution curve" do
38
+ expect(path.to_polygon(:min_angle => 150).length).to be < wkt.length
120
39
  end
121
40
 
122
- it "parses both to a multipolygon" do
123
- expect(path.to_multipolygon).to eq("MULTIPOLYGON(((293.9214 -533.9287,287.5357 -515.7812,291.4673 -514.8955,297.5484 -532.1855,293.9214 -533.9287,293.9214 -533.9287)),((287.5356 -515.7813,287.5356 -496.5,291.4672 -496.5,291.4672 -514.8955,287.5356 -515.7813,287.5356 -515.7813)))")
41
+ it "allows you to make a higher resolution curve" do
42
+ expect(path.to_polygon(:min_angle => 175).length).to be > wkt.length
124
43
  end
125
44
  end
126
45
  end
@@ -0,0 +1,91 @@
1
+ "absolute h":
2
+ path: 'M10 10H20l10 10H10z'
3
+ wkt:
4
+ - '10 -10,20 -10,30 -20,10 -20,10 -10'
5
+
6
+ "relative h":
7
+ path: "M10 10h20h10l10 10h-10z"
8
+ wkt:
9
+ - '10 -10,30 -10,40 -10,50 -20,40 -20,10 -10'
10
+
11
+ "absolute v":
12
+ path: 'M10 10l20 20V50V80z'
13
+ wkt:
14
+ - '10 -10,30 -30,30 -50,30 -80,10 -10'
15
+
16
+ "relative v":
17
+ path: "M10 10L20 10v10L10 20z"
18
+ wkt:
19
+ - '10 -10,20 -10,20 -20,10 -20,10 -10'
20
+
21
+ "absolute c":
22
+ path: 'M0 0,C0 200,200 200,200 0z'
23
+ wkt:
24
+ - '0 0,2 -35,8 -65,31 -112,46 -128,63 -140,81 -147,100 -150,118 -147,136 -140,153 -128,168 -112,181 -91,191 -65,200 0,0 0'
25
+
26
+ "relative c":
27
+ path: 'M100 100,c0 200,200 200,200 0z'
28
+ wkt:
29
+ - '100 -100,102 -135,108 -165,131 -212,146 -228,163 -240,181 -247,200 -250,218 -247,236 -240,253 -228,268 -212,281 -191,291 -165,300 -100,100 -100'
30
+
31
+ "absolute s":
32
+ path: 'M0 0,C0 200,200 200,200 0 S 400,-200 400 0 v400h-400z'
33
+ wkt:
34
+ - '0 0,2 -35,8 -65,31 -112,46 -128,63 -140,81 -147,100 -150,118 -147,136 -140,153 -128,168 -112,181 -91,191 -65,200 0,202 35,208 65,231 112,246 128,263 140,281 147,300 150,318 147,336 140,353 128,368 112,381 91,391 65,400 0,400 -400,0 -400,0 0'
35
+
36
+ "relative s":
37
+ path: 'M100 100,c0 200,200 200,200 0 s 200,-200 200 0 v400h-400z'
38
+ wkt:
39
+ - '100 -100,102 -135,108 -165,131 -212,146 -228,163 -240,181 -247,200 -250,218 -247,236 -240,253 -228,268 -212,281 -191,291 -165,300 -100,302 -64,308 -34,331 12,346 28,363 40,381 47,400 50,418 47,436 40,453 28,468 12,481 -8,491 -34,500 -100,500 -500,100 -500,100 -100'
40
+
41
+ "absolute q":
42
+ path: 'M10 10,Q110 210 210 10z'
43
+ wkt:
44
+ - '10 -10,35 -53,60 -85,72 -95,85 -103,97 -108,110 -110,122 -108,135 -103,147 -95,160 -85,185 -53,210 -10,10 -10'
45
+
46
+ "relative q":
47
+ path: 'M100 100,q100 100 200 0z'
48
+ wkt:
49
+ - '100 -100,125 -121,150 -137,175 -146,200 -150,225 -146,250 -137,275 -121,300 -100,100 -100'
50
+
51
+ "absolute t":
52
+ path: 'M100 100,q100 100 200 0T500 100v200h-400z'
53
+ wkt:
54
+ - '100 -100,125 -121,150 -137,175 -146,200 -150,225 -146,250 -137,275 -121,300 -100,325 -78,350 -62,375 -53,400 -50,425 -53,450 -62,475 -78,500 -100,500 -300,100 -300,100 -100'
55
+
56
+ "relative t":
57
+ path: 'M100 100,q100 100 200 0t100 100v200h-300z'
58
+ wkt:
59
+ - '100 -100,125 -121,150 -137,175 -146,200 -150,225 -146,250 -137,275 -121,300 -100,323 -79,343 -68,352 -66,360 -67,364 -68,368 -69,375 -75,380 -82,385 -92,393 -118,400 -200,400 -400,100 -400,100 -100'
60
+
61
+ "only M":
62
+ path: 'M197.5977 356.0957 227.0786 325.3271 229.667 328.4067 200.8188 358.5156 197.5977 356.0957'
63
+ wkt:
64
+ - '197.5977 -356.0957,227.0786 -325.3271,229.667 -328.4067,200.8188 -358.5156,197.5977 -356.0957'
65
+
66
+ "M with z":
67
+ path: 'M227.1177 371.5405 247.7852 349.9634 250.373 353.0425 230.2959 374.0044 z'
68
+ wkt:
69
+ - '227.1177 -371.5405,247.7852 -349.9634,250.373 -353.0425,230.2959 -374.0044,227.1177 -371.5405'
70
+
71
+ "L and l":
72
+ path: 'M722.3984,688.502L710,693.5693l-1.8115-3.5811l12.3096-5.0313L732.3984,688.502z'
73
+ wkt:
74
+ - '722.3984 -688.502,710.0 -693.5693,708.1885 -689.9882,720.4981 -684.9569,732.3984 -688.502,722.3984 -688.502'
75
+
76
+ "Two subpaths":
77
+ path: 'M227.1177 371.5405 247.7852 349.9634 250.373 353.0425 230.2959 374.0044 z M197.5977 356.0957 227.0786 325.3271 229.667 328.4067 200.8188 358.5156 197.5977 356.0957'
78
+ wkt:
79
+ - '227.1177 -371.5405,247.7852 -349.9634,250.373 -353.0425,230.2959 -374.0044,227.1177 -371.5405'
80
+ - '197.5977 -356.0957,227.0786 -325.3271,229.667 -328.4067,200.8188 -358.5156,197.5977 -356.0957'
81
+
82
+ "complex linear":
83
+ path: 'M293.9214,533.9287l-6.3857-18.1475l3.9316-0.8857l6.0811,17.29L293.9214,533.9287z M287.5356,515.7813V496.5h3.9316v18.3955 L287.5356,515.7813z'
84
+ wkt:
85
+ - '293.9214 -533.9287,287.5357 -515.7812,291.4673 -514.8955,297.5484 -532.1855,293.9214 -533.9287,293.9214 -533.9287'
86
+ - '287.5356 -515.7813,287.5356 -496.5,291.4672 -496.5,291.4672 -514.8955,287.5356 -515.7813,287.5356 -515.7813'
87
+
88
+ "complex curved":
89
+ path: 'M889.9277,494.0005c0,12.1528-0.8057,23.9614-2.3066,35.4341h10.1104 c1.4434-11.4824,2.1963-23.2969,2.1963-35.4341s-0.7529-23.9526-2.1963-35.4351h-10.1104 C889.1221,470.0381,889.9277,481.8467,889.9277,494.0005z'
90
+ wkt:
91
+ - '889.9277 -494.0005,889.3372 -511.9726,887.6211 -529.4346,897.7315 -529.4346,899.3709 -511.9631,899.9278 -494.0005,899.3709 -476.0374,897.7315 -458.5654,887.6211 -458.5654,889.3373 -476.0275,889.9277 -494.0005,889.9277 -494.0005'
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ module Wicket
4
+ describe Utilities do
5
+ describe "#radians_tolerance" do
6
+ it "raises for 0" do
7
+ expect{Utilities.radians_tolerance(:min_angle => 0)}.to raise_error
8
+
9
+ end
10
+ context "radians" do
11
+ it "does not convert when implicitly radians" do
12
+ t = Utilities.radians_tolerance(:min_angle => 3)
13
+ expect(t).to eq(3)
14
+ end
15
+
16
+ it "does not convert if explicitly set as radians" do
17
+ t = Utilities.radians_tolerance(:min_angle => 3.1, :min_angle_unit => :radians)
18
+ expect(t).to eq(3.1)
19
+ end
20
+
21
+ it "does not convert a radian explcitly set but out of range" do
22
+ t = Utilities.radians_tolerance(:min_angle => 0.9, :min_angle_unit => :radians)
23
+ expect(t).to eq(0.9)
24
+ end
25
+
26
+ it "raises if over pi" do
27
+ expect{Utilities.radians_tolerance(:min_angle => 4, :min_angle_unit => :radians)}.to raise_error
28
+ end
29
+ end
30
+
31
+ context "degrees" do
32
+ it "converts degrees explicitly" do
33
+ t = Utilities.radians_tolerance(:min_angle => 170, :min_angle_unit => :degrees)
34
+ expect(t).to be_within(0.00000001).of(2.96705973)
35
+ end
36
+
37
+ it "converts degrees implicitly" do
38
+ t = Utilities.radians_tolerance(:min_angle => 175)
39
+ expect(t).to be_within(0.00000001).of(3.05432619)
40
+ end
41
+
42
+ it "converts degrees out of range when explicit" do
43
+ t = Utilities.radians_tolerance(:min_angle => 95, :min_angle_unit => :degrees)
44
+ expect(t).to be_within(0.00000001).of(1.65806279)
45
+ end
46
+
47
+ it "raises if over 180" do
48
+ expect{Utilities.radians_tolerance(:min_angle => 190, :min_angle_unit => :degrees)}.to raise_error
49
+ end
50
+ end
51
+
52
+ context "percentage" do
53
+ it "converts percentages explicitly" do
54
+ t = Utilities.radians_tolerance(:min_angle => 95, :min_angle_unit => :percentage)
55
+ expect(t).to be_within(0.00000001).of(2.98451302)
56
+ end
57
+
58
+ it "converts percentages implicitly" do
59
+ t = Utilities.radians_tolerance(:min_angle => 90)
60
+ expect(t).to be_within(0.00000001).of(2.82743339)
61
+ end
62
+
63
+ it "converts percentages out of range when explicit" do
64
+ t = Utilities.radians_tolerance(:min_angle => 2, :min_angle_unit => :percentage)
65
+ expect(t).to be_within(0.00000001).of(0.06283185)
66
+ end
67
+
68
+ it "raises if over 100" do
69
+ expect{Utilities.radians_tolerance(:min_angle => 115, :min_angle_unit => :percentage)}.to raise_error
70
+ end
71
+ end
72
+
73
+
74
+ context "decimal percentage" do
75
+ it "converts decimal percentages explicitly" do
76
+ t = Utilities.radians_tolerance(:min_angle => 0.95, :min_angle_unit => :decimal_percentage)
77
+ expect(t).to be_within(0.00000001).of(2.98451302)
78
+ end
79
+
80
+ it "converts decimal percentages implicitly" do
81
+ t = Utilities.radians_tolerance(:min_angle => 0.90)
82
+ expect(t).to be_within(0.00000001).of(2.82743339)
83
+ end
84
+
85
+ it "raises if over 1" do
86
+ expect{Utilities.radians_tolerance(:min_angle => 1.15, :min_angle_unit => :decimal_percentage)}.to raise_error
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end