下面列出了android.graphics.Path#arcTo ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private void testArc(Canvas canvas) {
Path path=new Path();
int minWidth=400;
int br = minWidth / 2;
RectF bigCircle = new RectF(-br, -br, br, br);
int sr = minWidth / 4;
RectF smallCircle = new RectF(-sr, -sr, sr, sr);
float bigSweepAngle = 84;
float smallSweepAngle = -80;
path.addArc(bigCircle, 50, bigSweepAngle);
path.arcTo(smallCircle, 130, smallSweepAngle);
path.close();
canvas.drawPath(path, mDeafultPaint);
logRegion();
}
public void leftPath(RectF rect, Path path) {
path.moveTo(mAngle + mArrowWidth, rect.top);
path.lineTo(rect.width(), rect.top);
path.arcTo(new RectF(rect.right - mAngle * 2, rect.top, rect.right,
mAngle * 2 + rect.top), 270, 90);
path.lineTo(rect.right, rect.top);
path.arcTo(new RectF(rect.right - mAngle * 2, rect.bottom - mAngle * 2,
rect.right, rect.bottom), 0, 90);
path.lineTo(rect.left + mArrowWidth, rect.bottom);
path.arcTo(new RectF(rect.left + mArrowWidth, rect.bottom - mAngle * 2,
mAngle * 2 + rect.left + mArrowWidth, rect.bottom), 90, 90);
path.lineTo(rect.left + mArrowWidth, mArrowTop + mArrowHeight);
path.lineTo(rect.left, mArrowTop - mArrowOffset);
path.lineTo(rect.left + mArrowWidth, mArrowTop);
path.lineTo(rect.left + mArrowWidth, rect.top);
path.arcTo(new RectF(rect.left + mArrowWidth, rect.top, mAngle * 2
+ rect.left + mArrowWidth, mAngle * 2 + rect.top), 180, 90);
path.close();
}
@Override
protected void onBoundsChange(Rect bounds) {
int width = bounds.width();
int height = bounds.height();
RectF rectF = mTempRectF;
Path path = mPath;
path.reset();
if (width > height) {
int radius = height / 2;
path.moveTo(bounds.right - radius, bounds.top);
rectF.set(bounds.right - height, bounds.top, bounds.right, bounds.bottom);
path.arcTo(rectF, -90.0f, 180.0f, false);
path.lineTo(bounds.left + radius, bounds.bottom);
rectF.set(bounds.left, bounds.top, bounds.left + height, bounds.bottom);
path.arcTo(rectF, 90.0f, 180.0f, false);
path.lineTo(bounds.right - radius, bounds.top);
} else if (width == height) {
path.addCircle(bounds.centerX(), bounds.centerY(), width / 2, Path.Direction.CW);
} else {
// TODO
}
}
public void rightPath(RectF rect, Path path) {
path.moveTo(mAngle, rect.top);
path.lineTo(rect.width(), rect.top);
path.arcTo(new RectF(rect.right - mAngle * 2 - mArrowWidth, rect.top,
rect.right - mArrowWidth, mAngle * 2 + rect.top), 270, 90);
path.lineTo(rect.right - mArrowWidth, mArrowTop);
path.lineTo(rect.right, mArrowTop - mArrowOffset);
path.lineTo(rect.right - mArrowWidth, mArrowTop + mArrowHeight);
path.lineTo(rect.right - mArrowWidth, rect.height() - mAngle);
path.arcTo(new RectF(rect.right - mAngle * 2 - mArrowWidth, rect.bottom
- mAngle * 2, rect.right - mArrowWidth, rect.bottom), 0, 90);
path.lineTo(rect.left, rect.bottom);
path.arcTo(new RectF(rect.left, rect.bottom - mAngle * 2, mAngle * 2
+ rect.left, rect.bottom), 90, 90);
path.lineTo(rect.left, rect.top);
path.arcTo(new RectF(rect.left, rect.top, mAngle * 2 + rect.left,
mAngle * 2 + rect.top), 180, 90);
path.close();
}
private void initTopRoundedPath(RectF rect, Path path, float strokeWidth) {
path.moveTo(rect.left + Math.min(mArrowPosition, mCornersRadius) + strokeWidth, rect.top + mArrowHeight + strokeWidth);
path.lineTo(rect.left + mArrowPosition + (strokeWidth / 2), rect.top + mArrowHeight + strokeWidth);
path.lineTo(rect.left + mArrowWidth / 2 + mArrowPosition, rect.top + strokeWidth + strokeWidth);
path.lineTo(rect.left + mArrowWidth + mArrowPosition - (strokeWidth / 2), rect.top + mArrowHeight + strokeWidth);
path.lineTo(rect.right - mCornersRadius - strokeWidth, rect.top + mArrowHeight + strokeWidth);
path.arcTo(new RectF(rect.right - mCornersRadius,
rect.top + mArrowHeight + strokeWidth, rect.right - strokeWidth, mCornersRadius + rect.top + mArrowHeight), 270, 90);
path.lineTo(rect.right - strokeWidth, rect.bottom - mCornersRadius - strokeWidth);
path.arcTo(new RectF(rect.right - mCornersRadius, rect.bottom - mCornersRadius,
rect.right - strokeWidth, rect.bottom - strokeWidth), 0, 90);
path.lineTo(rect.left + mCornersRadius + strokeWidth, rect.bottom - strokeWidth);
path.arcTo(new RectF(rect.left + strokeWidth, rect.bottom - mCornersRadius,
mCornersRadius + rect.left, rect.bottom - strokeWidth), 90, 90);
path.lineTo(rect.left + strokeWidth, rect.top + mArrowHeight + mCornersRadius + strokeWidth);
path.arcTo(new RectF(rect.left + strokeWidth, rect.top + mArrowHeight + strokeWidth, mCornersRadius
+ rect.left, mCornersRadius + rect.top + mArrowHeight), 180, 90);
path.close();
}
private void drawLiftUp(Canvas canvas) {
Path path = new Path();
path.moveTo(0, roundHeight);
path.lineTo(0, 0);
path.lineTo(roundWidth, 0);
path.arcTo(new RectF(
0,
0,
roundWidth * 2,
roundHeight * 2),
-90,
-90);
path.close();
canvas.drawPath(path, paint);
}
private void clipRightDown(Canvas canvas) {
int height = getHeight();
int width = getWidth();
Path path = new Path();
path.moveTo(width-roundWidth, height);
path.lineTo(width, height);
path.lineTo(width, height-roundHeight);
RectF arc = new RectF(width - roundWidth * 2, height - roundHeight * 2, width, height);
float startAngle=0;
float sweepAngle=90;
path.arcTo(arc, startAngle, sweepAngle);
path.close();
canvas.drawPath(path, paint);
}
private void drawLeftUp(Canvas canvas) {
Path path = new Path();
path.moveTo(0, roundHeight);
path.lineTo(0, 0);
path.lineTo(roundWidth, 0);
path.arcTo(new RectF(0, 0, roundWidth * 2, roundHeight * 2), -90, -90);
path.close();
canvas.drawPath(path, paint);
}
private void drawRightDown(Canvas canvas) {
Path path = new Path();
path.moveTo(getWidth() - roundWidth, getHeight());
path.lineTo(getWidth(), getHeight());
path.lineTo(getWidth(), getHeight() - roundHeight);
path.arcTo(new RectF(getWidth() - roundWidth * 2, getHeight() - roundHeight * 2, getWidth(), getHeight()), 0, 90);
path.close();
canvas.drawPath(path, paint);
}
private void drawRightUp(Canvas canvas) {
Path path = new Path();
path.moveTo(getWidth(), roundHeight);
path.lineTo(getWidth(), 0);
path.lineTo(getWidth() - roundWidth, 0);
path.arcTo(new RectF(getWidth() - roundWidth * 2, 0, getWidth(), 0 + roundHeight * 2), -90, 90);
path.close();
canvas.drawPath(path, paint);
}
private Path getOutline(float scale) {
RectF outerBB = new RectF(-mOuter * scale, -mOuter * scale, mOuter * scale, mOuter * scale);
RectF innerBB = new RectF(-mInner * scale, -mInner * scale, mInner * scale, mInner * scale);
double gamma = (mInner + mOuter) * Math.sin(Math.toRadians(mGap / 2.0f));
float alphaOuter = (float) Math.toDegrees(Math.asin( gamma / (mOuter * 2.0f)));
float alphaInner = (float) Math.toDegrees(Math.asin( gamma / (mInner * 2.0f)));
Path path = new Path();
path.arcTo(outerBB, mStart + alphaOuter, mSweep - 2 * alphaOuter, true);
path.arcTo(innerBB, mStart + mSweep - alphaInner, 2 * alphaInner - mSweep);
path.close();
return path;
}
private void drawLiftDown(Canvas canvas) {
Path path = new Path();
path.moveTo(0, getHeight() - roundHeight);
path.lineTo(0, getHeight());
path.lineTo(roundWidth, getHeight());
path.arcTo(new RectF(0, getHeight() - roundHeight * 2, 0 + roundWidth * 2, getHeight()), 90, 90);
path.close();
canvas.drawPath(path, paint);
}
private void drawTopRight(Canvas canvas) {
if ((radius[2] > 0) || (radius[3] > 0)) {
int width = getWidth();
Path path = new Path();
path.moveTo(width - radius[2], 0);
path.lineTo(width, 0);
path.lineTo(width, radius[3]);
path.arcTo(new RectF(width - 2 * radius[2], 0, width,
radius[3] * 2), 0, -90);
path.close();
canvas.drawPath(path, roundPaint);
}
}
private void drawRightUp(Canvas canvas) {
Path path = new Path();
path.moveTo(getWidth(), roundHeight);
path.lineTo(getWidth(), 0);
path.lineTo(getWidth() - roundWidth, 0);
path.arcTo(new RectF(getWidth() - roundWidth * 2, 0, getWidth(), 0 + roundHeight * 2), -90, 90);
path.close();
canvas.drawPath(path, paint);
}
public static void drawArc(Path p, float lastX, float lastY, float x, float y, float rx, float
ry, float theta, int largeArc, int sweepArc) {
Log.d("drawArc", "from (" + lastX + "," + lastY + ") to (" + x + "," + y + ") r=(" + rx + "," + ry +
") theta=" + theta + " flags=" + largeArc + "," + sweepArc);
// http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
if (rx == 0 || ry == 0) {
p.lineTo(x, y);
return;
}
if (x == lastX && y == lastY) {
return; // nothing to draw
}
rx = Math.abs(rx);
ry = Math.abs(ry);
final float thrad = theta * (float) Math.PI / 180;
final float st = (float) Math.sin(thrad);
final float ct = (float) Math.cos(thrad);
final float xc = (lastX - x) / 2;
final float yc = (lastY - y) / 2;
final float x1t = ct * xc + st * yc;
final float y1t = -st * xc + ct * yc;
final float x1ts = x1t * x1t;
final float y1ts = y1t * y1t;
float rxs = rx * rx;
float rys = ry * ry;
float lambda = (x1ts / rxs + y1ts / rys) * 1.001f; // add 0.1% to be sure that no out of range occurs due to
// limited precision
if (lambda > 1) {
float lambdasr = (float) Math.sqrt(lambda);
rx *= lambdasr;
ry *= lambdasr;
rxs = rx * rx;
rys = ry * ry;
}
final float R =
(float) Math.sqrt((rxs * rys - rxs * y1ts - rys * x1ts) / (rxs * y1ts + rys * x1ts))
* ((largeArc == sweepArc) ? -1 : 1);
final float cxt = R * rx * y1t / ry;
final float cyt = -R * ry * x1t / rx;
final float cx = ct * cxt - st * cyt + (lastX + x) / 2;
final float cy = st * cxt + ct * cyt + (lastY + y) / 2;
final float th1 = angle(1, 0, (x1t - cxt) / rx, (y1t - cyt) / ry);
float dth = angle((x1t - cxt) / rx, (y1t - cyt) / ry, (-x1t - cxt) / rx, (-y1t - cyt) / ry);
if (sweepArc == 0 && dth > 0) {
dth -= 360;
} else if (sweepArc != 0 && dth < 0) {
dth += 360;
}
// draw
if ((theta % 360) == 0) {
// no rotate and translate need
arcRectf.set(cx - rx, cy - ry, cx + rx, cy + ry);
p.arcTo(arcRectf, th1, dth);
} else {
// this is the hard and slow part :-)
arcRectf.set(-rx, -ry, rx, ry);
arcMatrix.reset();
arcMatrix.postRotate(theta);
arcMatrix.postTranslate(cx, cy);
arcMatrix.invert(arcMatrix2);
p.transform(arcMatrix2);
p.arcTo(arcRectf, th1, dth);
p.transform(arcMatrix);
}
}
/**
* Creates a {@link Path} from an array of instructions constructed by JS
* (see ARTSerializablePath.js). Each instruction starts with a type (see PATH_TYPE_*) followed
* by arguments for that instruction. For example, to create a line the instruction will be
* 2 (PATH_LINE_TO), x, y. This will draw a line from the last draw point (or 0,0) to x,y.
*
* @param data the array of instructions
* @return the {@link Path} that can be drawn to a canvas
*/
private Path createPath(float[] data) {
Path path = new Path();
path.moveTo(0, 0);
int i = 0;
while (i < data.length) {
int type = (int) data[i++];
switch (type) {
case PATH_TYPE_MOVETO:
path.moveTo(data[i++] * mScale, data[i++] * mScale);
break;
case PATH_TYPE_CLOSE:
path.close();
break;
case PATH_TYPE_LINETO:
path.lineTo(data[i++] * mScale, data[i++] * mScale);
break;
case PATH_TYPE_CURVETO:
path.cubicTo(
data[i++] * mScale,
data[i++] * mScale,
data[i++] * mScale,
data[i++] * mScale,
data[i++] * mScale,
data[i++] * mScale);
break;
case PATH_TYPE_ARC:
{
float x = data[i++] * mScale;
float y = data[i++] * mScale;
float r = data[i++] * mScale;
float start = (float) Math.toDegrees(data[i++]);
float end = (float) Math.toDegrees(data[i++]);
boolean counterClockwise = !(data[i++] == 1f);
float sweep = end - start;
if (Math.abs(sweep) >= 360) {
path.addCircle(x, y, r, counterClockwise ? Path.Direction.CCW : Path.Direction.CW);
} else {
sweep = modulus(sweep, 360);
if (counterClockwise && sweep < 360) {
// Counter-clockwise sweeps are negative
sweep = -1 * (360 - sweep);
}
RectF oval = new RectF(x - r, y - r, x + r, y + r);
path.arcTo(oval, start, sweep);
}
break;
}
default:
throw new JSApplicationIllegalArgumentException(
"Unrecognized drawing instruction " + type);
}
}
return path;
}
/**
* Draws a corner shadow on the canvas in the current bounds with the matrix transform applied.
*/
public void drawCornerShadow(
@NonNull Canvas canvas,
@Nullable Matrix matrix,
@NonNull RectF bounds,
int elevation,
float startAngle,
float sweepAngle) {
boolean drawShadowInsideBounds = sweepAngle < 0;
Path arcBounds = scratch;
if (drawShadowInsideBounds) {
cornerColors[0] = 0;
cornerColors[1] = shadowEndColor;
cornerColors[2] = shadowMiddleColor;
cornerColors[3] = shadowStartColor;
} else {
// Calculate the arc bounds to prevent drawing shadow in the same part of the arc.
arcBounds.rewind();
arcBounds.moveTo(bounds.centerX(), bounds.centerY());
arcBounds.arcTo(bounds, startAngle, sweepAngle);
arcBounds.close();
bounds.inset(-elevation, -elevation);
cornerColors[0] = 0;
cornerColors[1] = shadowStartColor;
cornerColors[2] = shadowMiddleColor;
cornerColors[3] = shadowEndColor;
}
float startRatio = 1f - (elevation / (bounds.width() / 2f));
float midRatio = startRatio + ((1f - startRatio) / 2f);
cornerPositions[1] = startRatio;
cornerPositions[2] = midRatio;
cornerShadowPaint.setShader(
new RadialGradient(
bounds.centerX(),
bounds.centerY(),
bounds.width() / 2,
cornerColors,
cornerPositions,
Shader.TileMode.CLAMP));
// TODO(b/117606382): handle oval bounds by scaling the canvas.
canvas.save();
canvas.concat(matrix);
if (!drawShadowInsideBounds) {
canvas.clipPath(arcBounds, Op.DIFFERENCE);
// This line is required for the next drawArc to work correctly, I think.
canvas.drawPath(arcBounds, transparentPaint);
}
canvas.drawArc(bounds, startAngle, sweepAngle, true, cornerShadowPaint);
canvas.restore();
}
private void initLeftRoundedPath(RectF rect, Path path, float strokeWidth) {
path.moveTo(getArrowWidth() + rect.left + getCornersRadius() + strokeWidth, rect.top + strokeWidth);
path.lineTo(rect.width() - getCornersRadius() - strokeWidth, rect.top + strokeWidth);
path.arcTo(new RectF(rect.right - getCornersRadius(), rect.top + strokeWidth, rect.right - strokeWidth,
getCornersRadius() + rect.top), 270, 90);
path.lineTo(rect.right - strokeWidth, rect.bottom - getCornersRadius() - strokeWidth);
path.arcTo(new RectF(rect.right - getCornersRadius(), rect.bottom - getCornersRadius(),
rect.right - strokeWidth, rect.bottom - strokeWidth), 0, 90);
path.lineTo(rect.left + getArrowWidth() + getCornersRadius() + strokeWidth, rect.bottom - strokeWidth);
path.arcTo(new RectF(rect.left + getArrowWidth() + strokeWidth, rect.bottom - getCornersRadius(),
getCornersRadius() + rect.left + getArrowWidth(), rect.bottom - strokeWidth), 90, 90);
path.lineTo(rect.left + getArrowWidth() + strokeWidth, getArrowHeight() + getArrowPosition() - (strokeWidth / 2));
path.lineTo(rect.left + strokeWidth + strokeWidth, getArrowPosition() + getArrowHeight() / 2);
path.lineTo(rect.left + getArrowWidth() + strokeWidth, getArrowPosition() + (strokeWidth / 2));
path.lineTo(rect.left + getArrowWidth() + strokeWidth, rect.top + getCornersRadius() + strokeWidth);
path.arcTo(new RectF(rect.left + getArrowWidth() + strokeWidth, rect.top + strokeWidth, getCornersRadius()
+ rect.left + getArrowWidth(), getCornersRadius() + rect.top), 180, 90);
path.close();
}
/**
*
* @param path
* @param x
* @param y
* @param r radius
* @param sAngle start angle in degrees
* @param eAngle how many degrees relative to sAngle
*/
public static void arc(Path path, float x, float y, float r, float sAngle, float eAngle)
{
RectF oval = new RectF(x-r, y-r, x+r, y+r);
path.arcTo(oval, sAngle, eAngle, true);
}
/**
*
* @param path
* @param x
* @param y
* @param r radius
* @param sAngle start angle in degrees
* @param eAngle how many degrees relative to sAngle
* @param moveTo If true, begin a new contour
*/
public static void arc(Path path, float x, float y, float r, float sAngle, float eAngle, boolean moveTo)
{
RectF oval = new RectF(x-r, y-r, x+r, y+r);
path.arcTo(oval, sAngle, eAngle, moveTo);
}