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.
- checksums.yaml +4 -4
- data/.mvn/extensions.xml +8 -0
- data/.mvn/wrapper/maven-wrapper.properties +1 -0
- data/.travis.yml +14 -0
- data/CHANGELOG.md +4 -0
- data/COPYING.md +17 -0
- data/Gemfile +8 -1
- data/README.md +5 -1
- data/examples/README.md +1 -7
- data/examples/Rakefile +30 -0
- data/examples/data/ruby.svg +16 -0
- data/examples/f_agent.rb +30 -0
- data/examples/font_agent.rb +24 -0
- data/examples/hello_polygonize.rb +1 -1
- data/examples/hello_svg_to_pdf.rb +2 -2
- data/examples/hello_world.rb +1 -1
- data/examples/jruby_merge.rb +94 -0
- data/examples/physics_type.rb +1 -1
- data/examples/rotate_first_letter.rb +3 -4
- data/examples/typo_deform.rb +68 -0
- data/examples/typo_extra_bright.rb +62 -0
- data/examples/typo_merge.rb +94 -0
- data/geomerative.gemspec +2 -3
- data/lib/geomerative/version.rb +1 -1
- data/pom.rb +47 -0
- data/pom.xml +35 -65
- data/src/geomerative/FastRClip.java +1 -1
- data/src/geomerative/RCommand.java +1877 -1741
- data/src/geomerative/RContour.java +8 -1
- data/src/geomerative/RFont.java +8 -5
- data/src/geomerative/RG.java +8 -3
- data/src/geomerative/RGeomElem.java +8 -9
- data/src/geomerative/RGroup.java +50 -28
- data/src/geomerative/RMatrix.java +53 -57
- data/src/geomerative/RMesh.java +8 -3
- data/src/geomerative/RPath.java +34 -29
- data/src/geomerative/RPoint.java +408 -408
- data/src/geomerative/RPolygon.java +7 -3
- data/src/geomerative/RSVG.java +13 -10
- data/src/geomerative/RShape.java +18 -11
- data/src/geomerative/RStrip.java +5 -1
- data/src/geomerative/RStyle.java +15 -11
- 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
|
25
|
-
spec.add_development_dependency
|
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
|
data/lib/geomerative/version.rb
CHANGED
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
|
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>
|
5
|
+
<groupId>ruby-processing</groupId>
|
5
6
|
<artifactId>geomerative</artifactId>
|
6
|
-
<version>0.2
|
7
|
-
<
|
8
|
-
<description>
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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>
|
32
|
-
<url>http://www.gnu.org/licenses/
|
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>
|
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
|
-
<
|
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.
|
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.
|
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(
|
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
|
-
|
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
|
-
|
7
|
-
|
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
|
-
|
29
|
+
/**
|
30
|
+
* @invisible
|
31
|
+
*/
|
32
|
+
public int type = RGeomElem.COMMAND;
|
300
33
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
*
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
*
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
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
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
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
|
-
|
388
|
-
|
389
|
-
|
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
|
-
|
393
|
-
|
394
|
-
}
|
95
|
+
static int segmentSteps = 0;
|
96
|
+
static boolean segmentLines = false;
|
395
97
|
|
396
|
-
|
397
|
-
RCommand.segmentType = oldSegmentType;
|
98
|
+
int oldSegmentType = UNIFORMLENGTH;
|
398
99
|
|
399
100
|
/* Parameters for ADAPTATIVE (dependent of the PGraphics on which drawing) */
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
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
|
-
|
410
|
-
|
411
|
-
|
113
|
+
float oldSegmentLength = 4.0F;
|
114
|
+
float oldSegmentOffset = 0.0F;
|
115
|
+
float oldSegmentAccOffset = 0.0F;
|
412
116
|
|
413
117
|
/* Parameters for UNIFORMSTEP */
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
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
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
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
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
*
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
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
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
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
|
-
|
846
|
-
|
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
|
-
|
850
|
-
|
851
|
-
|
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
|
-
|
847
|
+
@Override
|
848
|
+
public RPoint[][] getPointsInPaths() {
|
849
|
+
PApplet.println("Feature not yet implemented for this class.");
|
850
|
+
return null;
|
851
|
+
}
|
858
852
|
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
853
|
+
@Override
|
854
|
+
public RPoint[][] getHandlesInPaths() {
|
855
|
+
PApplet.println("Feature not yet implemented for this class.");
|
856
|
+
return null;
|
863
857
|
}
|
864
858
|
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
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
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
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
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
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
|
-
|
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
|
-
|
890
|
-
|
891
|
-
|
903
|
+
a.beginShape();
|
904
|
+
for (RPoint point : points) {
|
905
|
+
a.vertex(point.x, point.y);
|
906
|
+
}
|
907
|
+
a.endShape();
|
892
908
|
}
|
893
909
|
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
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
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
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
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
}
|
951
|
+
case CUBICBEZIERTO:
|
952
|
+
return splitCubicBezier(t);
|
953
|
+
|
954
|
+
}
|
955
|
+
return null;
|
914
956
|
}
|
915
957
|
|
916
|
-
|
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
|
-
|
919
|
-
|
920
|
-
|
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
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
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[]
|
932
|
-
|
933
|
-
|
934
|
-
|
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
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
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
|
-
|
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
|
-
|
946
|
-
|
947
|
-
|
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
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
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
|
-
|
968
|
-
{
|
1079
|
+
//-----------------
|
1080
|
+
if (d * d <= segmentDistTolSqr * (dx * dx + dy * dy)) {
|
969
1081
|
// If the curvature doesn't exceed the distance_tolerance value
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
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
|
-
|
981
|
-
|
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
|
-
|
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
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
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
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
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
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
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
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
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
|
-
|
1166
|
+
case 1:
|
1060
1167
|
// p1,p2,p4 are collinear, p3 is considerable
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
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
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
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
|
-
|
1197
|
+
case 2:
|
1094
1198
|
// p1,p3,p4 are collinear, p2 is considerable
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
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
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
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
|
-
|
1228
|
+
case 3:
|
1128
1229
|
// Regular care
|
1129
|
-
|
1130
|
-
|
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
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
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
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
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
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
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
|
-
|
1178
|
-
|
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
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
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
|
-
|
1189
|
-
|
1287
|
+
float len = (float) Math.sqrt(dx * dx + dy * dy);
|
1288
|
+
steps = (int) (len * 0.25);
|
1190
1289
|
|
1191
|
-
|
1192
|
-
|
1290
|
+
if (steps < 4) {
|
1291
|
+
steps = 4;
|
1292
|
+
}
|
1293
|
+
}
|
1193
1294
|
|
1194
|
-
|
1295
|
+
float dt = 1F / steps;
|
1195
1296
|
|
1196
|
-
|
1297
|
+
float fx, fy, fdx, fdy;
|
1197
1298
|
|
1198
|
-
|
1199
|
-
|
1299
|
+
fx = startPoint.x;
|
1300
|
+
fdx = (endPoint.x - startPoint.x) * dt;
|
1200
1301
|
|
1201
|
-
|
1202
|
-
|
1302
|
+
fy = startPoint.y;
|
1303
|
+
fdy = (endPoint.y - startPoint.y) * dt;
|
1203
1304
|
|
1204
|
-
|
1205
|
-
|
1305
|
+
for (int loop = 0; loop < steps; loop++) {
|
1306
|
+
addCurvePoint(new RPoint(fx, fy));
|
1206
1307
|
|
1207
|
-
|
1308
|
+
fx = fx + fdx;
|
1208
1309
|
|
1209
|
-
|
1310
|
+
fy = fy + fdy;
|
1311
|
+
}
|
1312
|
+
addCurvePoint(new RPoint(endPoint));
|
1210
1313
|
}
|
1211
|
-
addCurvePoint(new RPoint(endPoint));
|
1212
|
-
}
|
1213
1314
|
|
1214
|
-
|
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
|
-
|
1217
|
-
|
1218
|
-
|
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
|
-
|
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
|
-
|
1333
|
+
if (steps < 4) {
|
1334
|
+
steps = 4;
|
1335
|
+
}
|
1336
|
+
}
|
1231
1337
|
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
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
|
-
|
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
|
-
|
1241
|
-
|
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
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
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
|
-
|
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
|
-
|
1260
|
-
|
1394
|
+
float fx, fy, fdx, fdy, fddx, fddy, fdd_per_2x, fdd_per_2y;
|
1395
|
+
float temp = dt * dt;
|
1261
1396
|
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
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
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
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
|
-
|
1276
|
-
|
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
|
-
|
1285
|
-
|
1410
|
+
fx = fx + fdx + fdd_per_2x;
|
1411
|
+
fdx = fdx + fddx;
|
1286
1412
|
|
1287
|
-
|
1413
|
+
fy = fy + fdy + fdd_per_2y;
|
1414
|
+
fdy = fdy + fddy;
|
1415
|
+
}
|
1416
|
+
addCurvePoint(new RPoint(endPoint));
|
1288
1417
|
}
|
1289
1418
|
|
1290
|
-
|
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
|
-
|
1293
|
-
|
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
|
-
|
1296
|
-
|
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
|
-
|
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
|
-
|
1306
|
-
|
1442
|
+
fx = startPoint.x;
|
1443
|
+
fdx = (endPoint.x - startPoint.x) * dt;
|
1307
1444
|
|
1308
|
-
|
1309
|
-
|
1445
|
+
fy = startPoint.y;
|
1446
|
+
fdy = (endPoint.y - startPoint.y) * dt;
|
1310
1447
|
|
1311
|
-
|
1312
|
-
|
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
|
-
|
1467
|
+
//----------------------
|
1468
|
+
private void quadBezierUniformLength() {
|
1320
1469
|
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
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
|
-
|
1326
|
-
|
1477
|
+
if (steps < 4) {
|
1478
|
+
steps = 4;
|
1479
|
+
}
|
1327
1480
|
|
1328
|
-
|
1481
|
+
float dt = 1F / steps;
|
1482
|
+
float untilPoint = RCommand.segmentAccOffset;
|
1329
1483
|
|
1330
|
-
|
1331
|
-
|
1484
|
+
float fx, fy, fdx, fdy, fddx, fddy, fdd_per_2x, fdd_per_2y, fix, fiy;
|
1485
|
+
float temp = dt * dt;
|
1332
1486
|
|
1333
|
-
|
1334
|
-
|
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
|
-
|
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
|
-
|
1339
|
-
|
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
|
-
|
1342
|
-
|
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
|
-
|
1345
|
-
|
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
|
-
|
1352
|
-
|
1512
|
+
fy = fy + fiy;
|
1513
|
+
fdy = fdy + fddy;
|
1514
|
+
}
|
1353
1515
|
|
1354
|
-
|
1355
|
-
|
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
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
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
|
-
|
1376
|
-
|
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
|
-
|
1379
|
-
|
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
|
-
|
1382
|
-
|
1383
|
-
|
1384
|
-
|
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
|
-
|
1387
|
-
|
1388
|
-
|
1389
|
-
|
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
|
-
|
1392
|
-
|
1393
|
-
|
1394
|
-
addCurvePoint(new RPoint(fx, fy));
|
1395
|
-
untilPoint += RCommand.segmentLength;
|
1396
|
-
}
|
1585
|
+
//addCurvePoint(new RPoint(endPoint));
|
1586
|
+
RCommand.segmentAccOffset = untilPoint;
|
1587
|
+
}
|
1397
1588
|
|
1398
|
-
|
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
|
-
|
1404
|
-
|
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
|
-
|
1407
|
-
|
1408
|
-
|
1598
|
+
if (steps < 4) {
|
1599
|
+
steps = 4;
|
1600
|
+
}
|
1409
1601
|
|
1410
|
-
|
1411
|
-
RCommand.segmentAccOffset = untilPoint;
|
1412
|
-
}
|
1602
|
+
float dt = 1F / steps;
|
1413
1603
|
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
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
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
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
|
-
|
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
|
-
|
1433
|
-
|
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
|
-
|
1436
|
-
|
1624
|
+
fx = fx + fix;
|
1625
|
+
fdx = fdx + fddx;
|
1437
1626
|
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
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
|
-
|
1447
|
-
|
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
|
-
|
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
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
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
|
-
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
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
|
-
|
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
|
-
|
1745
|
-
|
1746
|
-
|
1747
|
-
|
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
|
-
|
1752
|
-
|
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
|
-
|
1773
|
-
|
1774
|
-
|
1775
|
-
|
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
|
-
|
1724
|
+
this.controlPoints = newcontrolPoints;
|
1725
|
+
}
|
1778
1726
|
|
1779
|
-
|
1780
|
-
|
1781
|
-
if (
|
1782
|
-
|
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
|
-
|
1785
|
-
|
1786
|
-
|
1787
|
-
|
1788
|
-
|
1789
|
-
|
1790
|
-
|
1791
|
-
|
1792
|
-
|
1793
|
-
|
1794
|
-
|
1795
|
-
|
1796
|
-
|
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
|
-
|
1799
|
-
|
1800
|
-
|
1801
|
-
|
1802
|
-
|
1803
|
-
|
1804
|
-
|
1805
|
-
|
1806
|
-
|
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
|
-
|
1811
|
-
|
1812
|
-
|
1813
|
-
|
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
|
-
|
1816
|
-
|
1817
|
-
|
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
|
-
|
1821
|
-
|
1832
|
+
public static RPoint[] lineQuadIntersection(RCommand c1, RCommand c2) {
|
1833
|
+
return null;
|
1834
|
+
}
|
1822
1835
|
|
1823
|
-
|
1824
|
-
|
1825
|
-
|
1836
|
+
public static RPoint[] lineCubicIntersection(RCommand c1, RCommand c2) {
|
1837
|
+
return null;
|
1838
|
+
}
|
1826
1839
|
|
1827
|
-
RPoint
|
1828
|
-
|
1840
|
+
public static RPoint[] quadQuadIntersection(RCommand c1, RCommand c2) {
|
1841
|
+
return null;
|
1842
|
+
}
|
1829
1843
|
|
1830
|
-
RPoint
|
1831
|
-
|
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
|
-
|
1834
|
-
|
1943
|
+
return result;
|
1944
|
+
}
|
1835
1945
|
|
1836
|
-
|
1837
|
-
|
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
|
-
|
1950
|
+
RPoint ap = new RPoint(p);
|
1951
|
+
ap.sub(a);
|
1840
1952
|
|
1841
|
-
|
1842
|
-
|
1953
|
+
RPoint ab = new RPoint(b);
|
1954
|
+
ab.sub(a);
|
1843
1955
|
|
1844
|
-
|
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
|
-
|
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
|
-
|
1853
|
-
|
1965
|
+
t = t > 0.0f ? t : 0.0f;
|
1966
|
+
t = t < 1.0f ? t : 1.0f;
|
1854
1967
|
|
1855
|
-
|
1856
|
-
RPoint c2p2 = c2.getPoint(c2t2);
|
1968
|
+
return t;
|
1857
1969
|
|
1858
|
-
|
1859
|
-
float dist2c2 = c2p2.dist(c1e);
|
1970
|
+
}
|
1860
1971
|
|
1861
|
-
|
1862
|
-
|
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
|
-
|
1868
|
-
|
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
|
-
|
1871
|
-
|
2058
|
+
public static RClosest lineQuadClosest(RCommand c1, RCommand c2) {
|
2059
|
+
return null;
|
2060
|
+
}
|
1872
2061
|
|
1873
|
-
|
1874
|
-
|
1875
|
-
|
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
|
-
|
1880
|
-
|
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
|
-
|
1904
|
-
|
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
|
+
}
|