geomerative 0.2.0-java → 0.3.2-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.mvn/extensions.xml +8 -0
  3. data/.mvn/wrapper/maven-wrapper.properties +1 -0
  4. data/.travis.yml +14 -0
  5. data/CHANGELOG.md +4 -0
  6. data/COPYING.md +17 -0
  7. data/Gemfile +8 -1
  8. data/README.md +5 -1
  9. data/examples/README.md +1 -7
  10. data/examples/Rakefile +30 -0
  11. data/examples/data/ruby.svg +16 -0
  12. data/examples/f_agent.rb +30 -0
  13. data/examples/font_agent.rb +24 -0
  14. data/examples/hello_polygonize.rb +1 -1
  15. data/examples/hello_svg_to_pdf.rb +2 -2
  16. data/examples/hello_world.rb +1 -1
  17. data/examples/jruby_merge.rb +94 -0
  18. data/examples/physics_type.rb +1 -1
  19. data/examples/rotate_first_letter.rb +3 -4
  20. data/examples/typo_deform.rb +68 -0
  21. data/examples/typo_extra_bright.rb +62 -0
  22. data/examples/typo_merge.rb +94 -0
  23. data/geomerative.gemspec +2 -3
  24. data/lib/geomerative/version.rb +1 -1
  25. data/pom.rb +47 -0
  26. data/pom.xml +35 -65
  27. data/src/geomerative/FastRClip.java +1 -1
  28. data/src/geomerative/RCommand.java +1877 -1741
  29. data/src/geomerative/RContour.java +8 -1
  30. data/src/geomerative/RFont.java +8 -5
  31. data/src/geomerative/RG.java +8 -3
  32. data/src/geomerative/RGeomElem.java +8 -9
  33. data/src/geomerative/RGroup.java +50 -28
  34. data/src/geomerative/RMatrix.java +53 -57
  35. data/src/geomerative/RMesh.java +8 -3
  36. data/src/geomerative/RPath.java +34 -29
  37. data/src/geomerative/RPoint.java +408 -408
  38. data/src/geomerative/RPolygon.java +7 -3
  39. data/src/geomerative/RSVG.java +13 -10
  40. data/src/geomerative/RShape.java +18 -11
  41. data/src/geomerative/RStrip.java +5 -1
  42. data/src/geomerative/RStyle.java +15 -11
  43. metadata +17 -18
@@ -0,0 +1,62 @@
1
+ # --------- GEOMERATIVE EXAMPLES ---------------
2
+ # //////////////////////////////////////////////
3
+ # Title : TypoGeo_ExtraBright
4
+ # Date : 31/08/2011
5
+ # Version : v0.5
6
+ #
7
+ # Interactive work which you need to play with.
8
+ #
9
+ # Code adapted from an original idea by Stéphane Buellet
10
+ # http://www.chevalvert.fr/
11
+ #
12
+ # Licensed under GNU General Public License (GPL) version 3.
13
+ # http://www.gnu.org/licenses/gpl.html
14
+ #
15
+ # A series of tutorials for using the Geomerative Library
16
+ # developed by Ricard Marxer.
17
+ # http://www.ricardmarxer.com/geomerative/
18
+ #
19
+ # More info on these tutorials and workshops at :
20
+ # www.freeartbureau.org/blog
21
+ # translated for JRubyArt by Martin Prout
22
+ require 'geomerative'
23
+ require_relative 'f_agent'
24
+
25
+ attr_reader :my_agents
26
+
27
+ def settings
28
+ size(900, 350)
29
+ end
30
+
31
+ def setup
32
+ sketch_title 'Extra Bright'
33
+ background(0)
34
+ my_text = 'EXTRA BRIGHT'
35
+ x_incr = 0.000005
36
+ y_incr = 0.000008
37
+ RG.init(self)
38
+ my_font = RFont.new(data_path('FreeSans.ttf'), 97, CENTER)
39
+ RCommand.set_segment_length(1)
40
+ RCommand.set_segmentator(RCommand::UNIFORMLENGTH)
41
+ @my_agents = my_font.to_group(my_text).get_points.map do |point|
42
+ FontAgent.new(
43
+ loc: Vec2D.new(point.x, point.y),
44
+ increment: Vec2D.new(x_incr, y_incr)
45
+ )
46
+ end
47
+ end
48
+
49
+ def draw
50
+ translate(width / 2, height / 2)
51
+ background(0)
52
+ my_agents.each do |point|
53
+ m_point = point.motion
54
+ xr = (((100 / m_point) * 2) + mouse_x) - width / 2
55
+ yr = (((100 / m_point) * 2) + mouse_y) - height / 2
56
+ point.display(xr: xr, yr: yr, m_point: m_point)
57
+ end
58
+ end
59
+
60
+ def key_pressed
61
+ no_loop
62
+ end
@@ -0,0 +1,94 @@
1
+ #######################
2
+ # --------- GEOMERATIVE EXAMPLES ---------------
3
+ #######################
4
+ # Title : TypoGeo_Merge
5
+ # Date : 31/08/2011
6
+ # Version : v0.5
7
+ #
8
+ # Merges two words in an random fashion.
9
+ # Key 'f' = freezes motion
10
+ # key 's' saves the frame in png format
11
+ #
12
+ # Code adapted from an original idea by Bertrand _fevre
13
+ # during the Générative Typos workshop in Lure 2011.
14
+ #
15
+ # Licensed under GNU General Public License (GPL) version 3.
16
+ # http://www.gnu.org/licenses/gpl.html
17
+ #
18
+ # A series of tutorials for using the Geomerative Library
19
+ # developed by Ricard Marxer.
20
+ # http://www.ricardmarxer.com/geomerative/
21
+ #
22
+ # More info on these tutorials and workshops at :
23
+ # www.freeartbureau.org/blog
24
+ #
25
+ # Adapted for JRubyArt by Martin Prout
26
+ #######################
27
+ require 'geomerative'
28
+
29
+ attr_reader :my_font, :stop, :xoff, :yoff, :x_inc, :y_inc
30
+
31
+ TEXT = %w(Merge Design).freeze
32
+
33
+ def settings
34
+ size(900, 500)
35
+ end
36
+
37
+ def setup
38
+ sketch_title TEXT.join ' '
39
+ RG.init(self)
40
+ @my_font = RFont.new(data_path('FreeSans.ttf'), 230, CENTER)
41
+ @stop = false
42
+ no_fill
43
+ stroke(255)
44
+ stroke_weight(0.5)
45
+ rect_mode(CENTER)
46
+ @xoff = 0.0
47
+ @yoff = 0.0
48
+ @x_inc = 0.01
49
+ @y_inc = 0.015
50
+ end
51
+
52
+ def draw
53
+ background(0, 50)
54
+ displace_x = noise(xoff) * width
55
+ displace_y = noise(yoff) * height
56
+ @xoff += x_inc
57
+ @yoff += y_inc
58
+ translate(width / 2, height / 1.7)
59
+ frequency = map1d(displace_x, (300..500), (3..200))
60
+ RCommand.set_segment_length(frequency)
61
+ my_points = my_font.to_group(TEXT[0]).get_points
62
+ begin_shape
63
+ my_points.each do |point|
64
+ vertex(point.x, point.y)
65
+ rotation = map1d(displace_y, (0..height), (0..TWO_PI))
66
+ push_matrix
67
+ translate(point.x, point.y)
68
+ rotate(rotation)
69
+ size = frequency / 6
70
+ rect(0, 0, size, size)
71
+ pop_matrix
72
+ end
73
+ end_shape
74
+ frequency2 = map1d(displace_x, (300..500), (200..3))
75
+ RCommand.set_segment_length(frequency2)
76
+ my_points = my_font.to_group(TEXT[1]).get_points
77
+ begin_shape
78
+ my_points.each do |point|
79
+ vertex(point.x, point.y)
80
+ size = frequency2 / 7
81
+ ellipse(point.x, point.y, size, size)
82
+ end
83
+ end_shape
84
+ end
85
+
86
+ def key_pressed
87
+ case key
88
+ when 'f', 'F'
89
+ @stop = !stop
90
+ stop ? no_loop : loop
91
+ when 's', 'S'
92
+ save_frame('000_###.png')
93
+ end
94
+ end
data/geomerative.gemspec CHANGED
@@ -21,12 +21,11 @@ Gem::Specification.new do |spec|
21
21
  spec.files << 'lib/geomerative.jar'
22
22
  spec.require_paths = ['lib']
23
23
  spec.add_dependency 'jruby_art', '~> 1.0'
24
- spec.add_development_dependency "rake", "~> 10.0"
25
- spec.add_development_dependency "minitest", "~> 5.8"
24
+ spec.add_development_dependency 'rake', '~> 10.0'
25
+ # spec.add_development_dependency 'maven', '~> 3.3', '>= 3.3.3'
26
26
  spec.platform = 'java'
27
27
  spec.requirements << 'A decent graphics card'
28
28
  spec.requirements << 'java runtime >= 1.8+'
29
29
  spec.requirements << 'processing = 3.0.1+'
30
- spec.requirements << 'maven = 3.3.3'
31
30
  spec.requirements << 'jruby_art = 1.0+'
32
31
  end
@@ -1,3 +1,3 @@
1
1
  module Geomerative
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.2'
3
3
  end
data/pom.rb ADDED
@@ -0,0 +1,47 @@
1
+ project 'geomerative' do
2
+
3
+ model_version '4.0.0'
4
+ id 'ruby-processing:geomerative:0.3.2'
5
+ packaging 'jar'
6
+
7
+ description 'geomerative-library for JRubyArt'
8
+
9
+ organization 'ruby-processing', 'https://ruby-processing.github.io'
10
+
11
+ developer 'monkstone' do
12
+ name 'Martin Prout'
13
+ email 'mamba2928@yahoo.co.uk'
14
+ roles 'developer'
15
+ end
16
+
17
+ license 'GPL 3', 'http://www.gnu.org/licenses/gpl-3.0-standalone.html'
18
+
19
+ issue_management 'https://github.com/ruby-processing/geomerative/issues', 'Github'
20
+
21
+ source_control( :url => 'https://github.com/ruby-processing/geomerative',
22
+ :connection => 'scm:git:git://github.com/ruby-processing/geomerative.git',
23
+ :developer_connection => 'scm:git:git@github.com:ruby-processing/geomerative.git' )
24
+
25
+ properties( 'maven.compiler.source' => '1.8',
26
+ 'project.build.sourceEncoding' => 'UTF-8',
27
+ 'maven.compiler.target' => '1.8',
28
+ 'polyglot.dump.pom' => 'pom.xml'
29
+ )
30
+
31
+ jar 'org.processing:core:3.1'
32
+
33
+ plugin( :compiler, '3.3',
34
+ 'source' => '1.8',
35
+ 'target' => '1.8' )
36
+ plugin( :jar, '2.6',
37
+ 'archive' => {
38
+ 'manifestFile' => 'MANIFEST.MF'
39
+ } )
40
+ plugin :resources, '2.6'
41
+
42
+ build do
43
+ default_goal 'package'
44
+ source_directory 'src'
45
+ final_name 'geomerative'
46
+ end
47
+ end
data/pom.xml CHANGED
@@ -1,82 +1,62 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2
+ <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3
4
  <modelVersion>4.0.0</modelVersion>
4
- <groupId>org.ruby-processing</groupId>
5
+ <groupId>ruby-processing</groupId>
5
6
  <artifactId>geomerative</artifactId>
6
- <version>0.2.0</version>
7
- <packaging>jar</packaging>
8
- <description>
9
- geomerative-library for JRubyArt
10
- </description>
11
-
12
- <parent>
13
- <groupId>org.sonatype.oss</groupId>
14
- <artifactId>oss-parent</artifactId>
15
- <version>7</version>
16
- </parent>
17
-
18
- <issueManagement>
19
- <system>Github</system>
20
- <url>https://github.com/ruby-processing/geomerativegem/issues</url>
21
- </issueManagement>
22
-
23
- <scm>
24
- <connection>scm:git:git://github.com/ruby-processing/geomerativegem.git</connection>
25
- <developerConnection>scm:git:git@github.com:ruby-processing/geomerativegem.git</developerConnection>
26
- <url>https://github.com/ruby-processing/geomerative</url>
27
- </scm>
28
-
7
+ <version>0.3.2</version>
8
+ <name>geomerative</name>
9
+ <description>geomerative-library for JRubyArt</description>
10
+ <organization>
11
+ <name>ruby-processing</name>
12
+ <url>https://ruby-processing.github.io</url>
13
+ </organization>
29
14
  <licenses>
30
15
  <license>
31
- <name>AGPL 3</name>
32
- <url>http://www.gnu.org/licenses/agpl-3.0.html</url>
33
- </license>
34
- <license>
35
- <name>Apache 2</name>
36
- <url>http://www.apache.org/licenses/LICENSE-2.0</url>
16
+ <name>GPL 3</name>
17
+ <url>http://www.gnu.org/licenses/gpl-3.0-standalone.html</url>
37
18
  </license>
38
19
  </licenses>
39
-
40
20
  <developers>
41
21
  <developer>
42
22
  <id>monkstone</id>
43
23
  <name>Martin Prout</name>
44
- <email>martin_p@lineone.net</email>
24
+ <email>mamba2928@yahoo.co.uk</email>
25
+ <roles>
26
+ <role>developer</role>
27
+ </roles>
45
28
  </developer>
46
29
  </developers>
47
-
30
+ <scm>
31
+ <connection>scm:git:git://github.com/ruby-processing/geomerative.git</connection>
32
+ <developerConnection>scm:git:git@github.com:ruby-processing/geomerative.git</developerConnection>
33
+ <url>https://github.com/ruby-processing/geomerative</url>
34
+ </scm>
35
+ <issueManagement>
36
+ <system>Github</system>
37
+ <url>https://github.com/ruby-processing/geomerative/issues</url>
38
+ </issueManagement>
39
+ <properties>
40
+ <polyglot.dump.pom>pom.xml</polyglot.dump.pom>
41
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
42
+ <maven.compiler.source>1.8</maven.compiler.source>
43
+ <maven.compiler.target>1.8</maven.compiler.target>
44
+ </properties>
48
45
  <dependencies>
49
46
  <dependency>
50
47
  <groupId>org.processing</groupId>
51
48
  <artifactId>core</artifactId>
52
- <scope>system</scope>
53
- <version>3.0.1</version>
54
- <systemPath>${processing.home}/core/library/core.jar</systemPath>
49
+ <version>3.1</version>
55
50
  </dependency>
56
51
  </dependencies>
57
- <properties>
58
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
59
- <maven.compiler.source>1.8</maven.compiler.source>
60
- <maven.compiler.target>1.8</maven.compiler.target>
61
- <!-- for Mac developers, non Archlinux and Windows can probably figure it out
62
- <processing.home>/Applications/Processing.app/Contents/Java</processing.home>
63
- -->
64
- <processing.home>/usr/share/processing</processing.home>
65
- </properties>
66
52
  <build>
67
53
  <sourceDirectory>src</sourceDirectory>
54
+ <defaultGoal>package</defaultGoal>
68
55
  <finalName>geomerative</finalName>
69
- <extensions>
70
- <extension>
71
- <groupId>org.apache.maven.wagon</groupId>
72
- <artifactId>wagon-webdav-jackrabbit</artifactId>
73
- <version>2.1</version>
74
- </extension>
75
- </extensions>
76
56
  <plugins>
77
57
  <plugin>
78
58
  <artifactId>maven-compiler-plugin</artifactId>
79
- <version>3.1</version>
59
+ <version>3.3</version>
80
60
  <configuration>
81
61
  <source>1.8</source>
82
62
  <target>1.8</target>
@@ -84,7 +64,7 @@
84
64
  </plugin>
85
65
  <plugin>
86
66
  <artifactId>maven-jar-plugin</artifactId>
87
- <version>2.4</version>
67
+ <version>2.6</version>
88
68
  <configuration>
89
69
  <archive>
90
70
  <manifestFile>MANIFEST.MF</manifestFile>
@@ -95,16 +75,6 @@
95
75
  <artifactId>maven-resources-plugin</artifactId>
96
76
  <version>2.6</version>
97
77
  </plugin>
98
- <plugin>
99
- <groupId>org.apache.maven.plugins</groupId>
100
- <artifactId>maven-dependency-plugin</artifactId>
101
- <version>2.10</version>
102
- <executions>
103
- <execution>
104
- <id>default-cli</id>
105
- </execution>
106
- </executions>
107
- </plugin>
108
78
  </plugins>
109
79
  </build>
110
80
  </project>
@@ -127,7 +127,7 @@ class FastRClip
127
127
  */
128
128
  static RPolygon clip( OperationType op, RPolygon subj, RPolygon clip, Class polyClass )
129
129
  {
130
- RPolygon result = createNewPoly( polyClass );
130
+ RPolygon result = createNewPoly(polyClass);
131
131
  TopPolygonNode out_poly = new TopPolygonNode(); // used to create resulting RPolygon
132
132
 
133
133
  /* Test for trivial NULL result cases */
@@ -1,1941 +1,2077 @@
1
1
  /**
2
- Copyright 2004-2008 Ricard Marxer <email@ricardmarxer.com>
3
-
2
+ * Copyright 2004-2008 Ricard Marxer <email@ricardmarxer.com>
3
+ *
4
4
  This file is part of Geomerative.
5
+ *
6
+ * Geomerative is free software: you can redistribute it and/or modify it under
7
+ * the terms of the GNU General Public License as published by the Free Software
8
+ * Foundation, either version 3 of the License, or (at your option) any later
9
+ * version.
10
+ *
11
+ * Geomerative is distributed in the hope that it will be useful, but WITHOUT
12
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14
+ * details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License along with
17
+ * Geomerative. If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+ package geomerative;
5
20
 
6
- Geomerative is free software: you can redistribute it and/or modify
7
- it under the terms of the GNU General Public License as published by
8
- the Free Software Foundation, either version 3 of the License, or
9
- (at your option) any later version.
10
-
11
- Geomerative is distributed in the hope that it will be useful,
12
- but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- GNU General Public License for more details.
15
-
16
- You should have received a copy of the GNU General Public License
17
- along with Geomerative. If not, see <http://www.gnu.org/licenses/>.
18
- */
19
-
20
- package geomerative ;
21
- import processing.core.*;
21
+ import processing.core.PApplet;
22
+ import processing.core.PGraphics;
22
23
 
23
24
  /**
24
25
  * @extended
25
26
  */
26
- public class RCommand extends RGeomElem
27
- {
28
- /**
29
- * @invisible
30
- */
31
- public int type = RGeomElem.COMMAND;
32
-
33
- public RPoint[] controlPoints;
34
- public RPoint startPoint;
35
- public RPoint endPoint;
36
- int commandType;
37
-
38
- RPoint[] curvePoints;
39
-
40
- /**
41
- * @invisible
42
- * */
43
- public static final int LINETO = 0;
44
- /**
45
- * @invisible
46
- * */
47
- public static final int QUADBEZIERTO = 1;
48
- /**
49
- * @invisible
50
- * */
51
- public static final int CUBICBEZIERTO = 2;
52
-
53
- /**
54
- * @invisible
55
- * */
56
- public static final int ADAPTATIVE = 0;
57
- /**
58
- * @invisible
59
- * */
60
- public static final int UNIFORMLENGTH = 1;
61
- /**
62
- * @invisible
63
- * */
64
- public static final int UNIFORMSTEP = 2;
65
-
66
- public static int segmentType = UNIFORMLENGTH;
67
-
68
- /* Parameters for ADAPTATIVE (dependent of the PGraphics on which drawing) */
69
- static final int segmentRecursionLimit = 32;
70
- static final float segmentDistanceEpsilon = 1.192092896e-07F;
71
- static final float segmentCollinearityEpsilon = 1.192092896e-07F;
72
- static final float segmentAngleTolEpsilon = 0.01F;
73
-
74
- static float segmentGfxStrokeWeight = 1.0F;
75
- static float segmentGfxScale = 1.0F;
76
- static float segmentApproxScale = 1.0F;
77
- static float segmentDistTolSqr = 0.25F;
78
- static float segmentDistTolMnhttn = 4.0F;
79
- public static float segmentAngleTol = 0.0F;
80
- static float segmentCuspLimit = 0.0F;
81
-
82
- /* Parameters for UNIFORMLENGTH (dependent of the PGraphics on which drawing) */
83
- static float segmentLength = 4.0F;
84
- static float segmentOffset = 0.0F;
85
- static float segmentAccOffset = 0.0F;
86
-
87
- /* Parameters for UNIFORMSTEP */
88
- static int segmentSteps = 0;
89
- static boolean segmentLines = false;
90
-
91
- int oldSegmentType = UNIFORMLENGTH;
92
-
93
- /* Parameters for ADAPTATIVE (dependent of the PGraphics on which drawing) */
94
- float oldSegmentCollinearityEpsilon = 1.192092896e-07F;
95
- float oldSegmentAngleTolEpsilon = 0.01F;
96
-
97
- float oldSegmentGfxStrokeWeight = 1.0F;
98
- float oldSegmentGfxScale = 1.0F;
99
- float oldSegmentApproxScale = 1.0F;
100
- float oldSegmentDistTolSqr = 0.25F;
101
- float oldSegmentDistTolMnhttn = 4.0F;
102
- float oldSegmentAngleTol = 0.0F;
103
- float oldSegmentCuspLimit = 0.0F;
104
-
105
- /* Parameters for UNIFORMLENGTH (dependent of the PGraphics on which drawing) */
106
- float oldSegmentLength = 4.0F;
107
- float oldSegmentOffset = 0.0F;
108
- float oldSegmentAccOffset = 0.0F;
109
-
110
- /* Parameters for UNIFORMSTEP */
111
- int oldSegmentSteps = 0;
112
- boolean oldSegmentLines = false;
113
-
114
-
115
-
116
- static RCommand createLine(RPoint start, RPoint end){
117
- RCommand result = new RCommand();
118
- result.startPoint = start;
119
- result.endPoint = end;
120
- result.commandType = LINETO;
121
- return result;
122
- }
123
-
124
- static RCommand createLine(float startx, float starty, float endx, float endy){
125
- return createLine(new RPoint(startx,starty), new RPoint(endx,endy));
126
- }
127
-
128
- static RCommand createBezier3(RPoint start, RPoint cp1, RPoint end){
129
- RCommand result = new RCommand();
130
- result.startPoint = start;
131
- result.append(cp1);
132
- result.endPoint = end;
133
- result.commandType = QUADBEZIERTO;
134
- return result;
135
- }
136
-
137
- static RCommand createBezier3(float startx, float starty, float cp1x, float cp1y, float endx, float endy){
138
- return createBezier3(new RPoint(startx,starty), new RPoint(cp1x,cp1y), new RPoint(endx,endy));
139
- }
140
-
141
- static RCommand createBezier4(RPoint start, RPoint cp1, RPoint cp2, RPoint end){
142
- RCommand result = new RCommand();
143
- result.startPoint = start;
144
- result.append(cp1);
145
- result.append(cp2);
146
- result.endPoint = end;
147
- result.commandType = CUBICBEZIERTO;
148
- return result;
149
- }
150
-
151
- static RCommand createBezier4(float startx, float starty, float cp1x, float cp1y, float cp2x, float cp2y, float endx, float endy){
152
- return createBezier4(new RPoint(startx,starty), new RPoint(cp1x,cp1y), new RPoint(cp2x,cp2y), new RPoint(endx,endy));
153
- }
154
-
155
- /**
156
- * Create an empty command
157
- * @invisible
158
- */
159
- public RCommand(){
160
- controlPoints = null;
161
- }
162
-
163
- /**
164
- * Make a copy of another RCommand object. This can be useful when wanting to transform one but at the same time keep the original.
165
- * @param c the object of which to make the copy
166
- * @invisible
167
- */
168
- public RCommand(RCommand c){
169
- this.startPoint = new RPoint(c.startPoint);
170
- for(int i=0;i<c.countControlPoints();i++){
171
- this.append(new RPoint(c.controlPoints[i]));
172
- }
173
- this.endPoint = new RPoint(c.endPoint);
174
- this.commandType = c.commandType;
175
- }
176
-
177
- /**
178
- * Make a copy of another RCommand object with a specific start point.
179
- * @param c the object of which to make the copy
180
- * @param sp the start point of the command to be created
181
- */
182
- public RCommand(RCommand c, RPoint sp){
183
- this.startPoint = sp;
184
- for(int i=0;i<c.countControlPoints();i++){
185
- this.append(new RPoint(c.controlPoints[i]));
186
- }
187
- this.endPoint = new RPoint(c.endPoint);
188
- this.commandType = c.commandType;
189
- }
190
-
191
- /**
192
- * Create a LINETO command object with specific start and end points.
193
- * @param sp the start point of the command to be created
194
- * @param ep the end point of the command to be created
195
- */
196
- public RCommand(RPoint sp, RPoint ep){
197
- this.startPoint = sp;
198
- this.endPoint = ep;
199
- this.commandType = LINETO;
200
- }
201
-
202
- /**
203
- * Create a LINETO command object with specific start and end point coordinates.
204
- * @param spx the x coordinate of the start point of the command to be created
205
- * @param spy the y coordinate of the start point of the command to be created
206
- * @param epx the x coordinate of the end point of the command to be created
207
- * @param epy the y coordinate of the end point of the command to be created
208
- */
209
- public RCommand(float spx, float spy, float epx, float epy){
210
- this(new RPoint(spx, spy), new RPoint(epx, epy));
211
- }
212
-
213
- /**
214
- * Create a QUADBEZIERTO command object with specific start, control and end point coordinates.
215
- * @param sp the start point of the command to be created
216
- * @param cp1 the first control point of the command to be created
217
- * @param ep the end point of the command to be created
218
- */
219
- public RCommand(RPoint sp, RPoint cp1, RPoint ep){
220
- this.startPoint = sp;
221
- this.append(cp1);
222
- this.endPoint = ep;
223
- this.commandType = QUADBEZIERTO;
224
- }
225
-
226
- /**
227
- * Create a QUADBEZIERTO command object with specific start, control and end point coordinates.
228
- * @param spx the x coordinate of the start point of the command to be created
229
- * @param spy the y coordinate of the start point of the command to be created
230
- * @param cp1x the x coordinate of the first control point of the command to be created
231
- * @param cp1y the y coordinate of the first control point of the command to be created
232
- * @param epx the x coordinate of the end point of the command to be created
233
- * @param epy the y coordinate of the end point of the command to be created
234
- */
235
- public RCommand(float spx, float spy, float cp1x, float cp1y, float epx, float epy){
236
- this(new RPoint(spx, spy), new RPoint(cp1x, cp1y), new RPoint(epx, epy));
237
- }
238
-
239
-
240
- /**
241
- * Create a CUBICBEZIERTO command object with specific start, control and end point coordinates.
242
- * @param sp the start point of the command to be created
243
- * @param cp1 the first control point of the command to be created
244
- * @param cp2 the second control point of the command to be created
245
- * @param ep the end point of the command to be created
246
- */
247
- public RCommand(RPoint sp, RPoint cp1, RPoint cp2, RPoint ep){
248
- this.startPoint = sp;
249
- this.append(cp1);
250
- this.append(cp2);
251
- this.endPoint = ep;
252
- this.commandType = CUBICBEZIERTO;
253
- }
254
-
255
- /**
256
- * Create a CUBICBEZIERTO command object with specific start, control and end point coordinates.
257
- * @param spx the x coordinate of the start point of the command to be created
258
- * @param spy the y coordinate of the start point of the command to be created
259
- * @param cp1x the x coordinate of the first control point of the command to be created
260
- * @param cp1y the y coordinate of the first control point of the command to be created
261
- * @param cp2x the x coordinate of the second control point of the command to be created
262
- * @param cp2y the y coordinate of the second control point of the command to be created
263
- * @param epx the x coordinate of the end point of the command to be created
264
- * @param epy the y coordinate of the end point of the command to be created
265
- */
266
- public RCommand(float spx, float spy, float cp1x, float cp1y, float cp2x, float cp2y, float epx, float epy){
267
- this(new RPoint(spx, spy), new RPoint(cp1x, cp1y), new RPoint(cp2x, cp2y), new RPoint(epx, epy));
268
- }
269
-
270
- /**
271
- * @invisible
272
- */
273
- public RShape toShape(){
274
- return new RShape(new RPath(this));
275
- }
276
-
277
- public int getType(){
278
- return this.type;
279
- }
280
-
281
-
282
- /**
283
- * Use this to set the segmentator type. ADAPTATIVE segmentator minimizes the number of segments avoiding perceptual artifacts like angles or cusps. Use this in order to have Polygons and Meshes with the fewest possible vertices. This can be useful when using or drawing a lot the same Polygon or Mesh deriving from this Shape. UNIFORMLENGTH segmentator is the slowest segmentator and it segments the curve on segments of equal length. This can be useful for very specific applications when for example drawing incrementaly a shape with a uniform speed. UNIFORMSTEP segmentator is the fastest segmentator and it segments the curve based on a constant value of the step of the curve parameter, or on the number of segments wanted. This can be useful when segmpointsentating very often a Shape or when we know the amount of segments necessary for our specific application.
284
- * @eexample setSegment
285
- * */
286
- public static void setSegmentator(int segmentatorType){
287
- segmentType = segmentatorType;
288
- }
289
-
290
- /**
291
- * Use this to set the segmentator graphic context.
292
- * @eexample setSegmentGraphic
293
- * @param g graphics object too which to adapt the segmentation of the command.
294
- * */
295
- public static void setSegmentGraphic(PGraphics g){
296
- // Set the segmentApproxScale from the graphic context g
297
- segmentApproxScale = 1.0F;
27
+ public class RCommand extends RGeomElem {
298
28
 
299
- // Set all the gfx-context dependent parameters for all segmentators
29
+ /**
30
+ * @invisible
31
+ */
32
+ public int type = RGeomElem.COMMAND;
300
33
 
301
- segmentDistTolSqr = 0.5F / segmentApproxScale;
302
- segmentDistTolSqr *= segmentDistTolSqr;
303
- segmentDistTolMnhttn = 4.0F / segmentApproxScale;
304
- segmentAngleTol = 0.0F;
305
-
306
- if(g.stroke && (g.strokeWeight * segmentApproxScale > 1.0F))
307
- {
308
- segmentAngleTol = 0.1F;
309
- }
310
- }
311
-
312
- /**
313
- * Use this to set the segmentator angle tolerance for the ADAPTATIVE segmentator and set the segmentator to ADAPTATIVE.
314
- * @eexample setSegmentAngle
315
- * @param segmentAngleTolerance an angle from 0 to PI/2 it defines the maximum angle between segments.
316
- * */
317
- public static void setSegmentAngle(float segmentAngleTolerance){
318
- //segmentType = ADAPTATIVE;
319
-
320
- segmentAngleTol = segmentAngleTolerance;
321
- }
322
-
323
- /**
324
- * Use this to set the segmentator length for the UNIFORMLENGTH segmentator and set the segmentator to UNIFORMLENGTH.
325
- * @eexample setSegmentLength
326
- * @param segmentLngth the length of each resulting segment.
327
- * */
328
- public static void setSegmentLength(float segmentLngth){
329
- //segmentType = UNIFORMLENGTH;
330
- if(segmentLngth>=1){
331
- segmentLength = segmentLngth;
332
- }else{
333
- segmentLength = 4;
334
- }
335
- }
336
-
337
- /**
338
- * Use this to set the segmentator offset for the UNIFORMLENGTH segmentator and set the segmentator to UNIFORMLENGTH.
339
- * @eexample setSegmentOffset
340
- * @param segmentOffst the offset of the first point on the path.
341
- * */
342
- public static void setSegmentOffset(float segmentOffst){
343
- //segmentType = UNIFORMLENGTH;
344
- if(segmentOffst>=0){
345
- segmentOffset = segmentOffst;
346
- }else{
347
- segmentOffset = 0;
348
- }
349
- }
350
-
351
- /**
352
- * Use this to set the segmentator step for the UNIFORMSTEP segmentator and set the segmentator to UNIFORMSTEP.
353
- * @eexample setSegmentStep
354
- * @param segmentStps if a float from +0.0 to 1.0 is passed it's considered as the step, else it's considered as the number of steps. When a value of 0.0 is used the steps will be calculated automatically depending on an estimation of the length of the curve. The special value -1 is the same as 0.0 but also turning of the segmentation of lines (faster segmentation).
355
- * */
356
- public static void setSegmentStep(float segmentStps){
357
- //segmentType = UNIFORMSTEP;
358
- if(segmentStps == -1F){
359
- segmentLines=false;
360
- segmentStps=0F;
361
- }else{
362
- segmentLines=true;
363
- }
364
- // Set the parameters
365
- segmentStps = Math.abs(segmentStps);
366
- if(segmentStps>0.0F && segmentStps<1.0F){
367
- segmentSteps = (int)(1F/segmentStps);
368
- }else{
369
- segmentSteps = (int)segmentStps;
370
- }
371
- }
372
-
373
-
374
- protected void saveSegmentatorContext(){
375
- oldSegmentType = RCommand.segmentType;
34
+ public RPoint[] controlPoints;
35
+ public RPoint startPoint;
36
+ public RPoint endPoint;
37
+ int commandType;
38
+
39
+ RPoint[] curvePoints;
40
+
41
+ /**
42
+ * @invisible
43
+ *
44
+ */
45
+ public static final int LINETO = 0;
46
+ /**
47
+ * @invisible
48
+ *
49
+ */
50
+ public static final int QUADBEZIERTO = 1;
51
+ /**
52
+ * @invisible
53
+ *
54
+ */
55
+ public static final int CUBICBEZIERTO = 2;
56
+
57
+ /**
58
+ * @invisible
59
+ *
60
+ */
61
+ public static final int ADAPTATIVE = 0;
62
+ /**
63
+ * @invisible
64
+ *
65
+ */
66
+ public static final int UNIFORMLENGTH = 1;
67
+ /**
68
+ * @invisible
69
+ *
70
+ */
71
+ public static final int UNIFORMSTEP = 2;
72
+
73
+ public static int segmentType = UNIFORMLENGTH;
376
74
 
377
75
  /* Parameters for ADAPTATIVE (dependent of the PGraphics on which drawing) */
378
- oldSegmentGfxStrokeWeight = RCommand.segmentGfxStrokeWeight;
379
- oldSegmentGfxScale = RCommand.segmentGfxScale;
380
- oldSegmentApproxScale = RCommand.segmentApproxScale;
381
- oldSegmentDistTolSqr = RCommand.segmentDistTolSqr;
382
- oldSegmentDistTolMnhttn = RCommand.segmentDistTolMnhttn;
383
- oldSegmentAngleTol = RCommand.segmentAngleTol;
384
- oldSegmentCuspLimit = RCommand.segmentCuspLimit;
76
+ static final int segmentRecursionLimit = 32;
77
+ static final float segmentDistanceEpsilon = 1.192092896e-07F;
78
+ static final float segmentCollinearityEpsilon = 1.192092896e-07F;
79
+ static final float segmentAngleTolEpsilon = 0.01F;
80
+
81
+ static float segmentGfxStrokeWeight = 1.0F;
82
+ static float segmentGfxScale = 1.0F;
83
+ static float segmentApproxScale = 1.0F;
84
+ static float segmentDistTolSqr = 0.25F;
85
+ static float segmentDistTolMnhttn = 4.0F;
86
+ public static float segmentAngleTol = 0.0F;
87
+ static float segmentCuspLimit = 0.0F;
385
88
 
386
89
  /* Parameters for UNIFORMLENGTH (dependent of the PGraphics on which drawing) */
387
- oldSegmentLength = RCommand.segmentLength;
388
- oldSegmentOffset = RCommand.segmentOffset;
389
- oldSegmentAccOffset = RCommand.segmentAccOffset;
90
+ static float segmentLength = 4.0F;
91
+ static float segmentOffset = 0.0F;
92
+ static float segmentAccOffset = 0.0F;
390
93
 
391
94
  /* Parameters for UNIFORMSTEP */
392
- oldSegmentSteps = RCommand.segmentSteps;
393
- oldSegmentLines = RCommand.segmentLines;
394
- }
95
+ static int segmentSteps = 0;
96
+ static boolean segmentLines = false;
395
97
 
396
- protected void restoreSegmentatorContext(){
397
- RCommand.segmentType = oldSegmentType;
98
+ int oldSegmentType = UNIFORMLENGTH;
398
99
 
399
100
  /* Parameters for ADAPTATIVE (dependent of the PGraphics on which drawing) */
400
- RCommand.segmentGfxStrokeWeight = oldSegmentGfxStrokeWeight;
401
- RCommand.segmentGfxScale = oldSegmentGfxScale;
402
- RCommand.segmentApproxScale = oldSegmentApproxScale;
403
- RCommand.segmentDistTolSqr = oldSegmentDistTolSqr;
404
- RCommand.segmentDistTolMnhttn = oldSegmentDistTolMnhttn;
405
- RCommand.segmentAngleTol = oldSegmentAngleTol;
406
- RCommand.segmentCuspLimit = oldSegmentCuspLimit;
101
+ float oldSegmentCollinearityEpsilon = 1.192092896e-07F;
102
+ float oldSegmentAngleTolEpsilon = 0.01F;
103
+
104
+ float oldSegmentGfxStrokeWeight = 1.0F;
105
+ float oldSegmentGfxScale = 1.0F;
106
+ float oldSegmentApproxScale = 1.0F;
107
+ float oldSegmentDistTolSqr = 0.25F;
108
+ float oldSegmentDistTolMnhttn = 4.0F;
109
+ float oldSegmentAngleTol = 0.0F;
110
+ float oldSegmentCuspLimit = 0.0F;
407
111
 
408
112
  /* Parameters for UNIFORMLENGTH (dependent of the PGraphics on which drawing) */
409
- RCommand.segmentLength = oldSegmentLength;
410
- RCommand.segmentOffset = oldSegmentOffset;
411
- RCommand.segmentAccOffset = oldSegmentAccOffset;
113
+ float oldSegmentLength = 4.0F;
114
+ float oldSegmentOffset = 0.0F;
115
+ float oldSegmentAccOffset = 0.0F;
412
116
 
413
117
  /* Parameters for UNIFORMSTEP */
414
- RCommand.segmentSteps = oldSegmentSteps;
415
- RCommand.segmentLines = oldSegmentLines;
416
- }
417
-
418
- /**
419
- * Use this to return the number of control points of the curve.
420
- * @eexample countControlPoints
421
- * @return int, the number of control points.
422
- * */
423
- public int countControlPoints(){
424
- if (controlPoints == null){
425
- return 0;
426
- }
427
- return controlPoints.length;
428
- }
429
-
430
- /**
431
- * Use this to return the command type.
432
- * @eexample getCommandType
433
- * @return int, an integer which can take the following values: RCommand.LINETO, RCommand.QUADBEZIERTO, RCommand.CUBICBEZIERTO.
434
- * */
435
- public int getCommandType(){
436
- return commandType;
437
- }
438
-
439
- /**
440
- * Use this to return the start point of the curve.
441
- * @eexample getStartPoint
442
- * @return RPoint, the start point of the curve.
443
- * @invisible
444
- * */
445
- RPoint getStartPoint(){
446
- return startPoint;
447
- }
448
-
449
- /**
450
- * Use this to return the end point of the curve.
451
- * @eexample getEndPoint
452
- * @return RPoint, the end point of the curve.
453
- * @invisible
454
- * */
455
- RPoint getEndPoint(){
456
- return endPoint;
457
- }
458
-
459
- /**
460
- * Use this to return the control points of the curve. It returns the points in the way of an array of RPoint.
461
- * @eexample getControlPoints
462
- * @return RPoint[], the control points returned in an array.
463
- * @invisible
464
- * */
465
- RPoint[] getControlPoints(){
466
- return controlPoints;
467
- }
468
-
469
- /**
470
- * Use this to return the points on the curve. It returns the points in the way of an array of RPoint.
471
- * @eexample getPoints
472
- * @return RPoint[], the vertices returned in an array.
473
- * */
474
- public RPoint[] getPoints(){
475
- return getPoints(true);
476
- }
477
-
478
- protected RPoint[] getPoints(boolean resetSegmentator){
479
-
480
- if(resetSegmentator){
481
- saveSegmentatorContext();
482
- RCommand.segmentOffset = 0F;
483
- RCommand.segmentAccOffset = 0F;
484
- }
485
-
486
-
487
- RPoint[] result = null;
488
- switch(segmentType){
489
- case ADAPTATIVE:
490
- switch(commandType){
491
- case LINETO:
492
- result = new RPoint[2];
493
- result[0] = startPoint;
494
- result[1] = endPoint;
495
- break;
496
-
497
- case QUADBEZIERTO:
498
- quadBezierAdaptative();
499
- result = curvePoints;
500
- curvePoints = null;
501
- break;
502
-
503
- case CUBICBEZIERTO:
504
- cubicBezierAdaptative();
505
- result = curvePoints;
506
- curvePoints = null;
507
- break;
508
- }
509
- break;
510
-
511
- case UNIFORMLENGTH:
512
- switch(commandType){
513
- case LINETO:
514
- lineUniformLength();
515
- result = curvePoints;
516
- curvePoints = null;
517
- break;
518
-
519
- case QUADBEZIERTO:
520
- quadBezierUniformLength();
521
- result = curvePoints;
522
- curvePoints = null;
523
- break;
524
-
525
- case CUBICBEZIERTO:
526
- cubicBezierUniformLength();
527
- result = curvePoints;
528
- curvePoints = null;
529
- break;
530
- }
531
- break;
532
-
533
- case UNIFORMSTEP:
534
- switch(commandType){
535
- case LINETO:
536
- if(segmentLines){
537
- lineUniformStep();
538
- result = curvePoints;
539
- curvePoints = null;
540
- }else{
541
- result = new RPoint[2];
542
- result[0] = startPoint;
543
- result[1] = endPoint;
544
- }
545
- break;
546
-
547
- case QUADBEZIERTO:
548
- quadBezierUniformStep();
549
- result = curvePoints;
550
- curvePoints = null;
551
- break;
552
-
553
- case CUBICBEZIERTO:
554
- cubicBezierUniformStep();
555
- result = curvePoints;
556
- curvePoints = null;
557
- break;
558
- }
559
- break;
560
- }
561
-
562
-
563
- if(resetSegmentator){
564
- restoreSegmentatorContext();
565
- }
566
-
567
- return result;
568
- }
569
-
570
- /**
571
- * Use this to return a specific point on the curve. It returns the RPoint for a given advancement parameter t on the curve.
572
- * @eexample getPoint
573
- * @param t float, the parameter of advancement on the curve. t must have values between 0 and 1.
574
- * @return RPoint, the vertice returned.
575
- * */
576
- public RPoint getPoint(float t){
577
- /* limit the value of t between 0 and 1 */
578
- t = (t > 1F) ? 1F : t;
579
- t = (t < 0F) ? 0F : t;
580
- float ax, bx, cx;
581
- float ay, by, cy;
582
- float tSquared, tDoubled, tCubed;
583
- float dx, dy;
584
-
585
- switch(commandType){
586
- case LINETO:
587
- dx = endPoint.x - startPoint.x;
588
- dy = endPoint.y - startPoint.y;
589
- return new RPoint(startPoint.x + dx * t, startPoint.y + dy * t);
590
-
591
- case QUADBEZIERTO:
592
- /* calculate the polynomial coefficients */
593
- bx = controlPoints[0].x - startPoint.x;
594
- ax = endPoint.x - controlPoints[0].x - bx;
595
- by = controlPoints[0].y - startPoint.y;
596
- ay = endPoint.y - controlPoints[0].y - by;
597
-
598
- /* calculate the curve point at parameter value t */
599
- tSquared = t * t;
600
- tDoubled = 2F * t;
601
- return new RPoint((ax * tSquared) + (bx * tDoubled) + startPoint.x, (ay * tSquared) + (by * tDoubled) + startPoint.y);
602
-
603
- case CUBICBEZIERTO:
604
- /* calculate the polynomial coefficients */
605
- cx = 3F * (controlPoints[0].x - startPoint.x);
606
- bx = 3F * (controlPoints[1].x - controlPoints[0].x) - cx;
607
- ax = endPoint.x - startPoint.x - cx - bx;
608
- cy = 3F * (controlPoints[0].y - startPoint.y);
609
- by = 3F * (controlPoints[1].y - controlPoints[0].y) - cy;
610
- ay = endPoint.y - startPoint.y - cy - by;
611
-
612
- /* calculate the curve point at parameter value t */
613
- tSquared = t * t;
614
- tCubed = tSquared * t;
615
- return new RPoint((ax * tCubed) + (bx * tSquared) + (cx * t) + startPoint.x, (ay * tCubed) + (by * tSquared) + (cy * t) + startPoint.y);
616
- }
617
-
618
- return new RPoint();
619
- }
620
-
621
- /**
622
- * Use this to return the tangents on the curve. It returns the vectors in the form of an array of RPoint.
623
- * @eexample getTangents
624
- * @param segments int, the number of segments in which to divide the curve.
625
- * @return RPoint[], the tangent vectors returned in an array.
626
- * */
627
- public RPoint[] getTangents(int segments){
628
- RPoint[] result;
629
- float dt, t;
630
- switch(commandType)
631
- {
632
- case LINETO:
633
- result = new RPoint[2];
634
- result[0] = startPoint;
635
- result[1] = endPoint;
118
+ int oldSegmentSteps = 0;
119
+ boolean oldSegmentLines = false;
120
+
121
+ static RCommand createLine(RPoint start, RPoint end) {
122
+ RCommand result = new RCommand();
123
+ result.startPoint = start;
124
+ result.endPoint = end;
125
+ result.commandType = LINETO;
126
+ return result;
127
+ }
128
+
129
+ static RCommand createLine(float startx, float starty, float endx, float endy) {
130
+ return createLine(new RPoint(startx, starty), new RPoint(endx, endy));
131
+ }
132
+
133
+ static RCommand createBezier3(RPoint start, RPoint cp1, RPoint end) {
134
+ RCommand result = new RCommand();
135
+ result.startPoint = start;
136
+ result.append(cp1);
137
+ result.endPoint = end;
138
+ result.commandType = QUADBEZIERTO;
636
139
  return result;
637
- case QUADBEZIERTO:
638
- case CUBICBEZIERTO:
639
- result = new RPoint[segments];
640
- dt = 1F / segments;
641
- t = 0F;
642
- for(int i=0;i<segments;i++){
643
- result[i] = getTangent(t);
644
- t += dt;
140
+ }
141
+
142
+ static RCommand createBezier3(float startx, float starty, float cp1x, float cp1y, float endx, float endy) {
143
+ return createBezier3(new RPoint(startx, starty), new RPoint(cp1x, cp1y), new RPoint(endx, endy));
144
+ }
145
+
146
+ static RCommand createBezier4(RPoint start, RPoint cp1, RPoint cp2, RPoint end) {
147
+ RCommand result = new RCommand();
148
+ result.startPoint = start;
149
+ result.append(cp1);
150
+ result.append(cp2);
151
+ result.endPoint = end;
152
+ result.commandType = CUBICBEZIERTO;
153
+ return result;
154
+ }
155
+
156
+ static RCommand createBezier4(float startx, float starty, float cp1x, float cp1y, float cp2x, float cp2y, float endx, float endy) {
157
+ return createBezier4(new RPoint(startx, starty), new RPoint(cp1x, cp1y), new RPoint(cp2x, cp2y), new RPoint(endx, endy));
158
+ }
159
+
160
+ /**
161
+ * Create an empty command
162
+ *
163
+ * @invisible
164
+ */
165
+ public RCommand() {
166
+ controlPoints = null;
167
+ }
168
+
169
+ /**
170
+ * Make a copy of another RCommand object. This can be useful when wanting
171
+ * to transform one but at the same time keep the original.
172
+ *
173
+ * @param c the object of which to make the copy
174
+ * @invisible
175
+ */
176
+ public RCommand(RCommand c) {
177
+ this.startPoint = new RPoint(c.startPoint);
178
+ for (int i = 0; i < c.countControlPoints(); i++) {
179
+ this.append(new RPoint(c.controlPoints[i]));
180
+ }
181
+ this.endPoint = new RPoint(c.endPoint);
182
+ this.commandType = c.commandType;
183
+ }
184
+
185
+ /**
186
+ * Make a copy of another RCommand object with a specific start point.
187
+ *
188
+ * @param c the object of which to make the copy
189
+ * @param sp the start point of the command to be created
190
+ */
191
+ public RCommand(RCommand c, RPoint sp) {
192
+ this.startPoint = sp;
193
+ for (int i = 0; i < c.countControlPoints(); i++) {
194
+ this.append(new RPoint(c.controlPoints[i]));
645
195
  }
196
+ this.endPoint = new RPoint(c.endPoint);
197
+ this.commandType = c.commandType;
198
+ }
199
+
200
+ /**
201
+ * Create a LINETO command object with specific start and end points.
202
+ *
203
+ * @param sp the start point of the command to be created
204
+ * @param ep the end point of the command to be created
205
+ */
206
+ public RCommand(RPoint sp, RPoint ep) {
207
+ this.startPoint = sp;
208
+ this.endPoint = ep;
209
+ this.commandType = LINETO;
210
+ }
211
+
212
+ /**
213
+ * Create a LINETO command object with specific start and end point
214
+ * coordinates.
215
+ *
216
+ * @param spx the x coordinate of the start point of the command to be
217
+ * created
218
+ * @param spy the y coordinate of the start point of the command to be
219
+ * created
220
+ * @param epx the x coordinate of the end point of the command to be created
221
+ * @param epy the y coordinate of the end point of the command to be created
222
+ */
223
+ public RCommand(float spx, float spy, float epx, float epy) {
224
+ this(new RPoint(spx, spy), new RPoint(epx, epy));
225
+ }
226
+
227
+ /**
228
+ * Create a QUADBEZIERTO command object with specific start, control and end
229
+ * point coordinates.
230
+ *
231
+ * @param sp the start point of the command to be created
232
+ * @param cp1 the first control point of the command to be created
233
+ * @param ep the end point of the command to be created
234
+ */
235
+ public RCommand(RPoint sp, RPoint cp1, RPoint ep) {
236
+ this.startPoint = sp;
237
+ this.append(cp1);
238
+ this.endPoint = ep;
239
+ this.commandType = QUADBEZIERTO;
240
+ }
241
+
242
+ /**
243
+ * Create a QUADBEZIERTO command object with specific start, control and end
244
+ * point coordinates.
245
+ *
246
+ * @param spx the x coordinate of the start point of the command to be
247
+ * created
248
+ * @param spy the y coordinate of the start point of the command to be
249
+ * created
250
+ * @param cp1x the x coordinate of the first control point of the command to
251
+ * be created
252
+ * @param cp1y the y coordinate of the first control point of the command to
253
+ * be created
254
+ * @param epx the x coordinate of the end point of the command to be created
255
+ * @param epy the y coordinate of the end point of the command to be created
256
+ */
257
+ public RCommand(float spx, float spy, float cp1x, float cp1y, float epx, float epy) {
258
+ this(new RPoint(spx, spy), new RPoint(cp1x, cp1y), new RPoint(epx, epy));
259
+ }
260
+
261
+ /**
262
+ * Create a CUBICBEZIERTO command object with specific start, control and
263
+ * end point coordinates.
264
+ *
265
+ * @param sp the start point of the command to be created
266
+ * @param cp1 the first control point of the command to be created
267
+ * @param cp2 the second control point of the command to be created
268
+ * @param ep the end point of the command to be created
269
+ */
270
+ public RCommand(RPoint sp, RPoint cp1, RPoint cp2, RPoint ep) {
271
+ this.startPoint = sp;
272
+ this.append(cp1);
273
+ this.append(cp2);
274
+ this.endPoint = ep;
275
+ this.commandType = CUBICBEZIERTO;
276
+ }
277
+
278
+ /**
279
+ * Create a CUBICBEZIERTO command object with specific start, control and
280
+ * end point coordinates.
281
+ *
282
+ * @param spx the x coordinate of the start point of the command to be
283
+ * created
284
+ * @param spy the y coordinate of the start point of the command to be
285
+ * created
286
+ * @param cp1x the x coordinate of the first control point of the command to
287
+ * be created
288
+ * @param cp1y the y coordinate of the first control point of the command to
289
+ * be created
290
+ * @param cp2x the x coordinate of the second control point of the command
291
+ * to be created
292
+ * @param cp2y the y coordinate of the second control point of the command
293
+ * to be created
294
+ * @param epx the x coordinate of the end point of the command to be created
295
+ * @param epy the y coordinate of the end point of the command to be created
296
+ */
297
+ public RCommand(float spx, float spy, float cp1x, float cp1y, float cp2x, float cp2y, float epx, float epy) {
298
+ this(new RPoint(spx, spy), new RPoint(cp1x, cp1y), new RPoint(cp2x, cp2y), new RPoint(epx, epy));
299
+ }
300
+
301
+ /**
302
+ * @return @invisible
303
+ */
304
+ @Override
305
+ public RShape toShape() {
306
+ return new RShape(new RPath(this));
307
+ }
308
+
309
+ @Override
310
+ public int getType() {
311
+ return this.type;
312
+ }
313
+
314
+ /**
315
+ * Use this to set the segmentator type. ADAPTATIVE segmentator minimizes
316
+ * the number of segments avoiding perceptual artifacts like angles or
317
+ * cusps. Use this in order to have Polygons and Meshes with the fewest
318
+ * possible vertices. This can be useful when using or drawing a lot the
319
+ * same Polygon or Mesh deriving from this Shape. UNIFORMLENGTH segmentator
320
+ * is the slowest segmentator and it segments the curve on segments of equal
321
+ * length. This can be useful for very specific applications when for
322
+ * example drawing incrementaly a shape with a uniform speed. UNIFORMSTEP
323
+ * segmentator is the fastest segmentator and it segments the curve based on
324
+ * a constant value of the step of the curve parameter, or on the number of
325
+ * segments wanted. This can be useful when segmpointsentating very often a
326
+ * Shape or when we know the amount of segments necessary for our specific
327
+ * application.
328
+ *
329
+ * @param segmentatorType
330
+ * @eexample setSegment
331
+ *
332
+ */
333
+ public static void setSegmentator(int segmentatorType) {
334
+ segmentType = segmentatorType;
335
+ }
336
+
337
+ /**
338
+ * Use this to set the segmentator graphic context.
339
+ *
340
+ * @eexample setSegmentGraphic
341
+ * @param g graphics object too which to adapt the segmentation of the
342
+ * command.
343
+ *
344
+ */
345
+ public static void setSegmentGraphic(PGraphics g) {
346
+ // Set the segmentApproxScale from the graphic context g
347
+ segmentApproxScale = 1.0F;
348
+
349
+ // Set all the gfx-context dependent parameters for all segmentators
350
+ segmentDistTolSqr = 0.5F / segmentApproxScale;
351
+ segmentDistTolSqr *= segmentDistTolSqr;
352
+ segmentDistTolMnhttn = 4.0F / segmentApproxScale;
353
+ segmentAngleTol = 0.0F;
354
+
355
+ if (g.stroke && (g.strokeWeight * segmentApproxScale > 1.0F)) {
356
+ segmentAngleTol = 0.1F;
357
+ }
358
+ }
359
+
360
+ /**
361
+ * Use this to set the segmentator angle tolerance for the ADAPTATIVE
362
+ * segmentator and set the segmentator to ADAPTATIVE.
363
+ *
364
+ * @eexample setSegmentAngle
365
+ * @param segmentAngleTolerance an angle from 0 to PI/2 it defines the
366
+ * maximum angle between segments.
367
+ *
368
+ */
369
+ public static void setSegmentAngle(float segmentAngleTolerance) {
370
+ //segmentType = ADAPTATIVE;
371
+
372
+ segmentAngleTol = segmentAngleTolerance;
373
+ }
374
+
375
+ /**
376
+ * Use this to set the segmentator length for the UNIFORMLENGTH segmentator
377
+ * and set the segmentator to UNIFORMLENGTH.
378
+ *
379
+ * @eexample setSegmentLength
380
+ * @param segmentLngth the length of each resulting segment.
381
+ *
382
+ */
383
+ public static void setSegmentLength(float segmentLngth) {
384
+ //segmentType = UNIFORMLENGTH;
385
+ if (segmentLngth >= 1) {
386
+ segmentLength = segmentLngth;
387
+ } else {
388
+ segmentLength = 4;
389
+ }
390
+ }
391
+
392
+ /**
393
+ * Use this to set the segmentator offset for the UNIFORMLENGTH segmentator
394
+ * and set the segmentator to UNIFORMLENGTH.
395
+ *
396
+ * @eexample setSegmentOffset
397
+ * @param segmentOffst the offset of the first point on the path.
398
+ *
399
+ */
400
+ public static void setSegmentOffset(float segmentOffst) {
401
+ //segmentType = UNIFORMLENGTH;
402
+ if (segmentOffst >= 0) {
403
+ segmentOffset = segmentOffst;
404
+ } else {
405
+ segmentOffset = 0;
406
+ }
407
+ }
408
+
409
+ /**
410
+ * Use this to set the segmentator step for the UNIFORMSTEP segmentator and
411
+ * set the segmentator to UNIFORMSTEP.
412
+ *
413
+ * @eexample setSegmentStep
414
+ * @param segmentStps if a float from +0.0 to 1.0 is passed it's considered
415
+ * as the step, else it's considered as the number of steps. When a value of
416
+ * 0.0 is used the steps will be calculated automatically depending on an
417
+ * estimation of the length of the curve. The special value -1 is the same
418
+ * as 0.0 but also turning of the segmentation of lines (faster
419
+ * segmentation).
420
+ *
421
+ */
422
+ public static void setSegmentStep(float segmentStps) {
423
+ //segmentType = UNIFORMSTEP;
424
+ if (segmentStps == -1F) {
425
+ segmentLines = false;
426
+ segmentStps = 0F;
427
+ } else {
428
+ segmentLines = true;
429
+ }
430
+ // Set the parameters
431
+ segmentStps = Math.abs(segmentStps);
432
+ if (segmentStps > 0.0F && segmentStps < 1.0F) {
433
+ segmentSteps = (int) (1F / segmentStps);
434
+ } else {
435
+ segmentSteps = (int) segmentStps;
436
+ }
437
+ }
438
+
439
+ protected void saveSegmentatorContext() {
440
+ oldSegmentType = RCommand.segmentType;
441
+
442
+ /* Parameters for ADAPTATIVE (dependent of the PGraphics on which drawing) */
443
+ oldSegmentGfxStrokeWeight = RCommand.segmentGfxStrokeWeight;
444
+ oldSegmentGfxScale = RCommand.segmentGfxScale;
445
+ oldSegmentApproxScale = RCommand.segmentApproxScale;
446
+ oldSegmentDistTolSqr = RCommand.segmentDistTolSqr;
447
+ oldSegmentDistTolMnhttn = RCommand.segmentDistTolMnhttn;
448
+ oldSegmentAngleTol = RCommand.segmentAngleTol;
449
+ oldSegmentCuspLimit = RCommand.segmentCuspLimit;
450
+
451
+ /* Parameters for UNIFORMLENGTH (dependent of the PGraphics on which drawing) */
452
+ oldSegmentLength = RCommand.segmentLength;
453
+ oldSegmentOffset = RCommand.segmentOffset;
454
+ oldSegmentAccOffset = RCommand.segmentAccOffset;
455
+
456
+ /* Parameters for UNIFORMSTEP */
457
+ oldSegmentSteps = RCommand.segmentSteps;
458
+ oldSegmentLines = RCommand.segmentLines;
459
+ }
460
+
461
+ protected void restoreSegmentatorContext() {
462
+ RCommand.segmentType = oldSegmentType;
463
+
464
+ /* Parameters for ADAPTATIVE (dependent of the PGraphics on which drawing) */
465
+ RCommand.segmentGfxStrokeWeight = oldSegmentGfxStrokeWeight;
466
+ RCommand.segmentGfxScale = oldSegmentGfxScale;
467
+ RCommand.segmentApproxScale = oldSegmentApproxScale;
468
+ RCommand.segmentDistTolSqr = oldSegmentDistTolSqr;
469
+ RCommand.segmentDistTolMnhttn = oldSegmentDistTolMnhttn;
470
+ RCommand.segmentAngleTol = oldSegmentAngleTol;
471
+ RCommand.segmentCuspLimit = oldSegmentCuspLimit;
472
+
473
+ /* Parameters for UNIFORMLENGTH (dependent of the PGraphics on which drawing) */
474
+ RCommand.segmentLength = oldSegmentLength;
475
+ RCommand.segmentOffset = oldSegmentOffset;
476
+ RCommand.segmentAccOffset = oldSegmentAccOffset;
477
+
478
+ /* Parameters for UNIFORMSTEP */
479
+ RCommand.segmentSteps = oldSegmentSteps;
480
+ RCommand.segmentLines = oldSegmentLines;
481
+ }
482
+
483
+ /**
484
+ * Use this to return the number of control points of the curve.
485
+ *
486
+ * @eexample countControlPoints
487
+ * @return int, the number of control points.
488
+ *
489
+ */
490
+ public int countControlPoints() {
491
+ if (controlPoints == null) {
492
+ return 0;
493
+ }
494
+ return controlPoints.length;
495
+ }
496
+
497
+ /**
498
+ * Use this to return the command type.
499
+ *
500
+ * @eexample getCommandType
501
+ * @return int, an integer which can take the following values:
502
+ * RCommand.LINETO, RCommand.QUADBEZIERTO, RCommand.CUBICBEZIERTO.
503
+ *
504
+ */
505
+ public int getCommandType() {
506
+ return commandType;
507
+ }
508
+
509
+ /**
510
+ * Use this to return the start point of the curve.
511
+ *
512
+ * @eexample getStartPoint
513
+ * @return RPoint, the start point of the curve.
514
+ * @invisible
515
+ *
516
+ */
517
+ RPoint getStartPoint() {
518
+ return startPoint;
519
+ }
520
+
521
+ /**
522
+ * Use this to return the end point of the curve.
523
+ *
524
+ * @eexample getEndPoint
525
+ * @return RPoint, the end point of the curve.
526
+ * @invisible
527
+ *
528
+ */
529
+ RPoint getEndPoint() {
530
+ return endPoint;
531
+ }
532
+
533
+ /**
534
+ * Use this to return the control points of the curve. It returns the points
535
+ * in the way of an array of RPoint.
536
+ *
537
+ * @eexample getControlPoints
538
+ * @return RPoint[], the control points returned in an array.
539
+ * @invisible
540
+ *
541
+ */
542
+ RPoint[] getControlPoints() {
543
+ return controlPoints;
544
+ }
545
+
546
+ /**
547
+ * Use this to return the points on the curve. It returns the points in the
548
+ * way of an array of RPoint.
549
+ *
550
+ * @eexample getPoints
551
+ * @return RPoint[], the vertices returned in an array.
552
+ *
553
+ */
554
+ @Override
555
+ public RPoint[] getPoints() {
556
+ return getPoints(true);
557
+ }
558
+
559
+ protected RPoint[] getPoints(boolean resetSegmentator) {
560
+
561
+ if (resetSegmentator) {
562
+ saveSegmentatorContext();
563
+ RCommand.segmentOffset = 0F;
564
+ RCommand.segmentAccOffset = 0F;
565
+ }
566
+
567
+ RPoint[] result = null;
568
+ switch (segmentType) {
569
+ case ADAPTATIVE:
570
+ switch (commandType) {
571
+ case LINETO:
572
+ result = new RPoint[2];
573
+ result[0] = startPoint;
574
+ result[1] = endPoint;
575
+ break;
576
+
577
+ case QUADBEZIERTO:
578
+ quadBezierAdaptative();
579
+ result = curvePoints;
580
+ curvePoints = null;
581
+ break;
582
+
583
+ case CUBICBEZIERTO:
584
+ cubicBezierAdaptative();
585
+ result = curvePoints;
586
+ curvePoints = null;
587
+ break;
588
+ }
589
+ break;
590
+
591
+ case UNIFORMLENGTH:
592
+ switch (commandType) {
593
+ case LINETO:
594
+ lineUniformLength();
595
+ result = curvePoints;
596
+ curvePoints = null;
597
+ break;
598
+
599
+ case QUADBEZIERTO:
600
+ quadBezierUniformLength();
601
+ result = curvePoints;
602
+ curvePoints = null;
603
+ break;
604
+
605
+ case CUBICBEZIERTO:
606
+ cubicBezierUniformLength();
607
+ result = curvePoints;
608
+ curvePoints = null;
609
+ break;
610
+ }
611
+ break;
612
+
613
+ case UNIFORMSTEP:
614
+ switch (commandType) {
615
+ case LINETO:
616
+ if (segmentLines) {
617
+ lineUniformStep();
618
+ result = curvePoints;
619
+ curvePoints = null;
620
+ } else {
621
+ result = new RPoint[2];
622
+ result[0] = startPoint;
623
+ result[1] = endPoint;
624
+ }
625
+ break;
626
+
627
+ case QUADBEZIERTO:
628
+ quadBezierUniformStep();
629
+ result = curvePoints;
630
+ curvePoints = null;
631
+ break;
632
+
633
+ case CUBICBEZIERTO:
634
+ cubicBezierUniformStep();
635
+ result = curvePoints;
636
+ curvePoints = null;
637
+ break;
638
+ }
639
+ break;
640
+ }
641
+
642
+ if (resetSegmentator) {
643
+ restoreSegmentatorContext();
644
+ }
645
+
646
646
  return result;
647
- }
648
- return null;
649
- }
650
-
651
- public RPoint[] getTangents(){
652
-
653
- return getTangents(100);
654
- }
655
-
656
- /**
657
- * Use this to return a specific tangent on the curve. It returns the RPoint representing the tangent vector for a given value of the advancement parameter t on the curve.
658
- * @eexample getTangent
659
- * @param t float, the parameter of advancement on the curve. t must have values between 0 and 1.
660
- * @return RPoint, the vertice returned.
661
- * */
662
- public RPoint getTangent(float t){
663
- /* limit the value of t between 0 and 1 */
664
- t = (t > 1F) ? 1F : t;
665
- t = (t < 0F) ? 0F : t;
666
-
667
- float dx, dy, tx, ty, t2, t_1, t_12;
668
-
669
- switch(commandType){
670
- case LINETO:
671
- dx = endPoint.x - startPoint.x;
672
- dy = endPoint.y - startPoint.y;
673
- return new RPoint(dx, dy);
674
-
675
- case QUADBEZIERTO:
676
- /* calculate the curve point at parameter value t */
677
- tx = 2F * ((startPoint.x - 2*controlPoints[0].x + endPoint.x) * t + (controlPoints[0].x - startPoint.x));
678
- ty = 2F * ((startPoint.y - 2*controlPoints[0].y + endPoint.y) * t + (controlPoints[0].y - startPoint.y));
647
+ }
648
+
649
+ /**
650
+ * Use this to return a specific point on the curve. It returns the RPoint
651
+ * for a given advancement parameter t on the curve.
652
+ *
653
+ * @eexample getPoint
654
+ * @param t float, the parameter of advancement on the curve. t must have
655
+ * values between 0 and 1.
656
+ * @return RPoint, the vertice returned.
657
+ *
658
+ */
659
+ @Override
660
+ public RPoint getPoint(float t) {
661
+ /* limit the value of t between 0 and 1 */
662
+ t = (t > 1F) ? 1F : t;
663
+ t = (t < 0F) ? 0F : t;
664
+ float ax, bx, cx;
665
+ float ay, by, cy;
666
+ float tSquared, tDoubled, tCubed;
667
+ float dx, dy;
668
+
669
+ switch (commandType) {
670
+ case LINETO:
671
+ dx = endPoint.x - startPoint.x;
672
+ dy = endPoint.y - startPoint.y;
673
+ return new RPoint(startPoint.x + dx * t, startPoint.y + dy * t);
674
+
675
+ case QUADBEZIERTO:
676
+ /* calculate the polynomial coefficients */
677
+ bx = controlPoints[0].x - startPoint.x;
678
+ ax = endPoint.x - controlPoints[0].x - bx;
679
+ by = controlPoints[0].y - startPoint.y;
680
+ ay = endPoint.y - controlPoints[0].y - by;
681
+
682
+ /* calculate the curve point at parameter value t */
683
+ tSquared = t * t;
684
+ tDoubled = 2F * t;
685
+ return new RPoint((ax * tSquared) + (bx * tDoubled) + startPoint.x, (ay * tSquared) + (by * tDoubled) + startPoint.y);
686
+
687
+ case CUBICBEZIERTO:
688
+ /* calculate the polynomial coefficients */
689
+ cx = 3F * (controlPoints[0].x - startPoint.x);
690
+ bx = 3F * (controlPoints[1].x - controlPoints[0].x) - cx;
691
+ ax = endPoint.x - startPoint.x - cx - bx;
692
+ cy = 3F * (controlPoints[0].y - startPoint.y);
693
+ by = 3F * (controlPoints[1].y - controlPoints[0].y) - cy;
694
+ ay = endPoint.y - startPoint.y - cy - by;
695
+
696
+ /* calculate the curve point at parameter value t */
697
+ tSquared = t * t;
698
+ tCubed = tSquared * t;
699
+ return new RPoint((ax * tCubed) + (bx * tSquared) + (cx * t) + startPoint.x, (ay * tCubed) + (by * tSquared) + (cy * t) + startPoint.y);
700
+ }
701
+
702
+ return new RPoint();
703
+ }
704
+
705
+ /**
706
+ * Use this to return the tangents on the curve. It returns the vectors in
707
+ * the form of an array of RPoint.
708
+ *
709
+ * @eexample getTangents
710
+ * @param segments int, the number of segments in which to divide the curve.
711
+ * @return RPoint[], the tangent vectors returned in an array.
712
+ *
713
+ */
714
+ public RPoint[] getTangents(int segments) {
715
+ RPoint[] result;
716
+ float dt, t;
717
+ switch (commandType) {
718
+ case LINETO:
719
+ result = new RPoint[2];
720
+ result[0] = startPoint;
721
+ result[1] = endPoint;
722
+ return result;
723
+ case QUADBEZIERTO:
724
+ case CUBICBEZIERTO:
725
+ result = new RPoint[segments];
726
+ dt = 1F / segments;
727
+ t = 0F;
728
+ for (int i = 0; i < segments; i++) {
729
+ result[i] = getTangent(t);
730
+ t += dt;
731
+ }
732
+ return result;
733
+ }
734
+ return null;
735
+ }
736
+
737
+ @Override
738
+ public RPoint[] getTangents() {
739
+
740
+ return getTangents(100);
741
+ }
742
+
743
+ /**
744
+ * Use this to return a specific tangent on the curve. It returns the RPoint
745
+ * representing the tangent vector for a given value of the advancement
746
+ * parameter t on the curve.
747
+ *
748
+ * @eexample getTangent
749
+ * @param t float, the parameter of advancement on the curve. t must have
750
+ * values between 0 and 1.
751
+ * @return RPoint, the vertice returned.
752
+ *
753
+ */
754
+ @Override
755
+ public RPoint getTangent(float t) {
756
+ /* limit the value of t between 0 and 1 */
757
+ t = (t > 1F) ? 1F : t;
758
+ t = (t < 0F) ? 0F : t;
759
+
760
+ float dx, dy, tx, ty, t2, t_1, t_12;
761
+
762
+ switch (commandType) {
763
+ case LINETO:
764
+ dx = endPoint.x - startPoint.x;
765
+ dy = endPoint.y - startPoint.y;
766
+ return new RPoint(dx, dy);
767
+
768
+ case QUADBEZIERTO:
769
+ /* calculate the curve point at parameter value t */
770
+ tx = 2F * ((startPoint.x - 2 * controlPoints[0].x + endPoint.x) * t + (controlPoints[0].x - startPoint.x));
771
+ ty = 2F * ((startPoint.y - 2 * controlPoints[0].y + endPoint.y) * t + (controlPoints[0].y - startPoint.y));
679
772
  //float norm = (float)Math.sqrt(tx*tx + ty*ty);
680
- //return new RPoint(tx/norm,ty/norm);
681
- return new RPoint(tx, ty);
682
-
683
- case CUBICBEZIERTO:
684
- /* calculate the curve point at parameter value t */
685
- t2 = t*t;
686
- t_1 = 1-t;
687
- t_12 = t_1*t_1;
688
-
689
- return new RPoint(-3F*t_12*startPoint.x + 3F*(3F*t2 - 4F*t +1F)*controlPoints[0].x + 3F*t*(2F-3F*t)*controlPoints[1].x + 3F*t2*endPoint.x, -3F*t_12*startPoint.y + 3F*(3F*t2 - 4F*t +1F)*controlPoints[0].y + 3F*t*(2F-3F*t)*controlPoints[1].y + 3F*t2*endPoint.y);
690
- }
691
-
692
- return new RPoint();
693
- }
694
-
695
- /**
696
- * Use this to return arc length of a curve. It returns the float representing the length given the value of the advancement parameter t on the curve. The current implementation of this function is very slow, not recommended for using during frame draw.
697
- * @eexample RCommand_getCurveLength
698
- * @param t float, the parameter of advancement on the curve. t must have values between 0 and 1.
699
- * @return float, the length returned.
700
- * @invisible
701
- * */
702
- public float getCurveLength(float t){
703
-
704
- /* limit the value of t between 0 and 1 */
705
- t = (t > 1F) ? 1F : t;
706
- t = (t < 0F) ? 0F : t;
707
-
708
- float dx, dy, dx2, dy2, t2;
709
-
710
- switch(commandType){
711
- case LINETO:
712
- dx = endPoint.x - startPoint.x;
713
- dy = endPoint.y - startPoint.y;
714
- dx2 = dx*dx;
715
- dy2 = dy*dy;
716
- t2 = t*t;
717
- //RG.parent().println("RCommand/LINETO::: getCurveLength: " + (float)Math.sqrt(dx2*t2 + dy2*t2));
718
- return (float)Math.sqrt(dx2*t2 + dy2*t2);
719
-
720
- case QUADBEZIERTO:
721
- /* calculate the curve point at parameter value t */
722
- return quadBezierLength();
723
-
724
- case CUBICBEZIERTO:
725
- /* calculate the curve point at parameter value t */
726
- return cubicBezierLength();
727
- }
728
-
729
- return -1F;
730
- }
731
-
732
- /**
733
- * Use this to return arc length of a curve. It returns the float representing the length given the value of the advancement parameter t on the curve. The current implementation of this function is very slow, not recommended for using during frame draw.
734
- * @eexample RCommand_getCurveLength
735
- * @return float, the length returned.
736
- * @invisible
737
- * */
738
- public float getCurveLength(){
739
- return getCurveLength(1F);
740
- }
741
-
742
- public RPoint[][] getPointsInPaths(){
743
- PApplet.println("Feature not yet implemented for this class.");
744
- return null;
745
- }
746
-
747
- public RPoint[][] getHandlesInPaths(){
748
- PApplet.println("Feature not yet implemented for this class.");
749
- return null;
750
- }
751
-
752
- public RPoint[][] getTangentsInPaths(){
753
- PApplet.println("Feature not yet implemented for this class.");
754
- return null;
755
- }
756
-
757
- public boolean contains(RPoint p){
758
- PApplet.println("Feature not yet implemented for this class.");
759
- return false;
760
- }
761
-
762
- /**
763
- * Use this method to draw the command.
764
- * @eexample drawCommand
765
- * @param g PGraphics, the graphics object on which to draw the command
766
- */
767
- public void draw(PGraphics g){
768
- RPoint[] points = getPoints();
769
- if(points == null){
770
- return;
771
- }
772
- g.beginShape();
773
- for(int i=0;i<points.length;i++){
774
- g.vertex(points[i].x, points[i].y);
775
- }
776
- g.endShape();
777
- }
778
-
779
- /**
780
- * Use this method to draw the command.
781
- * @eexample drawCommand
782
- * @param a the applet object on which to draw the command
783
- */
784
- public void draw(PApplet a){
785
- RPoint[] points = getPoints();
786
- if(points == null){
787
- return;
788
- }
789
-
790
- a.beginShape();
791
- for(int i=0;i<points.length;i++){
792
- a.vertex(points[i].x, points[i].y);
793
- }
794
- a.endShape();
795
- }
796
-
797
-
798
- /**
799
- * Use this to return the start, control and end points of the curve. It returns the points in the way of an array of RPoint.
800
- * @eexample getHandles
801
- * @return RPoint[], the vertices returned in an array.
802
- * */
803
- public RPoint[] getHandles(){
804
- RPoint[] result;
805
- if(controlPoints==null){
806
- result = new RPoint[2];
807
- result[0] = startPoint;
808
- result[1] = endPoint;
809
- }else{
810
- result = new RPoint[controlPoints.length+2];
811
- result[0] = startPoint;
812
- System.arraycopy(controlPoints,0,result,1,controlPoints.length);
813
- result[result.length-1] = endPoint;
814
- }
815
- return result;
816
- }
817
-
818
- /**
819
- * Returns two commands resulting of splitting the command.
820
- * @eexample split
821
- * @param t the advancement on the curve where command should be split.
822
- * @return RPoint[], the tangent vectors returned in an array.
823
- * */
824
- public RCommand[] split(float t){
825
-
826
- switch(commandType)
827
- {
828
- case LINETO:
829
- return splitLine(t);
830
-
831
- case QUADBEZIERTO:
832
- return splitQuadBezier(t);
833
-
834
- case CUBICBEZIERTO:
835
- return splitCubicBezier(t);
836
-
837
- }
838
- return null;
839
- }
840
-
841
- /**
842
- * Taken from:
843
- * http://steve.hollasch.net/cgindex/curves/cbezarclen.html
773
+ //return new RPoint(tx/norm,ty/norm);
774
+ return new RPoint(tx, ty);
775
+
776
+ case CUBICBEZIERTO:
777
+ /* calculate the curve point at parameter value t */
778
+ t2 = t * t;
779
+ t_1 = 1 - t;
780
+ t_12 = t_1 * t_1;
781
+
782
+ return new RPoint(-3F * t_12 * startPoint.x + 3F * (3F * t2 - 4F * t + 1F) * controlPoints[0].x + 3F * t * (2F - 3F * t) * controlPoints[1].x + 3F * t2 * endPoint.x, -3F * t_12 * startPoint.y + 3F * (3F * t2 - 4F * t + 1F) * controlPoints[0].y + 3F * t * (2F - 3F * t) * controlPoints[1].y + 3F * t2 * endPoint.y);
783
+ }
784
+
785
+ return new RPoint();
786
+ }
787
+
788
+ /**
789
+ * Use this to return arc length of a curve. It returns the float
790
+ * representing the length given the value of the advancement parameter t on
791
+ * the curve. The current implementation of this function is very slow, not
792
+ * recommended for using during frame draw.
793
+ *
794
+ * @eexample RCommand_getCurveLength
795
+ * @param t float, the parameter of advancement on the curve. t must have
796
+ * values between 0 and 1.
797
+ * @return float, the length returned.
798
+ * @invisible
844
799
  *
845
- * who took it from:
846
- * Schneider's Bezier curve-fitter
800
+ */
801
+ public float getCurveLength(float t) {
802
+
803
+ /* limit the value of t between 0 and 1 */
804
+ t = (t > 1F) ? 1F : t;
805
+ t = (t < 0F) ? 0F : t;
806
+
807
+ float dx, dy, dx2, dy2, t2;
808
+
809
+ switch (commandType) {
810
+ case LINETO:
811
+ dx = endPoint.x - startPoint.x;
812
+ dy = endPoint.y - startPoint.y;
813
+ dx2 = dx * dx;
814
+ dy2 = dy * dy;
815
+ t2 = t * t;
816
+ //RG.parent().println("RCommand/LINETO::: getCurveLength: " + (float)Math.sqrt(dx2*t2 + dy2*t2));
817
+ return (float) Math.sqrt(dx2 * t2 + dy2 * t2);
818
+
819
+ case QUADBEZIERTO:
820
+ /* calculate the curve point at parameter value t */
821
+ return quadBezierLength();
822
+
823
+ case CUBICBEZIERTO:
824
+ /* calculate the curve point at parameter value t */
825
+ return cubicBezierLength();
826
+ }
827
+
828
+ return -1F;
829
+ }
830
+
831
+ /**
832
+ * Use this to return arc length of a curve. It returns the float
833
+ * representing the length given the value of the advancement parameter t on
834
+ * the curve. The current implementation of this function is very slow, not
835
+ * recommended for using during frame draw.
836
+ *
837
+ * @eexample RCommand_getCurveLength
838
+ * @return float, the length returned.
839
+ * @invisible
847
840
  *
848
- */
849
- private RCommand[] splitCubicBezier(float t){
850
- RPoint[][] triangleMatrix = new RPoint[4][4];
851
- for(int i=0; i<=3; i++){
852
- for(int j=0; j<=3; j++){
853
- triangleMatrix[i][j] = new RPoint();
854
- }
841
+ */
842
+ @Override
843
+ public float getCurveLength() {
844
+ return getCurveLength(1F);
855
845
  }
856
846
 
857
- RPoint[] ctrlPoints = this.getHandles();
847
+ @Override
848
+ public RPoint[][] getPointsInPaths() {
849
+ PApplet.println("Feature not yet implemented for this class.");
850
+ return null;
851
+ }
858
852
 
859
- // Copy control points to triangle matrix
860
- for(int i = 0; i <= 3; i++){
861
- triangleMatrix[0][i].x = ctrlPoints[i].x;
862
- triangleMatrix[0][i].y = ctrlPoints[i].y;
853
+ @Override
854
+ public RPoint[][] getHandlesInPaths() {
855
+ PApplet.println("Feature not yet implemented for this class.");
856
+ return null;
863
857
  }
864
858
 
865
- // Triangle computation
866
- for(int i = 1; i <= 3; i++){
867
- for(int j = 0; j <= 3 - i; j++){
868
- triangleMatrix[i][j].x = (1-t) * triangleMatrix[i-1][j].x + t * triangleMatrix[i-1][j+1].x;
869
- triangleMatrix[i][j].y = (1-t) * triangleMatrix[i-1][j].y + t * triangleMatrix[i-1][j+1].y;
870
- }
859
+ @Override
860
+ public RPoint[][] getTangentsInPaths() {
861
+ PApplet.println("Feature not yet implemented for this class.");
862
+ return null;
871
863
  }
872
864
 
873
- RCommand[] result = new RCommand[2];
874
- result[0] = createBezier4(startPoint, triangleMatrix[1][0], triangleMatrix[2][0], triangleMatrix[3][0]);
875
- result[1] = createBezier4(triangleMatrix[3][0], triangleMatrix[2][1], triangleMatrix[1][2], endPoint);
876
- return result;
877
- }
865
+ @Override
866
+ public boolean contains(RPoint p) {
867
+ PApplet.println("Feature not yet implemented for this class.");
868
+ return false;
869
+ }
878
870
 
879
- private RCommand[] splitQuadBezier(float t){
880
- RPoint[][] triangleMatrix = new RPoint[3][3];
881
- for(int i=0; i<=2; i++){
882
- for(int j=0; j<=2; j++){
883
- triangleMatrix[i][j] = new RPoint();
884
- }
871
+ /**
872
+ * Use this method to draw the command.
873
+ *
874
+ * @eexample drawCommand
875
+ * @param g PGraphics, the graphics object on which to draw the command
876
+ */
877
+ @Override
878
+ public void draw(PGraphics g) {
879
+ RPoint[] points = getPoints();
880
+ if (points == null) {
881
+ return;
882
+ }
883
+ g.beginShape();
884
+ for (RPoint point : points) {
885
+ g.vertex(point.x, point.y);
886
+ }
887
+ g.endShape();
885
888
  }
886
889
 
887
- RPoint[] ctrlPoints = this.getHandles();
890
+ /**
891
+ * Use this method to draw the command.
892
+ *
893
+ * @eexample drawCommand
894
+ * @param a the applet object on which to draw the command
895
+ */
896
+ @Override
897
+ public void draw(PApplet a) {
898
+ RPoint[] points = getPoints();
899
+ if (points == null) {
900
+ return;
901
+ }
888
902
 
889
- // Copy control points to triangle matrix
890
- for(int i = 0; i <= 2; i++){
891
- triangleMatrix[0][i] = ctrlPoints[i];
903
+ a.beginShape();
904
+ for (RPoint point : points) {
905
+ a.vertex(point.x, point.y);
906
+ }
907
+ a.endShape();
892
908
  }
893
909
 
894
- // Triangle computation
895
- for(int i = 1; i <= 2; i++){
896
- for(int j = 0; j <= 2 - i; j++){
897
- triangleMatrix[i][j].x = (1-t) * triangleMatrix[i-1][j].x + t * triangleMatrix[i-1][j+1].x;
898
- triangleMatrix[i][j].y = (1-t) * triangleMatrix[i-1][j].y + t * triangleMatrix[i-1][j+1].y;
899
- }
910
+ /**
911
+ * Use this to return the start, control and end points of the curve. It
912
+ * returns the points in the way of an array of RPoint.
913
+ *
914
+ * @eexample getHandles
915
+ * @return RPoint[], the vertices returned in an array.
916
+ *
917
+ */
918
+ @Override
919
+ public RPoint[] getHandles() {
920
+ RPoint[] result;
921
+ if (controlPoints == null) {
922
+ result = new RPoint[2];
923
+ result[0] = startPoint;
924
+ result[1] = endPoint;
925
+ } else {
926
+ result = new RPoint[controlPoints.length + 2];
927
+ result[0] = startPoint;
928
+ System.arraycopy(controlPoints, 0, result, 1, controlPoints.length);
929
+ result[result.length - 1] = endPoint;
930
+ }
931
+ return result;
900
932
  }
901
933
 
902
- RCommand[] result = new RCommand[2];
903
- result[0] = createBezier3(startPoint, triangleMatrix[1][0], triangleMatrix[2][0]);
904
- result[1] = createBezier3(triangleMatrix[2][0], triangleMatrix[1][1], endPoint);
905
- return result;
906
- }
934
+ /**
935
+ * Returns two commands resulting of splitting the command.
936
+ *
937
+ * @eexample split
938
+ * @param t the advancement on the curve where command should be split.
939
+ * @return RPoint[], the tangent vectors returned in an array.
940
+ *
941
+ */
942
+ public RCommand[] split(float t) {
943
+
944
+ switch (commandType) {
945
+ case LINETO:
946
+ return splitLine(t);
947
+
948
+ case QUADBEZIERTO:
949
+ return splitQuadBezier(t);
907
950
 
908
- private RCommand[] splitLine(float t){
909
- RPoint[][] triangleMatrix = new RPoint[2][2];
910
- for(int i=0; i<=1; i++){
911
- for(int j=0; j<=1; j++){
912
- triangleMatrix[i][j] = new RPoint();
913
- }
951
+ case CUBICBEZIERTO:
952
+ return splitCubicBezier(t);
953
+
954
+ }
955
+ return null;
914
956
  }
915
957
 
916
- RPoint[] ctrlPoints = this.getHandles();
958
+ /**
959
+ * Taken from: http://steve.hollasch.net/cgindex/curves/cbezarclen.html
960
+ *
961
+ * who took it from: Schneider's Bezier curve-fitter
962
+ *
963
+ */
964
+ private RCommand[] splitCubicBezier(float t) {
965
+ RPoint[][] triangleMatrix = new RPoint[4][4];
966
+ for (int i = 0; i <= 3; i++) {
967
+ for (int j = 0; j <= 3; j++) {
968
+ triangleMatrix[i][j] = new RPoint();
969
+ }
970
+ }
971
+
972
+ RPoint[] ctrlPoints = this.getHandles();
973
+
974
+ // Copy control points to triangle matrix
975
+ for (int i = 0; i <= 3; i++) {
976
+ triangleMatrix[0][i].x = ctrlPoints[i].x;
977
+ triangleMatrix[0][i].y = ctrlPoints[i].y;
978
+ }
979
+
980
+ // Triangle computation
981
+ for (int i = 1; i <= 3; i++) {
982
+ for (int j = 0; j <= 3 - i; j++) {
983
+ triangleMatrix[i][j].x = (1 - t) * triangleMatrix[i - 1][j].x + t * triangleMatrix[i - 1][j + 1].x;
984
+ triangleMatrix[i][j].y = (1 - t) * triangleMatrix[i - 1][j].y + t * triangleMatrix[i - 1][j + 1].y;
985
+ }
986
+ }
917
987
 
918
- // Copy control points to triangle matrix
919
- for(int i = 0; i <= 1; i++){
920
- triangleMatrix[0][i] = ctrlPoints[i];
988
+ RCommand[] result = new RCommand[2];
989
+ result[0] = createBezier4(startPoint, triangleMatrix[1][0], triangleMatrix[2][0], triangleMatrix[3][0]);
990
+ result[1] = createBezier4(triangleMatrix[3][0], triangleMatrix[2][1], triangleMatrix[1][2], endPoint);
991
+ return result;
921
992
  }
922
993
 
923
- // Triangle computation
924
- for(int i = 1; i <= 1; i++){
925
- for(int j = 0; j <= 1 - i; j++){
926
- triangleMatrix[i][j].x = (1-t) * triangleMatrix[i-1][j].x + t * triangleMatrix[i-1][j+1].x;
927
- triangleMatrix[i][j].y = (1-t) * triangleMatrix[i-1][j].y + t * triangleMatrix[i-1][j+1].y;
928
- }
994
+ private RCommand[] splitQuadBezier(float t) {
995
+ RPoint[][] triangleMatrix = new RPoint[3][3];
996
+ for (int i = 0; i <= 2; i++) {
997
+ for (int j = 0; j <= 2; j++) {
998
+ triangleMatrix[i][j] = new RPoint();
999
+ }
1000
+ }
1001
+
1002
+ RPoint[] ctrlPoints = this.getHandles();
1003
+
1004
+ // Copy control points to triangle matrix
1005
+ for (int i = 0; i <= 2; i++) {
1006
+ triangleMatrix[0][i] = ctrlPoints[i];
1007
+ }
1008
+
1009
+ // Triangle computation
1010
+ for (int i = 1; i <= 2; i++) {
1011
+ for (int j = 0; j <= 2 - i; j++) {
1012
+ triangleMatrix[i][j].x = (1 - t) * triangleMatrix[i - 1][j].x + t * triangleMatrix[i - 1][j + 1].x;
1013
+ triangleMatrix[i][j].y = (1 - t) * triangleMatrix[i - 1][j].y + t * triangleMatrix[i - 1][j + 1].y;
1014
+ }
1015
+ }
1016
+
1017
+ RCommand[] result = new RCommand[2];
1018
+ result[0] = createBezier3(startPoint, triangleMatrix[1][0], triangleMatrix[2][0]);
1019
+ result[1] = createBezier3(triangleMatrix[2][0], triangleMatrix[1][1], endPoint);
1020
+ return result;
929
1021
  }
930
1022
 
931
- RCommand[] result = new RCommand[2];
932
- result[0] = createLine(startPoint, triangleMatrix[1][0]);
933
- result[1] = createLine(triangleMatrix[1][0], endPoint);
934
- return result;
935
- }
1023
+ private RCommand[] splitLine(float t) {
1024
+ RPoint[][] triangleMatrix = new RPoint[2][2];
1025
+ for (int i = 0; i <= 1; i++) {
1026
+ for (int j = 0; j <= 1; j++) {
1027
+ triangleMatrix[i][j] = new RPoint();
1028
+ }
1029
+ }
1030
+
1031
+ RPoint[] ctrlPoints = this.getHandles();
1032
+
1033
+ // Copy control points to triangle matrix
1034
+ for (int i = 0; i <= 1; i++) {
1035
+ triangleMatrix[0][i] = ctrlPoints[i];
1036
+ }
936
1037
 
937
- private void quadBezierAdaptative(){
938
- addCurvePoint(new RPoint(startPoint));
939
- quadBezierAdaptativeRecursive(startPoint.x, startPoint.y, controlPoints[0].x, controlPoints[0].y, endPoint.x, endPoint.y, 0);
940
- addCurvePoint(new RPoint(endPoint));
941
- }
1038
+ // Triangle computation
1039
+ for (int i = 1; i <= 1; i++) {
1040
+ for (int j = 0; j <= 1 - i; j++) {
1041
+ triangleMatrix[i][j].x = (1 - t) * triangleMatrix[i - 1][j].x + t * triangleMatrix[i - 1][j + 1].x;
1042
+ triangleMatrix[i][j].y = (1 - t) * triangleMatrix[i - 1][j].y + t * triangleMatrix[i - 1][j + 1].y;
1043
+ }
1044
+ }
942
1045
 
943
- private void quadBezierAdaptativeRecursive(float x1, float y1, float x2, float y2, float x3, float y3, int level){
1046
+ RCommand[] result = new RCommand[2];
1047
+ result[0] = createLine(startPoint, triangleMatrix[1][0]);
1048
+ result[1] = createLine(triangleMatrix[1][0], endPoint);
1049
+ return result;
1050
+ }
944
1051
 
945
- if(level > segmentRecursionLimit)
946
- {
947
- return;
948
- }
1052
+ private void quadBezierAdaptative() {
1053
+ addCurvePoint(new RPoint(startPoint));
1054
+ quadBezierAdaptativeRecursive(startPoint.x, startPoint.y, controlPoints[0].x, controlPoints[0].y, endPoint.x, endPoint.y, 0);
1055
+ addCurvePoint(new RPoint(endPoint));
1056
+ }
1057
+
1058
+ private void quadBezierAdaptativeRecursive(float x1, float y1, float x2, float y2, float x3, float y3, int level) {
1059
+
1060
+ if (level > segmentRecursionLimit) {
1061
+ return;
1062
+ }
949
1063
 
950
1064
  // Calculate all the mid-points of the line segments
951
- //----------------------
952
- float x12 = (x1 + x2) / 2;
953
- float y12 = (y1 + y2) / 2;
954
- float x23 = (x2 + x3) / 2;
955
- float y23 = (y2 + y3) / 2;
956
- float x123 = (x12 + x23) / 2;
957
- float y123 = (y12 + y23) / 2;
958
-
959
- float dx = x3-x1;
960
- float dy = y3-y1;
961
- float d = Math.abs(((x2 - x3) * dy - (y2 - y3) * dx));
962
-
963
- if(d > segmentCollinearityEpsilon)
964
- {
1065
+ //----------------------
1066
+ float x12 = (x1 + x2) / 2;
1067
+ float y12 = (y1 + y2) / 2;
1068
+ float x23 = (x2 + x3) / 2;
1069
+ float y23 = (y2 + y3) / 2;
1070
+ float x123 = (x12 + x23) / 2;
1071
+ float y123 = (y12 + y23) / 2;
1072
+
1073
+ float dx = x3 - x1;
1074
+ float dy = y3 - y1;
1075
+ float d = Math.abs(((x2 - x3) * dy - (y2 - y3) * dx));
1076
+
1077
+ if (d > segmentCollinearityEpsilon) {
965
1078
  // Regular care
966
- //-----------------
967
- if(d * d <= segmentDistTolSqr * (dx*dx + dy*dy))
968
- {
1079
+ //-----------------
1080
+ if (d * d <= segmentDistTolSqr * (dx * dx + dy * dy)) {
969
1081
  // If the curvature doesn't exceed the distance_tolerance value
970
- // we tend to finish subdivisions.
971
- //----------------------
972
- if(segmentAngleTol < segmentAngleTolEpsilon)
973
- {
974
- addCurvePoint(new RPoint(x123, y123));
975
- return;
976
- }
1082
+ // we tend to finish subdivisions.
1083
+ //----------------------
1084
+ if (segmentAngleTol < segmentAngleTolEpsilon) {
1085
+ addCurvePoint(new RPoint(x123, y123));
1086
+ return;
1087
+ }
977
1088
 
978
1089
  // Angle & Cusp Condition
979
- //----------------------
980
- float da = Math.abs((float)Math.atan2(y3 - y2, x3 - x2) - (float)Math.atan2(y2 - y1, x2 - x1));
981
- if(da >= Math.PI) da = 2*(float)Math.PI - da;
1090
+ //----------------------
1091
+ float da = Math.abs((float) Math.atan2(y3 - y2, x3 - x2) - (float) Math.atan2(y2 - y1, x2 - x1));
1092
+ if (da >= Math.PI) {
1093
+ da = 2 * (float) Math.PI - da;
1094
+ }
982
1095
 
983
- if(da < segmentAngleTol)
984
- {
1096
+ if (da < segmentAngleTol) {
985
1097
  // Finally we can stop the recursion
986
- //----------------------
1098
+ //----------------------
1099
+ addCurvePoint(new RPoint(x123, y123));
1100
+ return;
1101
+ }
1102
+ }
1103
+ } else {
1104
+ if (Math.abs(x1 + x3 - x2 - x2) + Math.abs(y1 + y3 - y2 - y2) <= segmentDistTolMnhttn) {
987
1105
  addCurvePoint(new RPoint(x123, y123));
988
1106
  return;
989
- }
990
- }
991
- }
992
- else
993
- {
994
- if(Math.abs(x1 + x3 - x2 - x2) + Math.abs(y1 + y3 - y2 - y2) <= segmentDistTolMnhttn)
995
- {
996
- addCurvePoint(new RPoint(x123, y123));
997
- return;
998
- }
999
- }
1107
+ }
1108
+ }
1000
1109
 
1001
1110
  // Continue subdivision
1002
- //----------------------
1003
- quadBezierAdaptativeRecursive(x1, y1, x12, y12, x123, y123, level + 1);
1004
- quadBezierAdaptativeRecursive(x123, y123, x23, y23, x3, y3, level + 1);
1005
- }
1006
-
1007
- private void cubicBezierAdaptative(){
1008
- addCurvePoint(new RPoint(startPoint));
1009
- cubicBezierAdaptativeRecursive(startPoint.x, startPoint.y, controlPoints[0].x, controlPoints[0].y, controlPoints[1].x, controlPoints[1].y, endPoint.x, endPoint.y, 0);
1010
- addCurvePoint(new RPoint(endPoint));
1011
- }
1012
-
1013
- private void cubicBezierAdaptativeRecursive(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, int level){
1014
- if(level > segmentRecursionLimit)
1015
- {
1016
- return;
1017
- }
1111
+ //----------------------
1112
+ quadBezierAdaptativeRecursive(x1, y1, x12, y12, x123, y123, level + 1);
1113
+ quadBezierAdaptativeRecursive(x123, y123, x23, y23, x3, y3, level + 1);
1114
+ }
1115
+
1116
+ private void cubicBezierAdaptative() {
1117
+ addCurvePoint(new RPoint(startPoint));
1118
+ cubicBezierAdaptativeRecursive(startPoint.x, startPoint.y, controlPoints[0].x, controlPoints[0].y, controlPoints[1].x, controlPoints[1].y, endPoint.x, endPoint.y, 0);
1119
+ addCurvePoint(new RPoint(endPoint));
1120
+ }
1121
+
1122
+ private void cubicBezierAdaptativeRecursive(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, int level) {
1123
+ if (level > segmentRecursionLimit) {
1124
+ return;
1125
+ }
1018
1126
 
1019
1127
  // Calculate all the mid-points of the line segments
1020
- //----------------------
1021
- float x12 = (x1 + x2) / 2;
1022
- float y12 = (y1 + y2) / 2;
1023
- float x23 = (x2 + x3) / 2;
1024
- float y23 = (y2 + y3) / 2;
1025
- float x34 = (x3 + x4) / 2;
1026
- float y34 = (y3 + y4) / 2;
1027
- float x123 = (x12 + x23) / 2;
1028
- float y123 = (y12 + y23) / 2;
1029
- float x234 = (x23 + x34) / 2;
1030
- float y234 = (y23 + y34) / 2;
1031
- float x1234 = (x123 + x234) / 2;
1032
- float y1234 = (y123 + y234) / 2;
1128
+ //----------------------
1129
+ float x12 = (x1 + x2) / 2;
1130
+ float y12 = (y1 + y2) / 2;
1131
+ float x23 = (x2 + x3) / 2;
1132
+ float y23 = (y2 + y3) / 2;
1133
+ float x34 = (x3 + x4) / 2;
1134
+ float y34 = (y3 + y4) / 2;
1135
+ float x123 = (x12 + x23) / 2;
1136
+ float y123 = (y12 + y23) / 2;
1137
+ float x234 = (x23 + x34) / 2;
1138
+ float y234 = (y23 + y34) / 2;
1139
+ float x1234 = (x123 + x234) / 2;
1140
+ float y1234 = (y123 + y234) / 2;
1033
1141
 
1034
1142
  // Try to approximate the full cubic curve by a single straight line
1035
- //------------------
1036
- float dx = x4-x1;
1037
- float dy = y4-y1;
1038
-
1039
- float d2 = Math.abs(((x2 - x4) * dy - (y2 - y4) * dx));
1040
- float d3 = Math.abs(((x3 - x4) * dy - (y3 - y4) * dx));
1041
- float da1, da2;
1042
-
1043
- int d2b = (d2 > segmentCollinearityEpsilon)?1:0;
1044
- int d3b = (d3 > segmentCollinearityEpsilon)?1:0;
1045
- switch((d2b << 1) + d3b){
1046
- case 0:
1143
+ //------------------
1144
+ float dx = x4 - x1;
1145
+ float dy = y4 - y1;
1146
+
1147
+ float d2 = Math.abs(((x2 - x4) * dy - (y2 - y4) * dx));
1148
+ float d3 = Math.abs(((x3 - x4) * dy - (y3 - y4) * dx));
1149
+ float da1, da2;
1150
+
1151
+ int d2b = (d2 > segmentCollinearityEpsilon) ? 1 : 0;
1152
+ int d3b = (d3 > segmentCollinearityEpsilon) ? 1 : 0;
1153
+ switch ((d2b << 1) + d3b) {
1154
+ case 0:
1047
1155
  // All collinear OR p1==p4
1048
- //----------------------
1049
- if(Math.abs(x1 + x3 - x2 - x2) +
1050
- Math.abs(y1 + y3 - y2 - y2) +
1051
- Math.abs(x2 + x4 - x3 - x3) +
1052
- Math.abs(y2 + y4 - y3 - y3) <= segmentDistTolMnhttn)
1053
- {
1054
- addCurvePoint(new RPoint(x1234, y1234));
1055
- return;
1056
- }
1057
- break;
1156
+ //----------------------
1157
+ if (Math.abs(x1 + x3 - x2 - x2)
1158
+ + Math.abs(y1 + y3 - y2 - y2)
1159
+ + Math.abs(x2 + x4 - x3 - x3)
1160
+ + Math.abs(y2 + y4 - y3 - y3) <= segmentDistTolMnhttn) {
1161
+ addCurvePoint(new RPoint(x1234, y1234));
1162
+ return;
1163
+ }
1164
+ break;
1058
1165
 
1059
- case 1:
1166
+ case 1:
1060
1167
  // p1,p2,p4 are collinear, p3 is considerable
1061
- //----------------------
1062
- if(d3 * d3 <= segmentDistTolSqr * (dx*dx + dy*dy))
1063
- {
1064
- if(segmentAngleTol < segmentAngleTolEpsilon)
1065
- {
1066
- addCurvePoint(new RPoint(x23, y23));
1067
- return;
1068
- }
1168
+ //----------------------
1169
+ if (d3 * d3 <= segmentDistTolSqr * (dx * dx + dy * dy)) {
1170
+ if (segmentAngleTol < segmentAngleTolEpsilon) {
1171
+ addCurvePoint(new RPoint(x23, y23));
1172
+ return;
1173
+ }
1069
1174
 
1070
1175
  // Angle Condition
1071
- //----------------------
1072
- da1 = Math.abs((float)Math.atan2(y4 - y3, x4 - x3) - (float)Math.atan2(y3 - y2, x3 - x2));
1073
- if(da1 >= (float)Math.PI) da1 = 2*(float)Math.PI - da1;
1074
-
1075
- if(da1 < segmentAngleTol)
1076
- {
1077
- addCurvePoint(new RPoint(x2, y2));
1078
- addCurvePoint(new RPoint(x3, y3));
1079
- return;
1080
- }
1081
-
1082
- if(segmentCuspLimit != 0.0)
1083
- {
1084
- if(da1 > segmentCuspLimit)
1085
- {
1086
- addCurvePoint(new RPoint(x3, y3));
1087
- return;
1176
+ //----------------------
1177
+ da1 = Math.abs((float) Math.atan2(y4 - y3, x4 - x3) - (float) Math.atan2(y3 - y2, x3 - x2));
1178
+ if (da1 >= (float) Math.PI) {
1179
+ da1 = 2 * (float) Math.PI - da1;
1180
+ }
1181
+
1182
+ if (da1 < segmentAngleTol) {
1183
+ addCurvePoint(new RPoint(x2, y2));
1184
+ addCurvePoint(new RPoint(x3, y3));
1185
+ return;
1186
+ }
1187
+
1188
+ if (segmentCuspLimit != 0.0) {
1189
+ if (da1 > segmentCuspLimit) {
1190
+ addCurvePoint(new RPoint(x3, y3));
1191
+ return;
1192
+ }
1193
+ }
1088
1194
  }
1089
- }
1090
- }
1091
- break;
1195
+ break;
1092
1196
 
1093
- case 2:
1197
+ case 2:
1094
1198
  // p1,p3,p4 are collinear, p2 is considerable
1095
- //----------------------
1096
- if(d2 * d2 <= segmentDistTolSqr * (dx*dx + dy*dy))
1097
- {
1098
- if(segmentAngleTol < segmentAngleTolEpsilon)
1099
- {
1100
- addCurvePoint(new RPoint(x23, y23));
1101
- return;
1102
- }
1199
+ //----------------------
1200
+ if (d2 * d2 <= segmentDistTolSqr * (dx * dx + dy * dy)) {
1201
+ if (segmentAngleTol < segmentAngleTolEpsilon) {
1202
+ addCurvePoint(new RPoint(x23, y23));
1203
+ return;
1204
+ }
1103
1205
 
1104
1206
  // Angle Condition
1105
- //----------------------
1106
- da1 = Math.abs((float)Math.atan2(y3 - y2, x3 - x2) - (float)Math.atan2(y2 - y1, x2 - x1));
1107
- if(da1 >= (float)Math.PI) da1 = 2*(float)Math.PI - da1;
1108
-
1109
- if(da1 < segmentAngleTol)
1110
- {
1111
- addCurvePoint(new RPoint(x2, y2));
1112
- addCurvePoint(new RPoint(x3, y3));
1113
- return;
1114
- }
1115
-
1116
- if(segmentCuspLimit != 0.0)
1117
- {
1118
- if(da1 > segmentCuspLimit)
1119
- {
1120
- addCurvePoint(new RPoint(x2, y2));
1121
- return;
1207
+ //----------------------
1208
+ da1 = Math.abs((float) Math.atan2(y3 - y2, x3 - x2) - (float) Math.atan2(y2 - y1, x2 - x1));
1209
+ if (da1 >= (float) Math.PI) {
1210
+ da1 = 2 * (float) Math.PI - da1;
1211
+ }
1212
+
1213
+ if (da1 < segmentAngleTol) {
1214
+ addCurvePoint(new RPoint(x2, y2));
1215
+ addCurvePoint(new RPoint(x3, y3));
1216
+ return;
1217
+ }
1218
+
1219
+ if (segmentCuspLimit != 0.0) {
1220
+ if (da1 > segmentCuspLimit) {
1221
+ addCurvePoint(new RPoint(x2, y2));
1222
+ return;
1223
+ }
1224
+ }
1122
1225
  }
1123
- }
1124
- }
1125
- break;
1226
+ break;
1126
1227
 
1127
- case 3:
1228
+ case 3:
1128
1229
  // Regular care
1129
- //-----------------
1130
- if((d2 + d3)*(d2 + d3) <= segmentDistTolSqr * (dx*dx + dy*dy))
1131
- {
1230
+ //-----------------
1231
+ if ((d2 + d3) * (d2 + d3) <= segmentDistTolSqr * (dx * dx + dy * dy)) {
1132
1232
  // If the curvature doesn't exceed the distance_tolerance value
1133
- // we tend to finish subdivisions.
1134
- //----------------------
1135
- if(segmentAngleTol < segmentAngleTolEpsilon)
1136
- {
1137
- addCurvePoint(new RPoint(x23, y23));
1138
- return;
1139
- }
1233
+ // we tend to finish subdivisions.
1234
+ //----------------------
1235
+ if (segmentAngleTol < segmentAngleTolEpsilon) {
1236
+ addCurvePoint(new RPoint(x23, y23));
1237
+ return;
1238
+ }
1140
1239
 
1141
1240
  // Angle & Cusp Condition
1142
- //----------------------
1143
- float a23 = (float)Math.atan2(y3 - y2, x3 - x2);
1144
- da1 = Math.abs(a23 - (float)Math.atan2(y2 - y1, x2 - x1));
1145
- da2 = Math.abs((float)Math.atan2(y4 - y3, x4 - x3) - a23);
1146
- if(da1 >= (float)Math.PI) da1 = 2*(float)Math.PI - da1;
1147
- if(da2 >= (float)Math.PI) da2 = 2*(float)Math.PI - da2;
1148
-
1149
- if(da1 + da2 < segmentAngleTol)
1150
- {
1241
+ //----------------------
1242
+ float a23 = (float) Math.atan2(y3 - y2, x3 - x2);
1243
+ da1 = Math.abs(a23 - (float) Math.atan2(y2 - y1, x2 - x1));
1244
+ da2 = Math.abs((float) Math.atan2(y4 - y3, x4 - x3) - a23);
1245
+ if (da1 >= (float) Math.PI) {
1246
+ da1 = 2 * (float) Math.PI - da1;
1247
+ }
1248
+ if (da2 >= (float) Math.PI) {
1249
+ da2 = 2 * (float) Math.PI - da2;
1250
+ }
1251
+
1252
+ if (da1 + da2 < segmentAngleTol) {
1151
1253
  // Finally we can stop the recursion
1152
- //----------------------
1153
- addCurvePoint(new RPoint(x23, y23));
1154
- return;
1155
- }
1156
-
1157
- if(segmentCuspLimit != 0.0)
1158
- {
1159
- if(da1 > segmentCuspLimit)
1160
- {
1161
- addCurvePoint(new RPoint(x2, y2));
1162
- return;
1254
+ //----------------------
1255
+ addCurvePoint(new RPoint(x23, y23));
1256
+ return;
1257
+ }
1258
+
1259
+ if (segmentCuspLimit != 0.0) {
1260
+ if (da1 > segmentCuspLimit) {
1261
+ addCurvePoint(new RPoint(x2, y2));
1262
+ return;
1263
+ }
1264
+
1265
+ if (da2 > segmentCuspLimit) {
1266
+ addCurvePoint(new RPoint(x3, y3));
1267
+ return;
1268
+ }
1269
+ }
1163
1270
  }
1164
-
1165
- if(da2 > segmentCuspLimit)
1166
- {
1167
- addCurvePoint(new RPoint(x3, y3));
1168
- return;
1169
- }
1170
- }
1271
+ break;
1171
1272
  }
1172
- break;
1173
- }
1174
1273
 
1175
1274
  // Continue subdivision
1176
- //----------------------
1177
- cubicBezierAdaptativeRecursive(x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1);
1178
- cubicBezierAdaptativeRecursive(x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1);
1179
- }
1275
+ //----------------------
1276
+ cubicBezierAdaptativeRecursive(x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1);
1277
+ cubicBezierAdaptativeRecursive(x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1);
1278
+ }
1180
1279
 
1181
- private void lineUniformStep(){
1182
- // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1183
- int steps = segmentSteps;
1184
- if(segmentSteps==0.0F){
1185
- float dx = endPoint.x - startPoint.x;
1186
- float dy = endPoint.y - startPoint.y;
1280
+ private void lineUniformStep() {
1281
+ // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1282
+ int steps = segmentSteps;
1283
+ if (segmentSteps == 0.0F) {
1284
+ float dx = endPoint.x - startPoint.x;
1285
+ float dy = endPoint.y - startPoint.y;
1187
1286
 
1188
- float len = (float)Math.sqrt(dx * dx + dy * dy);
1189
- steps = (int)(len * 0.25);
1287
+ float len = (float) Math.sqrt(dx * dx + dy * dy);
1288
+ steps = (int) (len * 0.25);
1190
1289
 
1191
- if(steps < 4) steps = 4;
1192
- }
1290
+ if (steps < 4) {
1291
+ steps = 4;
1292
+ }
1293
+ }
1193
1294
 
1194
- float dt = 1F/steps;
1295
+ float dt = 1F / steps;
1195
1296
 
1196
- float fx, fy, fdx, fdy;
1297
+ float fx, fy, fdx, fdy;
1197
1298
 
1198
- fx = startPoint.x;
1199
- fdx = (endPoint.x - startPoint.x) * dt;
1299
+ fx = startPoint.x;
1300
+ fdx = (endPoint.x - startPoint.x) * dt;
1200
1301
 
1201
- fy = startPoint.y;
1202
- fdy = (endPoint.y - startPoint.y) * dt;
1302
+ fy = startPoint.y;
1303
+ fdy = (endPoint.y - startPoint.y) * dt;
1203
1304
 
1204
- for (int loop=0; loop < steps; loop++) {
1205
- addCurvePoint(new RPoint(fx,fy));
1305
+ for (int loop = 0; loop < steps; loop++) {
1306
+ addCurvePoint(new RPoint(fx, fy));
1206
1307
 
1207
- fx = fx + fdx;
1308
+ fx = fx + fdx;
1208
1309
 
1209
- fy = fy + fdy;
1310
+ fy = fy + fdy;
1311
+ }
1312
+ addCurvePoint(new RPoint(endPoint));
1210
1313
  }
1211
- addCurvePoint(new RPoint(endPoint));
1212
- }
1213
1314
 
1214
- private void cubicBezierUniformStep(){
1315
+ private void cubicBezierUniformStep() {
1316
+
1317
+ // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1318
+ int steps = segmentSteps;
1319
+ if (segmentSteps == 0.0F) {
1320
+ float dx1 = controlPoints[0].x - startPoint.x;
1321
+ float dy1 = controlPoints[0].y - startPoint.y;
1322
+ float dx2 = controlPoints[1].x - controlPoints[0].x;
1323
+ float dy2 = controlPoints[1].y - controlPoints[0].y;
1324
+ float dx3 = endPoint.x - controlPoints[1].x;
1325
+ float dy3 = endPoint.y - controlPoints[1].y;
1215
1326
 
1216
- // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1217
- int steps = segmentSteps;
1218
- if(segmentSteps==0.0F){
1219
- float dx1 = controlPoints[0].x - startPoint.x;
1220
- float dy1 = controlPoints[0].y - startPoint.y;
1221
- float dx2 = controlPoints[1].x - controlPoints[0].x;
1222
- float dy2 = controlPoints[1].y - controlPoints[0].y;
1223
- float dx3 = endPoint.x - controlPoints[1].x;
1224
- float dy3 = endPoint.y - controlPoints[1].y;
1327
+ float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1)
1328
+ + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2)
1329
+ + (float) Math.sqrt(dx3 * dx3 + dy3 * dy3);
1225
1330
 
1226
- float len = (float)Math.sqrt(dx1 * dx1 + dy1 * dy1) +
1227
- (float)Math.sqrt(dx2 * dx2 + dy2 * dy2) +
1228
- (float)Math.sqrt(dx3 * dx3 + dy3 * dy3);
1331
+ steps = (int) (len * 0.25);
1229
1332
 
1230
- steps = (int)(len * 0.25);
1333
+ if (steps < 4) {
1334
+ steps = 4;
1335
+ }
1336
+ }
1231
1337
 
1232
- if(steps < 4)
1233
- {
1234
- steps = 4;
1338
+ float dt = 1F / steps;
1339
+
1340
+ float fx, fy, fdx, fdy, fddx, fddy, fdddx, fdddy, fdd_per_2x, fdd_per_2y, fddd_per_2x, fddd_per_2y, fddd_per_6x, fddd_per_6y;
1341
+ float temp = dt * dt;
1342
+
1343
+ fx = startPoint.x;
1344
+ fdx = 3F * (controlPoints[0].x - startPoint.x) * dt;
1345
+ fdd_per_2x = 3F * (startPoint.x - 2F * controlPoints[0].x + controlPoints[1].x) * temp;
1346
+ fddd_per_2x = 3F * (3F * (controlPoints[0].x - controlPoints[1].x) + endPoint.x - startPoint.x) * temp * dt;
1347
+ fdddx = fddd_per_2x + fddd_per_2x;
1348
+ fddx = fdd_per_2x + fdd_per_2x;
1349
+ fddd_per_6x = fddd_per_2x * (1.0F / 3F);
1350
+
1351
+ fy = startPoint.y;
1352
+ fdy = 3F * (controlPoints[0].y - startPoint.y) * dt;
1353
+ fdd_per_2y = 3F * (startPoint.y - 2F * controlPoints[0].y + controlPoints[1].y) * temp;
1354
+ fddd_per_2y = 3F * (3F * (controlPoints[0].y - controlPoints[1].y) + endPoint.y - startPoint.y) * temp * dt;
1355
+ fdddy = fddd_per_2y + fddd_per_2y;
1356
+ fddy = fdd_per_2y + fdd_per_2y;
1357
+ fddd_per_6y = fddd_per_2y * (1.0F / 3F);
1358
+
1359
+ for (int loop = 0; loop < steps; loop++) {
1360
+ addCurvePoint(new RPoint(fx, fy));
1361
+
1362
+ fx = fx + fdx + fdd_per_2x + fddd_per_6x;
1363
+ fdx = fdx + fddx + fddd_per_2x;
1364
+ fddx = fddx + fdddx;
1365
+ fdd_per_2x = fdd_per_2x + fddd_per_2x;
1366
+
1367
+ fy = fy + fdy + fdd_per_2y + fddd_per_6y;
1368
+ fdy = fdy + fddy + fddd_per_2y;
1369
+ fddy = fddy + fdddy;
1370
+ fdd_per_2y = fdd_per_2y + fddd_per_2y;
1235
1371
  }
1372
+ addCurvePoint(new RPoint(endPoint));
1236
1373
  }
1237
1374
 
1238
- float dt = 1F/steps;
1375
+ private void quadBezierUniformStep() {
1376
+ // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1377
+ int steps = segmentSteps;
1378
+ if (segmentSteps == 0.0F) {
1379
+ float dx1 = controlPoints[0].x - startPoint.x;
1380
+ float dy1 = controlPoints[0].y - startPoint.y;
1381
+ float dx2 = endPoint.x - controlPoints[0].x;
1382
+ float dy2 = endPoint.y - controlPoints[0].y;
1239
1383
 
1240
- float fx, fy, fdx, fdy, fddx, fddy, fdddx, fdddy, fdd_per_2x, fdd_per_2y, fddd_per_2x, fddd_per_2y, fddd_per_6x, fddd_per_6y;
1241
- float temp = dt * dt;
1384
+ float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1) + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2);
1385
+ steps = (int) (len * 0.25);
1242
1386
 
1243
- fx = startPoint.x;
1244
- fdx = 3F * (controlPoints[0].x - startPoint.x) * dt;
1245
- fdd_per_2x = 3F * (startPoint.x - 2F * controlPoints[0].x + controlPoints[1].x) * temp;
1246
- fddd_per_2x = 3F * (3F * (controlPoints[0].x - controlPoints[1].x) + endPoint.x - startPoint.x) * temp * dt;
1247
- fdddx = fddd_per_2x + fddd_per_2x;
1248
- fddx = fdd_per_2x + fdd_per_2x;
1249
- fddd_per_6x = fddd_per_2x * (1.0F / 3F);
1387
+ if (steps < 4) {
1388
+ steps = 4;
1389
+ }
1390
+ }
1250
1391
 
1251
- fy = startPoint.y;
1252
- fdy = 3F * (controlPoints[0].y - startPoint.y) * dt;
1253
- fdd_per_2y = 3F * (startPoint.y - 2F * controlPoints[0].y + controlPoints[1].y) * temp;
1254
- fddd_per_2y = 3F * (3F * (controlPoints[0].y - controlPoints[1].y) + endPoint.y - startPoint.y) * temp * dt;
1255
- fdddy = fddd_per_2y + fddd_per_2y;
1256
- fddy = fdd_per_2y + fdd_per_2y;
1257
- fddd_per_6y = fddd_per_2y * (1.0F / 3F);
1392
+ float dt = 1F / steps;
1258
1393
 
1259
- for (int loop=0; loop < steps; loop++) {
1260
- addCurvePoint(new RPoint(fx,fy));
1394
+ float fx, fy, fdx, fdy, fddx, fddy, fdd_per_2x, fdd_per_2y;
1395
+ float temp = dt * dt;
1261
1396
 
1262
- fx = fx + fdx + fdd_per_2x + fddd_per_6x;
1263
- fdx = fdx + fddx + fddd_per_2x;
1264
- fddx = fddx + fdddx;
1265
- fdd_per_2x = fdd_per_2x + fddd_per_2x;
1397
+ fx = startPoint.x;
1398
+ fdx = 2F * (controlPoints[0].x - startPoint.x) * dt;
1399
+ fdd_per_2x = (startPoint.x - 2F * controlPoints[0].x + endPoint.x) * temp;
1400
+ fddx = fdd_per_2x + fdd_per_2x;
1266
1401
 
1267
- fy = fy + fdy + fdd_per_2y + fddd_per_6y;
1268
- fdy = fdy + fddy + fddd_per_2y;
1269
- fddy = fddy + fdddy;
1270
- fdd_per_2y = fdd_per_2y + fddd_per_2y;
1271
- }
1272
- addCurvePoint(new RPoint(endPoint));
1273
- }
1402
+ fy = startPoint.y;
1403
+ fdy = 2F * (controlPoints[0].y - startPoint.y) * dt;
1404
+ fdd_per_2y = (startPoint.y - 2F * controlPoints[0].y + endPoint.y) * temp;
1405
+ fddy = fdd_per_2y + fdd_per_2y;
1274
1406
 
1275
- private void quadBezierUniformStep(){
1276
- // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1277
- int steps = segmentSteps;
1278
- if(segmentSteps==0.0F){
1279
- float dx1 = controlPoints[0].x - startPoint.x;
1280
- float dy1 = controlPoints[0].y - startPoint.y;
1281
- float dx2 = endPoint.x - controlPoints[0].x;
1282
- float dy2 = endPoint.y - controlPoints[0].y;
1407
+ for (int loop = 0; loop < steps; loop++) {
1408
+ addCurvePoint(new RPoint(fx, fy));
1283
1409
 
1284
- float len = (float)Math.sqrt(dx1 * dx1 + dy1 * dy1) + (float)Math.sqrt(dx2 * dx2 + dy2 * dy2);
1285
- steps = (int)(len * 0.25);
1410
+ fx = fx + fdx + fdd_per_2x;
1411
+ fdx = fdx + fddx;
1286
1412
 
1287
- if(steps < 4) steps = 4;
1413
+ fy = fy + fdy + fdd_per_2y;
1414
+ fdy = fdy + fddy;
1415
+ }
1416
+ addCurvePoint(new RPoint(endPoint));
1288
1417
  }
1289
1418
 
1290
- float dt = 1F/steps;
1419
+ // Use Horner's method to advance
1420
+ //----------------------
1421
+ private void lineUniformLength() {
1422
+
1423
+ // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1424
+ float dx1 = endPoint.x - startPoint.x;
1425
+ float dy1 = endPoint.y - startPoint.y;
1426
+
1427
+ float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1);
1428
+ float steps = (int) (len * 2);
1291
1429
 
1292
- float fx, fy, fdx, fdy, fddx, fddy, fdd_per_2x, fdd_per_2y;
1293
- float temp = dt * dt;
1430
+ if (steps < 4) {
1431
+ steps = 4;
1432
+ }
1433
+
1434
+ // This holds the amount of steps used to calculate segment lengths
1435
+ float dt = 1F / steps;
1294
1436
 
1295
- fx = startPoint.x;
1296
- fdx = 2F * (controlPoints[0].x - startPoint.x) * dt;
1297
- fdd_per_2x = (startPoint.x - 2F * controlPoints[0].x + endPoint.x) * temp;
1298
- fddx = fdd_per_2x + fdd_per_2x;
1437
+ // This holds how much length has to bee advanced until adding a point
1438
+ float untilPoint = RCommand.segmentAccOffset;
1299
1439
 
1300
- fy = startPoint.y;
1301
- fdy = 2F * (controlPoints[0].y - startPoint.y) * dt;
1302
- fdd_per_2y = (startPoint.y - 2F * controlPoints[0].y + endPoint.y) * temp;
1303
- fddy = fdd_per_2y + fdd_per_2y;
1440
+ float fx, fy, fdx, fdy;
1304
1441
 
1305
- for (int loop=0; loop < steps; loop++) {
1306
- addCurvePoint(new RPoint(fx,fy));
1442
+ fx = startPoint.x;
1443
+ fdx = (endPoint.x - startPoint.x) * dt;
1307
1444
 
1308
- fx = fx + fdx + fdd_per_2x;
1309
- fdx = fdx + fddx;
1445
+ fy = startPoint.y;
1446
+ fdy = (endPoint.y - startPoint.y) * dt;
1310
1447
 
1311
- fy = fy + fdy + fdd_per_2y;
1312
- fdy = fdy + fddy;
1448
+ for (int loop = 0; loop <= steps; loop++) {
1449
+ /* Add point to curve if segment length is reached */
1450
+ if (untilPoint <= 0) {
1451
+ addCurvePoint(new RPoint(fx, fy));
1452
+ untilPoint += RCommand.segmentLength;
1453
+ }
1454
+
1455
+ /* Add segment differential to segment length */
1456
+ untilPoint -= (float) Math.sqrt(fdx * fdx + fdy * fdy); // Eventually try other distance measures
1457
+
1458
+ fx = fx + fdx;
1459
+ fy = fy + fdy;
1460
+ }
1461
+
1462
+ //addCurvePoint(new RPoint(endPoint));
1463
+ RCommand.segmentAccOffset = untilPoint;
1313
1464
  }
1314
- addCurvePoint(new RPoint(endPoint));
1315
- }
1316
1465
 
1317
1466
  // Use Horner's method to advance
1318
- //----------------------
1319
- private void lineUniformLength(){
1467
+ //----------------------
1468
+ private void quadBezierUniformLength() {
1320
1469
 
1321
- // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1322
- float dx1 = endPoint.x - startPoint.x;
1323
- float dy1 = endPoint.y - startPoint.y;
1470
+ float dx1 = controlPoints[0].x - startPoint.x;
1471
+ float dy1 = controlPoints[0].y - startPoint.y;
1472
+ float dx2 = endPoint.x - controlPoints[0].x;
1473
+ float dy2 = endPoint.y - controlPoints[0].y;
1474
+ float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1) + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2);
1475
+ float steps = (int) (len * 2);
1324
1476
 
1325
- float len = (float)Math.sqrt(dx1 * dx1 + dy1 * dy1);
1326
- float steps = (int)(len * 2);
1477
+ if (steps < 4) {
1478
+ steps = 4;
1479
+ }
1327
1480
 
1328
- if(steps < 4) steps = 4;
1481
+ float dt = 1F / steps;
1482
+ float untilPoint = RCommand.segmentAccOffset;
1329
1483
 
1330
- // This holds the amount of steps used to calculate segment lengths
1331
- float dt = 1F/steps;
1484
+ float fx, fy, fdx, fdy, fddx, fddy, fdd_per_2x, fdd_per_2y, fix, fiy;
1485
+ float temp = dt * dt;
1332
1486
 
1333
- // This holds how much length has to bee advanced until adding a point
1334
- float untilPoint = RCommand.segmentAccOffset;
1487
+ fx = startPoint.x;
1488
+ fdx = 2F * (controlPoints[0].x - startPoint.x) * dt;
1489
+ fdd_per_2x = (startPoint.x - 2F * controlPoints[0].x + endPoint.x) * temp;
1490
+ fddx = fdd_per_2x + fdd_per_2x;
1335
1491
 
1336
- float fx, fy, fdx, fdy;
1492
+ fy = startPoint.y;
1493
+ fdy = 2F * (controlPoints[0].y - startPoint.y) * dt;
1494
+ fdd_per_2y = (startPoint.y - 2F * controlPoints[0].y + endPoint.y) * temp;
1495
+ fddy = fdd_per_2y + fdd_per_2y;
1337
1496
 
1338
- fx = startPoint.x;
1339
- fdx = (endPoint.x - startPoint.x) * dt;
1497
+ for (int loop = 0; loop <= steps; loop++) {
1498
+ /* Add point to curve if segment length is reached */
1499
+ if (untilPoint <= 0) {
1500
+ addCurvePoint(new RPoint(fx, fy));
1501
+ untilPoint += RCommand.segmentLength;
1502
+ }
1340
1503
 
1341
- fy = startPoint.y;
1342
- fdy = (endPoint.y - startPoint.y) * dt;
1504
+ /* Add segment differential to segment length */
1505
+ fix = fdx + fdd_per_2x;
1506
+ fiy = fdy + fdd_per_2y;
1507
+ untilPoint -= (float) Math.sqrt(fix * fix + fiy * fiy); // Eventually try other distance measures
1343
1508
 
1344
- for (int loop=0; loop <= steps; loop++) {
1345
- /* Add point to curve if segment length is reached */
1346
- if (untilPoint <= 0) {
1347
- addCurvePoint(new RPoint(fx, fy));
1348
- untilPoint += RCommand.segmentLength;
1349
- }
1509
+ fx = fx + fix;
1510
+ fdx = fdx + fddx;
1350
1511
 
1351
- /* Add segment differential to segment length */
1352
- untilPoint -= (float)Math.sqrt(fdx*fdx + fdy*fdy); // Eventually try other distance measures
1512
+ fy = fy + fiy;
1513
+ fdy = fdy + fddy;
1514
+ }
1353
1515
 
1354
- fx = fx + fdx;
1355
- fy = fy + fdy;
1516
+ //addCurvePoint(new RPoint(endPoint));
1517
+ RCommand.segmentAccOffset = untilPoint;
1356
1518
  }
1357
1519
 
1358
- //addCurvePoint(new RPoint(endPoint));
1359
- RCommand.segmentAccOffset = untilPoint;
1360
- }
1361
-
1362
1520
  // Use Horner's method to advance
1363
- //----------------------
1364
- private void quadBezierUniformLength(){
1365
-
1366
- float dx1 = controlPoints[0].x - startPoint.x;
1367
- float dy1 = controlPoints[0].y - startPoint.y;
1368
- float dx2 = endPoint.x - controlPoints[0].x;
1369
- float dy2 = endPoint.y - controlPoints[0].y;
1370
- float len = (float)Math.sqrt(dx1 * dx1 + dy1 * dy1) + (float)Math.sqrt(dx2 * dx2 + dy2 * dy2);
1371
- float steps = (int)(len * 2);
1372
-
1373
- if(steps < 4) steps = 4;
1521
+ //----------------------
1522
+ private void cubicBezierUniformLength() {
1523
+
1524
+ float dx1 = controlPoints[0].x - startPoint.x;
1525
+ float dy1 = controlPoints[0].y - startPoint.y;
1526
+ float dx2 = controlPoints[1].x - controlPoints[0].x;
1527
+ float dy2 = controlPoints[1].y - controlPoints[0].y;
1528
+ float dx3 = endPoint.x - controlPoints[1].x;
1529
+ float dy3 = endPoint.y - controlPoints[1].y;
1530
+
1531
+ float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1)
1532
+ + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2)
1533
+ + (float) Math.sqrt(dx3 * dx3 + dy3 * dy3);
1534
+ float steps = (int) (len * 2);
1535
+
1536
+ if (steps < 4) {
1537
+ steps = 4;
1538
+ }
1374
1539
 
1375
- float dt = 1F/steps;
1376
- float untilPoint = RCommand.segmentAccOffset;
1540
+ float dt = 1F / steps;
1541
+ float untilPoint = RCommand.segmentAccOffset;
1542
+
1543
+ float fx, fy, fdx, fdy, fddx, fddy, fdddx, fdddy, fdd_per_2x, fdd_per_2y, fddd_per_2x, fddd_per_2y, fddd_per_6x, fddd_per_6y, fix, fiy;
1544
+ float temp = dt * dt;
1545
+
1546
+ fx = startPoint.x;
1547
+ fdx = 3F * (controlPoints[0].x - startPoint.x) * dt;
1548
+ fdd_per_2x = 3F * (startPoint.x - 2F * controlPoints[0].x + controlPoints[1].x) * temp;
1549
+ fddd_per_2x = 3F * (3F * (controlPoints[0].x - controlPoints[1].x) + endPoint.x - startPoint.x) * temp * dt;
1550
+ fdddx = fddd_per_2x + fddd_per_2x;
1551
+ fddx = fdd_per_2x + fdd_per_2x;
1552
+ fddd_per_6x = fddd_per_2x * (1.0F / 3F);
1553
+
1554
+ fy = startPoint.y;
1555
+ fdy = 3F * (controlPoints[0].y - startPoint.y) * dt;
1556
+ fdd_per_2y = 3F * (startPoint.y - 2F * controlPoints[0].y + controlPoints[1].y) * temp;
1557
+ fddd_per_2y = 3F * (3F * (controlPoints[0].y - controlPoints[1].y) + endPoint.y - startPoint.y) * temp * dt;
1558
+ fdddy = fddd_per_2y + fddd_per_2y;
1559
+ fddy = fdd_per_2y + fdd_per_2y;
1560
+ fddd_per_6y = fddd_per_2y * (1.0F / 3F);
1561
+
1562
+ for (int loop = 0; loop < steps; loop++) {
1563
+ /* Add point to curve if segment length is reached */
1564
+ if (untilPoint <= 0) {
1565
+ addCurvePoint(new RPoint(fx, fy));
1566
+ untilPoint += RCommand.segmentLength;
1567
+ }
1377
1568
 
1378
- float fx, fy, fdx, fdy, fddx, fddy, fdd_per_2x, fdd_per_2y, fix, fiy;
1379
- float temp = dt * dt;
1569
+ /* Add segment differential to segment length */
1570
+ fix = fdx + fdd_per_2x + fddd_per_6x;
1571
+ fiy = fdy + fdd_per_2y + fddd_per_6y;
1572
+ untilPoint -= (float) Math.sqrt(fix * fix + fiy * fiy); // Eventually try other distance measures
1380
1573
 
1381
- fx = startPoint.x;
1382
- fdx = 2F * (controlPoints[0].x - startPoint.x) * dt;
1383
- fdd_per_2x = (startPoint.x - 2F * controlPoints[0].x + endPoint.x) * temp;
1384
- fddx = fdd_per_2x + fdd_per_2x;
1574
+ fx = fx + fix;
1575
+ fdx = fdx + fddx + fddd_per_2x;
1576
+ fddx = fddx + fdddx;
1577
+ fdd_per_2x = fdd_per_2x + fddd_per_2x;
1385
1578
 
1386
- fy = startPoint.y;
1387
- fdy = 2F * (controlPoints[0].y - startPoint.y) * dt;
1388
- fdd_per_2y = (startPoint.y - 2F * controlPoints[0].y + endPoint.y) * temp;
1389
- fddy = fdd_per_2y + fdd_per_2y;
1579
+ fy = fy + fiy;
1580
+ fdy = fdy + fddy + fddd_per_2y;
1581
+ fddy = fddy + fdddy;
1582
+ fdd_per_2y = fdd_per_2y + fddd_per_2y;
1583
+ }
1390
1584
 
1391
- for (int loop=0; loop <= steps; loop++) {
1392
- /* Add point to curve if segment length is reached */
1393
- if (untilPoint <= 0) {
1394
- addCurvePoint(new RPoint(fx, fy));
1395
- untilPoint += RCommand.segmentLength;
1396
- }
1585
+ //addCurvePoint(new RPoint(endPoint));
1586
+ RCommand.segmentAccOffset = untilPoint;
1587
+ }
1397
1588
 
1398
- /* Add segment differential to segment length */
1399
- fix = fdx + fdd_per_2x;
1400
- fiy = fdy + fdd_per_2y;
1401
- untilPoint -= (float)Math.sqrt(fix*fix + fiy*fiy); // Eventually try other distance measures
1589
+ private float quadBezierLength() {
1402
1590
 
1403
- fx = fx + fix;
1404
- fdx = fdx + fddx;
1591
+ float dx1 = controlPoints[0].x - startPoint.x;
1592
+ float dy1 = controlPoints[0].y - startPoint.y;
1593
+ float dx2 = endPoint.x - controlPoints[0].x;
1594
+ float dy2 = endPoint.y - controlPoints[0].y;
1595
+ float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1) + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2);
1596
+ float steps = (int) (len * 2);
1405
1597
 
1406
- fy = fy + fiy;
1407
- fdy = fdy + fddy;
1408
- }
1598
+ if (steps < 4) {
1599
+ steps = 4;
1600
+ }
1409
1601
 
1410
- //addCurvePoint(new RPoint(endPoint));
1411
- RCommand.segmentAccOffset = untilPoint;
1412
- }
1602
+ float dt = 1F / steps;
1413
1603
 
1414
- // Use Horner's method to advance
1415
- //----------------------
1416
- private void cubicBezierUniformLength(){
1417
-
1418
- float dx1 = controlPoints[0].x - startPoint.x;
1419
- float dy1 = controlPoints[0].y - startPoint.y;
1420
- float dx2 = controlPoints[1].x - controlPoints[0].x;
1421
- float dy2 = controlPoints[1].y - controlPoints[0].y;
1422
- float dx3 = endPoint.x - controlPoints[1].x;
1423
- float dy3 = endPoint.y - controlPoints[1].y;
1604
+ float fx, fy, fdx, fdy, fddx, fddy, fdd_per_2x, fdd_per_2y, fix, fiy;
1605
+ float temp = dt * dt;
1606
+ float totallen = 0F;
1424
1607
 
1425
- float len = (float)Math.sqrt(dx1 * dx1 + dy1 * dy1) +
1426
- (float)Math.sqrt(dx2 * dx2 + dy2 * dy2) +
1427
- (float)Math.sqrt(dx3 * dx3 + dy3 * dy3);
1428
- float steps = (int)(len * 2);
1608
+ fx = startPoint.x;
1609
+ fdx = 2F * (controlPoints[0].x - startPoint.x) * dt;
1610
+ fdd_per_2x = (startPoint.x - 2F * controlPoints[0].x + endPoint.x) * temp;
1611
+ fddx = fdd_per_2x + fdd_per_2x;
1429
1612
 
1430
- if(steps < 4) steps = 4;
1613
+ fy = startPoint.y;
1614
+ fdy = 2F * (controlPoints[0].y - startPoint.y) * dt;
1615
+ fdd_per_2y = (startPoint.y - 2F * controlPoints[0].y + endPoint.y) * temp;
1616
+ fddy = fdd_per_2y + fdd_per_2y;
1431
1617
 
1432
- float dt = 1F/steps;
1433
- float untilPoint = RCommand.segmentAccOffset;
1618
+ for (int loop = 0; loop <= steps; loop++) {
1619
+ /* Add segment differential to segment length */
1620
+ fix = fdx + fdd_per_2x;
1621
+ fiy = fdy + fdd_per_2y;
1622
+ totallen += (float) Math.sqrt(fix * fix + fiy * fiy); // Eventually try other distance measures
1434
1623
 
1435
- float fx, fy, fdx, fdy, fddx, fddy, fdddx, fdddy, fdd_per_2x, fdd_per_2y, fddd_per_2x, fddd_per_2y, fddd_per_6x, fddd_per_6y, fix, fiy;
1436
- float temp = dt * dt;
1624
+ fx = fx + fix;
1625
+ fdx = fdx + fddx;
1437
1626
 
1438
- fx = startPoint.x;
1439
- fdx = 3F * (controlPoints[0].x - startPoint.x) * dt;
1440
- fdd_per_2x = 3F * (startPoint.x - 2F * controlPoints[0].x + controlPoints[1].x) * temp;
1441
- fddd_per_2x = 3F * (3F * (controlPoints[0].x - controlPoints[1].x) + endPoint.x - startPoint.x) * temp * dt;
1442
- fdddx = fddd_per_2x + fddd_per_2x;
1443
- fddx = fdd_per_2x + fdd_per_2x;
1444
- fddd_per_6x = fddd_per_2x * (1.0F / 3F);
1627
+ fy = fy + fiy;
1628
+ fdy = fdy + fddy;
1629
+ }
1445
1630
 
1446
- fy = startPoint.y;
1447
- fdy = 3F * (controlPoints[0].y - startPoint.y) * dt;
1448
- fdd_per_2y = 3F * (startPoint.y - 2F * controlPoints[0].y + controlPoints[1].y) * temp;
1449
- fddd_per_2y = 3F * (3F * (controlPoints[0].y - controlPoints[1].y) + endPoint.y - startPoint.y) * temp * dt;
1450
- fdddy = fddd_per_2y + fddd_per_2y;
1451
- fddy = fdd_per_2y + fdd_per_2y;
1452
- fddd_per_6y = fddd_per_2y * (1.0F / 3F);
1631
+ return totallen;
1632
+ }
1453
1633
 
1454
- for (int loop=0; loop < steps; loop++) {
1455
- /* Add point to curve if segment length is reached */
1456
- if (untilPoint <= 0) {
1457
- addCurvePoint(new RPoint(fx, fy));
1458
- untilPoint += RCommand.segmentLength;
1459
- }
1634
+ private float cubicBezierLength() {
1460
1635
 
1461
- /* Add segment differential to segment length */
1462
- fix = fdx + fdd_per_2x + fddd_per_6x;
1463
- fiy = fdy + fdd_per_2y + fddd_per_6y;
1464
- untilPoint -= (float)Math.sqrt(fix*fix + fiy*fiy); // Eventually try other distance measures
1636
+ float dx1 = controlPoints[0].x - startPoint.x;
1637
+ float dy1 = controlPoints[0].y - startPoint.y;
1638
+ float dx2 = controlPoints[1].x - controlPoints[0].x;
1639
+ float dy2 = controlPoints[1].y - controlPoints[0].y;
1640
+ float dx3 = endPoint.x - controlPoints[1].x;
1641
+ float dy3 = endPoint.y - controlPoints[1].y;
1465
1642
 
1466
- fx = fx + fix;
1467
- fdx = fdx + fddx + fddd_per_2x;
1468
- fddx = fddx + fdddx;
1469
- fdd_per_2x = fdd_per_2x + fddd_per_2x;
1470
-
1471
- fy = fy + fiy;
1472
- fdy = fdy + fddy + fddd_per_2y;
1473
- fddy = fddy + fdddy;
1474
- fdd_per_2y = fdd_per_2y + fddd_per_2y;
1475
- }
1476
-
1477
- //addCurvePoint(new RPoint(endPoint));
1478
- RCommand.segmentAccOffset = untilPoint;
1479
- }
1480
-
1481
- private float quadBezierLength(){
1482
-
1483
- float dx1 = controlPoints[0].x - startPoint.x;
1484
- float dy1 = controlPoints[0].y - startPoint.y;
1485
- float dx2 = endPoint.x - controlPoints[0].x;
1486
- float dy2 = endPoint.y - controlPoints[0].y;
1487
- float len = (float)Math.sqrt(dx1 * dx1 + dy1 * dy1) + (float)Math.sqrt(dx2 * dx2 + dy2 * dy2);
1488
- float steps = (int)(len * 2);
1643
+ float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1)
1644
+ + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2)
1645
+ + (float) Math.sqrt(dx3 * dx3 + dy3 * dy3);
1646
+ float steps = (int) (len * 2);
1489
1647
 
1490
- if(steps < 4) steps = 4;
1491
-
1492
- float dt = 1F/steps;
1493
-
1494
-
1495
- float fx, fy, fdx, fdy, fddx, fddy, fdd_per_2x, fdd_per_2y, fix, fiy;
1496
- float temp = dt * dt;
1497
- float totallen = 0F;
1498
-
1499
- fx = startPoint.x;
1500
- fdx = 2F * (controlPoints[0].x - startPoint.x) * dt;
1501
- fdd_per_2x = (startPoint.x - 2F * controlPoints[0].x + endPoint.x) * temp;
1502
- fddx = fdd_per_2x + fdd_per_2x;
1503
-
1504
- fy = startPoint.y;
1505
- fdy = 2F * (controlPoints[0].y - startPoint.y) * dt;
1506
- fdd_per_2y = (startPoint.y - 2F * controlPoints[0].y + endPoint.y) * temp;
1507
- fddy = fdd_per_2y + fdd_per_2y;
1508
-
1509
- for (int loop=0; loop <= steps; loop++) {
1510
- /* Add segment differential to segment length */
1511
- fix = fdx + fdd_per_2x;
1512
- fiy = fdy + fdd_per_2y;
1513
- totallen += (float)Math.sqrt(fix*fix + fiy*fiy); // Eventually try other distance measures
1514
-
1515
- fx = fx + fix;
1516
- fdx = fdx + fddx;
1517
-
1518
- fy = fy + fiy;
1519
- fdy = fdy + fddy;
1520
- }
1521
-
1522
- return totallen;
1523
- }
1524
-
1525
-
1526
- private float cubicBezierLength(){
1527
-
1528
- float dx1 = controlPoints[0].x - startPoint.x;
1529
- float dy1 = controlPoints[0].y - startPoint.y;
1530
- float dx2 = controlPoints[1].x - controlPoints[0].x;
1531
- float dy2 = controlPoints[1].y - controlPoints[0].y;
1532
- float dx3 = endPoint.x - controlPoints[1].x;
1533
- float dy3 = endPoint.y - controlPoints[1].y;
1534
-
1535
- float len = (float)Math.sqrt(dx1 * dx1 + dy1 * dy1) +
1536
- (float)Math.sqrt(dx2 * dx2 + dy2 * dy2) +
1537
- (float)Math.sqrt(dx3 * dx3 + dy3 * dy3);
1538
- float steps = (int)(len * 2);
1539
-
1540
- if(steps < 4) steps = 4;
1541
-
1542
- float dt = 1F/steps;
1543
-
1544
- float fx, fy, fdx, fdy, fddx, fddy, fdddx, fdddy, fdd_per_2x, fdd_per_2y, fddd_per_2x, fddd_per_2y, fddd_per_6x, fddd_per_6y, fix, fiy;
1545
- float temp = dt * dt;
1546
- float totallen = 0F;
1547
-
1548
- fx = startPoint.x;
1549
- fdx = 3F * (controlPoints[0].x - startPoint.x) * dt;
1550
- fdd_per_2x = 3F * (startPoint.x - 2F * controlPoints[0].x + controlPoints[1].x) * temp;
1551
- fddd_per_2x = 3F * (3F * (controlPoints[0].x - controlPoints[1].x) + endPoint.x - startPoint.x) * temp * dt;
1552
- fdddx = fddd_per_2x + fddd_per_2x;
1553
- fddx = fdd_per_2x + fdd_per_2x;
1554
- fddd_per_6x = fddd_per_2x * (1.0F / 3F);
1555
-
1556
- fy = startPoint.y;
1557
- fdy = 3F * (controlPoints[0].y - startPoint.y) * dt;
1558
- fdd_per_2y = 3F * (startPoint.y - 2F * controlPoints[0].y + controlPoints[1].y) * temp;
1559
- fddd_per_2y = 3F * (3F * (controlPoints[0].y - controlPoints[1].y) + endPoint.y - startPoint.y) * temp * dt;
1560
-
1561
- fdddy = fddd_per_2y + fddd_per_2y;
1562
- fddy = fdd_per_2y + fdd_per_2y;
1563
- fddd_per_6y = fddd_per_2y * (1.0F / 3F);
1564
-
1565
- for (int loop=0; loop < steps; loop++) {
1566
- /* Add segment differential to segment length */
1567
- fix = fdx + fdd_per_2x + fddd_per_6x;
1568
- fiy = fdy + fdd_per_2y + fddd_per_6y;
1569
- totallen += (float)Math.sqrt(fix*fix + fiy*fiy); // Eventually try other distance measures
1570
-
1571
- fx = fx + fix;
1572
- fdx = fdx + fddx + fddd_per_2x;
1573
- fddx = fddx + fdddx;
1574
- fdd_per_2x = fdd_per_2x + fddd_per_2x;
1575
-
1576
- fy = fy + fiy;
1577
- fdy = fdy + fddy + fddd_per_2y;
1578
- fddy = fddy + fdddy;
1579
- fdd_per_2y = fdd_per_2y + fddd_per_2y;
1580
- }
1581
-
1582
- return totallen;
1583
- }
1584
-
1585
-
1586
- /**
1587
- * Use this method to transform the command.
1588
- * @eexample transformCommand
1589
- * @param g PGraphics, the graphics object on which to apply an affine transformation to the command
1590
- */
1591
- /*
1592
- public void transform(RMatrix m){
1593
- int numControlPoints = countControlPoints();
1594
- if(numControlPoints!=0){
1595
- for(int i=0;i<numControlPoints;i++){
1596
- controlPoints[i].transform(m);
1597
- }
1598
- }
1599
- startPoint.transform(m);
1600
- endPoint.transform(m);
1601
- }
1602
- */
1603
- private void append(RPoint nextcontrolpoint)
1604
- {
1605
- RPoint[] newcontrolPoints;
1606
- if(controlPoints==null){
1607
- newcontrolPoints = new RPoint[1];
1608
- newcontrolPoints[0] = nextcontrolpoint;
1609
- }else{
1610
- newcontrolPoints = new RPoint[controlPoints.length+1];
1611
- System.arraycopy(controlPoints,0,newcontrolPoints,0,controlPoints.length);
1612
- newcontrolPoints[controlPoints.length]=nextcontrolpoint;
1613
- }
1614
- this.controlPoints=newcontrolPoints;
1615
- }
1616
-
1617
- private void addCurvePoint(RPoint nextcurvepoint)
1618
- {
1619
- RPoint[] newcurvePoints;
1620
- if(curvePoints==null){
1621
- newcurvePoints = new RPoint[1];
1622
- newcurvePoints[0] = nextcurvepoint;
1623
- }else{
1624
- newcurvePoints = new RPoint[curvePoints.length+1];
1625
- System.arraycopy(curvePoints,0,newcurvePoints,0,curvePoints.length);
1626
- newcurvePoints[curvePoints.length]=nextcurvepoint;
1627
- }
1628
- this.curvePoints=newcurvePoints;
1629
- }
1630
-
1631
- public RPoint[] intersectionPoints(RCommand other)
1632
- {
1633
- RPoint[] result = null;
1634
-
1635
- switch (commandType) {
1636
- case LINETO:
1637
- switch (other.getCommandType()) {
1638
- case LINETO:
1639
- result = lineLineIntersection(this, other);
1640
- break;
1641
-
1642
- case QUADBEZIERTO:
1643
- result = lineQuadIntersection(this, other);
1644
- break;
1645
-
1646
- case CUBICBEZIERTO:
1647
- result = lineCubicIntersection(this, other);
1648
- break;
1649
- }
1650
- break;
1651
-
1652
- case QUADBEZIERTO:
1653
- switch (other.getCommandType()) {
1654
- case LINETO:
1655
- result = lineQuadIntersection(other, this);
1656
- break;
1657
-
1658
- case QUADBEZIERTO:
1659
- result = quadQuadIntersection(this, other);
1660
- break;
1661
-
1662
- case CUBICBEZIERTO:
1663
- result = quadCubicIntersection(this, other);
1664
- break;
1665
- }
1666
- break;
1667
-
1668
- case CUBICBEZIERTO:
1669
- switch (other.getCommandType()) {
1670
- case LINETO:
1671
- result = lineCubicIntersection(other, this);
1672
- break;
1673
-
1674
- case QUADBEZIERTO:
1675
- result = quadCubicIntersection(other, this);
1676
- break;
1677
-
1678
- case CUBICBEZIERTO:
1679
- result = cubicCubicIntersection(this, other);
1680
- break;
1681
- }
1682
- break;
1683
- }
1684
-
1685
- return result;
1686
- }
1687
-
1688
- public static RPoint[] lineLineIntersection(RCommand c1, RCommand c2) {
1689
- RPoint a = new RPoint(c1.startPoint);
1690
- RPoint b = new RPoint(c1.endPoint);
1691
-
1692
- RPoint c = new RPoint(c2.startPoint);
1693
- RPoint d = new RPoint(c2.endPoint);
1694
-
1695
- float epsilon = 1e-9f;
1696
-
1697
- //test for parallel case
1698
- float denom = (d.y - c.y)*(b.x - a.x) - (d.x - c.x)*(b.y - a.y);
1699
- if(Math.abs(denom) < epsilon)
1700
- return null;
1701
-
1702
- //calculate segment parameter and ensure its within bounds
1703
- float t1 = ((d.x - c.x)*(a.y - c.y) - (d.y - c.y)*(a.x - c.x))/denom;
1704
- float t2 = ((b.x - a.x)*(a.y - c.y) - (b.y - a.y)*(a.x - c.x))/denom;
1705
-
1706
- if ( t1 < 0.0f || t1 > 1.0f || t2 < 0.0f || t2 > 1.0f )
1707
- return null;
1708
-
1709
- //store actual intersection
1710
- RPoint[] result = new RPoint[1];
1711
-
1712
- RPoint temp = new RPoint(b);
1713
- temp.sub(a);
1714
- temp.scale(t1);
1715
-
1716
- result[0] = new RPoint(a);
1717
- result[0].add(temp);
1718
-
1719
- return result;
1720
- }
1721
-
1722
- public static RPoint[] lineQuadIntersection(RCommand c1, RCommand c2) { return null; }
1723
- public static RPoint[] lineCubicIntersection(RCommand c1, RCommand c2) { return null; }
1724
- public static RPoint[] quadQuadIntersection(RCommand c1, RCommand c2) { return null; }
1725
- public static RPoint[] quadCubicIntersection(RCommand c1, RCommand c2) { return null; }
1726
- public static RPoint[] cubicCubicIntersection(RCommand c1, RCommand c2) { return null; }
1727
-
1728
- public RClosest closestPoints(RCommand other)
1729
- {
1730
- RClosest result = new RClosest();
1731
- result.distance = 0;
1732
- RPoint temp;
1733
-
1734
- switch (commandType) {
1735
- case LINETO:
1736
- switch (other.getCommandType()) {
1737
- case LINETO:
1738
- result.intersects = lineLineIntersection(this, other);
1739
- if (result.intersects == null) {
1740
- result = lineLineClosest(this, other);
1648
+ if (steps < 4) {
1649
+ steps = 4;
1741
1650
  }
1742
- break;
1743
1651
 
1744
- case QUADBEZIERTO:
1745
- result.intersects = lineQuadIntersection(this, other);
1746
- if (result.intersects == null) {
1747
- result = lineQuadClosest(this, other);
1652
+ float dt = 1F / steps;
1653
+
1654
+ float fx, fy, fdx, fdy, fddx, fddy, fdddx, fdddy, fdd_per_2x, fdd_per_2y, fddd_per_2x, fddd_per_2y, fddd_per_6x, fddd_per_6y, fix, fiy;
1655
+ float temp = dt * dt;
1656
+ float totallen = 0F;
1657
+
1658
+ fx = startPoint.x;
1659
+ fdx = 3F * (controlPoints[0].x - startPoint.x) * dt;
1660
+ fdd_per_2x = 3F * (startPoint.x - 2F * controlPoints[0].x + controlPoints[1].x) * temp;
1661
+ fddd_per_2x = 3F * (3F * (controlPoints[0].x - controlPoints[1].x) + endPoint.x - startPoint.x) * temp * dt;
1662
+ fdddx = fddd_per_2x + fddd_per_2x;
1663
+ fddx = fdd_per_2x + fdd_per_2x;
1664
+ fddd_per_6x = fddd_per_2x * (1.0F / 3F);
1665
+
1666
+ fy = startPoint.y;
1667
+ fdy = 3F * (controlPoints[0].y - startPoint.y) * dt;
1668
+ fdd_per_2y = 3F * (startPoint.y - 2F * controlPoints[0].y + controlPoints[1].y) * temp;
1669
+ fddd_per_2y = 3F * (3F * (controlPoints[0].y - controlPoints[1].y) + endPoint.y - startPoint.y) * temp * dt;
1670
+
1671
+ fdddy = fddd_per_2y + fddd_per_2y;
1672
+ fddy = fdd_per_2y + fdd_per_2y;
1673
+ fddd_per_6y = fddd_per_2y * (1.0F / 3F);
1674
+
1675
+ for (int loop = 0; loop < steps; loop++) {
1676
+ /* Add segment differential to segment length */
1677
+ fix = fdx + fdd_per_2x + fddd_per_6x;
1678
+ fiy = fdy + fdd_per_2y + fddd_per_6y;
1679
+ totallen += (float) Math.sqrt(fix * fix + fiy * fiy); // Eventually try other distance measures
1680
+
1681
+ fx = fx + fix;
1682
+ fdx = fdx + fddx + fddd_per_2x;
1683
+ fddx = fddx + fdddx;
1684
+ fdd_per_2x = fdd_per_2x + fddd_per_2x;
1685
+
1686
+ fy = fy + fiy;
1687
+ fdy = fdy + fddy + fddd_per_2y;
1688
+ fddy = fddy + fdddy;
1689
+ fdd_per_2y = fdd_per_2y + fddd_per_2y;
1748
1690
  }
1749
- break;
1750
1691
 
1751
- case CUBICBEZIERTO:
1752
- result.intersects = lineCubicIntersection(this, other);
1753
- if (result.intersects == null) {
1754
- result = lineCubicClosest(this, other);
1755
- }
1756
- break;
1757
- }
1758
- break;
1759
-
1760
- case QUADBEZIERTO:
1761
- switch (other.getCommandType()) {
1762
- case LINETO:
1763
- result.intersects = lineQuadIntersection(other, this);
1764
- if (result.intersects == null) {
1765
- result = lineQuadClosest(other, this);
1766
- temp = result.closest[0];
1767
- result.closest[0] = result.closest[1];
1768
- result.closest[1] = temp;
1769
- }
1770
- break;
1692
+ return totallen;
1693
+ }
1771
1694
 
1772
- case QUADBEZIERTO:
1773
- result.intersects = quadQuadIntersection(this, other);
1774
- if (result.intersects == null) {
1775
- result = quadQuadClosest(this, other);
1695
+ /**
1696
+ * Use this method to transform the command.
1697
+ *
1698
+ * @eexample transformCommand
1699
+ * @param g PGraphics, the graphics object on which to apply an affine
1700
+ * transformation to the command
1701
+ */
1702
+ /*
1703
+ public void transform(RMatrix m){
1704
+ int numControlPoints = countControlPoints();
1705
+ if(numControlPoints!=0){
1706
+ for(int i=0;i<numControlPoints;i++){
1707
+ controlPoints[i].transform(m);
1708
+ }
1709
+ }
1710
+ startPoint.transform(m);
1711
+ endPoint.transform(m);
1712
+ }
1713
+ */
1714
+ private void append(RPoint nextcontrolpoint) {
1715
+ RPoint[] newcontrolPoints;
1716
+ if (controlPoints == null) {
1717
+ newcontrolPoints = new RPoint[1];
1718
+ newcontrolPoints[0] = nextcontrolpoint;
1719
+ } else {
1720
+ newcontrolPoints = new RPoint[controlPoints.length + 1];
1721
+ System.arraycopy(controlPoints, 0, newcontrolPoints, 0, controlPoints.length);
1722
+ newcontrolPoints[controlPoints.length] = nextcontrolpoint;
1776
1723
  }
1777
- break;
1724
+ this.controlPoints = newcontrolPoints;
1725
+ }
1778
1726
 
1779
- case CUBICBEZIERTO:
1780
- result.intersects = quadCubicIntersection(this, other);
1781
- if (result.intersects == null) {
1782
- result = quadCubicClosest(this, other);
1727
+ private void addCurvePoint(RPoint nextcurvepoint) {
1728
+ RPoint[] newcurvePoints;
1729
+ if (curvePoints == null) {
1730
+ newcurvePoints = new RPoint[1];
1731
+ newcurvePoints[0] = nextcurvepoint;
1732
+ } else {
1733
+ newcurvePoints = new RPoint[curvePoints.length + 1];
1734
+ System.arraycopy(curvePoints, 0, newcurvePoints, 0, curvePoints.length);
1735
+ newcurvePoints[curvePoints.length] = nextcurvepoint;
1783
1736
  }
1784
- break;
1785
- }
1786
- break;
1787
-
1788
- case CUBICBEZIERTO:
1789
- switch (other.getCommandType()) {
1790
- case LINETO:
1791
- result.intersects = lineCubicIntersection(other, this);
1792
- if (result.intersects == null) {
1793
- result = lineCubicClosest(other, this);
1794
- temp = result.closest[0];
1795
- result.closest[0] = result.closest[1];
1796
- result.closest[1] = temp;
1737
+ this.curvePoints = newcurvePoints;
1738
+ }
1739
+
1740
+ public RPoint[] intersectionPoints(RCommand other) {
1741
+ RPoint[] result = null;
1742
+
1743
+ switch (commandType) {
1744
+ case LINETO:
1745
+ switch (other.getCommandType()) {
1746
+ case LINETO:
1747
+ result = lineLineIntersection(this, other);
1748
+ break;
1749
+
1750
+ case QUADBEZIERTO:
1751
+ result = lineQuadIntersection(this, other);
1752
+ break;
1753
+
1754
+ case CUBICBEZIERTO:
1755
+ result = lineCubicIntersection(this, other);
1756
+ break;
1757
+ }
1758
+ break;
1759
+
1760
+ case QUADBEZIERTO:
1761
+ switch (other.getCommandType()) {
1762
+ case LINETO:
1763
+ result = lineQuadIntersection(other, this);
1764
+ break;
1765
+
1766
+ case QUADBEZIERTO:
1767
+ result = quadQuadIntersection(this, other);
1768
+ break;
1769
+
1770
+ case CUBICBEZIERTO:
1771
+ result = quadCubicIntersection(this, other);
1772
+ break;
1773
+ }
1774
+ break;
1775
+
1776
+ case CUBICBEZIERTO:
1777
+ switch (other.getCommandType()) {
1778
+ case LINETO:
1779
+ result = lineCubicIntersection(other, this);
1780
+ break;
1781
+
1782
+ case QUADBEZIERTO:
1783
+ result = quadCubicIntersection(other, this);
1784
+ break;
1785
+
1786
+ case CUBICBEZIERTO:
1787
+ result = cubicCubicIntersection(this, other);
1788
+ break;
1789
+ }
1790
+ break;
1797
1791
  }
1798
- break;
1799
-
1800
- case QUADBEZIERTO:
1801
- result.intersects = quadCubicIntersection(other, this);
1802
- if (result.intersects == null) {
1803
- result = quadCubicClosest(other, this);
1804
- temp = result.closest[0];
1805
- result.closest[0] = result.closest[1];
1806
- result.closest[1] = temp;
1792
+
1793
+ return result;
1794
+ }
1795
+
1796
+ public static RPoint[] lineLineIntersection(RCommand c1, RCommand c2) {
1797
+ RPoint a = new RPoint(c1.startPoint);
1798
+ RPoint b = new RPoint(c1.endPoint);
1799
+
1800
+ RPoint c = new RPoint(c2.startPoint);
1801
+ RPoint d = new RPoint(c2.endPoint);
1802
+
1803
+ float epsilon = 1e-9f;
1804
+
1805
+ //test for parallel case
1806
+ float denom = (d.y - c.y) * (b.x - a.x) - (d.x - c.x) * (b.y - a.y);
1807
+ if (Math.abs(denom) < epsilon) {
1808
+ return null;
1807
1809
  }
1808
- break;
1809
1810
 
1810
- case CUBICBEZIERTO:
1811
- result.intersects = cubicCubicIntersection(this, other);
1812
- if (result.intersects == null) {
1813
- result = cubicCubicClosest(this, other);
1811
+ //calculate segment parameter and ensure its within bounds
1812
+ float t1 = ((d.x - c.x) * (a.y - c.y) - (d.y - c.y) * (a.x - c.x)) / denom;
1813
+ float t2 = ((b.x - a.x) * (a.y - c.y) - (b.y - a.y) * (a.x - c.x)) / denom;
1814
+
1815
+ if (t1 < 0.0f || t1 > 1.0f || t2 < 0.0f || t2 > 1.0f) {
1816
+ return null;
1814
1817
  }
1815
- break;
1816
- }
1817
- break;
1818
+
1819
+ //store actual intersection
1820
+ RPoint[] result = new RPoint[1];
1821
+
1822
+ RPoint temp = new RPoint(b);
1823
+ temp.sub(a);
1824
+ temp.scale(t1);
1825
+
1826
+ result[0] = new RPoint(a);
1827
+ result[0].add(temp);
1828
+
1829
+ return result;
1818
1830
  }
1819
1831
 
1820
- return result;
1821
- }
1832
+ public static RPoint[] lineQuadIntersection(RCommand c1, RCommand c2) {
1833
+ return null;
1834
+ }
1822
1835
 
1823
- public static float closestAdvFrom(RCommand c, RPoint p) {
1824
- RPoint a = new RPoint(c.startPoint);
1825
- RPoint b = new RPoint(c.endPoint);
1836
+ public static RPoint[] lineCubicIntersection(RCommand c1, RCommand c2) {
1837
+ return null;
1838
+ }
1826
1839
 
1827
- RPoint ap = new RPoint(p);
1828
- ap.sub(a);
1840
+ public static RPoint[] quadQuadIntersection(RCommand c1, RCommand c2) {
1841
+ return null;
1842
+ }
1829
1843
 
1830
- RPoint ab = new RPoint(b);
1831
- ab.sub(a);
1844
+ public static RPoint[] quadCubicIntersection(RCommand c1, RCommand c2) {
1845
+ return null;
1846
+ }
1847
+
1848
+ public static RPoint[] cubicCubicIntersection(RCommand c1, RCommand c2) {
1849
+ return null;
1850
+ }
1851
+
1852
+ public RClosest closestPoints(RCommand other) {
1853
+ RClosest result = new RClosest();
1854
+ result.distance = 0;
1855
+ RPoint temp;
1856
+
1857
+ switch (commandType) {
1858
+ case LINETO:
1859
+ switch (other.getCommandType()) {
1860
+ case LINETO:
1861
+ result.intersects = lineLineIntersection(this, other);
1862
+ if (result.intersects == null) {
1863
+ result = lineLineClosest(this, other);
1864
+ }
1865
+ break;
1866
+
1867
+ case QUADBEZIERTO:
1868
+ result.intersects = lineQuadIntersection(this, other);
1869
+ if (result.intersects == null) {
1870
+ result = lineQuadClosest(this, other);
1871
+ }
1872
+ break;
1873
+
1874
+ case CUBICBEZIERTO:
1875
+ result.intersects = lineCubicIntersection(this, other);
1876
+ if (result.intersects == null) {
1877
+ result = lineCubicClosest(this, other);
1878
+ }
1879
+ break;
1880
+ }
1881
+ break;
1882
+
1883
+ case QUADBEZIERTO:
1884
+ switch (other.getCommandType()) {
1885
+ case LINETO:
1886
+ result.intersects = lineQuadIntersection(other, this);
1887
+ if (result.intersects == null) {
1888
+ result = lineQuadClosest(other, this);
1889
+ temp = result.closest[0];
1890
+ result.closest[0] = result.closest[1];
1891
+ result.closest[1] = temp;
1892
+ }
1893
+ break;
1894
+
1895
+ case QUADBEZIERTO:
1896
+ result.intersects = quadQuadIntersection(this, other);
1897
+ if (result.intersects == null) {
1898
+ result = quadQuadClosest(this, other);
1899
+ }
1900
+ break;
1901
+
1902
+ case CUBICBEZIERTO:
1903
+ result.intersects = quadCubicIntersection(this, other);
1904
+ if (result.intersects == null) {
1905
+ result = quadCubicClosest(this, other);
1906
+ }
1907
+ break;
1908
+ }
1909
+ break;
1910
+
1911
+ case CUBICBEZIERTO:
1912
+ switch (other.getCommandType()) {
1913
+ case LINETO:
1914
+ result.intersects = lineCubicIntersection(other, this);
1915
+ if (result.intersects == null) {
1916
+ result = lineCubicClosest(other, this);
1917
+ temp = result.closest[0];
1918
+ result.closest[0] = result.closest[1];
1919
+ result.closest[1] = temp;
1920
+ }
1921
+ break;
1922
+
1923
+ case QUADBEZIERTO:
1924
+ result.intersects = quadCubicIntersection(other, this);
1925
+ if (result.intersects == null) {
1926
+ result = quadCubicClosest(other, this);
1927
+ temp = result.closest[0];
1928
+ result.closest[0] = result.closest[1];
1929
+ result.closest[1] = temp;
1930
+ }
1931
+ break;
1932
+
1933
+ case CUBICBEZIERTO:
1934
+ result.intersects = cubicCubicIntersection(this, other);
1935
+ if (result.intersects == null) {
1936
+ result = cubicCubicClosest(this, other);
1937
+ }
1938
+ break;
1939
+ }
1940
+ break;
1941
+ }
1832
1942
 
1833
- float denom = ab.sqrnorm();
1834
- float epsilon = 1e-19f;
1943
+ return result;
1944
+ }
1835
1945
 
1836
- if(denom < epsilon)
1837
- return 0.5f;
1946
+ public static float closestAdvFrom(RCommand c, RPoint p) {
1947
+ RPoint a = new RPoint(c.startPoint);
1948
+ RPoint b = new RPoint(c.endPoint);
1838
1949
 
1839
- float t = (ab.x*ap.x + ab.y*ap.y) / denom;
1950
+ RPoint ap = new RPoint(p);
1951
+ ap.sub(a);
1840
1952
 
1841
- t = t > 0.0f ? t : 0.0f;
1842
- t = t < 1.0f ? t : 1.0f;
1953
+ RPoint ab = new RPoint(b);
1954
+ ab.sub(a);
1843
1955
 
1844
- return t;
1956
+ float denom = ab.sqrnorm();
1957
+ float epsilon = 1e-19f;
1845
1958
 
1846
- }
1959
+ if (denom < epsilon) {
1960
+ return 0.5f;
1961
+ }
1847
1962
 
1848
- public static RClosest lineLineClosest(RCommand c1, RCommand c2) {
1849
- RPoint c1b = new RPoint(c1.startPoint);
1850
- RPoint c1e = new RPoint(c1.endPoint);
1963
+ float t = (ab.x * ap.x + ab.y * ap.y) / denom;
1851
1964
 
1852
- float c2t1 = closestAdvFrom(c2, c1b);
1853
- float c2t2 = closestAdvFrom(c2, c1e);
1965
+ t = t > 0.0f ? t : 0.0f;
1966
+ t = t < 1.0f ? t : 1.0f;
1854
1967
 
1855
- RPoint c2p1 = c2.getPoint(c2t1);
1856
- RPoint c2p2 = c2.getPoint(c2t2);
1968
+ return t;
1857
1969
 
1858
- float dist1c2 = c2p1.dist(c1b);
1859
- float dist2c2 = c2p2.dist(c1e);
1970
+ }
1860
1971
 
1861
- RPoint c2b = new RPoint(c2.startPoint);
1862
- RPoint c2e = new RPoint(c2.endPoint);
1972
+ public static RClosest lineLineClosest(RCommand c1, RCommand c2) {
1973
+ RPoint c1b = new RPoint(c1.startPoint);
1974
+ RPoint c1e = new RPoint(c1.endPoint);
1975
+
1976
+ float c2t1 = closestAdvFrom(c2, c1b);
1977
+ float c2t2 = closestAdvFrom(c2, c1e);
1978
+
1979
+ RPoint c2p1 = c2.getPoint(c2t1);
1980
+ RPoint c2p2 = c2.getPoint(c2t2);
1981
+
1982
+ float dist1c2 = c2p1.dist(c1b);
1983
+ float dist2c2 = c2p2.dist(c1e);
1984
+
1985
+ RPoint c2b = new RPoint(c2.startPoint);
1986
+ RPoint c2e = new RPoint(c2.endPoint);
1987
+
1988
+ float c1t1 = closestAdvFrom(c1, c2b);
1989
+ float c1t2 = closestAdvFrom(c1, c2e);
1990
+
1991
+ RPoint c1p1 = c1.getPoint(c1t1);
1992
+ RPoint c1p2 = c1.getPoint(c1t2);
1993
+
1994
+ float dist1c1 = c1p1.dist(c2b);
1995
+ float dist2c1 = c1p2.dist(c2e);
1996
+
1997
+ RClosest result = new RClosest();
1998
+ result.distance = Math.min(Math.min(dist1c2, dist2c2), Math.min(dist1c1, dist2c1));
1999
+ result.closest = new RPoint[2];
2000
+ result.advancements = new float[2];
2001
+
2002
+ if (result.distance == dist1c2) {
2003
+ result.closest[0] = c1b;
2004
+ result.closest[1] = c2p1;
2005
+ result.advancements[0] = 0;
2006
+ result.advancements[1] = c2t1;
2007
+ } else if (result.distance == dist2c2) {
2008
+ result.closest[0] = c1e;
2009
+ result.closest[1] = c2p2;
2010
+ result.advancements[0] = 1;
2011
+ result.advancements[1] = c2t2;
2012
+ } else if (result.distance == dist1c1) {
2013
+ result.closest[0] = c2b;
2014
+ result.closest[1] = c1p1;
2015
+ result.advancements[0] = 0;
2016
+ result.advancements[1] = c1t1;
2017
+ } else /*if (result.distance == dist2c1)*/ {
2018
+ result.closest[0] = c2e;
2019
+ result.closest[1] = c1p2;
2020
+ result.advancements[0] = 1;
2021
+ result.advancements[1] = c1t2;
2022
+ }
1863
2023
 
1864
- float c1t1 = closestAdvFrom(c1, c2b);
1865
- float c1t2 = closestAdvFrom(c1, c2e);
1866
2024
 
1867
- RPoint c1p1 = c1.getPoint(c1t1);
1868
- RPoint c1p2 = c1.getPoint(c1t2);
2025
+ /*
2026
+ RPoint c = new RPoint(c2.startPoint);
2027
+ RPoint d = new RPoint(c2.endPoint);
2028
+
2029
+ float t1 = closestAdvFrom(c1, c);
2030
+ float t2 = closestAdvFrom(c1, d);
2031
+
2032
+ RPoint p1 = c1.getPoint(t1);
2033
+ RPoint p2 = c1.getPoint(t2);
2034
+
2035
+ float dist1 = p1.dist(c);
2036
+ float dist2 = p2.dist(d);
2037
+
2038
+ RClosest result = new RClosest();
2039
+ result.closest = new RPoint[2];
2040
+ result.advancements = new float[2];
2041
+ if (dist1 < dist2) {
2042
+ result.closest[0] = p1;
2043
+ result.closest[1] = c;
2044
+ result.distance = dist1;
2045
+ result.advancements[0] = t1;
2046
+ result.advancements[1] = t2;
2047
+ } else {
2048
+ result.closest[0] = p2;
2049
+ result.closest[1] = d;
2050
+ result.distance = dist2;
2051
+ result.advancements[0] = t1;
2052
+ result.advancements[1] = t2;
2053
+ }
2054
+ */
2055
+ return result;
2056
+ }
1869
2057
 
1870
- float dist1c1 = c1p1.dist(c2b);
1871
- float dist2c1 = c1p2.dist(c2e);
2058
+ public static RClosest lineQuadClosest(RCommand c1, RCommand c2) {
2059
+ return null;
2060
+ }
1872
2061
 
1873
-
1874
- RClosest result = new RClosest();
1875
- result.distance = Math.min(Math.min(dist1c2, dist2c2), Math.min(dist1c1, dist2c1));
1876
- result.closest = new RPoint[2];
1877
- result.advancements = new float[2];
2062
+ public static RClosest lineCubicClosest(RCommand c1, RCommand c2) {
2063
+ return null;
2064
+ }
1878
2065
 
1879
- if (result.distance == dist1c2) {
1880
- result.closest[0] = c1b;
1881
- result.closest[1] = c2p1;
1882
- result.advancements[0] = 0;
1883
- result.advancements[1] = c2t1;
1884
- } else if (result.distance == dist2c2) {
1885
- result.closest[0] = c1e;
1886
- result.closest[1] = c2p2;
1887
- result.advancements[0] = 1;
1888
- result.advancements[1] = c2t2;
1889
- } else if (result.distance == dist1c1) {
1890
- result.closest[0] = c2b;
1891
- result.closest[1] = c1p1;
1892
- result.advancements[0] = 0;
1893
- result.advancements[1] = c1t1;
1894
- } else /*if (result.distance == dist2c1)*/ {
1895
- result.closest[0] = c2e;
1896
- result.closest[1] = c1p2;
1897
- result.advancements[0] = 1;
1898
- result.advancements[1] = c1t2;
2066
+ public static RClosest quadQuadClosest(RCommand c1, RCommand c2) {
2067
+ return null;
1899
2068
  }
1900
2069
 
2070
+ public static RClosest quadCubicClosest(RCommand c1, RCommand c2) {
2071
+ return null;
2072
+ }
1901
2073
 
1902
- /*
1903
- RPoint c = new RPoint(c2.startPoint);
1904
- RPoint d = new RPoint(c2.endPoint);
1905
-
1906
- float t1 = closestAdvFrom(c1, c);
1907
- float t2 = closestAdvFrom(c1, d);
1908
-
1909
- RPoint p1 = c1.getPoint(t1);
1910
- RPoint p2 = c1.getPoint(t2);
1911
-
1912
- float dist1 = p1.dist(c);
1913
- float dist2 = p2.dist(d);
1914
-
1915
- RClosest result = new RClosest();
1916
- result.closest = new RPoint[2];
1917
- result.advancements = new float[2];
1918
- if (dist1 < dist2) {
1919
- result.closest[0] = p1;
1920
- result.closest[1] = c;
1921
- result.distance = dist1;
1922
- result.advancements[0] = t1;
1923
- result.advancements[1] = t2;
1924
- } else {
1925
- result.closest[0] = p2;
1926
- result.closest[1] = d;
1927
- result.distance = dist2;
1928
- result.advancements[0] = t1;
1929
- result.advancements[1] = t2;
1930
- }
1931
- */
1932
-
1933
- return result;
1934
- }
1935
-
1936
- public static RClosest lineQuadClosest(RCommand c1, RCommand c2) { return null; }
1937
- public static RClosest lineCubicClosest(RCommand c1, RCommand c2) { return null; }
1938
- public static RClosest quadQuadClosest(RCommand c1, RCommand c2) { return null; }
1939
- public static RClosest quadCubicClosest(RCommand c1, RCommand c2) { return null; }
1940
- public static RClosest cubicCubicClosest(RCommand c1, RCommand c2) { return null; }
1941
- }
2074
+ public static RClosest cubicCubicClosest(RCommand c1, RCommand c2) {
2075
+ return null;
2076
+ }
2077
+ }