Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
1a979c7a
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看板
提交
1a979c7a
编写于
4月 28, 2011
作者:
D
dlila
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
7036754: NaNs in stroked quadratics.
Summary: Check for them and remove them. Reviewed-by: flar
上级
e4e8ddb4
变更
2
显示空白变更内容
内联
并排
Showing
2 changed file
with
185 addition
and
125 deletion
+185
-125
src/share/classes/sun/java2d/pisces/Stroker.java
src/share/classes/sun/java2d/pisces/Stroker.java
+127
-125
test/sun/java2d/pisces/Test7036754.java
test/sun/java2d/pisces/Test7036754.java
+58
-0
未找到文件。
src/share/classes/sun/java2d/pisces/Stroker.java
浏览文件 @
1a979c7a
...
...
@@ -27,6 +27,8 @@ package sun.java2d.pisces;
import
java.util.Arrays
;
import
java.util.Iterator
;
import
static
java
.
lang
.
Math
.
ulp
;
import
static
java
.
lang
.
Math
.
sqrt
;
import
sun.awt.geom.PathConsumer2D
;
...
...
@@ -130,7 +132,7 @@ final class Stroker implements PathConsumer2D {
private
static
void
computeOffset
(
final
float
lx
,
final
float
ly
,
final
float
w
,
final
float
[]
m
)
{
final
float
len
=
(
float
)
Math
.
sqrt
(
lx
*
lx
+
ly
*
ly
);
final
float
len
=
(
float
)
sqrt
(
lx
*
lx
+
ly
*
ly
);
if
(
len
==
0
)
{
m
[
0
]
=
m
[
1
]
=
0
;
}
else
{
...
...
@@ -217,7 +219,7 @@ final class Stroker implements PathConsumer2D {
// this normal's length is at least 0.5 and at most sqrt(2)/2 (because
// we know the angle of the arc is > 90 degrees).
float
nx
=
my
-
omy
,
ny
=
omx
-
mx
;
float
nlen
=
(
float
)
Math
.
sqrt
(
nx
*
nx
+
ny
*
ny
);
float
nlen
=
(
float
)
sqrt
(
nx
*
nx
+
ny
*
ny
);
float
scale
=
lineWidth2
/
nlen
;
float
mmx
=
nx
*
scale
,
mmy
=
ny
*
scale
;
...
...
@@ -246,8 +248,8 @@ final class Stroker implements PathConsumer2D {
// define the bezier curve we're computing.
// It is computed using the constraints that P1-P0 and P3-P2 are parallel
// to the arc tangents at the endpoints, and that |P1-P0|=|P3-P2|.
float
cv
=
(
float
)
((
4.0
/
3.0
)
*
Math
.
sqrt
(
0.5
-
cosext2
)
/
(
1.0
+
Math
.
sqrt
(
cosext2
+
0.5
)));
float
cv
=
(
float
)
((
4.0
/
3.0
)
*
sqrt
(
0.5
-
cosext2
)
/
(
1.0
+
sqrt
(
cosext2
+
0.5
)));
// if clockwise, we need to negate cv.
if
(
rev
)
{
// rev is equivalent to isCW(omx, omy, mx, my)
cv
=
-
cv
;
...
...
@@ -284,9 +286,10 @@ final class Stroker implements PathConsumer2D {
false
);
}
// Return the intersection point of the lines (x0, y0) -> (x1, y1)
// and (x0p, y0p) -> (x1p, y1p) in m[0] and m[1]
private
void
computeMiter
(
final
float
x0
,
final
float
y0
,
// Put the intersection point of the lines (x0, y0) -> (x1, y1)
// and (x0p, y0p) -> (x1p, y1p) in m[off] and m[off+1].
// If the lines are parallel, it will put a non finite number in m.
private
void
computeIntersection
(
final
float
x0
,
final
float
y0
,
final
float
x1
,
final
float
y1
,
final
float
x0p
,
final
float
y0p
,
final
float
x1p
,
final
float
y1p
,
...
...
@@ -297,15 +300,6 @@ final class Stroker implements PathConsumer2D {
float
x10p
=
x1p
-
x0p
;
float
y10p
=
y1p
-
y0p
;
// if this is 0, the lines are parallel. If they go in the
// same direction, there is no intersection so m[off] and
// m[off+1] will contain infinity, so no miter will be drawn.
// If they go in the same direction that means that the start of the
// current segment and the end of the previous segment have the same
// tangent, in which case this method won't even be involved in
// miter drawing because it won't be called by drawMiter (because
// (mx == omx && my == omy) will be true, and drawMiter will return
// immediately).
float
den
=
x10
*
y10p
-
x10p
*
y10
;
float
t
=
x10p
*(
y0
-
y0p
)
-
y10p
*(
x0
-
x0p
);
t
/=
den
;
...
...
@@ -321,7 +315,8 @@ final class Stroker implements PathConsumer2D {
{
if
((
mx
==
omx
&&
my
==
omy
)
||
(
pdx
==
0
&&
pdy
==
0
)
||
(
dx
==
0
&&
dy
==
0
))
{
(
dx
==
0
&&
dy
==
0
))
{
return
;
}
...
...
@@ -332,12 +327,17 @@ final class Stroker implements PathConsumer2D {
my
=
-
my
;
}
compute
Miter
((
x0
-
pdx
)
+
omx
,
(
y0
-
pdy
)
+
omy
,
x0
+
omx
,
y0
+
omy
,
compute
Intersection
((
x0
-
pdx
)
+
omx
,
(
y0
-
pdy
)
+
omy
,
x0
+
omx
,
y0
+
omy
,
(
dx
+
x0
)
+
mx
,
(
dy
+
y0
)
+
my
,
x0
+
mx
,
y0
+
my
,
miter
,
0
);
float
lenSq
=
(
miter
[
0
]-
x0
)*(
miter
[
0
]-
x0
)
+
(
miter
[
1
]-
y0
)*(
miter
[
1
]-
y0
);
// If the lines are parallel, lenSq will be either NaN or +inf
// (actually, I'm not sure if the latter is possible. The important
// thing is that -inf is not possible, because lenSq is a square).
// For both of those values, the comparison below will fail and
// no miter will be drawn, which is correct.
if
(
lenSq
<
miterLimitSq
)
{
emitLineTo
(
miter
[
0
],
miter
[
1
],
rev
);
}
...
...
@@ -566,8 +566,8 @@ final class Stroker implements PathConsumer2D {
// if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
// in which case ignore if p1 == p2
final
boolean
p1eqp2
=
within
(
x1
,
y1
,
x2
,
y2
,
6
*
Math
.
ulp
(
y2
));
final
boolean
p3eqp4
=
within
(
x3
,
y3
,
x4
,
y4
,
6
*
Math
.
ulp
(
y4
));
final
boolean
p1eqp2
=
within
(
x1
,
y1
,
x2
,
y2
,
6
*
ulp
(
y2
));
final
boolean
p3eqp4
=
within
(
x3
,
y3
,
x4
,
y4
,
6
*
ulp
(
y4
));
if
(
p1eqp2
&&
p3eqp4
)
{
getLineOffsets
(
x1
,
y1
,
x4
,
y4
,
leftOff
,
rightOff
);
return
4
;
...
...
@@ -583,7 +583,7 @@ final class Stroker implements PathConsumer2D {
float
dotsq
=
(
dx1
*
dx4
+
dy1
*
dy4
);
dotsq
=
dotsq
*
dotsq
;
float
l1sq
=
dx1
*
dx1
+
dy1
*
dy1
,
l4sq
=
dx4
*
dx4
+
dy4
*
dy4
;
if
(
Helpers
.
within
(
dotsq
,
l1sq
*
l4sq
,
4
*
Math
.
ulp
(
dotsq
)))
{
if
(
Helpers
.
within
(
dotsq
,
l1sq
*
l4sq
,
4
*
ulp
(
dotsq
)))
{
getLineOffsets
(
x1
,
y1
,
x4
,
y4
,
leftOff
,
rightOff
);
return
4
;
}
...
...
@@ -693,8 +693,6 @@ final class Stroker implements PathConsumer2D {
return
8
;
}
// compute offset curves using bezier spline through t=0.5 (i.e.
// ComputedCurve(0.5) == IdealParallelCurve(0.5))
// return the kind of curve in the right and left arrays.
private
int
computeOffsetQuad
(
float
[]
pts
,
final
int
off
,
float
[]
leftOff
,
float
[]
rightOff
)
...
...
@@ -703,58 +701,69 @@ final class Stroker implements PathConsumer2D {
final
float
x2
=
pts
[
off
+
2
],
y2
=
pts
[
off
+
3
];
final
float
x3
=
pts
[
off
+
4
],
y3
=
pts
[
off
+
5
];
float
dx3
=
x3
-
x2
;
float
dy3
=
y3
-
y2
;
float
dx1
=
x2
-
x1
;
float
dy1
=
y2
-
y1
;
f
inal
f
loat
dx3
=
x3
-
x2
;
f
inal
f
loat
dy3
=
y3
-
y2
;
f
inal
f
loat
dx1
=
x2
-
x1
;
f
inal
f
loat
dy1
=
y2
-
y1
;
// if p1=p2 or p3=p4 it means that the derivative at the endpoint
// vanishes, which creates problems with computeOffset. Usually
// this happens when this stroker object is trying to winden
// a curve with a cusp. What happens is that curveTo splits
// the input curve at the cusp, and passes it to this function.
// because of inaccuracies in the splitting, we consider points
// equal if they're very close to each other.
// this computes the offsets at t = 0, 1
computeOffset
(
dx1
,
dy1
,
lineWidth2
,
offset
[
0
]);
computeOffset
(
dx3
,
dy3
,
lineWidth2
,
offset
[
1
]);
// if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
// in which case ignore.
final
boolean
p1eqp2
=
within
(
x1
,
y1
,
x2
,
y2
,
6
*
Math
.
ulp
(
y2
));
final
boolean
p2eqp3
=
within
(
x2
,
y2
,
x3
,
y3
,
6
*
Math
.
ulp
(
y3
));
if
(
p1eqp2
||
p2eqp3
)
{
leftOff
[
0
]
=
x1
+
offset
[
0
][
0
];
leftOff
[
1
]
=
y1
+
offset
[
0
][
1
];
leftOff
[
4
]
=
x3
+
offset
[
1
][
0
];
leftOff
[
5
]
=
y3
+
offset
[
1
][
1
];
rightOff
[
0
]
=
x1
-
offset
[
0
][
0
];
rightOff
[
1
]
=
y1
-
offset
[
0
][
1
];
rightOff
[
4
]
=
x3
-
offset
[
1
][
0
];
rightOff
[
5
]
=
y3
-
offset
[
1
][
1
];
float
x1p
=
leftOff
[
0
];
// start
float
y1p
=
leftOff
[
1
];
// point
float
x3p
=
leftOff
[
4
];
// end
float
y3p
=
leftOff
[
5
];
// point
// Corner cases:
// 1. If the two control vectors are parallel, we'll end up with NaN's
// in leftOff (and rightOff in the body of the if below), so we'll
// do getLineOffsets, which is right.
// 2. If the first or second two points are equal, then (dx1,dy1)==(0,0)
// or (dx3,dy3)==(0,0), so (x1p, y1p)==(x1p+dx1, y1p+dy1)
// or (x3p, y3p)==(x3p-dx3, y3p-dy3), which means that
// computeIntersection will put NaN's in leftOff and right off, and
// we will do getLineOffsets, which is right.
computeIntersection
(
x1p
,
y1p
,
x1p
+
dx1
,
y1p
+
dy1
,
x3p
,
y3p
,
x3p
-
dx3
,
y3p
-
dy3
,
leftOff
,
2
);
float
cx
=
leftOff
[
2
];
float
cy
=
leftOff
[
3
];
if
(!(
isFinite
(
cx
)
&&
isFinite
(
cy
)))
{
// maybe the right path is not degenerate.
x1p
=
rightOff
[
0
];
y1p
=
rightOff
[
1
];
x3p
=
rightOff
[
4
];
y3p
=
rightOff
[
5
];
computeIntersection
(
x1p
,
y1p
,
x1p
+
dx1
,
y1p
+
dy1
,
x3p
,
y3p
,
x3p
-
dx3
,
y3p
-
dy3
,
rightOff
,
2
);
cx
=
rightOff
[
2
];
cy
=
rightOff
[
3
];
if
(!(
isFinite
(
cx
)
&&
isFinite
(
cy
)))
{
// both are degenerate. This curve is a line.
getLineOffsets
(
x1
,
y1
,
x3
,
y3
,
leftOff
,
rightOff
);
return
4
;
}
// if p2-p1 and p4-p3 are parallel, that must mean this curve is a line
float
dotsq
=
(
dx1
*
dx3
+
dy1
*
dy3
);
dotsq
=
dotsq
*
dotsq
;
float
l1sq
=
dx1
*
dx1
+
dy1
*
dy1
,
l3sq
=
dx3
*
dx3
+
dy3
*
dy3
;
if
(
Helpers
.
within
(
dotsq
,
l1sq
*
l3sq
,
4
*
Math
.
ulp
(
dotsq
)))
{
getLineOffsets
(
x1
,
y1
,
x3
,
y3
,
leftOff
,
rightOff
);
return
4
;
// {left,right}Off[0,1,4,5] are already set to the correct values.
leftOff
[
2
]
=
2
*
x2
-
cx
;
leftOff
[
3
]
=
2
*
y2
-
cy
;
return
6
;
}
// this computes the offsets at t=0, 0.5, 1, using the property that
// for any bezier curve the vectors p2-p1 and p4-p3 are parallel to
// the (dx/dt, dy/dt) vectors at the endpoints.
computeOffset
(
dx1
,
dy1
,
lineWidth2
,
offset
[
0
]);
computeOffset
(
dx3
,
dy3
,
lineWidth2
,
offset
[
1
]);
float
x1p
=
x1
+
offset
[
0
][
0
];
// start
float
y1p
=
y1
+
offset
[
0
][
1
];
// point
float
x3p
=
x3
+
offset
[
1
][
0
];
// end
float
y3p
=
y3
+
offset
[
1
][
1
];
// point
computeMiter
(
x1p
,
y1p
,
x1p
+
dx1
,
y1p
+
dy1
,
x3p
,
y3p
,
x3p
-
dx3
,
y3p
-
dy3
,
leftOff
,
2
);
leftOff
[
0
]
=
x1p
;
leftOff
[
1
]
=
y1p
;
leftOff
[
4
]
=
x3p
;
leftOff
[
5
]
=
y3p
;
x1p
=
x1
-
offset
[
0
][
0
];
y1p
=
y1
-
offset
[
0
][
1
];
x3p
=
x3
-
offset
[
1
][
0
];
y3p
=
y3
-
offset
[
1
][
1
];
computeMiter
(
x1p
,
y1p
,
x1p
+
dx1
,
y1p
+
dy1
,
x3p
,
y3p
,
x3p
-
dx3
,
y3p
-
dy3
,
rightOff
,
2
);
rightOff
[
0
]
=
x1p
;
rightOff
[
1
]
=
y1p
;
rightOff
[
4
]
=
x3p
;
rightOff
[
5
]
=
y3p
;
// rightOff[2,3] = (x2,y2) - ((left_x2, left_y2) - (x2, y2))
// == 2*(x2, y2) - (left_x2, left_y2)
rightOff
[
2
]
=
2
*
x2
-
cx
;
rightOff
[
3
]
=
2
*
y2
-
cy
;
return
6
;
}
private
static
boolean
isFinite
(
float
x
)
{
return
(
Float
.
NEGATIVE_INFINITY
<
x
&&
x
<
Float
.
POSITIVE_INFINITY
);
}
// This is where the curve to be processed is put. We give it
// enough room to store 2 curves: one for the current subdivision, the
// other for the rest of the curve.
...
...
@@ -812,12 +821,12 @@ final class Stroker implements PathConsumer2D {
// if these vectors are too small, normalize them, to avoid future
// precision problems.
if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
float len = (float)
Math.
sqrt(dxs*dxs + dys*dys);
float len = (float)
sqrt(dxs*dxs + dys*dys);
dxs /= len;
dys /= len;
}
if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
float len = (float)
Math.
sqrt(dxf*dxf + dyf*dyf);
float len = (float)
sqrt(dxf*dxf + dyf*dyf);
dxf /= len;
dyf /= len;
}
...
...
@@ -834,7 +843,6 @@ final class Stroker implements PathConsumer2D {
while(it.hasNext()) {
int curCurveOff = it.next();
kind = 0;
switch (type) {
case 8:
kind = computeOffsetCubic(middle, curCurveOff, lp, rp);
...
...
@@ -843,7 +851,6 @@ final class Stroker implements PathConsumer2D {
kind = computeOffsetQuad(middle, curCurveOff, lp, rp);
break;
}
if (kind != 0) {
emitLineTo(lp[0], lp[1]);
switch(kind) {
case 8:
...
...
@@ -861,7 +868,6 @@ final class Stroker implements PathConsumer2D {
}
emitLineTo(rp[kind - 2], rp[kind - 1], true);
}
}
this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2;
this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2;
...
...
@@ -887,7 +893,7 @@ final class Stroker implements PathConsumer2D {
// we rotate it so that the first vector in the control polygon is
// parallel to the x-axis. This will ensure that rotated quarter
// circles won't be subdivided.
final
float
hypot
=
(
float
)
Math
.
sqrt
(
x12
*
x12
+
y12
*
y12
);
final
float
hypot
=
(
float
)
sqrt
(
x12
*
x12
+
y12
*
y12
);
final
float
cos
=
x12
/
hypot
;
final
float
sin
=
y12
/
hypot
;
final
float
x1
=
cos
*
pts
[
0
]
+
sin
*
pts
[
1
];
...
...
@@ -976,12 +982,12 @@ final class Stroker implements PathConsumer2D {
// if these vectors are too small, normalize them, to avoid future
// precision problems.
if
(
Math
.
abs
(
dxs
)
<
0.1f
&&
Math
.
abs
(
dys
)
<
0.1f
)
{
float
len
=
(
float
)
Math
.
sqrt
(
dxs
*
dxs
+
dys
*
dys
);
float
len
=
(
float
)
sqrt
(
dxs
*
dxs
+
dys
*
dys
);
dxs
/=
len
;
dys
/=
len
;
}
if
(
Math
.
abs
(
dxf
)
<
0.1f
&&
Math
.
abs
(
dyf
)
<
0.1f
)
{
float
len
=
(
float
)
Math
.
sqrt
(
dxf
*
dxf
+
dyf
*
dyf
);
float
len
=
(
float
)
sqrt
(
dxf
*
dxf
+
dyf
*
dyf
);
dxf
/=
len
;
dyf
/=
len
;
}
...
...
@@ -999,7 +1005,6 @@ final class Stroker implements PathConsumer2D {
int
curCurveOff
=
it
.
next
();
kind
=
computeOffsetCubic
(
middle
,
curCurveOff
,
lp
,
rp
);
if
(
kind
!=
0
)
{
emitLineTo
(
lp
[
0
],
lp
[
1
]);
switch
(
kind
)
{
case
8
:
...
...
@@ -1013,7 +1018,6 @@ final class Stroker implements PathConsumer2D {
}
emitLineTo
(
rp
[
kind
-
2
],
rp
[
kind
-
1
],
true
);
}
}
this
.
cmx
=
(
lp
[
kind
-
2
]
-
rp
[
kind
-
2
])
/
2
;
this
.
cmy
=
(
lp
[
kind
-
1
]
-
rp
[
kind
-
1
])
/
2
;
...
...
@@ -1050,12 +1054,12 @@ final class Stroker implements PathConsumer2D {
// if these vectors are too small, normalize them, to avoid future
// precision problems.
if
(
Math
.
abs
(
dxs
)
<
0.1f
&&
Math
.
abs
(
dys
)
<
0.1f
)
{
float
len
=
(
float
)
Math
.
sqrt
(
dxs
*
dxs
+
dys
*
dys
);
float
len
=
(
float
)
sqrt
(
dxs
*
dxs
+
dys
*
dys
);
dxs
/=
len
;
dys
/=
len
;
}
if
(
Math
.
abs
(
dxf
)
<
0.1f
&&
Math
.
abs
(
dyf
)
<
0.1f
)
{
float
len
=
(
float
)
Math
.
sqrt
(
dxf
*
dxf
+
dyf
*
dyf
);
float
len
=
(
float
)
sqrt
(
dxf
*
dxf
+
dyf
*
dyf
);
dxf
/=
len
;
dyf
/=
len
;
}
...
...
@@ -1073,7 +1077,6 @@ final class Stroker implements PathConsumer2D {
int
curCurveOff
=
it
.
next
();
kind
=
computeOffsetQuad
(
middle
,
curCurveOff
,
lp
,
rp
);
if
(
kind
!=
0
)
{
emitLineTo
(
lp
[
0
],
lp
[
1
]);
switch
(
kind
)
{
case
6
:
...
...
@@ -1087,7 +1090,6 @@ final class Stroker implements PathConsumer2D {
}
emitLineTo
(
rp
[
kind
-
2
],
rp
[
kind
-
1
],
true
);
}
}
this
.
cmx
=
(
lp
[
kind
-
2
]
-
rp
[
kind
-
2
])
/
2
;
this
.
cmy
=
(
lp
[
kind
-
1
]
-
rp
[
kind
-
1
])
/
2
;
...
...
test/sun/java2d/pisces/Test7036754.java
0 → 100644
浏览文件 @
1a979c7a
/*
* 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 7036754
*
* @summary Verifies that there are no non-finite numbers when stroking
* certain quadratic curves.
*
* @author Jim Graham
* @run main Test7036754
*/
import
java.awt.*
;
import
java.awt.geom.*
;
public
class
Test7036754
{
public
static
void
main
(
String
argv
[])
{
Shape
s
=
new
QuadCurve2D
.
Float
(
839.24677f
,
508.97888f
,
839.2953f
,
508.97122f
,
839.3438f
,
508.96353f
);
s
=
new
BasicStroke
(
10
f
).
createStrokedShape
(
s
);
float
nsegs
[]
=
{
2
,
2
,
4
,
6
,
0
};
float
coords
[]
=
new
float
[
6
];
PathIterator
pi
=
s
.
getPathIterator
(
null
);
while
(!
pi
.
isDone
())
{
int
type
=
pi
.
currentSegment
(
coords
);
for
(
int
i
=
0
;
i
<
nsegs
[
type
];
i
++)
{
float
c
=
coords
[
i
];
if
(
Float
.
isNaN
(
c
)
||
Float
.
isInfinite
(
c
))
{
throw
new
RuntimeException
(
"bad value in stroke"
);
}
}
pi
.
next
();
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录