OSDN Git Service

Add group scaling factor into stroke width.
authorztenghui <ztenghui@google.com>
Wed, 1 Apr 2015 23:38:44 +0000 (16:38 -0700)
committerztenghui <ztenghui@google.com>
Thu, 2 Apr 2015 23:09:03 +0000 (16:09 -0700)
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
graphics/java/android/graphics/drawable/VectorDrawable.java
tests/VectorDrawableTest/res/drawable/vector_drawable_scale0.xml [new file with mode: 0644]
tests/VectorDrawableTest/res/drawable/vector_drawable_scale1.xml [new file with mode: 0644]
tests/VectorDrawableTest/res/drawable/vector_drawable_scale2.xml [new file with mode: 0644]
tests/VectorDrawableTest/res/drawable/vector_drawable_scale3.xml [new file with mode: 0644]
tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java

index 36d5b50..8b57d3d 100644 (file)
@@ -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;
     }
index b827682..0fbd320 100644 (file)
@@ -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 (file)
index 0000000..88bf777
--- /dev/null
@@ -0,0 +1,57 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:pivotX="0"
+        android:pivotY="0"
+        android:rotation="90" >
+        <group
+            android:scaleX="1.5"
+            android:scaleY="1" >
+            <group
+                android:pivotX="0"
+                android:pivotY="0"
+                android:rotation="-90" >
+                <group
+                    android:scaleX="1.5"
+                    android:scaleY="1" >
+                    <path
+                        android:name="twoLines"
+                        android:fillColor="#FFFF0000"
+                        android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+                        android:strokeColor="#FF00FF00"
+                        android:strokeWidth="10" />
+                </group>
+            </group>
+        </group>
+    </group>
+
+</vector>
\ 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 (file)
index 0000000..530c73b
--- /dev/null
@@ -0,0 +1,52 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:scaleX="-1"
+        android:scaleY="-1" >
+        <group
+            android:scaleX="-1"
+            android:scaleY="-1" >
+            <group
+                android:pivotX="100"
+                android:pivotY="100"
+                android:rotation="45" >
+                <path
+                    android:name="twoLines"
+                    android:fillColor="#FFFF0000"
+                    android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+                    android:strokeColor="#FF00FF00"
+                    android:strokeWidth="10" />
+            </group>
+        </group>
+    </group>
+
+</vector>
\ 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 (file)
index 0000000..200eb61
--- /dev/null
@@ -0,0 +1,48 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:scaleX="2"
+        android:scaleY="0.5" >
+        <group
+            android:pivotX="100"
+            android:pivotY="100"
+            android:rotation="45" >
+            <path
+                android:name="twoLines"
+                android:fillColor="#FFFF0000"
+                android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+                android:strokeColor="#FF00FF00"
+                android:strokeWidth="10" />
+        </group>
+    </group>
+
+</vector>
\ 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 (file)
index 0000000..a40fc9c
--- /dev/null
@@ -0,0 +1,62 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:pivotX="0"
+        android:pivotY="0"
+        android:rotation="45" >
+        <group
+            android:pivotX="0"
+            android:pivotY="0"
+            android:rotation="90" >
+            <group
+                android:scaleX="1.5"
+                android:scaleY="1" >
+                <group
+                    android:pivotX="0"
+                    android:pivotY="0"
+                    android:rotation="-90" >
+                    <group
+                        android:scaleX="1.5"
+                        android:scaleY="1" >
+                        <path
+                            android:name="twoLines"
+                            android:fillColor="#FFFF0000"
+                            android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+                            android:strokeColor="#FF00FF00"
+                            android:strokeWidth="10" />
+                    </group>
+                </group>
+            </group>
+        </group>
+    </group>
+
+</vector>
\ No newline at end of file
index d029050..b4a93f6 100644 (file)
@@ -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) {