├── .gitignore
├── .idea
├── encodings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
└── runConfigurations.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── app
│ │ └── com
│ │ └── pixelmeasrumenttool
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── app
│ │ │ └── com
│ │ │ └── pixelmeasrumenttool
│ │ │ └── MainActivity.kt
│ └── res
│ │ ├── drawable
│ │ └── background.png
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ └── content_main.xml
│ │ ├── menu
│ │ └── menu_main.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-v21
│ │ └── styles.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── app
│ └── com
│ └── pixelmeasrumenttool
│ └── ExampleUnitTest.java
├── art
├── pic-1.png
├── pic-2.png
├── pic-3.png
├── pic-all.png
└── pixel_measure.gif
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── pixelmeasuringview
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── app
│ │ └── com
│ │ └── pixelmeasuringview
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── app
│ │ │ └── com
│ │ │ └── pixelmeasuringview
│ │ │ ├── CircleDrawable.kt
│ │ │ ├── PixelMeasuringCallback.kt
│ │ │ ├── PixelMeasuringView.kt
│ │ │ └── Ruler.kt
│ └── res
│ │ └── values
│ │ ├── attrs.xml
│ │ └── strings.xml
│ └── test
│ └── java
│ └── app
│ └── com
│ └── pixelmeasuringview
│ └── ExampleUnitTest.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Add any directories, files, or patterns you don't want to be tracked by version control
2 | .gradle
3 | reports
4 | local.properties
5 | .idea
6 | *.iml
7 | build
8 | .DS_Store
9 | app/*.apk
10 | app/*.iml
11 | fastlane/report.xml
12 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android-PixelMeasuringTool
2 | A tool to measure the pixel between items in the picture.
3 |
4 | I don't know what might be possible usage.
5 | I used it in a calculation of the actual distance of the balls in a game called lawn bowls. If you know the approximate height of the phone when the picture was taken (and getting a little bit of help from the gyroscope to be sure that the phone is parallel to the ground) you can get the actual distance between the two items in the picture.
6 |
7 | 
8 |
9 | ## Download
10 |
11 | via Gradle:
12 |
13 | dependencies {
14 | implementation 'com.zekapp.library:pixelmeasuringview:1.0.10'
15 | }
16 |
17 | ## Usage
18 |
19 |
32 |
33 | ## Getting Pixel Programmatically
34 |
35 | @Override
36 | protected void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | setContentView(R.layout.activity_main);
39 |
40 | PixelMeasuringView measure = (PixelMeasuringView)findViewById(R.id.image);
41 | measure.setCallback(new PixelMeasuringCallback() {
42 | @Override
43 | public void distanceBetweenCircles(float distance) {
44 |
45 | }
46 | });
47 | }
48 |
49 | 
50 |
51 | ## License
52 |
53 | Copyright (C) 2015 Zeki Guler
54 | Copyright (C) 2011 The Android Open Source Project
55 |
56 | Licensed under the Apache License, Version 2.0 (the "License");
57 | you may not use this file except in compliance with the License.
58 | You may obtain a copy of the License at
59 |
60 | http://www.apache.org/licenses/LICENSE-2.0
61 |
62 | Unless required by applicable law or agreed to in writing, software
63 | distributed under the License is distributed on an "AS IS" BASIS,
64 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
65 | See the License for the specific language governing permissions and
66 | limitations under the License.
67 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 |
4 | android {
5 | compileSdkVersion 27
6 | buildToolsVersion '27.0.3'
7 |
8 | defaultConfig {
9 | applicationId "app.com.pixelmeasrumenttool"
10 | minSdkVersion 21
11 | targetSdkVersion 27
12 | versionCode 1
13 | versionName "1.0.0"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | }
22 |
23 | dependencies {
24 |
25 | implementation fileTree(dir: 'libs', include: ['*.jar'])
26 | testImplementation 'junit:junit:4.12'
27 | implementation 'com.android.support:support-compat:27.1.1'
28 | implementation 'com.android.support:design:27.1.1'
29 | implementation project(':pixelmeasuringview')
30 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
31 | }
32 |
33 | repositories {
34 | mavenCentral()
35 | }
36 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/appscoredev2/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/app/com/pixelmeasrumenttool/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package app.com.pixelmeasrumenttool;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/app/com/pixelmeasrumenttool/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package app.com.pixelmeasrumenttool
2 |
3 | import android.os.Bundle
4 | import android.support.design.widget.FloatingActionButton
5 | import android.support.design.widget.Snackbar
6 | import android.support.v7.app.AppCompatActivity
7 | import android.support.v7.widget.Toolbar
8 | import android.view.View
9 | import android.view.Menu
10 | import android.view.MenuItem
11 |
12 | import app.com.pixelmeasuringview.PixelMeasuringCallback
13 | import app.com.pixelmeasuringview.PixelMeasuringView
14 |
15 | class MainActivity : AppCompatActivity() {
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | setContentView(R.layout.activity_main)
20 | val toolbar = findViewById(R.id.toolbar)
21 | setSupportActionBar(toolbar)
22 |
23 | val fab = findViewById(R.id.fab)
24 | fab.setOnClickListener { view ->
25 | Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
26 | .setAction("Action", null).show()
27 | }
28 |
29 | val measure = findViewById(R.id.lawn_ball_layout)
30 | measure.setCallback(callback = object : PixelMeasuringCallback{
31 | override fun distanceBetweenCircles(distance: Float) {
32 |
33 | }
34 | })
35 | }
36 |
37 | override fun onCreateOptionsMenu(menu: Menu): Boolean {
38 | // Inflate the menu; this adds items to the action bar if it is present.
39 | menuInflater.inflate(R.menu.menu_main, menu)
40 | return true
41 | }
42 |
43 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
44 | // Handle action bar item clicks here. The action bar will
45 | // automatically handle clicks on the Home/Up button, so long
46 | // as you specify a parent activity in AndroidManifest.xml.
47 | val id = item.itemId
48 |
49 |
50 | return if (id == R.id.action_settings) {
51 | true
52 | } else super.onOptionsItemSelected(item)
53 |
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekapp/Android-PixelMeasuringTool/46211793e2531f966a37ee5256e13de84a372a0d/app/src/main/res/drawable/background.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
22 |
23 |
24 |
25 |
26 |
27 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekapp/Android-PixelMeasuringTool/46211793e2531f966a37ee5256e13de84a372a0d/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekapp/Android-PixelMeasuringTool/46211793e2531f966a37ee5256e13de84a372a0d/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekapp/Android-PixelMeasuringTool/46211793e2531f966a37ee5256e13de84a372a0d/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekapp/Android-PixelMeasuringTool/46211793e2531f966a37ee5256e13de84a372a0d/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekapp/Android-PixelMeasuringTool/46211793e2531f966a37ee5256e13de84a372a0d/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #1B5E20
7 | #4A148C
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PixelMeasrumentTool
3 | Settings
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/test/java/app/com/pixelmeasrumenttool/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package app.com.pixelmeasrumenttool;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/art/pic-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekapp/Android-PixelMeasuringTool/46211793e2531f966a37ee5256e13de84a372a0d/art/pic-1.png
--------------------------------------------------------------------------------
/art/pic-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekapp/Android-PixelMeasuringTool/46211793e2531f966a37ee5256e13de84a372a0d/art/pic-2.png
--------------------------------------------------------------------------------
/art/pic-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekapp/Android-PixelMeasuringTool/46211793e2531f966a37ee5256e13de84a372a0d/art/pic-3.png
--------------------------------------------------------------------------------
/art/pic-all.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekapp/Android-PixelMeasuringTool/46211793e2531f966a37ee5256e13de84a372a0d/art/pic-all.png
--------------------------------------------------------------------------------
/art/pixel_measure.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekapp/Android-PixelMeasuringTool/46211793e2531f966a37ee5256e13de84a372a0d/art/pixel_measure.gif
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.kotlin_version = '1.2.51'
4 | repositories {
5 | jcenter()
6 | google()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.1.3'
10 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
11 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
13 |
14 | // NOTE: Do not place your application dependencies here; they belong
15 | // in the individual module build.gradle files
16 | }
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | jcenter()
22 | google()
23 | }
24 | }
25 |
26 | task clean(type: Delete) {
27 | delete rootProject.buildDir
28 | }
29 |
30 | subprojects {
31 | tasks.withType(Javadoc).all { enabled = false }
32 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekapp/Android-PixelMeasuringTool/46211793e2531f966a37ee5256e13de84a372a0d/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Oct 21 11:34:03 PDT 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/pixelmeasuringview/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/pixelmeasuringview/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 |
4 | def libVer = '1.0.10'
5 |
6 | ext {
7 | bintrayRepo = 'Maven'
8 | bintrayName = 'pixel-measuring-tool'
9 |
10 | publishedGroupId = 'com.zekapp.library'
11 | libraryName = 'pixel-measuring-tool'
12 | artifact = 'pixelmeasuringview'
13 |
14 | libraryDescription = 'A imageView with a tool to calculate the pixel between items in the picture'
15 |
16 | siteUrl = 'https://github.com/zekapp/Android-PixelMeasuringTool'
17 | gitUrl = 'https://github.com/zekapp/Android-PixelMeasuringTool.git'
18 |
19 | libraryVersion = libVer
20 |
21 | developerId = 'zekapp'
22 | developerName = 'Zeki Guler'
23 | developerEmail = 'zeki.gulerl@icloud.com'
24 |
25 | licenseName = 'The Apache Software License, Version 2.0'
26 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
27 | allLicenses = ["Apache-2.0"]
28 | }
29 |
30 | android {
31 | compileSdkVersion 27
32 | buildToolsVersion '27.0.3'
33 |
34 | defaultConfig {
35 | minSdkVersion 19
36 | targetSdkVersion 27
37 | versionCode 1
38 | versionName libVer
39 | }
40 | buildTypes {
41 | release {
42 | minifyEnabled false
43 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
44 | }
45 | }
46 | }
47 |
48 | dependencies {
49 | implementation fileTree(dir: 'libs', include: ['*.jar'])
50 | testImplementation 'junit:junit:4.12'
51 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
52 | }
53 | repositories {
54 | mavenCentral()
55 | }
56 |
57 | //Add these lines to publish library to bintray. This is the readymade scripts made by github user nuuneoi to make uploading to bintray easy.
58 | //Place it at the end of the file
59 | if (project.rootProject.file('local.properties').exists()) {
60 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle'
61 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle'
62 | }
63 |
64 | //apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle'
65 | //apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle'
66 |
67 | // install and uploading the library
68 | // ./gradlew install
69 | // ./gradlew bintrayUpload
70 |
71 | // usage
72 |
--------------------------------------------------------------------------------
/pixelmeasuringview/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/appscoredev2/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/pixelmeasuringview/src/androidTest/java/app/com/pixelmeasuringview/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package app.com.pixelmeasuringview;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/pixelmeasuringview/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pixelmeasuringview/src/main/java/app/com/pixelmeasuringview/CircleDrawable.kt:
--------------------------------------------------------------------------------
1 | package app.com.pixelmeasuringview
2 |
3 | import android.graphics.DashPathEffect
4 | import android.graphics.Paint
5 | import android.graphics.drawable.ShapeDrawable
6 | import android.graphics.drawable.shapes.OvalShape
7 |
8 | /**
9 | * Created by Zeki Guler on 07,December,2015
10 | * ©2015 Appscore. All Rights Reserved
11 | */
12 | class CircleDrawable(color: Int) : ShapeDrawable(OvalShape()) {
13 |
14 | var posX: Float = 0.toFloat()
15 | var posY: Float = 0.toFloat()
16 | var scaleFactor = 1f
17 | set(scaleFactor) {
18 | field = scaleFactor
19 | height = INITIAL_HEIGHT * scaleFactor
20 | width = INITIAL_WIDTH * scaleFactor
21 | paint.strokeWidth = if (mIsSelected) DEFAULT_STROKE_WIDTH else SELECTED_STROKE_WIDTH
22 | }
23 | var height: Float = 0.toFloat()
24 | private set
25 | var width: Float = 0.toFloat()
26 | private set
27 | private val mPathEffect: DashPathEffect
28 | private var mIsSelected: Boolean = false
29 |
30 |
31 | val exactCenterX: Float
32 | get() = posX + height / 2
33 | val exactCenterY: Float
34 | get() = posY + height / 2
35 |
36 | val diameter: Float
37 | get() = height + paint.strokeWidth * scaleFactor
38 |
39 | init {
40 | this.height = INITIAL_HEIGHT
41 | this.width = INITIAL_WIDTH
42 | this.posX = 0f
43 | this.posY = 0f
44 | this.mPathEffect = DashPathEffect(floatArrayOf(10f, 5.0f), 0f)
45 | paint.style = Paint.Style.STROKE
46 | paint.color = color
47 | paint.pathEffect = mPathEffect
48 | paint.strokeWidth = DEFAULT_STROKE_WIDTH
49 | setBounds(0, 0, INITIAL_HEIGHT.toInt(), INITIAL_WIDTH.toInt())
50 | }
51 |
52 | fun setAsSelected(isSelected: Boolean) {
53 | mIsSelected = isSelected
54 | paint.strokeWidth = if (isSelected) SELECTED_STROKE_WIDTH else DEFAULT_STROKE_WIDTH
55 | paint.pathEffect = mPathEffect
56 | }
57 |
58 | companion object {
59 |
60 | private const val INITIAL_HEIGHT = 100f
61 | private const val INITIAL_WIDTH = 100f
62 | private const val DEFAULT_STROKE_WIDTH = 2f
63 | private const val SELECTED_STROKE_WIDTH = 5f
64 | }
65 | }
--------------------------------------------------------------------------------
/pixelmeasuringview/src/main/java/app/com/pixelmeasuringview/PixelMeasuringCallback.kt:
--------------------------------------------------------------------------------
1 | package app.com.pixelmeasuringview
2 |
3 | /**
4 | * Created by Zeki Guler on 07,December,2015
5 | * ©2015 Appscore. All Rights Reserved
6 | */
7 | interface PixelMeasuringCallback {
8 | fun distanceBetweenCircles(distance: Float)
9 | }
10 |
--------------------------------------------------------------------------------
/pixelmeasuringview/src/main/java/app/com/pixelmeasuringview/PixelMeasuringView.kt:
--------------------------------------------------------------------------------
1 | package app.com.pixelmeasuringview
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.graphics.Canvas
6 | import android.graphics.Color
7 | import android.graphics.drawable.Drawable
8 | import android.util.AttributeSet
9 | import android.util.Log
10 | import android.view.MotionEvent
11 | import android.view.ScaleGestureDetector
12 | import android.widget.ImageView
13 |
14 | import java.util.ArrayList
15 |
16 | /**
17 | * Created by Zeki Guler on 07,December,2015
18 | * ©2015 Appscore. All Rights Reserved
19 | */
20 | class PixelMeasuringView : ImageView {
21 | private var mScaleDetector: ScaleGestureDetector? = null
22 | private var mLastTouchX: Float = 0.toFloat()
23 | private var mLastTouchY: Float = 0.toFloat()
24 | private var mActivePointerId = INVALID_POINTER_ID
25 | private var mCallback: PixelMeasuringCallback? = null
26 |
27 | private val mCircles = ArrayList()
28 | private var mSelectedCircle: CircleDrawable? = null
29 | private var isCircleLocked = false
30 | private var isCircleMoving = false
31 | private var mRuler: Ruler? = null
32 | private var isMeasureTextVisible = false
33 | private var isLineAllwaysActive = true
34 |
35 | private val closestCircle: CircleDrawable
36 | get() {
37 | var curX: Float
38 | var curY: Float
39 | var minDis = java.lang.Double.MAX_VALUE
40 |
41 | var closestCircle = mCircles[0]
42 |
43 | unSelectAll()
44 |
45 | for (circle in mCircles) {
46 | curX = circle.posX
47 | curY = circle.posY
48 |
49 | val dist = Math.sqrt(((curX - mLastTouchX) * (curX - mLastTouchX) + (curY - mLastTouchY) * (curY - mLastTouchY)).toDouble())
50 |
51 | circle.setAsSelected(false)
52 | if (minDis > dist) {
53 | closestCircle = circle
54 | minDis = dist
55 | }
56 | }
57 |
58 | closestCircle.setAsSelected(true)
59 | return closestCircle
60 | }
61 |
62 | constructor(context: Context) : super(context) {
63 | init(context, false, true, Color.BLACK, Color.BLACK)
64 | }
65 |
66 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
67 |
68 | val a = context.obtainStyledAttributes(attrs, R.styleable.InstantMeasuringView)
69 |
70 | val isTextVisible = a.getBoolean(R.styleable.InstantMeasuringView_is_measure_text_visible, false)
71 | val isLineAllwaysActive = a.getBoolean(R.styleable.InstantMeasuringView_is_line_all_visible, false)
72 | val cirlesColor = a.getColor(R.styleable.InstantMeasuringView_circles_color, Color.BLACK)
73 | val rulerColor = a.getColor(R.styleable.InstantMeasuringView_ruler_color, Color.BLACK)
74 |
75 | a.recycle()
76 |
77 | init(context, isTextVisible, isLineAllwaysActive, cirlesColor, rulerColor)
78 | }
79 |
80 | constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
81 |
82 | val a = context.obtainStyledAttributes(attrs, R.styleable.InstantMeasuringView, defStyle, 0)
83 |
84 | val isTextVisible = a.getBoolean(R.styleable.InstantMeasuringView_is_measure_text_visible, false)
85 | val isLineAllwaysActive = a.getBoolean(R.styleable.InstantMeasuringView_is_line_all_visible, false)
86 | val cirlesColor = a.getColor(R.styleable.InstantMeasuringView_circles_color, Color.BLACK)
87 | val rulerColor = a.getColor(R.styleable.InstantMeasuringView_ruler_color, Color.BLACK)
88 |
89 | a.recycle()
90 | init(context, isTextVisible, isLineAllwaysActive, cirlesColor, rulerColor)
91 | }
92 |
93 | private fun init(context: Context, visible: Boolean, active: Boolean, cirleColor: Int, rulerColor: Int) {
94 |
95 | this.isMeasureTextVisible = visible
96 | this.isLineAllwaysActive = active
97 |
98 |
99 | mRuler = Ruler(rulerColor)
100 |
101 | val c1 = CircleDrawable(cirleColor)
102 | c1.posX = 100f
103 | c1.posY = 400f
104 | mCircles.add(c1)
105 |
106 | val c2 = CircleDrawable(cirleColor)
107 | c2.posX = 400f
108 | c2.posY = 600f
109 | c2.scaleFactor = 1.7f
110 | mCircles.add(c2)
111 |
112 | drawLineBetweenCircles()
113 |
114 | mScaleDetector = ScaleGestureDetector(context, ScaleListener())
115 | }
116 |
117 | fun setCallback(callback: PixelMeasuringCallback) {
118 | this.mCallback = callback
119 | }
120 |
121 | @SuppressLint("ClickableViewAccessibility")
122 | override fun onTouchEvent(ev: MotionEvent): Boolean {
123 |
124 | // if circle locked by user do not create any event.
125 | if (isCircleLocked) return false
126 |
127 | // Let the ScaleGestureDetector inspect all events.
128 | mScaleDetector!!.onTouchEvent(ev)
129 |
130 | val action = ev.action
131 | when (action and MotionEvent.ACTION_MASK) {
132 |
133 | MotionEvent.ACTION_DOWN -> {
134 |
135 | val x = ev.x
136 | val y = ev.y
137 |
138 | mLastTouchX = x
139 | mLastTouchY = y
140 |
141 | mActivePointerId = ev.getPointerId(0)
142 | mSelectedCircle = closestCircle
143 | invalidate()
144 | }
145 |
146 | MotionEvent.ACTION_MOVE -> {
147 | val pointerIndex = ev.findPointerIndex(mActivePointerId)
148 | val x = ev.getX(pointerIndex)
149 | val y = ev.getY(pointerIndex)
150 |
151 | // Only move if the ScaleGestureDetector isn't processing a gesture.
152 | if (!mScaleDetector!!.isInProgress) {
153 |
154 | val dx = x - mLastTouchX
155 | val dy = y - mLastTouchY
156 |
157 | mSelectedCircle!!.posX = mSelectedCircle!!.posX + dx
158 | mSelectedCircle!!.posY = mSelectedCircle!!.posY + dy
159 |
160 | Log.d("ACTION_MOVE", " dx : $dx dy: $dy")
161 | invalidate()
162 | }
163 |
164 | mLastTouchX = x
165 | mLastTouchY = y
166 |
167 | drawLineBetweenCircles()
168 |
169 | isCircleMoving = true
170 | }
171 |
172 | MotionEvent.ACTION_UP -> {
173 | mActivePointerId = INVALID_POINTER_ID
174 | isCircleMoving = false
175 | invalidate()
176 | }
177 |
178 | MotionEvent.ACTION_CANCEL -> {
179 | mActivePointerId = INVALID_POINTER_ID
180 | isCircleMoving = false
181 | invalidate()
182 | }
183 |
184 | MotionEvent.ACTION_POINTER_UP -> {
185 | val pointerIndex = ev.action and MotionEvent.ACTION_POINTER_INDEX_MASK shr MotionEvent.ACTION_POINTER_INDEX_SHIFT
186 | val pointerId = ev.getPointerId(pointerIndex)
187 | if (pointerId == mActivePointerId) {
188 | // This was our active pointer going up. Choose a new
189 | // active pointer and adjust accordingly.
190 | val newPointerIndex = if (pointerIndex == 0) 1 else 0
191 | mLastTouchX = ev.getX(newPointerIndex)
192 | mLastTouchY = ev.getY(newPointerIndex)
193 | mActivePointerId = ev.getPointerId(newPointerIndex)
194 | }
195 | }
196 | }
197 |
198 | return true
199 | }
200 |
201 | private fun drawLineBetweenCircles() {
202 | if (mCircles.size < 2)
203 | return
204 |
205 | calculateDistance()
206 |
207 | val r1 = mCircles[0].diameter / 2
208 | val x1 = mCircles[0].exactCenterX
209 | val y1 = mCircles[0].exactCenterY
210 |
211 | val r2 = mCircles[1].diameter / 2
212 | val x2 = mCircles[1].exactCenterX
213 | val y2 = mCircles[1].exactCenterY
214 |
215 | mRuler!!.path = getLineStartEndPointBetweenCircles(r1, x1, y1, r2, x2, y2)
216 |
217 | }
218 |
219 | /**
220 | * This function returns the start and end points of the shortest path
221 | * between two circles.
222 | *
223 | * @param r1: radius of circle 1
224 | * @param x1: x coordinate of the the circle's center
225 | * @param y1: y coordinate of the the circle's center
226 | * @param r2: radius of circle 2
227 | * @param x2: x coordinate of the the circle's center
228 | * @param y2: y coordinate of the the circle's center
229 | *
230 | * @return : 2d float array
231 | * first row gives the touch point's coordinate of the circle-1
232 | * second row gives the touch point's coordinate of the circle-2
233 | *
234 | * [x1'][y1']
235 | * [x2'][y2']
236 | */
237 | private fun getLineStartEndPointBetweenCircles(r1: Float, x1: Float, y1: Float, r2: Float, x2: Float, y2: Float): Array {
238 |
239 | val p = Array(2) { FloatArray(2) }
240 |
241 | val d = centerToCenterDist().toFloat()
242 |
243 | // x1'
244 | p[0][0] = (r1 * x2 + x1 * (d - r1)) / d
245 |
246 | // y1'
247 | p[0][1] = (r1 * y2 + y1 * (d - r1)) / d
248 |
249 | // x2'
250 | p[1][0] = (r2 * x1 + x2 * (d - r2)) / d
251 |
252 | // y2'
253 | p[1][1] = (r2 * y1 + y2 * (d - r2)) / d
254 |
255 |
256 | return p
257 |
258 | }
259 |
260 | private fun calculateDistance() {
261 | if (mCircles.size < 2)
262 | return
263 |
264 | var distance = centerToCenterDist()
265 | val sumOfDiameters = sumOfDiameters()
266 |
267 | distance -= sumOfDiameters / 2
268 |
269 | mRuler!!.setLength(distance)
270 |
271 | if (mCallback != null)
272 | mCallback!!.distanceBetweenCircles(distance.toFloat())
273 | }
274 |
275 | private fun centerToCenterDist(): Double {
276 | val centers = findCentersOfCircles()
277 | return Math.sqrt(calculateDifference(centers))
278 | }
279 |
280 | private fun sumOfDiameters(): Double {
281 | var sum = 0.0
282 | for (c in mCircles) {
283 | sum += c.diameter.toDouble()
284 | }
285 | return sum
286 | }
287 |
288 | private fun calculateDifference(centers: Array): Double {
289 | // (x1 - x2) * (x1 - x2)
290 | val dx2 = ((centers[0][0] - centers[1][0]) * (centers[0][0] - centers[1][0])).toDouble()
291 | // (y1 - y2) * (y1 - y2)
292 | val dy2 = ((centers[0][1] - centers[1][1]) * (centers[0][1] - centers[1][1])).toDouble()
293 |
294 | return dx2 + dy2
295 | }
296 |
297 | private fun findCentersOfCircles(): Array {
298 | val centers = Array(mCircles.size) { FloatArray(2) }
299 |
300 | for ((i, c) in mCircles.withIndex()) {
301 | centers[i][0] = c.posX + c.width / 2
302 | centers[i][1] = c.posY + c.height / 2
303 | }
304 |
305 | return centers
306 | }
307 |
308 | private fun unSelectAll() {
309 | for (c in mCircles) {
310 | c.setAsSelected(false)
311 | }
312 | }
313 |
314 | public override fun onDraw(canvas: Canvas) {
315 | super.onDraw(canvas)
316 |
317 |
318 | for (circle in mCircles) {
319 | canvas.save()
320 | canvas.translate(circle.posX, circle.posY)
321 | canvas.scale(circle.scaleFactor, circle.scaleFactor)
322 | circle.draw(canvas)
323 | canvas.restore()
324 | }
325 |
326 | // stop complain Ide
327 | val ruler = mRuler?:return
328 |
329 | if (ruler.path != null) {
330 |
331 | if (isLineAllwaysActive || !isCircleMoving) {
332 | val p = ruler.path!!
333 | canvas.drawLine(p[0][0], p[0][1], p[1][0], p[1][1], ruler.linePaint)
334 |
335 | if (isMeasureTextVisible) {
336 | val c = ruler.centerOfRuler
337 | canvas.drawText(ruler.length, c[0], c[1], ruler.rulerTextPaint)
338 | }
339 |
340 | }
341 | }
342 | }
343 |
344 | override fun setBackground(background: Drawable) {
345 | super.setBackground(background)
346 | }
347 |
348 | private inner class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener() {
349 | override fun onScale(detector: ScaleGestureDetector): Boolean {
350 | var mScaleFactor = mSelectedCircle!!.scaleFactor
351 | mScaleFactor *= detector.scaleFactor
352 |
353 | // Don't let the object get too small or too large.
354 | mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f))
355 | mSelectedCircle!!.scaleFactor = mScaleFactor
356 | invalidate()
357 | return true
358 | }
359 | }
360 |
361 | companion object {
362 |
363 | private const val INVALID_POINTER_ID = -1
364 | }
365 | }
366 |
--------------------------------------------------------------------------------
/pixelmeasuringview/src/main/java/app/com/pixelmeasuringview/Ruler.kt:
--------------------------------------------------------------------------------
1 | package app.com.pixelmeasuringview
2 |
3 | import android.graphics.DashPathEffect
4 | import android.graphics.Paint
5 |
6 | import java.text.NumberFormat
7 |
8 | /**
9 | * Created by Zeki Guler on 10,December,2015
10 | * ©2015 Appscore. All Rights Reserved
11 | */
12 | class Ruler(color: Int) {
13 |
14 | val rulerTextPaint: Paint
15 | val linePaint: Paint
16 | private val mNumberFormat: NumberFormat = NumberFormat.getInstance()
17 | var path: Array? = null
18 | private var mLength = 0.0
19 |
20 | val centerOfRuler: FloatArray
21 | get() {
22 | val center = floatArrayOf(0f, 0f)
23 | if (path == null) return center
24 |
25 | val x1 = path!![0][0]
26 | val y1 = path!![0][1]
27 | val x2 = path!![1][0]
28 | val y2 = path!![1][1]
29 |
30 | center[0] = (x1 + x2) / 2
31 | center[1] = (y1 + y2) / 2
32 |
33 | return center
34 |
35 | }
36 |
37 | val length: String
38 | get() = mNumberFormat.format(mLength) + " px"
39 |
40 | init {
41 |
42 | mNumberFormat.maximumFractionDigits = 3
43 |
44 | // initLinePaint
45 | linePaint = Paint()
46 | linePaint.strokeWidth = 2f
47 | linePaint.color = color
48 | linePaint.style = Paint.Style.STROKE
49 | linePaint.pathEffect = DashPathEffect(floatArrayOf(10f, 5.0f), 5f)
50 |
51 | //init textPaint
52 | rulerTextPaint = Paint()
53 | rulerTextPaint.color = color
54 | rulerTextPaint.textSize = 41f
55 | }
56 |
57 | fun setLength(length: Double) {
58 | mLength = length
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/pixelmeasuringview/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/pixelmeasuringview/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PixelMeasuringView
3 |
4 |
--------------------------------------------------------------------------------
/pixelmeasuringview/src/test/java/app/com/pixelmeasuringview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package app.com.pixelmeasuringview;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':pixelmeasuringview'
2 |
--------------------------------------------------------------------------------