diff --git a/app/build.gradle b/app/build.gradle index 1b28df4..ee7b576 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion '26.0.2' + compileSdkVersion 28 + buildToolsVersion '28.0.3' defaultConfig { applicationId "com.sdsmdg.harjot.vectormasterdemo" minSdkVersion 16 - targetSdkVersion 25 + targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -21,7 +21,7 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:25.3.0' - compile project(":vectormaster") + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation project(":vectormaster") } diff --git a/build.gradle b/build.gradle index a0db355..d50214f 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.3.2' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1' diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8909a54..1eb2bea 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Nov 17 02:03:24 IST 2017 +#Tue Mar 26 22:16:32 CET 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip diff --git a/vectormaster/build.gradle b/vectormaster/build.gradle index d121b0c..d57ac72 100644 --- a/vectormaster/build.gradle +++ b/vectormaster/build.gradle @@ -13,7 +13,7 @@ ext { siteUrl = 'https://github.com/harjot-oberai/VectorMaster/' gitUrl = 'https://github.com/harjot-oberai/VectorMaster/.git' - libraryVersion = '1.1.3' + libraryVersion = '1.2.0' developerId = 'harjot-oberai' developerName = 'Harjot Singh Oberai' @@ -25,12 +25,12 @@ ext { } android { - compileSdkVersion 25 - buildToolsVersion '26.0.2' + compileSdkVersion 28 + buildToolsVersion '28.0.3' defaultConfig { minSdkVersion 16 - targetSdkVersion 25 + targetSdkVersion 28 versionCode 1 versionName "1.0" @@ -46,8 +46,7 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:25.3.0' + implementation fileTree(dir: 'libs', include: ['*.jar']) } apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle' diff --git a/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/ModelParser.java b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/ModelParser.java new file mode 100644 index 0000000..13d5101 --- /dev/null +++ b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/ModelParser.java @@ -0,0 +1,222 @@ +package com.sdsmdg.harjot.vectormaster; + +import android.content.res.Resources; +import com.sdsmdg.harjot.vectormaster.models.ClipPathModel; +import com.sdsmdg.harjot.vectormaster.models.GroupModel; +import com.sdsmdg.harjot.vectormaster.models.ParentModel; +import com.sdsmdg.harjot.vectormaster.models.PathModel; +import com.sdsmdg.harjot.vectormaster.models.VectorModel; +import com.sdsmdg.harjot.vectormaster.utilities.Utils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.Stack; + +public class ModelParser { + + int getAttrPosition(XmlPullParser xpp, String attrName) { + for (int i = 0; i < xpp.getAttributeCount(); i++) { + if (xpp.getAttributeName(i).equals(attrName)) { + return i; + } + } + return -1; + } + + public VectorModel buildVectorModel(Resources resources, int resID, boolean useLegacyParser) { + + if (resID == -1) { + return null; + } + + XmlPullParser xpp = resources.getXml(resID); + + int tempPosition; + VectorModel vectorModel = new VectorModel(); + PathModel pathModel = new PathModel(); + GroupModel groupModel = new GroupModel(); + ClipPathModel clipPathModel = new ClipPathModel(); + Stack parentModelStack = new Stack<>(); + parentModelStack.push(vectorModel); + + try { + int event = xpp.getEventType(); + while (event != XmlPullParser.END_DOCUMENT) { + String name = xpp.getName(); + switch (event) { + case XmlPullParser.START_TAG: + if (name.equals("vector")) { + tempPosition = getAttrPosition(xpp, "viewportWidth"); + vectorModel.setViewportWidth((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.VECTOR_VIEWPORT_WIDTH); + + tempPosition = getAttrPosition(xpp, "viewportHeight"); + vectorModel.setViewportHeight((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.VECTOR_VIEWPORT_HEIGHT); + + tempPosition = getAttrPosition(xpp, "alpha"); + vectorModel.setAlpha((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.VECTOR_ALPHA); + + tempPosition = getAttrPosition(xpp, "name"); + vectorModel.setName((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); + + tempPosition = getAttrPosition(xpp, "width"); + vectorModel.setWidth((tempPosition != -1) ? + Utils.getFloatFromDimensionString(xpp.getAttributeValue(tempPosition)) : + DefaultValues.VECTOR_WIDTH); + + tempPosition = getAttrPosition(xpp, "height"); + vectorModel.setHeight((tempPosition != -1) ? + Utils.getFloatFromDimensionString(xpp.getAttributeValue(tempPosition)) : + DefaultValues.VECTOR_HEIGHT); + } else if (name.equals("path")) { + pathModel = new PathModel(); + + tempPosition = getAttrPosition(xpp, "name"); + pathModel.setName((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); + + tempPosition = getAttrPosition(xpp, "fillAlpha"); + pathModel.setFillAlpha((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.PATH_FILL_ALPHA); + + tempPosition = getAttrPosition(xpp, "fillColor"); + pathModel.setFillColor((tempPosition != -1) ? + Utils.getColorFromString(xpp.getAttributeValue(tempPosition)) : + DefaultValues.PATH_FILL_COLOR); + + tempPosition = getAttrPosition(xpp, "fillType"); + pathModel.setFillType((tempPosition != -1) ? + Utils.getFillTypeFromString(xpp.getAttributeValue(tempPosition)) : + DefaultValues.PATH_FILL_TYPE); + + tempPosition = getAttrPosition(xpp, "pathData"); + pathModel.setPathData((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null, useLegacyParser); + + tempPosition = getAttrPosition(xpp, "strokeAlpha"); + pathModel.setStrokeAlpha((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.PATH_STROKE_ALPHA); + + tempPosition = getAttrPosition(xpp, "strokeColor"); + pathModel.setStrokeColor((tempPosition != -1) ? + Utils.getColorFromString(xpp.getAttributeValue(tempPosition)) : + DefaultValues.PATH_STROKE_COLOR); + + tempPosition = getAttrPosition(xpp, "strokeLineCap"); + pathModel.setStrokeLineCap((tempPosition != -1) ? + Utils.getLineCapFromString(xpp.getAttributeValue(tempPosition)) : + DefaultValues.PATH_STROKE_LINE_CAP); + + tempPosition = getAttrPosition(xpp, "strokeLineJoin"); + pathModel.setStrokeLineJoin((tempPosition != -1) ? + Utils.getLineJoinFromString(xpp.getAttributeValue(tempPosition)) : + DefaultValues.PATH_STROKE_LINE_JOIN); + + tempPosition = getAttrPosition(xpp, "strokeMiterLimit"); + pathModel.setStrokeMiterLimit((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.PATH_STROKE_MITER_LIMIT); + + tempPosition = getAttrPosition(xpp, "strokeWidth"); + pathModel.setStrokeWidth((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.PATH_STROKE_WIDTH); + + tempPosition = getAttrPosition(xpp, "trimPathEnd"); + pathModel.setTrimPathEnd((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.PATH_TRIM_PATH_END); + + tempPosition = getAttrPosition(xpp, "trimPathOffset"); + pathModel.setTrimPathOffset((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.PATH_TRIM_PATH_OFFSET); + + tempPosition = getAttrPosition(xpp, "trimPathStart"); + pathModel.setTrimPathStart((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.PATH_TRIM_PATH_START); + + } else if (name.equals("group")) { + groupModel = new GroupModel(); + + tempPosition = getAttrPosition(xpp, "name"); + groupModel.setName((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); + + tempPosition = getAttrPosition(xpp, "pivotX"); + groupModel.setPivotX((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.GROUP_PIVOT_X); + + tempPosition = getAttrPosition(xpp, "pivotY"); + groupModel.setPivotY((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.GROUP_PIVOT_Y); + + tempPosition = getAttrPosition(xpp, "rotation"); + groupModel.setRotation((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.GROUP_ROTATION); + + tempPosition = getAttrPosition(xpp, "scaleX"); + groupModel.setScaleX((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.GROUP_SCALE_X); + + tempPosition = getAttrPosition(xpp, "scaleY"); + groupModel.setScaleY((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.GROUP_SCALE_Y); + + tempPosition = getAttrPosition(xpp, "translateX"); + groupModel.setTranslateX((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.GROUP_TRANSLATE_X); + + tempPosition = getAttrPosition(xpp, "translateY"); + groupModel.setTranslateY((tempPosition != -1) ? + Float.parseFloat(xpp.getAttributeValue(tempPosition)) : + DefaultValues.GROUP_TRANSLATE_Y); + + parentModelStack.push(groupModel); + } else if (name.equals("clip-path")) { + clipPathModel = new ClipPathModel(); + + tempPosition = getAttrPosition(xpp, "name"); + clipPathModel.setName((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); + + tempPosition = getAttrPosition(xpp, "pathData"); + clipPathModel.setPathData((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null, useLegacyParser); + } + break; + + case XmlPullParser.END_TAG: + if (name.equals("path")) { + parentModelStack.peek().addChild(pathModel); + } else if (name.equals("clip-path")) { + parentModelStack.peek().addChild(clipPathModel); + } else if (name.equals("group")) { + ParentModel topGroupModel = parentModelStack.pop(); + parentModelStack.peek().addChild(topGroupModel); + } else if (name.equals("vector")) { + //we are done with parsing + } + break; + } + event = xpp.next(); + } + } catch (XmlPullParserException | IOException e) { + e.printStackTrace(); + } + + return vectorModel; + + } + +} diff --git a/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/VectorMasterDrawable.java b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/VectorMasterDrawable.java index 8fd7d1e..6f71cdb 100644 --- a/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/VectorMasterDrawable.java +++ b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/VectorMasterDrawable.java @@ -16,12 +16,7 @@ import com.sdsmdg.harjot.vectormaster.models.PathModel; import com.sdsmdg.harjot.vectormaster.models.VectorModel; import com.sdsmdg.harjot.vectormaster.utilities.Utils; - import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.Stack; public class VectorMasterDrawable extends Drawable { @@ -35,11 +30,11 @@ public class VectorMasterDrawable extends Drawable { private float offsetX = 0.0f, offsetY = 0.0f; private float scaleX = 1.0f, scaleY = 1.0f; - private XmlPullParser xpp; - String TAG = "VECTOR_MASTER"; - private Matrix scaleMatrix; + private Matrix scaleMatrix = new Matrix(); + private boolean scaleMatrixChanged = true; + private Matrix newScaleMatrix = new Matrix(); //create a matrix object which is reused on every scaleMatrix creation private int width = -1, height = -1; @@ -78,166 +73,11 @@ private void init() { } private void buildVectorModel() { - if (resID == -1) { vectorModel = null; return; } - - xpp = resources.getXml(resID); - - int tempPosition; - PathModel pathModel = new PathModel(); - vectorModel = new VectorModel(); - GroupModel groupModel = new GroupModel(); - ClipPathModel clipPathModel = new ClipPathModel(); - Stack groupModelStack = new Stack<>(); - - try { - int event = xpp.getEventType(); - while (event != XmlPullParser.END_DOCUMENT) { - String name = xpp.getName(); - switch (event) { - case XmlPullParser.START_TAG: - if (name.equals("vector")) { - tempPosition = getAttrPosition(xpp, "viewportWidth"); - vectorModel.setViewportWidth((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.VECTOR_VIEWPORT_WIDTH); - - tempPosition = getAttrPosition(xpp, "viewportHeight"); - vectorModel.setViewportHeight((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.VECTOR_VIEWPORT_HEIGHT); - - tempPosition = getAttrPosition(xpp, "alpha"); - vectorModel.setAlpha((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.VECTOR_ALPHA); - - tempPosition = getAttrPosition(xpp, "name"); - vectorModel.setName((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); - - tempPosition = getAttrPosition(xpp, "width"); - vectorModel.setWidth((tempPosition != -1) ? Utils.getFloatFromDimensionString(xpp.getAttributeValue(tempPosition)) : DefaultValues.VECTOR_WIDTH); - - tempPosition = getAttrPosition(xpp, "height"); - vectorModel.setHeight((tempPosition != -1) ? Utils.getFloatFromDimensionString(xpp.getAttributeValue(tempPosition)) : DefaultValues.VECTOR_HEIGHT); - } else if (name.equals("path")) { - pathModel = new PathModel(); - - tempPosition = getAttrPosition(xpp, "name"); - pathModel.setName((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); - - tempPosition = getAttrPosition(xpp, "fillAlpha"); - pathModel.setFillAlpha((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_FILL_ALPHA); - - tempPosition = getAttrPosition(xpp, "fillColor"); - pathModel.setFillColor((tempPosition != -1) ? Utils.getColorFromString(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_FILL_COLOR); - - tempPosition = getAttrPosition(xpp, "fillType"); - pathModel.setFillType((tempPosition != -1) ? Utils.getFillTypeFromString(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_FILL_TYPE); - - tempPosition = getAttrPosition(xpp, "pathData"); - pathModel.setPathData((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); - - tempPosition = getAttrPosition(xpp, "strokeAlpha"); - pathModel.setStrokeAlpha((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_STROKE_ALPHA); - - tempPosition = getAttrPosition(xpp, "strokeColor"); - pathModel.setStrokeColor((tempPosition != -1) ? Utils.getColorFromString(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_STROKE_COLOR); - - tempPosition = getAttrPosition(xpp, "strokeLineCap"); - pathModel.setStrokeLineCap((tempPosition != -1) ? Utils.getLineCapFromString(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_STROKE_LINE_CAP); - - tempPosition = getAttrPosition(xpp, "strokeLineJoin"); - pathModel.setStrokeLineJoin((tempPosition != -1) ? Utils.getLineJoinFromString(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_STROKE_LINE_JOIN); - - tempPosition = getAttrPosition(xpp, "strokeMiterLimit"); - pathModel.setStrokeMiterLimit((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_STROKE_MITER_LIMIT); - - tempPosition = getAttrPosition(xpp, "strokeWidth"); - pathModel.setStrokeWidth((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_STROKE_WIDTH); - - tempPosition = getAttrPosition(xpp, "trimPathEnd"); - pathModel.setTrimPathEnd((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_TRIM_PATH_END); - - tempPosition = getAttrPosition(xpp, "trimPathOffset"); - pathModel.setTrimPathOffset((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_TRIM_PATH_OFFSET); - - tempPosition = getAttrPosition(xpp, "trimPathStart"); - pathModel.setTrimPathStart((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_TRIM_PATH_START); - - pathModel.buildPath(useLegacyParser); - } else if (name.equals("group")) { - groupModel = new GroupModel(); - - tempPosition = getAttrPosition(xpp, "name"); - groupModel.setName((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); - - tempPosition = getAttrPosition(xpp, "pivotX"); - groupModel.setPivotX((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.GROUP_PIVOT_X); - - tempPosition = getAttrPosition(xpp, "pivotY"); - groupModel.setPivotY((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.GROUP_PIVOT_Y); - - tempPosition = getAttrPosition(xpp, "rotation"); - groupModel.setRotation((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.GROUP_ROTATION); - - tempPosition = getAttrPosition(xpp, "scaleX"); - groupModel.setScaleX((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.GROUP_SCALE_X); - - tempPosition = getAttrPosition(xpp, "scaleY"); - groupModel.setScaleY((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.GROUP_SCALE_Y); - - tempPosition = getAttrPosition(xpp, "translateX"); - groupModel.setTranslateX((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.GROUP_TRANSLATE_X); - - tempPosition = getAttrPosition(xpp, "translateY"); - groupModel.setTranslateY((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.GROUP_TRANSLATE_Y); - - groupModelStack.push(groupModel); - } else if (name.equals("clip-path")) { - clipPathModel = new ClipPathModel(); - - tempPosition = getAttrPosition(xpp, "name"); - clipPathModel.setName((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); - - tempPosition = getAttrPosition(xpp, "pathData"); - clipPathModel.setPathData((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); - - clipPathModel.buildPath(useLegacyParser); - } - break; - - case XmlPullParser.END_TAG: - if (name.equals("path")) { - if (groupModelStack.size() == 0) { - vectorModel.addPathModel(pathModel); - } else { - groupModelStack.peek().addPathModel(pathModel); - } - vectorModel.getFullpath().addPath(pathModel.getPath()); - } else if (name.equals("clip-path")) { - if (groupModelStack.size() == 0) { - vectorModel.addClipPathModel(clipPathModel); - } else { - groupModelStack.peek().addClipPathModel(clipPathModel); - } - } else if (name.equals("group")) { - GroupModel topGroupModel = groupModelStack.pop(); - if (groupModelStack.size() == 0) { - topGroupModel.setParent(null); - vectorModel.addGroupModel(topGroupModel); - } else { - topGroupModel.setParent(groupModelStack.peek()); - groupModelStack.peek().addGroupModel(topGroupModel); - } - } else if (name.equals("vector")) { - vectorModel.buildTransformMatrices(); - } - break; - } - event = xpp.next(); - } - } catch (XmlPullParserException | IOException e) { - e.printStackTrace(); - } - + vectorModel = new ModelParser().buildVectorModel(resources, resID, useLegacyParser); } private int getAttrPosition(XmlPullParser xpp, String attrName) { @@ -282,8 +122,6 @@ protected void onBoundsChange(Rect bounds) { height = bounds.height(); buildScaleMatrix(); - scaleAllPaths(); - scaleAllStrokes(); } } @@ -301,15 +139,20 @@ public void draw(Canvas canvas) { setBounds(0, 0, temp1, temp2); } + strokeRatio = Math.min(width / vectorModel.getWidth(), height / vectorModel.getHeight()); + setAlpha(Utils.getAlphaFromFloat(vectorModel.getAlpha())); + vectorModel.calculate(scaleMatrix, scaleMatrixChanged, strokeRatio); + scaleMatrixChanged = false; + if (left != 0 || top != 0) { tempSaveCount = canvas.save(); canvas.translate(left, top); - vectorModel.drawPaths(canvas, offsetX, offsetY, scaleX, scaleY); + vectorModel.draw(canvas); canvas.restoreToCount(tempSaveCount); } else { - vectorModel.drawPaths(canvas, offsetX, offsetY, scaleX, scaleY); + vectorModel.draw(canvas); } } @@ -340,9 +183,9 @@ public int getIntrinsicHeight() { } private void buildScaleMatrix() { - scaleMatrix = new Matrix(); - scaleMatrix.postTranslate(width / 2 - vectorModel.getViewportWidth() / 2, height / 2 - vectorModel.getViewportHeight() / 2); + newScaleMatrix.reset(); + newScaleMatrix.postTranslate(width / 2 - vectorModel.getViewportWidth() / 2, height / 2 - vectorModel.getViewportHeight() / 2); float widthRatio = width / vectorModel.getViewportWidth(); float heightRatio = height / vectorModel.getViewportHeight(); @@ -350,16 +193,13 @@ private void buildScaleMatrix() { scaleRatio = ratio; - scaleMatrix.postScale(ratio, ratio, width / 2, height / 2); - } + newScaleMatrix.postScale(ratio, ratio, width / 2, height / 2); - private void scaleAllPaths() { - vectorModel.scaleAllPaths(scaleMatrix); - } + newScaleMatrix.postTranslate(offsetX, offsetY); + newScaleMatrix.postScale(scaleX, scaleY); - private void scaleAllStrokes() { - strokeRatio = Math.min(width / vectorModel.getWidth(), height / vectorModel.getHeight()); - vectorModel.scaleAllStrokeWidth(strokeRatio); + scaleMatrix.set(newScaleMatrix); + scaleMatrixChanged = true; } public Path getFullPath() { @@ -370,47 +210,15 @@ public Path getFullPath() { } public GroupModel getGroupModelByName(String name) { - GroupModel gModel; - for (GroupModel groupModel : vectorModel.getGroupModels()) { - if (Utils.isEqual(groupModel.getName(), name)) { - return groupModel; - } else { - gModel = groupModel.getGroupModelByName(name); - if (gModel != null) - return gModel; - } - } - return null; + return vectorModel.getGroupModelByName(name); } public PathModel getPathModelByName(String name) { - PathModel pModel = null; - for (PathModel pathModel : vectorModel.getPathModels()) { - if (Utils.isEqual(pathModel.getName(), name)) { - return pathModel; - } - } - for (GroupModel groupModel : vectorModel.getGroupModels()) { - pModel = groupModel.getPathModelByName(name); - if (pModel != null && Utils.isEqual(pModel.getName(), name)) - return pModel; - } - return pModel; + return vectorModel.getPathModelByName(name); } public ClipPathModel getClipPathModelByName(String name) { - ClipPathModel cModel = null; - for (ClipPathModel clipPathModel : vectorModel.getClipPathModels()) { - if (Utils.isEqual(clipPathModel.getName(), name)) { - return clipPathModel; - } - } - for (GroupModel groupModel : vectorModel.getGroupModels()) { - cModel = groupModel.getClipPathModelByName(name); - if (cModel != null && Utils.isEqual(cModel.getName(), name)) - return cModel; - } - return cModel; + return vectorModel.getClipPathModelByName(name); } public void update() { @@ -426,7 +234,7 @@ public float getStrokeRatio() { } public Matrix getScaleMatrix() { - return scaleMatrix; + return new Matrix(scaleMatrix); //make a copy so that from outside the real scaleMatrix cannot be manipulated because this would not be propagated to the VectorModel correctly because scaleMatrixChanged would not be set. } public float getOffsetX() { @@ -435,6 +243,7 @@ public float getOffsetX() { public void setOffsetX(float offsetX) { this.offsetX = offsetX; + buildScaleMatrix(); invalidateSelf(); } @@ -444,6 +253,7 @@ public float getOffsetY() { public void setOffsetY(float offsetY) { this.offsetY = offsetY; + buildScaleMatrix(); invalidateSelf(); } @@ -453,6 +263,7 @@ public float getScaleX() { public void setScaleX(float scaleX) { this.scaleX = scaleX; + buildScaleMatrix(); invalidateSelf(); } @@ -462,6 +273,7 @@ public float getScaleY() { public void setScaleY(float scaleY) { this.scaleY = scaleY; + buildScaleMatrix(); invalidateSelf(); } } diff --git a/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/VectorMasterView.java b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/VectorMasterView.java index 0f63c36..f30dfe3 100644 --- a/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/VectorMasterView.java +++ b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/VectorMasterView.java @@ -13,13 +13,6 @@ import com.sdsmdg.harjot.vectormaster.models.GroupModel; import com.sdsmdg.harjot.vectormaster.models.PathModel; import com.sdsmdg.harjot.vectormaster.models.VectorModel; -import com.sdsmdg.harjot.vectormaster.utilities.Utils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.Stack; public class VectorMasterView extends View { @@ -30,11 +23,12 @@ public class VectorMasterView extends View { int resID = -1; boolean useLegacyParser = true; - XmlPullParser xpp; - String TAG = "VECTOR_MASTER"; - private Matrix scaleMatrix; + private Matrix scaleMatrix = new Matrix(); + private boolean scaleMatrixChanged; + private Matrix newScaleMatrix = new Matrix(); //create a matrix object which is reused on every scaleMatrix creation + int width = 0, height = 0; @@ -83,171 +77,10 @@ void buildVectorModel() { return; } - xpp = resources.getXml(resID); - - int tempPosition; - PathModel pathModel = new PathModel(); - vectorModel = new VectorModel(); - GroupModel groupModel = new GroupModel(); - ClipPathModel clipPathModel = new ClipPathModel(); - Stack groupModelStack = new Stack<>(); - - try { - int event = xpp.getEventType(); - while (event != XmlPullParser.END_DOCUMENT) { - String name = xpp.getName(); - switch (event) { - case XmlPullParser.START_TAG: - if (name.equals("vector")) { - tempPosition = getAttrPosition(xpp, "viewportWidth"); - vectorModel.setViewportWidth((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.VECTOR_VIEWPORT_WIDTH); - - tempPosition = getAttrPosition(xpp, "viewportHeight"); - vectorModel.setViewportHeight((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.VECTOR_VIEWPORT_HEIGHT); - - tempPosition = getAttrPosition(xpp, "alpha"); - vectorModel.setAlpha((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.VECTOR_ALPHA); - - tempPosition = getAttrPosition(xpp, "name"); - vectorModel.setName((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); - - tempPosition = getAttrPosition(xpp, "width"); - vectorModel.setWidth((tempPosition != -1) ? Utils.getFloatFromDimensionString(xpp.getAttributeValue(tempPosition)) : DefaultValues.VECTOR_WIDTH); - - tempPosition = getAttrPosition(xpp, "height"); - vectorModel.setHeight((tempPosition != -1) ? Utils.getFloatFromDimensionString(xpp.getAttributeValue(tempPosition)) : DefaultValues.VECTOR_HEIGHT); - } else if (name.equals("path")) { - pathModel = new PathModel(); - - tempPosition = getAttrPosition(xpp, "name"); - pathModel.setName((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); - - tempPosition = getAttrPosition(xpp, "fillAlpha"); - pathModel.setFillAlpha((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_FILL_ALPHA); - - tempPosition = getAttrPosition(xpp, "fillColor"); - pathModel.setFillColor((tempPosition != -1) ? Utils.getColorFromString(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_FILL_COLOR); - - tempPosition = getAttrPosition(xpp, "fillType"); - pathModel.setFillType((tempPosition != -1) ? Utils.getFillTypeFromString(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_FILL_TYPE); - - tempPosition = getAttrPosition(xpp, "pathData"); - pathModel.setPathData((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); - - tempPosition = getAttrPosition(xpp, "strokeAlpha"); - pathModel.setStrokeAlpha((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_STROKE_ALPHA); - - tempPosition = getAttrPosition(xpp, "strokeColor"); - pathModel.setStrokeColor((tempPosition != -1) ? Utils.getColorFromString(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_STROKE_COLOR); - - tempPosition = getAttrPosition(xpp, "strokeLineCap"); - pathModel.setStrokeLineCap((tempPosition != -1) ? Utils.getLineCapFromString(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_STROKE_LINE_CAP); - - tempPosition = getAttrPosition(xpp, "strokeLineJoin"); - pathModel.setStrokeLineJoin((tempPosition != -1) ? Utils.getLineJoinFromString(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_STROKE_LINE_JOIN); - - tempPosition = getAttrPosition(xpp, "strokeMiterLimit"); - pathModel.setStrokeMiterLimit((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_STROKE_MITER_LIMIT); - - tempPosition = getAttrPosition(xpp, "strokeWidth"); - pathModel.setStrokeWidth((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_STROKE_WIDTH); - - tempPosition = getAttrPosition(xpp, "trimPathEnd"); - pathModel.setTrimPathEnd((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_TRIM_PATH_END); - - tempPosition = getAttrPosition(xpp, "trimPathOffset"); - pathModel.setTrimPathOffset((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_TRIM_PATH_OFFSET); - - tempPosition = getAttrPosition(xpp, "trimPathStart"); - pathModel.setTrimPathStart((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.PATH_TRIM_PATH_START); - - pathModel.buildPath(useLegacyParser); - } else if (name.equals("group")) { - groupModel = new GroupModel(); - - tempPosition = getAttrPosition(xpp, "name"); - groupModel.setName((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); - - tempPosition = getAttrPosition(xpp, "pivotX"); - groupModel.setPivotX((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.GROUP_PIVOT_X); - - tempPosition = getAttrPosition(xpp, "pivotY"); - groupModel.setPivotY((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.GROUP_PIVOT_Y); - - tempPosition = getAttrPosition(xpp, "rotation"); - groupModel.setRotation((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.GROUP_ROTATION); - - tempPosition = getAttrPosition(xpp, "scaleX"); - groupModel.setScaleX((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.GROUP_SCALE_X); - - tempPosition = getAttrPosition(xpp, "scaleY"); - groupModel.setScaleY((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.GROUP_SCALE_Y); - - tempPosition = getAttrPosition(xpp, "translateX"); - groupModel.setTranslateX((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.GROUP_TRANSLATE_X); - - tempPosition = getAttrPosition(xpp, "translateY"); - groupModel.setTranslateY((tempPosition != -1) ? Float.parseFloat(xpp.getAttributeValue(tempPosition)) : DefaultValues.GROUP_TRANSLATE_Y); - - groupModelStack.push(groupModel); - } else if (name.equals("clip-path")) { - clipPathModel = new ClipPathModel(); - - tempPosition = getAttrPosition(xpp, "name"); - clipPathModel.setName((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); - - tempPosition = getAttrPosition(xpp, "pathData"); - clipPathModel.setPathData((tempPosition != -1) ? xpp.getAttributeValue(tempPosition) : null); - - clipPathModel.buildPath(useLegacyParser); - } - break; - - case XmlPullParser.END_TAG: - if (name.equals("path")) { - if (groupModelStack.size() == 0) { - vectorModel.addPathModel(pathModel); - } else { - groupModelStack.peek().addPathModel(pathModel); - } - vectorModel.getFullpath().addPath(pathModel.getPath()); - } else if (name.equals("clip-path")) { - if (groupModelStack.size() == 0) { - vectorModel.addClipPathModel(clipPathModel); - } else { - groupModelStack.peek().addClipPathModel(clipPathModel); - } - } else if (name.equals("group")) { - GroupModel topGroupModel = groupModelStack.pop(); - if (groupModelStack.size() == 0) { - topGroupModel.setParent(null); - vectorModel.addGroupModel(topGroupModel); - } else { - topGroupModel.setParent(groupModelStack.peek()); - groupModelStack.peek().addGroupModel(topGroupModel); - } - } else if (name.equals("vector")) { - vectorModel.buildTransformMatrices(); - } - break; - } - event = xpp.next(); - } - } catch (XmlPullParserException | IOException e) { - e.printStackTrace(); - } + vectorModel = new ModelParser().buildVectorModel(resources, resID, useLegacyParser); } - int getAttrPosition(XmlPullParser xpp, String attrName) { - for (int i = 0; i < xpp.getAttributeCount(); i++) { - if (xpp.getAttributeName(i).equals(attrName)) { - return i; - } - } - return -1; - } - public int getResID() { return resID; } @@ -264,8 +97,6 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) { height = h; buildScaleMatrix(); - scaleAllPaths(); - scaleAllStrokes(); } } @@ -280,17 +111,20 @@ protected void onDraw(Canvas canvas) { return; } + strokeRatio = Math.min(width / vectorModel.getWidth(), height / vectorModel.getHeight()); + setAlpha(vectorModel.getAlpha()); - vectorModel.drawPaths(canvas); + vectorModel.calculate(scaleMatrix, scaleMatrixChanged, strokeRatio); + scaleMatrixChanged = false; + vectorModel.draw(canvas); } void buildScaleMatrix() { - scaleMatrix = new Matrix(); - - scaleMatrix.postTranslate(width / 2 - vectorModel.getViewportWidth() / 2, height / 2 - vectorModel.getViewportHeight() / 2); + newScaleMatrix.reset(); + newScaleMatrix.postTranslate(width / 2 - vectorModel.getViewportWidth() / 2, height / 2 - vectorModel.getViewportHeight() / 2); float widthRatio = width / vectorModel.getViewportWidth(); float heightRatio = height / vectorModel.getViewportHeight(); @@ -298,16 +132,10 @@ void buildScaleMatrix() { scaleRatio = ratio; - scaleMatrix.postScale(ratio, ratio, width / 2, height / 2); - } + newScaleMatrix.postScale(ratio, ratio, width / 2, height / 2); - void scaleAllPaths() { - vectorModel.scaleAllPaths(scaleMatrix); - } - - void scaleAllStrokes() { - strokeRatio = Math.min(width / vectorModel.getWidth(), height / vectorModel.getHeight()); - vectorModel.scaleAllStrokeWidth(strokeRatio); + scaleMatrix.set(newScaleMatrix); + scaleMatrixChanged = true; } public Path getFullPath() { @@ -318,47 +146,15 @@ public Path getFullPath() { } public GroupModel getGroupModelByName(String name) { - GroupModel gModel; - for (GroupModel groupModel : vectorModel.getGroupModels()) { - if (Utils.isEqual(groupModel.getName(), name)) { - return groupModel; - } else { - gModel = groupModel.getGroupModelByName(name); - if (gModel != null) - return gModel; - } - } - return null; + return vectorModel.getGroupModelByName(name); } public PathModel getPathModelByName(String name) { - PathModel pModel = null; - for (PathModel pathModel : vectorModel.getPathModels()) { - if (Utils.isEqual(pathModel.getName(), name)) { - return pathModel; - } - } - for (GroupModel groupModel : vectorModel.getGroupModels()) { - pModel = groupModel.getPathModelByName(name); - if (pModel != null && Utils.isEqual(pModel.getName(), name)) - return pModel; - } - return pModel; + return vectorModel.getPathModelByName(name); } public ClipPathModel getClipPathModelByName(String name) { - ClipPathModel cModel = null; - for (ClipPathModel clipPathModel : vectorModel.getClipPathModels()) { - if (Utils.isEqual(clipPathModel.getName(), name)) { - return clipPathModel; - } - } - for (GroupModel groupModel : vectorModel.getGroupModels()) { - cModel = groupModel.getClipPathModelByName(name); - if (cModel != null && Utils.isEqual(cModel.getName(), name)) - return cModel; - } - return cModel; + return vectorModel.getClipPathModelByName(name); } public void update() { @@ -374,6 +170,6 @@ public float getStrokeRatio() { } public Matrix getScaleMatrix() { - return scaleMatrix; + return new Matrix(scaleMatrix); } } diff --git a/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/ClipPathModel.java b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/ClipPathModel.java index d37c0df..5a66745 100644 --- a/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/ClipPathModel.java +++ b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/ClipPathModel.java @@ -1,93 +1,89 @@ package com.sdsmdg.harjot.vectormaster.models; - +import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; -import android.graphics.RectF; - import com.sdsmdg.harjot.vectormaster.utilities.parser.PathParser; -public class ClipPathModel { - private String name; - private String pathData; +public class ClipPathModel extends Model { + private String pathData; - private Path originalPath; - private Path path; + private Path path; + private Path transformedPath = new Path(); + private Matrix lastParentTransformation; - private Paint clipPaint; + private Paint clipPaint; - public ClipPathModel() { - path = new Path(); + public ClipPathModel() { + path = new Path(); + clipPaint = new Paint(); + clipPaint.setAntiAlias(true); + clipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + } - clipPaint = new Paint(); - clipPaint.setAntiAlias(true); - clipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + @Override + public void calculate(Matrix parentTransformation, Boolean transformationChanged, float strokeRatio) { + if (transformationChanged || lastParentTransformation == null) { + lastParentTransformation = parentTransformation; + calculateTransformedPath(); } + } - public void buildPath(boolean useLegacyParser) { - if (useLegacyParser) { - originalPath = com.sdsmdg.harjot.vectormaster.utilities.legacyparser.PathParser.createPathFromPathData(pathData); - } else { - originalPath = PathParser.doPath(pathData); - } - - path = new Path(originalPath); - } + @Override + public void prepare(Canvas canvas) { + canvas.clipPath(transformedPath); + } - public void transform(Matrix matrix) { - path = new Path(originalPath); + @Override + public void draw(Canvas canvas) { + //clip path does no drawing + } - path.transform(matrix); + private void calculateTransformedPath() { + if (path == null || lastParentTransformation == null) { + return; } - - public Paint getClipPaint() { - return clipPaint; + transformedPath.rewind(); + path.transform(lastParentTransformation, transformedPath); + } + + public Paint getClipPaint() { + return clipPaint; + } + + public void setClipPaint(Paint clipPaint) { + this.clipPaint = clipPaint; + } + + public String getPathData() { + return pathData; + } + + public void setPathData(String pathData) { + setPathData(pathData, true); + } + + public void setPathData(String pathData, boolean useLegacyParser) { + this.pathData = pathData; + Path path = null; + if (useLegacyParser) { + path = com.sdsmdg.harjot.vectormaster.utilities.legacyparser.PathParser.createPathFromPathData(pathData); + } else { + path = PathParser.doPath(pathData); } + setPath(path); + } - public void setClipPaint(Paint clipPaint) { - this.clipPaint = clipPaint; - } + public Path getPath() { + return path; + } - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getPathData() { - return pathData; - } - - public void setPathData(String pathData) { - this.pathData = pathData; - } - - public Path getPath() { - return path; - } - - public void setPath(Path path) { - this.path = path; - } - - public Path getScaledAndOffsetPath(float offsetX, float offsetY, float scaleX, float scaleY) { - Path newPath = new Path(path); - newPath.offset(offsetX, offsetY); - newPath.transform(getScaleMatrix(newPath, scaleX, scaleY)); - return newPath; - } - - public Matrix getScaleMatrix(Path srcPath, float scaleX, float scaleY) { - Matrix scaleMatrix = new Matrix(); - RectF rectF = new RectF(); - srcPath.computeBounds(rectF, true); - scaleMatrix.setScale(scaleX, scaleY, rectF.left, rectF.top); - return scaleMatrix; - } + public void setPath(Path path) { + this.path = path; + calculateTransformedPath(); + } } diff --git a/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/GroupModel.java b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/GroupModel.java index af4f439..3ac3690 100644 --- a/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/GroupModel.java +++ b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/GroupModel.java @@ -1,278 +1,130 @@ package com.sdsmdg.harjot.vectormaster.models; - -import android.graphics.Canvas; import android.graphics.Matrix; - import com.sdsmdg.harjot.vectormaster.DefaultValues; -import com.sdsmdg.harjot.vectormaster.utilities.Utils; - -import java.util.ArrayList; - -public class GroupModel { - private String name; - - private float rotation; - private float pivotX, pivotY; - private float scaleX, scaleY; - private float translateX, translateY; - - private Matrix scaleMatrix; - private Matrix originalTransformMatrix; - private Matrix finalTransformMatrix; - private GroupModel parent; - - private ArrayList groupModels; - private ArrayList pathModels; - private ArrayList clipPathModels; - - public GroupModel() { - rotation = DefaultValues.GROUP_ROTATION; - pivotX = DefaultValues.GROUP_PIVOT_X; - pivotY = DefaultValues.GROUP_PIVOT_Y; - scaleX = DefaultValues.GROUP_SCALE_X; - scaleY = DefaultValues.GROUP_SCALE_Y; - translateX = DefaultValues.GROUP_TRANSLATE_X; - translateY = DefaultValues.GROUP_TRANSLATE_Y; - - groupModels = new ArrayList<>(); - pathModels = new ArrayList<>(); - clipPathModels = new ArrayList<>(); - } - - public void drawPaths(Canvas canvas, float offsetX, float offsetY, float scaleX, float scaleY) { - for (ClipPathModel clipPathModel : clipPathModels) { - canvas.clipPath(clipPathModel.getScaledAndOffsetPath(offsetX, offsetY, scaleX, scaleY)); - } - for (GroupModel groupModel : groupModels) { - groupModel.drawPaths(canvas, offsetX, offsetY, scaleX, scaleY); - } - for (PathModel pathModel : pathModels) { - if (pathModel.isFillAndStroke()) { - pathModel.makeFillPaint(); - canvas.drawPath(pathModel.getScaledAndOffsetPath(offsetX, offsetY, scaleX, scaleY), pathModel.getPathPaint()); - pathModel.makeStrokePaint(); - canvas.drawPath(pathModel.getScaledAndOffsetPath(offsetX, offsetY, scaleX, scaleY), pathModel.getPathPaint()); - } else { - canvas.drawPath(pathModel.getScaledAndOffsetPath(offsetX, offsetY, scaleX, scaleY), pathModel.getPathPaint()); - } - } - } - - public void drawPaths(Canvas canvas) { - for (ClipPathModel clipPathModel : clipPathModels) { - canvas.clipPath(clipPathModel.getPath()); - } - for (GroupModel groupModel : groupModels) { - groupModel.drawPaths(canvas); - } - for (PathModel pathModel : pathModels) { - if (pathModel.isFillAndStroke()) { - pathModel.makeFillPaint(); - canvas.drawPath(pathModel.getPath(), pathModel.getPathPaint()); - pathModel.makeStrokePaint(); - canvas.drawPath(pathModel.getPath(), pathModel.getPathPaint()); - } else { - canvas.drawPath(pathModel.getPath(), pathModel.getPathPaint()); - } - } - } - - public void scaleAllPaths(Matrix scaleMatrix) { - this.scaleMatrix = scaleMatrix; - finalTransformMatrix = new Matrix(originalTransformMatrix); - finalTransformMatrix.postConcat(scaleMatrix); - for (GroupModel groupModel : groupModels) { - groupModel.scaleAllPaths(scaleMatrix); - } - for (PathModel pathModel : pathModels) { - pathModel.transform(finalTransformMatrix); - } - for (ClipPathModel clipPathModel : clipPathModels) { - clipPathModel.transform(finalTransformMatrix); - } - } - - public void scaleAllStrokeWidth(float ratio) { - for (GroupModel groupModel : groupModels) { - groupModel.scaleAllStrokeWidth(ratio); - } - for (PathModel pathModel : pathModels) { - pathModel.setStrokeRatio(ratio); - } - } - - public void buildTransformMatrix() { - - originalTransformMatrix = new Matrix(); - - originalTransformMatrix.postScale(scaleX, scaleY, pivotX, pivotY); - originalTransformMatrix.postRotate(rotation, pivotX, pivotY); - originalTransformMatrix.postTranslate(translateX, translateY); - if (parent != null) { - originalTransformMatrix.postConcat(parent.getOriginalTransformMatrix()); - } - - for (GroupModel groupModel : groupModels) { - groupModel.buildTransformMatrix(); - } - } - - public void updateAndScalePaths() { - if (scaleMatrix != null) { - buildTransformMatrix(); - scaleAllPaths(scaleMatrix); - } - } - - public GroupModel getGroupModelByName(String name) { - GroupModel grpModel = null; - for (GroupModel groupModel : groupModels) { - if (Utils.isEqual(groupModel.getName(), name)) { - grpModel = groupModel; - return grpModel; - } else { - grpModel = groupModel.getGroupModelByName(name); - if (grpModel != null) - return grpModel; - } - } - return grpModel; - } - - public PathModel getPathModelByName(String name) { - PathModel pModel = null; - for (PathModel pathModel : pathModels) { - if (Utils.isEqual(pathModel.getName(), name)) { - return pathModel; - } - } - for (GroupModel groupModel : groupModels) { - pModel = groupModel.getPathModelByName(name); - if (pModel != null && Utils.isEqual(pModel.getName(), name)) - return pModel; - } - return pModel; - } - - public ClipPathModel getClipPathModelByName(String name) { - ClipPathModel cModel = null; - for (ClipPathModel clipPathModel : getClipPathModels()) { - if (Utils.isEqual(clipPathModel.getName(), name)) { - return clipPathModel; - } - } - for (GroupModel groupModel : getGroupModels()) { - cModel = groupModel.getClipPathModelByName(name); - if (cModel != null && Utils.isEqual(cModel.getName(), name)) - return cModel; - } - return cModel; - } - - public Matrix getOriginalTransformMatrix() { - return originalTransformMatrix; - } - - public GroupModel getParent() { - return parent; - } - - public void setParent(GroupModel parent) { - this.parent = parent; - } - - public void addGroupModel(GroupModel groupModel) { - groupModels.add(groupModel); - } - - public ArrayList getGroupModels() { - return groupModels; - } - - public void addPathModel(PathModel pathModel) { - pathModels.add(pathModel); - } - - public ArrayList getPathModels() { - return pathModels; - } - - public void addClipPathModel(ClipPathModel clipPathModel) { - clipPathModels.add(clipPathModel); - } - - public ArrayList getClipPathModels() { - return clipPathModels; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public float getRotation() { - return rotation; - } - - public void setRotation(float rotation) { - this.rotation = rotation; - updateAndScalePaths(); - } - - public float getPivotX() { - return pivotX; - } - - public void setPivotX(float pivotX) { - this.pivotX = pivotX; - } - - public float getPivotY() { - return pivotY; - } - - public void setPivotY(float pivotY) { - this.pivotY = pivotY; - } - - public float getScaleX() { - return scaleX; - } - - public void setScaleX(float scaleX) { - this.scaleX = scaleX; - updateAndScalePaths(); - } - - public float getScaleY() { - return scaleY; - } - - public void setScaleY(float scaleY) { - this.scaleY = scaleY; - updateAndScalePaths(); - } - - public float getTranslateX() { - return translateX; - } - - public void setTranslateX(float translateX) { - this.translateX = translateX; - updateAndScalePaths(); - } - - public float getTranslateY() { - return translateY; - } - - public void setTranslateY(float translateY) { - this.translateY = translateY; - updateAndScalePaths(); - } +public class GroupModel extends ParentModel { + + private float rotation; + private float pivotX, pivotY; + private float scaleX, scaleY; + private float translateX, translateY; + private Matrix ownTransformation; + private Matrix ownTransformationWorkMatrix; //reuses this one matrix object if lastTransformation is created by concatination + private boolean ownTransformationChanged = true; + private boolean hasOwnTransformation = false; + private Matrix lastTransformation; + private Matrix lastTransformationWorkMatrix; //reuses this one matrix object if lastTransformation is created by concatination + + public GroupModel() { + rotation = DefaultValues.GROUP_ROTATION; + pivotX = DefaultValues.GROUP_PIVOT_X; + pivotY = DefaultValues.GROUP_PIVOT_Y; + scaleX = DefaultValues.GROUP_SCALE_X; + scaleY = DefaultValues.GROUP_SCALE_Y; + translateX = DefaultValues.GROUP_TRANSLATE_X; + translateY = DefaultValues.GROUP_TRANSLATE_Y; + } + + @Override + public void calculate(Matrix parentTransformation, Boolean transformationChanged, float strokeRatio) { + if (ownTransformationChanged || transformationChanged) { + ownTransformationChanged = false; + + if (hasOwnTransformation) { + lastTransformationWorkMatrix = initializeMatrix(lastTransformationWorkMatrix, null); + lastTransformationWorkMatrix.setConcat(parentTransformation, ownTransformation); //own transformation necessary, so concat with parent transformation + lastTransformation = lastTransformationWorkMatrix; + } else { + lastTransformation = parentTransformation; //no own transformation necessary, so passthrough + } + + super.calculate(lastTransformation, true, strokeRatio); + } else { + super.calculate(lastTransformation, false, strokeRatio); + } + } + + protected void createOwnTransformation() { + //check if we need an own transformation matrix. if there is nothing to transform, do not build a matrix + if (scaleX != 1.0 || scaleY != 1.0 || rotation != 0 || translateX != 0 || translateY != 0) { + ownTransformationWorkMatrix = initializeMatrix(ownTransformationWorkMatrix, null); + ownTransformationWorkMatrix.postScale(scaleX, scaleY, pivotX, pivotY); + ownTransformationWorkMatrix.postRotate(rotation, pivotX, pivotY); + ownTransformationWorkMatrix.postTranslate(translateX, translateY); + ownTransformation = initializeMatrix(ownTransformation, ownTransformationWorkMatrix); + hasOwnTransformation = true; + } else { + hasOwnTransformation = false; + } + + ownTransformationChanged = true; + } + + private void markAsDirty() { + createOwnTransformation(); + } + + public float getRotation() { + return rotation; + } + + public void setRotation(float rotation) { + this.rotation = rotation; + markAsDirty(); + } + + public float getPivotX() { + return pivotX; + } + + public void setPivotX(float pivotX) { + this.pivotX = pivotX; + markAsDirty(); + } + + public float getPivotY() { + return pivotY; + } + + public void setPivotY(float pivotY) { + this.pivotY = pivotY; + markAsDirty(); + } + + public float getScaleX() { + return scaleX; + } + + public void setScaleX(float scaleX) { + this.scaleX = scaleX; + markAsDirty(); + } + + public float getScaleY() { + return scaleY; + } + + public void setScaleY(float scaleY) { + this.scaleY = scaleY; + markAsDirty(); + } + + public float getTranslateX() { + return translateX; + } + + public void setTranslateX(float translateX) { + this.translateX = translateX; + markAsDirty(); + } + + public float getTranslateY() { + return translateY; + } + + public void setTranslateY(float translateY) { + this.translateY = translateY; + markAsDirty(); + } } diff --git a/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/Model.java b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/Model.java new file mode 100644 index 0000000..8c96e03 --- /dev/null +++ b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/Model.java @@ -0,0 +1,63 @@ +package com.sdsmdg.harjot.vectormaster.models; + +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Path; + +public abstract class Model { + + private String name; + private ParentModel parent; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ParentModel getParent() { + return parent; + } + + public void setParent(ParentModel parent) { + this.parent = parent; + } + + /** + * The rendering process always calls calculate(), perform(), draw() so that the models recalculate dynamically if needed. + * The methods should cache as much as possible and avoid allocation of new objects. + * @param parentTransformation + * @param transformationChanged + * @param strokeRatio + */ + public abstract void calculate(Matrix parentTransformation, Boolean transformationChanged, float strokeRatio); + public abstract void prepare(Canvas canvas); + public abstract void draw(Canvas canvas); + + /** + * adds the UNTRANSFORMED path (if the model has one) to collectedPath + * @return + */ + public void collectFullPath(Path collectedPath) { + //by default nothing to collect + } + + protected Matrix initializeMatrix(Matrix matrix, Matrix initialValue) { + if (matrix == null) { + matrix = new Matrix(); //try to create new matrix objects as less as possible + if (initialValue != null) { + matrix.set(initialValue); + } + } else { + if (initialValue != null) { + matrix.set(initialValue); + } else { + matrix.reset(); + } + } + return matrix; + } + +} diff --git a/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/ParentModel.java b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/ParentModel.java new file mode 100644 index 0000000..43ac613 --- /dev/null +++ b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/ParentModel.java @@ -0,0 +1,96 @@ +package com.sdsmdg.harjot.vectormaster.models; + +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Path; + +import java.util.ArrayList; + +public abstract class ParentModel extends Model { + + private ArrayList children = new ArrayList<>(0); + + /** + * If you want to add a model consider using addChild() instead. + * Gets the list of children from this parent model. + * Make sure to add/remove/insert models only on the main-thread because the list of children is not thread save. + * Also make sure to call childModel.setParent(parent) when adding children to this list. + */ + public ArrayList getChildren() { + return children; + } + + /** + * Adds a child model to this parent model. Also automatically sets the parent on the child model. + * Make sure to add new models on the main-thread because the list of children is not thread save. + * @param model + */ + public void addChild(Model model) { + model.setParent(this); + getChildren().add(model); + } + + @Override + public void calculate(Matrix parentTransformation, Boolean transformationChanged, float strokeRatio) { + for (Model child : getChildren()) { + child.calculate(parentTransformation, transformationChanged, strokeRatio); + } + } + + @Override + public void prepare(Canvas canvas) { + //parents by default do not prepare the canvas recursively + } + + @Override + public void draw(Canvas canvas) { + //parents prepare just their own children before they draw + for (Model child : getChildren()) { + child.prepare(canvas); + } + for (Model child : getChildren()) { + child.draw(canvas); + } + } + + @Override + public void collectFullPath(Path collectedPath) { + for (Model child : getChildren()) { + child.collectFullPath(collectedPath); + } + } + + public GroupModel getGroupModelByName(String name) { + return (GroupModel) getModelByTypeAndName(GroupModel.class, name); + } + + public PathModel getPathModelByName(String name) { + return (PathModel) getModelByTypeAndName(PathModel.class, name); + } + + public ClipPathModel getClipPathModelByName(String name) { + return (ClipPathModel) getModelByTypeAndName(ClipPathModel.class, name); + } + + public Model getModelByTypeAndName(Class clazz, String name) { + if (name == null) { + return null; + } + for (Model child : children) { + //check if the child is the searched model + if (name.equals(child.getName()) && clazz.isAssignableFrom(child.getClass())) { + return child; + } + //ask the child to check its children for the searched model + if (child instanceof ParentModel) { + Model subchild = ((ParentModel) child).getModelByTypeAndName(clazz, name); + if (subchild != null) { + return subchild; + } + } + //its not this child and not one of its children or children-children, so go on to the next child + } + return null; //searched element was not found withis this parent + } + +} diff --git a/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/PathModel.java b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/PathModel.java index d91dc67..a20e586 100644 --- a/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/PathModel.java +++ b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/PathModel.java @@ -1,314 +1,329 @@ package com.sdsmdg.harjot.vectormaster.models; +import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathMeasure; -import android.graphics.RectF; import com.sdsmdg.harjot.vectormaster.DefaultValues; -import com.sdsmdg.harjot.vectormaster.VectorMasterView; import com.sdsmdg.harjot.vectormaster.utilities.Utils; import com.sdsmdg.harjot.vectormaster.utilities.parser.PathParser; -public class PathModel { +public class PathModel extends Model { + + private float fillAlpha; + private int fillColor; + + private Path.FillType fillType; + + private String pathData; + + private float trimPathStart, trimPathEnd, trimPathOffset; + + private float strokeAlpha; + private int strokeColor; + private Paint.Cap strokeLineCap; + private Paint.Join strokeLineJoin; + private float strokeMiterLimit; + private float strokeWidth; + private float strokeRatio; + private boolean strokeChanged; + + private boolean isFillAndStroke = false; + + private Path path; + private PathMeasure pathMeasure; + private Path trimmedPath; + private Path transformedPath = new Path(); + private Paint pathPaint; + + private Matrix lastParentTransformation; + private float lastStrokeRatio; + + public PathModel() { + fillAlpha = DefaultValues.PATH_FILL_ALPHA; + fillColor = DefaultValues.PATH_FILL_COLOR; + fillType = DefaultValues.PATH_FILL_TYPE; + trimPathStart = DefaultValues.PATH_TRIM_PATH_START; + trimPathEnd = DefaultValues.PATH_TRIM_PATH_END; + trimPathOffset = DefaultValues.PATH_TRIM_PATH_OFFSET; + strokeAlpha = DefaultValues.PATH_STROKE_ALPHA; + strokeColor = DefaultValues.PATH_STROKE_COLOR; + strokeLineCap = DefaultValues.PATH_STROKE_LINE_CAP; + strokeLineJoin = DefaultValues.PATH_STROKE_LINE_JOIN; + strokeMiterLimit = DefaultValues.PATH_STROKE_MITER_LIMIT; + strokeWidth = DefaultValues.PATH_STROKE_WIDTH; + strokeRatio = DefaultValues.PATH_STROKE_RATIO; + + pathPaint = new Paint(); + pathPaint.setAntiAlias(true); + updatePaint(); + } + + @Override + public void calculate(Matrix parentTransformation, Boolean transformationChanged, float strokeRatio) { + if (transformationChanged || lastParentTransformation == null) { + lastParentTransformation = parentTransformation; + calculateTransformedPath(); + } + if (strokeChanged || lastStrokeRatio != strokeRatio) { + strokeChanged = false; + lastStrokeRatio = strokeRatio; + pathPaint.setStrokeWidth(strokeWidth * this.strokeRatio * strokeRatio); + } + } + + @Override + public void prepare(Canvas canvas) { + //path do not prepare + } + + @Override + public void draw(Canvas canvas) { + transformedPath.setFillType(fillType); + if (isFillAndStroke()) { + makeFillPaint(); + canvas.drawPath(transformedPath, getPathPaint()); + makeStrokePaint(); + canvas.drawPath(transformedPath, getPathPaint()); + } else { + canvas.drawPath(transformedPath, getPathPaint()); + } + } + + public void updatePaint() { + if (fillColor != Color.TRANSPARENT && strokeColor != Color.TRANSPARENT) { + isFillAndStroke = true; + } else if (fillColor != Color.TRANSPARENT) { + pathPaint.setColor(fillColor); + pathPaint.setAlpha(Utils.getAlphaFromFloat(fillAlpha)); + pathPaint.setStyle(Paint.Style.FILL); + isFillAndStroke = false; + } else if (strokeColor != Color.TRANSPARENT) { + pathPaint.setColor(strokeColor); + pathPaint.setAlpha(Utils.getAlphaFromFloat(strokeAlpha)); + pathPaint.setStyle(Paint.Style.STROKE); + isFillAndStroke = false; + } else { + pathPaint.setColor(Color.TRANSPARENT); + } + + pathPaint.setStrokeCap(strokeLineCap); + pathPaint.setStrokeJoin(strokeLineJoin); + pathPaint.setStrokeMiter(strokeMiterLimit); + } + + public void makeStrokePaint() { + pathPaint.setColor(strokeColor); + pathPaint.setAlpha(Utils.getAlphaFromFloat(strokeAlpha)); + pathPaint.setStyle(Paint.Style.STROKE); + } + + public void makeFillPaint() { + pathPaint.setColor(fillColor); + pathPaint.setAlpha(Utils.getAlphaFromFloat(fillAlpha)); + pathPaint.setStyle(Paint.Style.FILL); + } + + private void calculateTransformedPath() { + if (trimmedPath == null || lastParentTransformation == null) { + return; + } + + //transformedPath.rewind(); + trimmedPath.transform(lastParentTransformation, transformedPath); + } + + private void calculateTrimmedPath() { + if (path == null) { + return; + } + + if (trimPathStart != 0 || trimPathEnd != 1 || trimPathOffset != 0) { + float trimStart = trimPathStart + trimPathOffset; + float trimEnd = trimPathEnd + trimPathOffset; + float length = pathMeasure.getLength(); + trimmedPath.rewind(); + pathMeasure.getSegment( + trimStart * length, + trimEnd * length, + trimmedPath, + true); + } else { + trimmedPath.set(path); + } + + calculateTransformedPath(); + } + + @Override + public void collectFullPath(Path collectedPath) { + collectedPath.addPath(getPath()); + } + + public Path getTrimmedPath() { + return new Path(trimmedPath); + } + + public Path getPath() { + return path; + } + + public void setPath(Path path) { + this.path = path; + this.pathMeasure = new PathMeasure(path, false); + this.trimmedPath = new Path(path); + calculateTrimmedPath(); + } + + public Paint getPathPaint() { + return pathPaint; + } + + public void setPathPaint(Paint pathPaint) { + this.pathPaint = pathPaint; + strokeChanged = true; + } + + public float getFillAlpha() { + return fillAlpha; + } + + public void setFillAlpha(float fillAlpha) { + this.fillAlpha = fillAlpha; + updatePaint(); + } + + public int getFillColor() { + return fillColor; + } + + public void setFillColor(int fillColor) { + this.fillColor = fillColor; + updatePaint(); + } + + public Path.FillType getFillType() { + return fillType; + } + + public void setFillType(Path.FillType fillType) { + this.fillType = fillType; + } + + public String getPathData() { + return pathData; + } + + public void setPathData(String pathData) { + setPathData(pathData, true); + } + + public void setPathData(String pathData, boolean useLegacyParser) { + this.pathData = pathData; + Path path = null; + if (useLegacyParser) { + path = com.sdsmdg.harjot.vectormaster.utilities.legacyparser.PathParser.createPathFromPathData(pathData); + } else { + path = PathParser.doPath(pathData); + } + setPath(path); + } + + public float getTrimPathStart() { + return trimPathStart; + } + + public void setTrimPathStart(float trimPathStart) { + this.trimPathStart = trimPathStart; + calculateTrimmedPath(); + } + + public float getTrimPathEnd() { + return trimPathEnd; + } + + public void setTrimPathEnd(float trimPathEnd) { + this.trimPathEnd = trimPathEnd; + calculateTrimmedPath(); + } + + public float getTrimPathOffset() { + return trimPathOffset; + } + + public void setTrimPathOffset(float trimPathOffset) { + this.trimPathOffset = trimPathOffset; + calculateTrimmedPath(); + } + + public float getStrokeAlpha() { + return strokeAlpha; + } + + public void setStrokeAlpha(float strokeAlpha) { + this.strokeAlpha = strokeAlpha; + updatePaint(); + } + + public int getStrokeColor() { + return strokeColor; + } + + public void setStrokeColor(int strokeColor) { + this.strokeColor = strokeColor; + updatePaint(); + } + + public Paint.Cap getStrokeLineCap() { + return strokeLineCap; + } + + public void setStrokeLineCap(Paint.Cap strokeLineCap) { + this.strokeLineCap = strokeLineCap; + updatePaint(); + } + + public Paint.Join getStrokeLineJoin() { + return strokeLineJoin; + } + + public void setStrokeLineJoin(Paint.Join strokeLineJoin) { + this.strokeLineJoin = strokeLineJoin; + updatePaint(); + } + + public float getStrokeMiterLimit() { + return strokeMiterLimit; + } + + public void setStrokeMiterLimit(float strokeMiterLimit) { + this.strokeMiterLimit = strokeMiterLimit; + updatePaint(); + } + + public float getStrokeWidth() { + return strokeWidth; + } + + public void setStrokeWidth(float strokeWidth) { + this.strokeWidth = strokeWidth; + strokeChanged = true; + } + + public boolean isFillAndStroke() { + return isFillAndStroke; + } + + public float getStrokeRatio() { + return strokeRatio; + } + + public void setStrokeRatio(float strokeRatio) { + this.strokeRatio = strokeRatio; + strokeChanged = true; + } - private String name; - - private float fillAlpha; - private int fillColor; - - private Path.FillType fillType; - - private String pathData; - - private float trimPathStart, trimPathEnd, trimPathOffset; - - private float strokeAlpha; - private int strokeColor; - private Paint.Cap strokeLineCap; - private Paint.Join strokeLineJoin; - private float strokeMiterLimit; - private float strokeWidth; - - private float strokeRatio; - - private boolean isFillAndStroke = false; - - // Support for trim-paths is not available - - private Path originalPath; - private Path path; - private Path trimmedPath; - private Paint pathPaint; - - private Matrix scaleMatrix; - - public PathModel() { - fillAlpha = DefaultValues.PATH_FILL_ALPHA; - fillColor = DefaultValues.PATH_FILL_COLOR; - fillType = DefaultValues.PATH_FILL_TYPE; - trimPathStart = DefaultValues.PATH_TRIM_PATH_START; - trimPathEnd = DefaultValues.PATH_TRIM_PATH_END; - trimPathOffset = DefaultValues.PATH_TRIM_PATH_OFFSET; - strokeAlpha = DefaultValues.PATH_STROKE_ALPHA; - strokeColor = DefaultValues.PATH_STROKE_COLOR; - strokeLineCap = DefaultValues.PATH_STROKE_LINE_CAP; - strokeLineJoin = DefaultValues.PATH_STROKE_LINE_JOIN; - strokeMiterLimit = DefaultValues.PATH_STROKE_MITER_LIMIT; - strokeWidth = DefaultValues.PATH_STROKE_WIDTH; - strokeRatio = DefaultValues.PATH_STROKE_RATIO; - - pathPaint = new Paint(); - pathPaint.setAntiAlias(true); - updatePaint(); - } - - public void buildPath(boolean useLegacyParser) { - if (useLegacyParser) { - originalPath = com.sdsmdg.harjot.vectormaster.utilities.legacyparser.PathParser.createPathFromPathData(pathData); - } else { - originalPath = PathParser.doPath(pathData); - } - if (originalPath != null) - originalPath.setFillType(fillType); - - path = new Path(originalPath); - } - - public void updatePaint() { - pathPaint.setStrokeWidth(strokeWidth * strokeRatio); - - if (fillColor != Color.TRANSPARENT && strokeColor != Color.TRANSPARENT) { - isFillAndStroke = true; - } else if (fillColor != Color.TRANSPARENT) { - pathPaint.setColor(fillColor); - pathPaint.setAlpha(Utils.getAlphaFromFloat(fillAlpha)); - pathPaint.setStyle(Paint.Style.FILL); - isFillAndStroke = false; - } else if (strokeColor != Color.TRANSPARENT) { - pathPaint.setColor(strokeColor); - pathPaint.setAlpha(Utils.getAlphaFromFloat(strokeAlpha)); - pathPaint.setStyle(Paint.Style.STROKE); - isFillAndStroke = false; - } else { - pathPaint.setColor(Color.TRANSPARENT); - } - - pathPaint.setStrokeCap(strokeLineCap); - pathPaint.setStrokeJoin(strokeLineJoin); - pathPaint.setStrokeMiter(strokeMiterLimit); - } - - public void makeStrokePaint() { - pathPaint.setColor(strokeColor); - pathPaint.setAlpha(Utils.getAlphaFromFloat(strokeAlpha)); - pathPaint.setStyle(Paint.Style.STROKE); - } - - public void makeFillPaint() { - pathPaint.setColor(fillColor); - pathPaint.setAlpha(Utils.getAlphaFromFloat(fillAlpha)); - pathPaint.setStyle(Paint.Style.FILL); - } - - public void transform(Matrix matrix) { - scaleMatrix = matrix; - - trimPath(); - } - - public void trimPath() { - if (scaleMatrix != null) { - if (trimPathStart == 0 && trimPathEnd == 1 && trimPathOffset == 0) { - path = new Path(originalPath); - path.transform(scaleMatrix); - } else { - PathMeasure pathMeasure = new PathMeasure(originalPath, false); - float length = pathMeasure.getLength(); - trimmedPath = new Path(); - pathMeasure.getSegment((trimPathStart + trimPathOffset) * length, (trimPathEnd + trimPathOffset) * length, trimmedPath, true); - path = new Path(trimmedPath); - path.transform(scaleMatrix); - } - } - } - - public Path getTrimmedPath() { - return trimmedPath; - } - - public void setTrimmedPath(Path trimmedPath) { - this.trimmedPath = trimmedPath; - } - - public Path getPath() { - return path; - } - - public void setPath(Path path) { - this.path = path; - } - - public Path getScaledAndOffsetPath(float offsetX, float offsetY, float scaleX, float scaleY) { - Path newPath = new Path(path); - newPath.offset(offsetX, offsetY); - newPath.transform(getScaleMatrix(newPath, scaleX, scaleY)); - return newPath; - } - - public Matrix getScaleMatrix(Path srcPath, float scaleX, float scaleY) { - Matrix scaleMatrix = new Matrix(); - RectF rectF = new RectF(); - srcPath.computeBounds(rectF, true); - scaleMatrix.setScale(scaleX, scaleY, rectF.left, rectF.top); - return scaleMatrix; - } - - public Paint getPathPaint() { - return pathPaint; - } - - public void setPathPaint(Paint pathPaint) { - this.pathPaint = pathPaint; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public float getFillAlpha() { - return fillAlpha; - } - - public void setFillAlpha(float fillAlpha) { - this.fillAlpha = fillAlpha; - updatePaint(); - } - - public int getFillColor() { - return fillColor; - } - - public void setFillColor(int fillColor) { - this.fillColor = fillColor; - updatePaint(); - } - - public Path.FillType getFillType() { - return fillType; - } - - public void setFillType(Path.FillType fillType) { - this.fillType = fillType; - if (originalPath != null) - originalPath.setFillType(fillType); - } - - public String getPathData() { - return pathData; - } - - public void setPathData(String pathData) { - this.pathData = pathData; - } - - public float getTrimPathStart() { - return trimPathStart; - } - - public void setTrimPathStart(float trimPathStart) { - this.trimPathStart = trimPathStart; - trimPath(); - } - - public float getTrimPathEnd() { - return trimPathEnd; - } - - public void setTrimPathEnd(float trimPathEnd) { - this.trimPathEnd = trimPathEnd; - trimPath(); - } - - public float getTrimPathOffset() { - return trimPathOffset; - } - - public void setTrimPathOffset(float trimPathOffset) { - this.trimPathOffset = trimPathOffset; - trimPath(); - } - - public float getStrokeAlpha() { - return strokeAlpha; - } - - public void setStrokeAlpha(float strokeAlpha) { - this.strokeAlpha = strokeAlpha; - updatePaint(); - } - - public int getStrokeColor() { - return strokeColor; - } - - public void setStrokeColor(int strokeColor) { - this.strokeColor = strokeColor; - updatePaint(); - } - - public Paint.Cap getStrokeLineCap() { - return strokeLineCap; - } - - public void setStrokeLineCap(Paint.Cap strokeLineCap) { - this.strokeLineCap = strokeLineCap; - updatePaint(); - } - - public Paint.Join getStrokeLineJoin() { - return strokeLineJoin; - } - - public void setStrokeLineJoin(Paint.Join strokeLineJoin) { - this.strokeLineJoin = strokeLineJoin; - updatePaint(); - } - - public float getStrokeMiterLimit() { - return strokeMiterLimit; - } - - public void setStrokeMiterLimit(float strokeMiterLimit) { - this.strokeMiterLimit = strokeMiterLimit; - updatePaint(); - } - - public float getStrokeWidth() { - return strokeWidth; - } - - public void setStrokeWidth(float strokeWidth) { - this.strokeWidth = strokeWidth; - updatePaint(); - } - - public float getStrokeRatio() { - return strokeRatio; - } - - public void setStrokeRatio(float strokeRatio) { - this.strokeRatio = strokeRatio; - updatePaint(); - } - - public boolean isFillAndStroke() { - return isFillAndStroke; - } } diff --git a/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/VectorModel.java b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/VectorModel.java index c523c95..1c76571 100644 --- a/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/VectorModel.java +++ b/vectormaster/src/main/java/com/sdsmdg/harjot/vectormaster/models/VectorModel.java @@ -1,212 +1,97 @@ package com.sdsmdg.harjot.vectormaster.models; -import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.Matrix; import android.graphics.Path; -import android.graphics.Region; import com.sdsmdg.harjot.vectormaster.enums.TintMode; -import java.util.ArrayList; - -public class VectorModel { - - private String name; - - private float width, height; - - private float alpha = 1.0f; - - private boolean autoMirrored = false; - - private int tint = Color.TRANSPARENT; - private TintMode tintMode = TintMode.SCR_IN; - - private float viewportWidth, viewportHeight; - - private ArrayList groupModels; - private ArrayList pathModels; - private ArrayList clipPathModels; - - private Path fullpath; - - private Matrix scaleMatrix; - - public VectorModel() { - groupModels = new ArrayList<>(); - pathModels = new ArrayList<>(); - clipPathModels = new ArrayList<>(); - fullpath = new Path(); - } - - public void drawPaths(Canvas canvas, float offsetX, float offsetY, float scaleX, float scaleY) { - for (ClipPathModel clipPathModel : clipPathModels) { - canvas.clipPath(clipPathModel.getScaledAndOffsetPath(offsetX, offsetY, scaleX, scaleY)); - } - for (GroupModel groupModel : groupModels) { - groupModel.drawPaths(canvas, offsetX, offsetY, scaleX, scaleY); - } - for (PathModel pathModel : pathModels) { - if (pathModel.isFillAndStroke()) { - pathModel.makeFillPaint(); - canvas.drawPath(pathModel.getScaledAndOffsetPath(offsetX, offsetY, scaleX, scaleY), pathModel.getPathPaint()); - pathModel.makeStrokePaint(); - canvas.drawPath(pathModel.getScaledAndOffsetPath(offsetX, offsetY, scaleX, scaleY), pathModel.getPathPaint()); - } else { - canvas.drawPath(pathModel.getScaledAndOffsetPath(offsetX, offsetY, scaleX, scaleY), pathModel.getPathPaint()); - } - } - } - - public void drawPaths(Canvas canvas) { - for (ClipPathModel clipPathModel : clipPathModels) { - canvas.clipPath(clipPathModel.getPath()); - } - for (GroupModel groupModel : groupModels) { - groupModel.drawPaths(canvas); - } - for (PathModel pathModel : pathModels) { - if (pathModel.isFillAndStroke()) { - pathModel.makeFillPaint(); - canvas.drawPath(pathModel.getPath(), pathModel.getPathPaint()); - pathModel.makeStrokePaint(); - canvas.drawPath(pathModel.getPath(), pathModel.getPathPaint()); - } else { - canvas.drawPath(pathModel.getPath(), pathModel.getPathPaint()); - } - } - } - - public void scaleAllPaths(Matrix scaleMatrix) { - this.scaleMatrix = scaleMatrix; - for (GroupModel groupModel : groupModels) { - groupModel.scaleAllPaths(scaleMatrix); - } - for (PathModel pathModel : pathModels) { - pathModel.transform(scaleMatrix); - } - for (ClipPathModel clipPathModel : clipPathModels) { - clipPathModel.transform(scaleMatrix); - } - } - - public void scaleAllStrokeWidth(float ratio) { - for (GroupModel groupModel : groupModels) { - groupModel.scaleAllStrokeWidth(ratio); - } - for (PathModel pathModel : pathModels) { - pathModel.setStrokeRatio(ratio); - } - } - - public void buildTransformMatrices() { - for (GroupModel groupModel : groupModels) { - groupModel.buildTransformMatrix(); - } - } - - public void addGroupModel(GroupModel groupModel) { - groupModels.add(groupModel); - } - - public ArrayList getGroupModels() { - return groupModels; - } - - public void addPathModel(PathModel pathModel) { - pathModels.add(pathModel); - } - - public ArrayList getPathModels() { - return pathModels; - } - - public void addClipPathModel(ClipPathModel clipPathModel) { - clipPathModels.add(clipPathModel); - } - - public ArrayList getClipPathModels() { - return clipPathModels; - } - - public Path getFullpath() { - return fullpath; - } - - public void setFullpath(Path fullpath) { - this.fullpath = fullpath; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public float getWidth() { - return width; - } - - public void setWidth(float width) { - this.width = width; - } - - public float getHeight() { - return height; - } - - public void setHeight(float height) { - this.height = height; - } - - public float getAlpha() { - return alpha; - } - - public void setAlpha(float alpha) { - this.alpha = alpha; - } - - public boolean isAutoMirrored() { - return autoMirrored; - } - - public void setAutoMirrored(boolean autoMirrored) { - this.autoMirrored = autoMirrored; - } - - public int getTint() { - return tint; - } - - public void setTint(int tint) { - this.tint = tint; - } - - public TintMode getTintMode() { - return tintMode; - } - - public void setTintMode(TintMode tintMode) { - this.tintMode = tintMode; - } - - public float getViewportWidth() { - return viewportWidth; - } - - public void setViewportWidth(float viewportWidth) { - this.viewportWidth = viewportWidth; - } - - public float getViewportHeight() { - return viewportHeight; - } +public class VectorModel extends ParentModel { - public void setViewportHeight(float viewportHeight) { - this.viewportHeight = viewportHeight; - } + private float width, height; + + private float alpha = 1.0f; + + private boolean autoMirrored = false; + + private int tint = Color.TRANSPARENT; + private TintMode tintMode = TintMode.SCR_IN; + + private float viewportWidth, viewportHeight; + + public VectorModel() { + } + + /** + * returns the UNTRANSFORMED paths + * @return + */ + public Path getFullpath() { + Path fullPath = new Path(); + collectFullPath(fullPath); + return fullPath; + } + + public float getWidth() { + return width; + } + + public void setWidth(float width) { + this.width = width; + } + + public float getHeight() { + return height; + } + + public void setHeight(float height) { + this.height = height; + } + + public float getAlpha() { + return alpha; + } + + public void setAlpha(float alpha) { + this.alpha = alpha; + } + + public boolean isAutoMirrored() { + return autoMirrored; + } + + public void setAutoMirrored(boolean autoMirrored) { + this.autoMirrored = autoMirrored; + } + + public int getTint() { + return tint; + } + + public void setTint(int tint) { + this.tint = tint; + } + + public TintMode getTintMode() { + return tintMode; + } + + public void setTintMode(TintMode tintMode) { + this.tintMode = tintMode; + } + + public float getViewportWidth() { + return viewportWidth; + } + + public void setViewportWidth(float viewportWidth) { + this.viewportWidth = viewportWidth; + } + + public float getViewportHeight() { + return viewportHeight; + } + + public void setViewportHeight(float viewportHeight) { + this.viewportHeight = viewportHeight; + } }