From 9af77a4ce22540726fbddd275f89e65fd1a1edf8 Mon Sep 17 00:00:00 2001 From: ztenghui Date: Wed, 1 Apr 2015 16:38:44 -0700 Subject: [PATCH] Add group scaling factor into stroke width. Originally, stroke width is independent of group scaling. But that is a bug and causing animation trouble. b/19501782 Change-Id: I33d5e44f2f8b2a82fee1a5a326223a39aaffa86c --- core/java/android/util/MathUtils.java | 20 ++++-- .../graphics/drawable/VectorDrawable.java | 41 +++++++++++- .../res/drawable/vector_drawable_scale0.xml | 57 +++++++++++++++++ .../res/drawable/vector_drawable_scale1.xml | 52 ++++++++++++++++ .../res/drawable/vector_drawable_scale2.xml | 48 ++++++++++++++ .../res/drawable/vector_drawable_scale3.xml | 62 +++++++++++++++++++ .../dynamic/VectorDrawablePerformance.java | 4 ++ 7 files changed, 276 insertions(+), 8 deletions(-) create mode 100644 tests/VectorDrawableTest/res/drawable/vector_drawable_scale0.xml create mode 100644 tests/VectorDrawableTest/res/drawable/vector_drawable_scale1.xml create mode 100644 tests/VectorDrawableTest/res/drawable/vector_drawable_scale2.xml create mode 100644 tests/VectorDrawableTest/res/drawable/vector_drawable_scale3.xml diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java index 36d5b505d4de5..8b57d3d3d6c49 100644 --- a/core/java/android/util/MathUtils.java +++ b/core/java/android/util/MathUtils.java @@ -20,7 +20,7 @@ import java.util.Random; /** * A class that contains utility methods related to numbers. - * + * * @hide Pending API council approval */ public final class MathUtils { @@ -32,7 +32,7 @@ public final class MathUtils { } public static float abs(float v) { - return v > 0 ? v : -v; + return v > 0 ? v : -v; } public static int constrain(int amount, int low, int high) { @@ -116,6 +116,14 @@ public final class MathUtils { return v * v; } + public static float dot(float v1x, float v1y, float v2x, float v2y) { + return v1x * v2x + v1y * v2y; + } + + public static float cross(float v1x, float v1y, float v2x, float v2y) { + return v1x * v2y - v1y * v2x; + } + public static float radians(float degrees) { return degrees * DEG_TO_RAD; } @@ -142,16 +150,16 @@ public final class MathUtils { public static float tan(float angle) { return (float) Math.tan(angle); - } + } public static float lerp(float start, float stop, float amount) { return start + (stop - start) * amount; } - + public static float norm(float start, float stop, float value) { return (value - start) / (stop - start); } - + public static float map(float minStart, float minStop, float maxStart, float maxStop, float value) { return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart)); } @@ -164,7 +172,7 @@ public final class MathUtils { if (howsmall >= howbig) return howsmall; return (int) (sRandom.nextFloat() * (howbig - howsmall) + howsmall); } - + public static float random(float howbig) { return sRandom.nextFloat() * howbig; } diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index b82768255ca0f..0fbd320f91066 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -36,6 +36,7 @@ import android.util.ArrayMap; import android.util.AttributeSet; import android.util.LayoutDirection; import android.util.Log; +import android.util.MathUtils; import android.util.PathParser; import android.util.Xml; @@ -955,10 +956,16 @@ public class VectorDrawable extends Drawable { final float scaleX = w / mViewportWidth; final float scaleY = h / mViewportHeight; final float minScale = Math.min(scaleX, scaleY); + final Matrix groupStackedMatrix = vGroup.mStackedMatrix; - mFinalPathMatrix.set(vGroup.mStackedMatrix); + mFinalPathMatrix.set(groupStackedMatrix); mFinalPathMatrix.postScale(scaleX, scaleY); + final float matrixScale = getMatrixScale(groupStackedMatrix); + if (matrixScale == 0) { + // When either x or y is scaled to 0, we don't need to draw anything. + return; + } vPath.toPath(mPath); final Path path = mPath; @@ -1024,11 +1031,41 @@ public class VectorDrawable extends Drawable { strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit); strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, fullPath.mStrokeAlpha)); strokePaint.setColorFilter(filter); - strokePaint.setStrokeWidth(fullPath.mStrokeWidth * minScale); + final float finalStrokeScale = minScale * matrixScale; + strokePaint.setStrokeWidth(fullPath.mStrokeWidth * finalStrokeScale); canvas.drawPath(mRenderPath, strokePaint); } } } + + private float getMatrixScale(Matrix groupStackedMatrix) { + // Given unit vectors A = (0, 1) and B = (1, 0). + // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'. + // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)), + // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|); + // If max (|A'|, |B'|) = 0, that means either x or y has a scale of 0. + // + // For non-skew case, which is most of the cases, matrix scale is computing exactly the + // scale on x and y axis, and take the minimal of these two. + // For skew case, an unit square will mapped to a parallelogram. And this function will + // return the minimal height of the 2 bases. + float[] unitVectors = new float[] {0, 1, 1, 0}; + groupStackedMatrix.mapVectors(unitVectors); + float scaleX = MathUtils.mag(unitVectors[0], unitVectors[1]); + float scaleY = MathUtils.mag(unitVectors[2], unitVectors[3]); + float crossProduct = MathUtils.cross(unitVectors[0], unitVectors[1], + unitVectors[2], unitVectors[3]); + float maxScale = MathUtils.max(scaleX, scaleY); + + float matrixScale = 0; + if (maxScale > 0) { + matrixScale = MathUtils.abs(crossProduct) / maxScale; + } + if (DBG_VECTOR_DRAWABLE) { + Log.d(LOGTAG, "Scale x " + scaleX + " y " + scaleY + " final " + matrixScale); + } + return matrixScale; + } } private static class VGroup { diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_scale0.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale0.xml new file mode 100644 index 0000000000000..88bf777bdaeae --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale0.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_scale1.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale1.xml new file mode 100644 index 0000000000000..530c73b20e44f --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale1.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_scale2.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale2.xml new file mode 100644 index 0000000000000..200eb617a9e8b --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale2.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_scale3.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale3.xml new file mode 100644 index 0000000000000..a40fc9c215958 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale3.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java index d029050c2cf4b..b4a93f68f6c99 100644 --- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java @@ -65,6 +65,10 @@ public class VectorDrawablePerformance extends Activity { R.drawable.vector_drawable28, R.drawable.vector_drawable29, R.drawable.vector_drawable30, + R.drawable.vector_drawable_scale0, + R.drawable.vector_drawable_scale1, + R.drawable.vector_drawable_scale2, + R.drawable.vector_drawable_scale3, }; public static VectorDrawable create(Resources resources, int rid) {