Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
8225db03
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
8225db03
编写于
1月 27, 2011
作者:
D
dlila
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
4645692: solveCubic does not return all solutions.
Summary: more robust solveCubic implementation. Reviewed-by: flar
上级
aef47390
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
426 addition
and
232 deletion
+426
-232
src/share/classes/java/awt/geom/CubicCurve2D.java
src/share/classes/java/awt/geom/CubicCurve2D.java
+289
-232
test/java/awt/geom/CubicCurve2D/ContainsTest.java
test/java/awt/geom/CubicCurve2D/ContainsTest.java
+46
-0
test/java/awt/geom/CubicCurve2D/IntersectsTest.java
test/java/awt/geom/CubicCurve2D/IntersectsTest.java
+48
-0
test/java/awt/geom/CubicCurve2D/SolveCubicTest.java
test/java/awt/geom/CubicCurve2D/SolveCubicTest.java
+43
-0
未找到文件。
src/share/classes/java/awt/geom/CubicCurve2D.java
浏览文件 @
8225db03
...
@@ -31,6 +31,10 @@ import java.util.Arrays;
...
@@ -31,6 +31,10 @@ import java.util.Arrays;
import
java.io.Serializable
;
import
java.io.Serializable
;
import
sun.awt.geom.Curve
;
import
sun.awt.geom.Curve
;
import
static
java
.
lang
.
Math
.
abs
;
import
static
java
.
lang
.
Math
.
max
;
import
static
java
.
lang
.
Math
.
ulp
;
/**
/**
* The <code>CubicCurve2D</code> class defines a cubic parametric curve
* The <code>CubicCurve2D</code> class defines a cubic parametric curve
* segment in {@code (x,y)} coordinate space.
* segment in {@code (x,y)} coordinate space.
...
@@ -1083,159 +1087,316 @@ public abstract class CubicCurve2D implements Shape, Cloneable {
...
@@ -1083,159 +1087,316 @@ public abstract class CubicCurve2D implements Shape, Cloneable {
* @since 1.3
* @since 1.3
*/
*/
public
static
int
solveCubic
(
double
eqn
[],
double
res
[])
{
public
static
int
solveCubic
(
double
eqn
[],
double
res
[])
{
// From
Numerical Recipes, 5.6, Quadratic and Cubic Equations
// From
Graphics Gems:
double
d
=
eqn
[
3
];
// http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c
if
(
d
==
0.0
)
{
final
double
d
=
eqn
[
3
];
// The cubic has degenerated to quadratic (or line or ...).
if
(
d
==
0
)
{
return
QuadCurve2D
.
solveQuadratic
(
eqn
,
res
);
return
QuadCurve2D
.
solveQuadratic
(
eqn
,
res
);
}
}
double
a
=
eqn
[
2
]
/
d
;
double
b
=
eqn
[
1
]
/
d
;
/* normal form: x^3 + Ax^2 + Bx + C = 0 */
double
c
=
eqn
[
0
]
/
d
;
final
double
A
=
eqn
[
2
]
/
d
;
int
roots
=
0
;
final
double
B
=
eqn
[
1
]
/
d
;
double
Q
=
(
a
*
a
-
3.0
*
b
)
/
9.0
;
final
double
C
=
eqn
[
0
]
/
d
;
double
R
=
(
2.0
*
a
*
a
*
a
-
9.0
*
a
*
b
+
27.0
*
c
)
/
54.0
;
double
R2
=
R
*
R
;
double
Q3
=
Q
*
Q
*
Q
;
// substitute x = y - A/3 to eliminate quadratic term:
a
=
a
/
3.0
;
// x^3 +Px + Q = 0
if
(
R2
<
Q3
)
{
//
double
theta
=
Math
.
acos
(
R
/
Math
.
sqrt
(
Q3
));
// Since we actually need P/3 and Q/2 for all of the
Q
=
-
2.0
*
Math
.
sqrt
(
Q
);
// calculations that follow, we will calculate
// p = P/3
// q = Q/2
// instead and use those values for simplicity of the code.
double
sq_A
=
A
*
A
;
double
p
=
1.0
/
3
*
(-
1.0
/
3
*
sq_A
+
B
);
double
q
=
1.0
/
2
*
(
2.0
/
27
*
A
*
sq_A
-
1.0
/
3
*
A
*
B
+
C
);
/* use Cardano's formula */
double
cb_p
=
p
*
p
*
p
;
double
D
=
q
*
q
+
cb_p
;
final
double
sub
=
1.0
/
3
*
A
;
int
num
;
if
(
D
<
0
)
{
/* Casus irreducibilis: three real solutions */
// see: http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method
double
phi
=
1.0
/
3
*
Math
.
acos
(-
q
/
Math
.
sqrt
(-
cb_p
));
double
t
=
2
*
Math
.
sqrt
(-
p
);
if
(
res
==
eqn
)
{
if
(
res
==
eqn
)
{
// Copy the eqn so that we don't clobber it with the
eqn
=
Arrays
.
copyOf
(
eqn
,
4
);
// roots. This is needed so that fixRoots can do its
// work with the original equation.
eqn
=
new
double
[
4
];
System
.
arraycopy
(
res
,
0
,
eqn
,
0
,
4
);
}
}
res
[
roots
++]
=
Q
*
Math
.
cos
(
theta
/
3.0
)
-
a
;
res
[
roots
++]
=
Q
*
Math
.
cos
((
theta
+
Math
.
PI
*
2.0
)/
3.0
)
-
a
;
res
[
0
]
=
(
t
*
Math
.
cos
(
phi
));
res
[
roots
++]
=
Q
*
Math
.
cos
((
theta
-
Math
.
PI
*
2.0
)/
3.0
)
-
a
;
res
[
1
]
=
(-
t
*
Math
.
cos
(
phi
+
Math
.
PI
/
3
));
fixRoots
(
res
,
eqn
);
res
[
2
]
=
(-
t
*
Math
.
cos
(
phi
-
Math
.
PI
/
3
));
}
else
{
num
=
3
;
boolean
neg
=
(
R
<
0.0
);
double
S
=
Math
.
sqrt
(
R2
-
Q3
);
for
(
int
i
=
0
;
i
<
num
;
++
i
)
{
if
(
neg
)
{
res
[
i
]
-=
sub
;
R
=
-
R
;
}
}
double
A
=
Math
.
pow
(
R
+
S
,
1.0
/
3.0
);
if
(!
neg
)
{
}
else
{
A
=
-
A
;
// Please see the comment in fixRoots marked 'XXX' before changing
// any of the code in this case.
double
sqrt_D
=
Math
.
sqrt
(
D
);
double
u
=
Math
.
cbrt
(
sqrt_D
-
q
);
double
v
=
-
Math
.
cbrt
(
sqrt_D
+
q
);
double
uv
=
u
+
v
;
num
=
1
;
double
err
=
1200000000
*
ulp
(
abs
(
uv
)
+
abs
(
sub
));
if
(
iszero
(
D
,
err
)
||
within
(
u
,
v
,
err
))
{
if
(
res
==
eqn
)
{
eqn
=
Arrays
.
copyOf
(
eqn
,
4
);
}
res
[
1
]
=
-(
uv
/
2
)
-
sub
;
num
=
2
;
}
}
double
B
=
(
A
==
0.0
)
?
0.0
:
(
Q
/
A
);
// this must be done after the potential Arrays.copyOf
res
[
roots
++]
=
(
A
+
B
)
-
a
;
res
[
0
]
=
uv
-
sub
;
}
}
return
roots
;
}
/*
if
(
num
>
1
)
{
// num == 3 || num == 2
* This pruning step is necessary since solveCubic uses the
num
=
fixRoots
(
eqn
,
res
,
num
);
* cosine function to calculate the roots when there are 3
}
* of them. Since the cosine method can have an error of
if
(
num
>
2
&&
(
res
[
2
]
==
res
[
1
]
||
res
[
2
]
==
res
[
0
]))
{
* +/- 1E-14 we need to make sure that we don't make any
num
--;
* bad decisions due to an error.
}
*
if
(
num
>
1
&&
res
[
1
]
==
res
[
0
])
{
* If the root is not near one of the endpoints, then we will
res
[
1
]
=
res
[--
num
];
// Copies res[2] to res[1] if needed
* only have a slight inaccuracy in calculating the x intercept
* which will only cause a slightly wrong answer for some
* points very close to the curve. While the results in that
* case are not as accurate as they could be, they are not
* disastrously inaccurate either.
*
* On the other hand, if the error happens near one end of
* the curve, then our processing to reject values outside
* of the t=[0,1] range will fail and the results of that
* failure will be disastrous since for an entire horizontal
* range of test points, we will either overcount or undercount
* the crossings and get a wrong answer for all of them, even
* when they are clearly and obviously inside or outside the
* curve.
*
* To work around this problem, we try a couple of Newton-Raphson
* iterations to see if the true root is closer to the endpoint
* or further away. If it is further away, then we can stop
* since we know we are on the right side of the endpoint. If
* we change direction, then either we are now being dragged away
* from the endpoint in which case the first condition will cause
* us to stop, or we have passed the endpoint and are headed back.
* In the second case, we simply evaluate the slope at the
* endpoint itself and place ourselves on the appropriate side
* of it or on it depending on that result.
*/
private
static
void
fixRoots
(
double
res
[],
double
eqn
[])
{
final
double
EPSILON
=
1
E
-
5
;
for
(
int
i
=
0
;
i
<
3
;
i
++)
{
double
t
=
res
[
i
];
if
(
Math
.
abs
(
t
)
<
EPSILON
)
{
res
[
i
]
=
findZero
(
t
,
0
,
eqn
);
}
else
if
(
Math
.
abs
(
t
-
1
)
<
EPSILON
)
{
res
[
i
]
=
findZero
(
t
,
1
,
eqn
);
}
}
}
return
num
;
}
}
private
static
double
solveEqn
(
double
eqn
[],
int
order
,
double
t
)
{
// preconditions: eqn != res && eqn[3] != 0 && num > 1
double
v
=
eqn
[
order
];
// This method tries to improve the accuracy of the roots of eqn (which
while
(--
order
>=
0
)
{
// should be in res). It also might eliminate roots in res if it decideds
v
=
v
*
t
+
eqn
[
order
];
// that they're not real roots. It will not check for roots that the
// computation of res might have missed, so this method should only be
// used when the roots in res have been computed using an algorithm
// that never underestimates the number of roots (such as solveCubic above)
private
static
int
fixRoots
(
double
[]
eqn
,
double
[]
res
,
int
num
)
{
double
[]
intervals
=
{
eqn
[
1
],
2
*
eqn
[
2
],
3
*
eqn
[
3
]};
int
critCount
=
QuadCurve2D
.
solveQuadratic
(
intervals
,
intervals
);
if
(
critCount
==
2
&&
intervals
[
0
]
==
intervals
[
1
])
{
critCount
--;
}
}
return
v
;
if
(
critCount
==
2
&&
intervals
[
0
]
>
intervals
[
1
])
{
double
tmp
=
intervals
[
0
];
intervals
[
0
]
=
intervals
[
1
];
intervals
[
1
]
=
tmp
;
}
// below we use critCount to possibly filter out roots that shouldn't
// have been computed. We require that eqn[3] != 0, so eqn is a proper
// cubic, which means that its limits at -/+inf are -/+inf or +/-inf.
// Therefore, if critCount==2, the curve is shaped like a sideways S,
// and it could have 1-3 roots. If critCount==0 it is monotonic, and
// if critCount==1 it is monotonic with a single point where it is
// flat. In the last 2 cases there can only be 1 root. So in cases
// where num > 1 but critCount < 2, we eliminate all roots in res
// except one.
if
(
num
==
3
)
{
double
xe
=
getRootUpperBound
(
eqn
);
double
x0
=
-
xe
;
Arrays
.
sort
(
res
,
0
,
num
);
if
(
critCount
==
2
)
{
// this just tries to improve the accuracy of the computed
// roots using Newton's method.
res
[
0
]
=
refineRootWithHint
(
eqn
,
x0
,
intervals
[
0
],
res
[
0
]);
res
[
1
]
=
refineRootWithHint
(
eqn
,
intervals
[
0
],
intervals
[
1
],
res
[
1
]);
res
[
2
]
=
refineRootWithHint
(
eqn
,
intervals
[
1
],
xe
,
res
[
2
]);
return
3
;
}
else
if
(
critCount
==
1
)
{
// we only need fx0 and fxe for the sign of the polynomial
// at -inf and +inf respectively, so we don't need to do
// fx0 = solveEqn(eqn, 3, x0); fxe = solveEqn(eqn, 3, xe)
double
fxe
=
eqn
[
3
];
double
fx0
=
-
fxe
;
double
x1
=
intervals
[
0
];
double
fx1
=
solveEqn
(
eqn
,
3
,
x1
);
// if critCount == 1 or critCount == 0, but num == 3 then
// something has gone wrong. This branch and the one below
// would ideally never execute, but if they do we can't know
// which of the computed roots is closest to the real root;
// therefore, we can't use refineRootWithHint. But even if
// we did know, being here most likely means that the
// curve is very flat close to two of the computed roots
// (or maybe even all three). This might make Newton's method
// fail altogether, which would be a pain to detect and fix.
// This is why we use a very stable bisection method.
if
(
oppositeSigns
(
fx0
,
fx1
))
{
res
[
0
]
=
bisectRootWithHint
(
eqn
,
x0
,
x1
,
res
[
0
]);
}
else
if
(
oppositeSigns
(
fx1
,
fxe
))
{
res
[
0
]
=
bisectRootWithHint
(
eqn
,
x1
,
xe
,
res
[
2
]);
}
else
/* fx1 must be 0 */
{
res
[
0
]
=
x1
;
}
// return 1
}
else
if
(
critCount
==
0
)
{
res
[
0
]
=
bisectRootWithHint
(
eqn
,
x0
,
xe
,
res
[
1
]);
// return 1
}
}
else
if
(
num
==
2
&&
critCount
==
2
)
{
// XXX: here we assume that res[0] has better accuracy than res[1].
// This is true because this method is only used from solveCubic
// which puts in res[0] the root that it would compute anyway even
// if num==1. If this method is ever used from any other method, or
// if the solveCubic implementation changes, this assumption should
// be reevaluated, and the choice of goodRoot might have to become
// goodRoot = (abs(eqn'(res[0])) > abs(eqn'(res[1]))) ? res[0] : res[1]
// where eqn' is the derivative of eqn.
double
goodRoot
=
res
[
0
];
double
badRoot
=
res
[
1
];
double
x1
=
intervals
[
0
];
double
x2
=
intervals
[
1
];
// If a cubic curve really has 2 roots, one of those roots must be
// at a critical point. That can't be goodRoot, so we compute x to
// be the farthest critical point from goodRoot. If there are two
// roots, x must be the second one, so we evaluate eqn at x, and if
// it is zero (or close enough) we put x in res[1] (or badRoot, if
// |solveEqn(eqn, 3, badRoot)| < |solveEqn(eqn, 3, x)| but this
// shouldn't happen often).
double
x
=
abs
(
x1
-
goodRoot
)
>
abs
(
x2
-
goodRoot
)
?
x1
:
x2
;
double
fx
=
solveEqn
(
eqn
,
3
,
x
);
if
(
iszero
(
fx
,
10000000
*
ulp
(
x
)))
{
double
badRootVal
=
solveEqn
(
eqn
,
3
,
badRoot
);
res
[
1
]
=
abs
(
badRootVal
)
<
abs
(
fx
)
?
badRoot
:
x
;
return
2
;
}
}
// else there can only be one root - goodRoot, and it is already in res[0]
return
1
;
}
}
private
static
double
findZero
(
double
t
,
double
target
,
double
eqn
[])
{
// use newton's method.
double
slopeqn
[]
=
{
eqn
[
1
],
2
*
eqn
[
2
],
3
*
eqn
[
3
]};
private
static
double
refineRootWithHint
(
double
[]
eqn
,
double
min
,
double
max
,
double
t
)
{
double
slope
;
if
(!
inInterval
(
t
,
min
,
max
))
{
double
origdelta
=
0
;
return
t
;
}
double
[]
deriv
=
{
eqn
[
1
],
2
*
eqn
[
2
],
3
*
eqn
[
3
]};
double
origt
=
t
;
double
origt
=
t
;
while
(
true
)
{
for
(
int
i
=
0
;
i
<
3
;
i
++)
{
slope
=
solveEqn
(
slopeqn
,
2
,
t
);
double
slope
=
solveEqn
(
deriv
,
2
,
t
);
if
(
slope
==
0
)
{
// At a local minima - must return
return
t
;
}
double
y
=
solveEqn
(
eqn
,
3
,
t
);
double
y
=
solveEqn
(
eqn
,
3
,
t
);
if
(
y
==
0
)
{
// Found it! - return it
return
t
;
}
// assert(slope != 0 && y != 0);
double
delta
=
-
(
y
/
slope
);
double
delta
=
-
(
y
/
slope
);
// assert(delta != 0);
double
newt
=
t
+
delta
;
if
(
origdelta
==
0
)
{
origdelta
=
delta
;
if
(
slope
==
0
||
y
==
0
||
t
==
newt
)
{
break
;
}
}
if
(
t
<
target
)
{
if
(
delta
<
0
)
return
t
;
t
=
newt
;
}
else
if
(
t
>
target
)
{
}
if
(
delta
>
0
)
return
t
;
if
(
within
(
t
,
origt
,
1000
*
ulp
(
origt
))
&&
inInterval
(
t
,
min
,
max
))
{
}
else
{
/* t == target */
return
t
;
return
(
delta
>
0
}
?
(
target
+
java
.
lang
.
Double
.
MIN_VALUE
)
return
origt
;
:
(
target
-
java
.
lang
.
Double
.
MIN_VALUE
));
}
private
static
double
bisectRootWithHint
(
double
[]
eqn
,
double
x0
,
double
xe
,
double
hint
)
{
double
delta1
=
Math
.
min
(
abs
(
hint
-
x0
)
/
64
,
0.0625
);
double
delta2
=
Math
.
min
(
abs
(
hint
-
xe
)
/
64
,
0.0625
);
double
x02
=
hint
-
delta1
;
double
xe2
=
hint
+
delta2
;
double
fx02
=
solveEqn
(
eqn
,
3
,
x02
);
double
fxe2
=
solveEqn
(
eqn
,
3
,
xe2
);
while
(
oppositeSigns
(
fx02
,
fxe2
))
{
if
(
x02
>=
xe2
)
{
return
x02
;
}
}
double
newt
=
t
+
delta
;
x0
=
x02
;
if
(
t
==
newt
)
{
xe
=
xe2
;
// The deltas are so small that we aren't moving...
delta1
/=
64
;
return
t
;
delta2
/=
64
;
x02
=
hint
-
delta1
;
xe2
=
hint
+
delta2
;
fx02
=
solveEqn
(
eqn
,
3
,
x02
);
fxe2
=
solveEqn
(
eqn
,
3
,
xe2
);
}
if
(
fx02
==
0
)
{
return
x02
;
}
if
(
fxe2
==
0
)
{
return
xe2
;
}
return
bisectRoot
(
eqn
,
x0
,
xe
);
}
private
static
double
bisectRoot
(
double
[]
eqn
,
double
x0
,
double
xe
)
{
double
fx0
=
solveEqn
(
eqn
,
3
,
x0
);
double
m
=
x0
+
(
xe
-
x0
)
/
2
;
while
(
m
!=
x0
&&
m
!=
xe
)
{
double
fm
=
solveEqn
(
eqn
,
3
,
m
);
if
(
fm
==
0
)
{
return
m
;
}
}
if
(
delta
*
origdelta
<
0
)
{
if
(
oppositeSigns
(
fx0
,
fm
))
{
// We have reversed our path.
xe
=
m
;
int
tag
=
(
origt
<
t
?
getTag
(
target
,
origt
,
t
)
:
getTag
(
target
,
t
,
origt
));
if
(
tag
!=
INSIDE
)
{
// Local minima found away from target - return the middle
return
(
origt
+
t
)
/
2
;
}
// Local minima somewhere near target - move to target
// and let the slope determine the resulting t.
t
=
target
;
}
else
{
}
else
{
t
=
newt
;
fx0
=
fm
;
x0
=
m
;
}
}
m
=
x0
+
(
xe
-
x0
)/
2
;
}
return
m
;
}
private
static
boolean
inInterval
(
double
t
,
double
min
,
double
max
)
{
return
min
<=
t
&&
t
<=
max
;
}
private
static
boolean
within
(
double
x
,
double
y
,
double
err
)
{
double
d
=
y
-
x
;
return
(
d
<=
err
&&
d
>=
-
err
);
}
private
static
boolean
iszero
(
double
x
,
double
err
)
{
return
within
(
x
,
0
,
err
);
}
private
static
boolean
oppositeSigns
(
double
x1
,
double
x2
)
{
return
(
x1
<
0
&&
x2
>
0
)
||
(
x1
>
0
&&
x2
<
0
);
}
private
static
double
solveEqn
(
double
eqn
[],
int
order
,
double
t
)
{
double
v
=
eqn
[
order
];
while
(--
order
>=
0
)
{
v
=
v
*
t
+
eqn
[
order
];
}
}
return
v
;
}
/*
* Computes M+1 where M is an upper bound for all the roots in of eqn.
* See: http://en.wikipedia.org/wiki/Sturm%27s_theorem#Applications.
* The above link doesn't contain a proof, but I [dlila] proved it myself
* so the result is reliable. The proof isn't difficult, but it's a bit
* long to include here.
* Precondition: eqn must represent a cubic polynomial
*/
private
static
double
getRootUpperBound
(
double
[]
eqn
)
{
double
d
=
eqn
[
3
];
double
a
=
eqn
[
2
];
double
b
=
eqn
[
1
];
double
c
=
eqn
[
0
];
double
M
=
1
+
max
(
max
(
abs
(
a
),
abs
(
b
)),
abs
(
c
))
/
abs
(
d
);
M
+=
ulp
(
M
)
+
1
;
return
M
;
}
}
/**
/**
* {@inheritDoc}
* {@inheritDoc}
* @since 1.2
* @since 1.2
...
@@ -1273,110 +1434,6 @@ public abstract class CubicCurve2D implements Shape, Cloneable {
...
@@ -1273,110 +1434,6 @@ public abstract class CubicCurve2D implements Shape, Cloneable {
return
contains
(
p
.
getX
(),
p
.
getY
());
return
contains
(
p
.
getX
(),
p
.
getY
());
}
}
/*
* Fill an array with the coefficients of the parametric equation
* in t, ready for solving against val with solveCubic.
* We currently have:
* <pre>
* val = P(t) = C1(1-t)^3 + 3CP1 t(1-t)^2 + 3CP2 t^2(1-t) + C2 t^3
* = C1 - 3C1t + 3C1t^2 - C1t^3 +
* 3CP1t - 6CP1t^2 + 3CP1t^3 +
* 3CP2t^2 - 3CP2t^3 +
* C2t^3
* 0 = (C1 - val) +
* (3CP1 - 3C1) t +
* (3C1 - 6CP1 + 3CP2) t^2 +
* (C2 - 3CP2 + 3CP1 - C1) t^3
* 0 = C + Bt + At^2 + Dt^3
* C = C1 - val
* B = 3*CP1 - 3*C1
* A = 3*CP2 - 6*CP1 + 3*C1
* D = C2 - 3*CP2 + 3*CP1 - C1
* </pre>
*/
private
static
void
fillEqn
(
double
eqn
[],
double
val
,
double
c1
,
double
cp1
,
double
cp2
,
double
c2
)
{
eqn
[
0
]
=
c1
-
val
;
eqn
[
1
]
=
(
cp1
-
c1
)
*
3.0
;
eqn
[
2
]
=
(
cp2
-
cp1
-
cp1
+
c1
)
*
3.0
;
eqn
[
3
]
=
c2
+
(
cp1
-
cp2
)
*
3.0
-
c1
;
return
;
}
/*
* Evaluate the t values in the first num slots of the vals[] array
* and place the evaluated values back into the same array. Only
* evaluate t values that are within the range <0, 1>, including
* the 0 and 1 ends of the range iff the include0 or include1
* booleans are true. If an "inflection" equation is handed in,
* then any points which represent a point of inflection for that
* cubic equation are also ignored.
*/
private
static
int
evalCubic
(
double
vals
[],
int
num
,
boolean
include0
,
boolean
include1
,
double
inflect
[],
double
c1
,
double
cp1
,
double
cp2
,
double
c2
)
{
int
j
=
0
;
for
(
int
i
=
0
;
i
<
num
;
i
++)
{
double
t
=
vals
[
i
];
if
((
include0
?
t
>=
0
:
t
>
0
)
&&
(
include1
?
t
<=
1
:
t
<
1
)
&&
(
inflect
==
null
||
inflect
[
1
]
+
(
2
*
inflect
[
2
]
+
3
*
inflect
[
3
]*
t
)*
t
!=
0
))
{
double
u
=
1
-
t
;
vals
[
j
++]
=
c1
*
u
*
u
*
u
+
3
*
cp1
*
t
*
u
*
u
+
3
*
cp2
*
t
*
t
*
u
+
c2
*
t
*
t
*
t
;
}
}
return
j
;
}
private
static
final
int
BELOW
=
-
2
;
private
static
final
int
LOWEDGE
=
-
1
;
private
static
final
int
INSIDE
=
0
;
private
static
final
int
HIGHEDGE
=
1
;
private
static
final
int
ABOVE
=
2
;
/*
* Determine where coord lies with respect to the range from
* low to high. It is assumed that low <= high. The return
* value is one of the 5 values BELOW, LOWEDGE, INSIDE, HIGHEDGE,
* or ABOVE.
*/
private
static
int
getTag
(
double
coord
,
double
low
,
double
high
)
{
if
(
coord
<=
low
)
{
return
(
coord
<
low
?
BELOW
:
LOWEDGE
);
}
if
(
coord
>=
high
)
{
return
(
coord
>
high
?
ABOVE
:
HIGHEDGE
);
}
return
INSIDE
;
}
/*
* Determine if the pttag represents a coordinate that is already
* in its test range, or is on the border with either of the two
* opttags representing another coordinate that is "towards the
* inside" of that test range. In other words, are either of the
* two "opt" points "drawing the pt inward"?
*/
private
static
boolean
inwards
(
int
pttag
,
int
opt1tag
,
int
opt2tag
)
{
switch
(
pttag
)
{
case
BELOW:
case
ABOVE:
default
:
return
false
;
case
LOWEDGE:
return
(
opt1tag
>=
INSIDE
||
opt2tag
>=
INSIDE
);
case
INSIDE:
return
true
;
case
HIGHEDGE:
return
(
opt1tag
<=
INSIDE
||
opt2tag
<=
INSIDE
);
}
}
/**
/**
* {@inheritDoc}
* {@inheritDoc}
* @since 1.2
* @since 1.2
...
...
test/java/awt/geom/CubicCurve2D/ContainsTest.java
0 → 100644
浏览文件 @
8225db03
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4724552
* @summary Verifies that CubicCurve2D.contains(Rectangle2D) does not return
* true when the rectangle is only partially contained.
* @run main ContainsTest
*/
import
java.awt.geom.CubicCurve2D
;
import
java.awt.geom.Rectangle2D
;
public
class
ContainsTest
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
CubicCurve2D
c
=
new
CubicCurve2D
.
Double
(
0
,
0
,
4
,
-
4
,
-
2
,
-
4
,
2
,
0
);
Rectangle2D
r
=
new
Rectangle2D
.
Double
(
0.75
,
-
2.5
,
0.5
,
2
);
if
(
c
.
contains
(
r
))
{
throw
new
Exception
(
"The rectangle should not be contained in the curve"
);
}
}
}
test/java/awt/geom/CubicCurve2D/IntersectsTest.java
0 → 100644
浏览文件 @
8225db03
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4493128
* @summary Verifies that CubicCurve2D returns true for obvious intersection
* @run main IntersectsTest
*/
import
java.awt.geom.CubicCurve2D
;
import
java.awt.geom.Rectangle2D
;
public
class
IntersectsTest
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
CubicCurve2D
c
=
new
CubicCurve2D
.
Double
(
50.0
,
300.0
,
150.0
,
166.6666717529297
,
238.0
,
456.66668701171875
,
350.0
,
300.0
);
Rectangle2D
r
=
new
Rectangle2D
.
Double
(
260
,
300
,
10
,
10
);
if
(!
c
.
intersects
(
r
))
{
throw
new
Exception
(
"The rectangle is contained. "
+
"intersects(Rectangle2D) should return true"
);
}
}
}
test/java/awt/geom/CubicCurve2D/SolveCubicTest.java
0 → 100644
浏览文件 @
8225db03
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4645692
* @summary Verifies that SolveCubic doesn't miss any roots.
* @run main SolveCubicTest
*/
import
static
java
.
awt
.
geom
.
CubicCurve2D
.
solveCubic
;
public
class
SolveCubicTest
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
double
[]
eqn
=
{
0
,
0
,
1
,
1
};
int
numRoots
=
solveCubic
(
eqn
,
eqn
);
if
(
numRoots
<
2
)
{
throw
new
Exception
(
"There are 2 roots. Only "
+
numRoots
+
" were found."
);
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录