diff --git a/.gitignore b/.gitignore index 7a7e556..f62dc57 100644 --- a/.gitignore +++ b/.gitignore @@ -48,5 +48,4 @@ fastlane/report.xml fastlane/Preview.html fastlane/screenshots fastlane/test_output -fastlane/readme.md - +fastlane/readme.md \ No newline at end of file diff --git a/LICENSE b/LICENSE index 0623387..4796b80 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2018 zTrap + Copyright 2024 zTrap Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index b652346..e3c089e 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Bezier curves creator -The simple helper for build [Bezier curves](https://en.wikipedia.org/wiki/B%C3%A9zier_curve). Fully compatible with projects written in java/kotlin +The simple multiplatform helper for build [Bezier curves](https://en.wikipedia.org/wiki/B%C3%A9zier_curve) [ ![Download](https://maven-badges.herokuapp.com/maven-central/ru.ztrap/beziercurve/badge.svg) ](https://maven-badges.herokuapp.com/maven-central/ru.ztrap/beziercurve/) ## Install ```gradle -implementation 'ru.ztrap:beziercurve:1.0.2' +implementation 'ru.ztrap:beziercurve:1.0.3' ``` ## Usage @@ -28,20 +28,16 @@ val curve = BezierCurve( ```kotlin val point = curve.calculate(progress) -// or -curve.calculate(progress) -val point = curve.point ``` ## Developed By - Peter Gulko - ztrap.developer@gmail.com - - [paypal.me/zTrap](https://www.paypal.me/zTrap) ## License - Copyright 2021 zTrap + Copyright 2024 zTrap Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/beziercurve/.gitignore b/beziercurve/.gitignore deleted file mode 100644 index 796b96d..0000000 --- a/beziercurve/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/beziercurve/build.gradle b/beziercurve/build.gradle deleted file mode 100644 index 0049b07..0000000 --- a/beziercurve/build.gradle +++ /dev/null @@ -1,14 +0,0 @@ -apply plugin: 'org.jetbrains.dokka' -apply plugin: 'kotlin' - -apply from: '../publishing.gradle' - -compileKotlin { - kotlinOptions { - jvmTarget = setup.jvm - } -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$versions.kotlin" -} \ No newline at end of file diff --git a/beziercurve/src/main/kotlin/ru/ztrap/beziercurve/BezierCurve.kt b/beziercurve/src/main/kotlin/ru/ztrap/beziercurve/BezierCurve.kt deleted file mode 100644 index dabea8b..0000000 --- a/beziercurve/src/main/kotlin/ru/ztrap/beziercurve/BezierCurve.kt +++ /dev/null @@ -1,116 +0,0 @@ -package ru.ztrap.beziercurve - -import kotlin.math.pow - -private val APPLICABLE_VALUES = 0f..1f - -/** - * @author pa.gulko zTrap (16.04.2019) - * - * Primary constructor. Use this if you want to construct some Bezier curve. Use this format for providing - * points `[x, y]` - */ -data class BezierCurve( - val start: Pair, - val end: Pair, - val controls: List> -) { - constructor( - start: Pair, - end: Pair, - vararg controls: Pair - ) : this( - start, - end, - listOf(*controls) - ) - - @Deprecated("Use another constructor", ReplaceWith("BezierCurve(start, end, control1, control2)")) - constructor( - control1: Pair, - control2: Pair, - start: Pair, - end: Pair - ) : this( - start, - end, - listOf(control1, control2) - ) - - /** - * Use this constructor if you want to construct some quad Bezier curve. Use this format for providing - * points `[x, y]` - */ - @Deprecated("Use another constructor", ReplaceWith("BezierCurve(start, end, control)")) - constructor( - control: Pair, - start: Pair, - end: Pair - ) : this( - start, - end, - listOf(control) - ) - - /** - * Use this constructor if you want to construct some linear Bezier curve. Use this format for providing - * points `[x, y]` - */ - @Deprecated("Use another constructor", ReplaceWith("BezierCurve(start, end, emptyList())")) - constructor( - start: Pair, - end: Pair - ) : this( - start, - end, - emptyList() - ) - - private val internalPoint = Point() - - /** Point container. Contains `x` and `y` values for last calculation */ - val point: Point - get() = internalPoint.copy() - - /** Calculates linear Bezier curve for presented [t]. Acceptable value for [t] in `[0,1]` */ - fun calculate(t: Float): Point { - require(t in APPLICABLE_VALUES) { "Wrong t value = $t. Applicable values in [0,1]" } - - return internalPoint.apply { - when(controls.size) { - 0 -> { - x = (1 - t) * start.x + t * end.x - y = (1 - t) * start.y + t * end.y - } - else -> { - x = 0f - y = 0f - - controls.forEachIndexed { index, control -> - val polynomial = bernstein(t, controls.size - 1, index + 1) - x += polynomial * control.x - y += polynomial * control.y - } - } - } - } - } - - /** Calculates linear Bezier curve for presented [t]. Acceptable value for [t] in `[0,1]` */ - @Deprecated("Use common calculate function", ReplaceWith("calculate(t)")) - fun linearFor(t: Float): Point = calculate(t) - - /** Calculates quadratic Bezier curve for presented [t]. Acceptable value for [t] in `[0,1]` */ - @Deprecated("Use common calculate function", ReplaceWith("calculate(t)")) - fun quadFor(t: Float): Point = calculate(t) - - /** Calculates cubic Bezier curve for presented [t]. Acceptable value for [t] in `[0,1]` */ - @Deprecated("Use common calculate function", ReplaceWith("calculate(t)")) - fun cubicFor(t: Float): Point = calculate(t) - - private fun fact(n: Int): Int = (1..n).reduce { acc, i -> acc * i } - - private fun bernstein(t: Float, n: Int, i: Int): Float { - return fact(n) / (fact(i) * fact(n - i)) * (1 - t).pow(n - i) * t.pow(i) - } -} \ No newline at end of file diff --git a/beziercurve/src/main/kotlin/ru/ztrap/beziercurve/Point.kt b/beziercurve/src/main/kotlin/ru/ztrap/beziercurve/Point.kt deleted file mode 100644 index c2f18bc..0000000 --- a/beziercurve/src/main/kotlin/ru/ztrap/beziercurve/Point.kt +++ /dev/null @@ -1,12 +0,0 @@ -package ru.ztrap.beziercurve - -/** - * @author pa.gulko zTrap (16.04.2019) - * - * Container for point values - */ -data class Point(var x: Float, var y: Float) { - - /** Empty constructor for creating point on starts of axis */ - constructor() : this(0f, 0f) -} \ No newline at end of file diff --git a/beziercurve/src/main/kotlin/ru/ztrap/beziercurve/extensions.kt b/beziercurve/src/main/kotlin/ru/ztrap/beziercurve/extensions.kt deleted file mode 100644 index 53abb49..0000000 --- a/beziercurve/src/main/kotlin/ru/ztrap/beziercurve/extensions.kt +++ /dev/null @@ -1,15 +0,0 @@ -@file:Suppress("NOTHING_TO_INLINE") - -package ru.ztrap.beziercurve - -import kotlin.math.pow - -internal inline val Pair.x: Float - get() = first - -internal inline val Pair.y: Float - get() = second - -internal inline fun Float.quad() = pow(2) - -internal inline fun Float.cube() = pow(3) \ No newline at end of file diff --git a/build.gradle b/build.gradle deleted file mode 100644 index fc25109..0000000 --- a/build.gradle +++ /dev/null @@ -1,27 +0,0 @@ -buildscript { - apply from: 'dependencies.gradle' - - repositories { - mavenCentral() - maven { url "https://plugins.gradle.org/m2/" } - } - - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin" - classpath "org.jetbrains.dokka:dokka-gradle-plugin:$versions.dokka" - classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:$versions.nexus_staging" - } -} - -allprojects { - repositories { - mavenCentral() - maven { url "https://plugins.gradle.org/m2/" } - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} - -apply plugin: 'io.codearte.nexus-staging' \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..801d8bc --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,53 @@ +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig + +plugins { + alias(libs.plugins.kotlin.multiplatform) + id("convention.publication") +} + +group = PublishingInfo.GROUP +version = PublishingInfo.Artifact.VERSION + +kotlin { + @OptIn(ExperimentalKotlinGradlePluginApi::class) + compilerOptions { + explicitApi() + } + + jvm() + + @OptIn(ExperimentalWasmDsl::class) + wasmJs { + moduleName = PublishingInfo.Artifact.NAME + browser { + commonWebpackConfig { + outputFileName = "${PublishingInfo.Artifact.NAME}.js" + devServer = (devServer ?: KotlinWebpackConfig.DevServer()).apply { + static = (static ?: mutableListOf()).apply { + // Serve sources to debug inside browser + add(project.projectDir.path) + } + } + } + } + binaries.executable() + } + + listOf( + iosX64(), + iosArm64(), + iosSimulatorArm64() + ).forEach { + it.binaries.framework { + baseName = PublishingInfo.Artifact.NAME + isStatic = true + } + } + + //https://kotlinlang.org/docs/native-objc-interop.html#export-of-kdoc-comments-to-generated-objective-c-headers + targets.withType { + compilations["main"].compilerOptions.options.freeCompilerArgs.add("-Xexport-kdoc") + } +} diff --git a/convention-plugins/build.gradle.kts b/convention-plugins/build.gradle.kts new file mode 100644 index 0000000..c5a80b7 --- /dev/null +++ b/convention-plugins/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + `kotlin-dsl` // Is needed to turn our build logic written in Kotlin into Gralde Plugin +} + +repositories { + gradlePluginPortal() // To use 'maven-publish' and 'signing' plugins in our own plugin +} \ No newline at end of file diff --git a/convention-plugins/src/main/kotlin/PublishingInfo.kt b/convention-plugins/src/main/kotlin/PublishingInfo.kt new file mode 100644 index 0000000..6302159 --- /dev/null +++ b/convention-plugins/src/main/kotlin/PublishingInfo.kt @@ -0,0 +1,36 @@ +object PublishingInfo { + const val BASE_ARTIFACT_NAME = "beziercurve" + const val BASE_REPO_BUCKET = "zTrap/$BASE_ARTIFACT_NAME" + const val BASE_REPO_URL = "https://github.com/$BASE_REPO_BUCKET" + + const val GROUP = "ru.ztrap" + + object Repo { + const val URL = BASE_REPO_URL + } + + object Scm { + const val URL = BASE_REPO_URL + const val CONNECTION = "scm:git@github.com:${BASE_REPO_BUCKET}.git" + const val DEV_CONNECTION = "scm:git@github.com:${BASE_REPO_BUCKET}.git" + } + + object License { + const val NAME = "the apache software license, version 2.0" + const val URL = "http://www.apache.org/licenses/license-2.0.txt" + const val DIST = "repo" + } + + object Developer { + const val ID = "ztrap" + const val NAME = "peter gulko" + const val EMAIL = "ztrap.developer@gmail.com" + } + + object Artifact { + const val ID = BASE_ARTIFACT_NAME + const val NAME = "Bezier curves creator" + const val DESCRIPTION = "The simple multiplatform helper for build Bezier curves" + const val VERSION = "1.0.3" + } +} \ No newline at end of file diff --git a/convention-plugins/src/main/kotlin/convention.publication.gradle.kts b/convention-plugins/src/main/kotlin/convention.publication.gradle.kts new file mode 100644 index 0000000..96ee664 --- /dev/null +++ b/convention-plugins/src/main/kotlin/convention.publication.gradle.kts @@ -0,0 +1,86 @@ +//Publishing your Kotlin Multiplatform library to Maven Central +//https://dev.to/kotlin/how-to-build-and-publish-a-kotlin-multiplatform-library-going-public-4a8k + +import org.gradle.api.publish.maven.MavenPublication +import org.gradle.api.tasks.bundling.Jar + +plugins { + id("maven-publish") + id("signing") +} + +ext["signing.keyId"] = project.findProperty("signing.opensource.key") +ext["signing.password"] = project.findProperty("signing.opensource.password") +ext["signing.secretKeyRingFile"] = project.findProperty("signing.opensource.file") +ext["nexus.username"] = project.findProperty("nexus.username") +ext["nexus.password"] = project.findProperty("nexus.password") + +val javadocJar by tasks.registering(Jar::class) { + archiveClassifier.set("javadoc") +} + +fun getExtraString(name: String) = ext[name]?.toString() + +publishing { + // Configure maven central repository + repositories { + maven { + name = "sonatype" + setUrl("https://oss.sonatype.org/service/local/staging/deploy/maven2/") + credentials { + username = getExtraString("nexus.username") + password = getExtraString("nexus.password") + } + } + } + + // Configure all publications + publications.withType { + groupId = PublishingInfo.GROUP + artifactId = PublishingInfo.Artifact.ID + version = PublishingInfo.Artifact.VERSION + + // Stub javadoc.jar artifact + artifact(javadocJar.get()) + + // Provide artifacts information requited by Maven Central + pom { + name.set(PublishingInfo.Artifact.NAME) + description.set(PublishingInfo.Artifact.DESCRIPTION) + url.set(PublishingInfo.Repo.URL) + + licenses { + license { + name.set(PublishingInfo.License.NAME) + url.set(PublishingInfo.License.URL) + distribution.set(PublishingInfo.License.DIST) + } + } + developers { + developer { + id.set(PublishingInfo.Developer.ID) + name.set(PublishingInfo.Developer.NAME) + email.set(PublishingInfo.Developer.EMAIL) + } + } + scm { + url.set(PublishingInfo.Scm.URL) + connection.set(PublishingInfo.Scm.CONNECTION) + developerConnection.set(PublishingInfo.Scm.DEV_CONNECTION) + } + } + } +} + +// Signing artifacts. Signing.* extra properties values will be used +signing { + if (getExtraString("signing.keyId") != null) { + sign(publishing.publications) + } +} + +//https://github.com/gradle/gradle/issues/26132 +val signingTasks = tasks.withType() +tasks.withType().configureEach { + mustRunAfter(signingTasks) +} \ No newline at end of file diff --git a/dependencies.gradle b/dependencies.gradle deleted file mode 100644 index 0379b3e..0000000 --- a/dependencies.gradle +++ /dev/null @@ -1,43 +0,0 @@ -ext { - baseArtifactName = "beziercurve" - baseRepoBucket = "zTrap/$baseArtifactName" - baseRepoUrl = "https://github.com/$baseRepoBucket" - - setup = [ - jvm: JavaVersion.VERSION_1_8 - ] - versions = [ - kotlin : "1.4.31", - dokka : "0.10.1", - nexus_staging: "0.30.0", - ] - pom_info = [ - group : "ru.ztrap", - packaging: "jar", - repo : [ - type: "maven", - vcs : "${baseRepoUrl}.git", - url : baseRepoUrl, - ], - scm : [ - url : baseRepoUrl, - connection : "scm:git@github.com:${baseRepoBucket}.git", - dev_connection: "scm:git@github.com:${baseRepoBucket}.git" - ], - license : [ - name: "the apache software license, version 2.0", - url : "http://www.apache.org/licenses/license-2.0.txt", - dist: "repo", - ], - developer: [ - id : "ztrap", - name: "peter gulko" - ], - artifact : [ - id : baseArtifactName, - name : "Bezier curves creator", - description: "The simple helper for build Bezier curves. Fully compatible with projects written in java/kotlin", - version : "1.0.2", - ] - ] -} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 85be9ea..f1185fc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,15 +1,8 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx1536m -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true -# Kotlin code style for this project: "official" or "obsolete": +#Gradle +org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M" +org.gradle.caching=true +org.gradle.configuration-cache=true + +#Kotlin kotlin.code.style=official +kotlin.js.compiler=ir diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..5e9c277 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,5 @@ +[versions] +kotlin = "1.9.23" + +[plugins] +kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f6b961f..e644113 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4306757..b82aa23 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ -#Fri Apr 19 17:28:39 MSK 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.3-bin.zip diff --git a/gradlew b/gradlew index cccdd3d..1aa94a4 100644 --- a/gradlew +++ b/gradlew @@ -1,78 +1,127 @@ -#!/usr/bin/env sh +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -81,92 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" fi +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index f955316..25da30d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,4 +1,20 @@ -@if "%DEBUG%" == "" @echo off +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -9,25 +25,29 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -35,48 +55,36 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/publishing.gradle b/publishing.gradle deleted file mode 100644 index 8ba1f43..0000000 --- a/publishing.gradle +++ /dev/null @@ -1,120 +0,0 @@ -apply plugin: 'maven-publish' -apply plugin: 'signing' -apply plugin: 'org.jetbrains.dokka' - -ext["signing.keyId"] = project.getProperty('signing.opensource.key') -ext["signing.password"] = project.getProperty('signing.opensource.password') -ext["signing.secretKeyRingFile"] = project.getProperty('signing.opensource.file') - -group = pom_info.group -version = pom_info.artifact.version - -task cleanLocalPublish(type: GradleBuild) { - group = "publishing" - tasks = ['clean', 'assemble', 'publishReleasePublicationToMavenLocal'] -} - -task cleanSonatypePublish(type: GradleBuild) { - group = "publishing" - tasks = ['clean', 'assemble', 'publishReleasePublicationToSonatypeRepository'] -} - -task sourcesJar(type: Jar) { - archiveClassifier.set('sources') - if (project.plugins.findPlugin("com.android.library")) { - // For Android libraries - from android.sourceSets.main.kotlin.srcDirs - exclude '**/BuildConfig.java' - } else { - // For pure Kotlin libraries, in case you have them - from sourceSets.main.kotlin.srcDirs - } -} - -task javadocJar(type: Jar, dependsOn: dokka) { - getArchiveClassifier().set('javadoc') - from dokka.outputDirectory -} - -artifacts { - archives sourcesJar - archives javadocJar -} - -publishing { - publications { - release(MavenPublication) { - groupId = pom_info.group - artifactId = pom_info.artifact.id - version = pom_info.artifact.version - - if (project.plugins.findPlugin("com.android.library")) { - artifact("$buildDir/outputs/aar/${project.getName()}-release.aar") - } else { - artifact("$buildDir/libs/${project.getName()}-${version}.jar") - } - artifact sourcesJar - artifact javadocJar - - pom { - name = pom_info.artifact.name - packaging = pom_info.packaging - description = pom_info.artifact.description - url = pom_info.repo.url - - scm { - url = pom_info.scm.url - connection = pom_info.scm.connection - developerConnection = pom_info.scm.dev_connection - } - - licenses { - license { - name = pom_info.license.name - url = pom_info.license.url - distribution = pom_info.license.dist - } - } - - developers { - developer { - id = pom_info.developer.id - name = pom_info.developer.name - } - } - - withXml { - def dependenciesNode = asNode().appendNode('dependencies') - - project.configurations.implementation.allDependencies.each { - def dependencyNode = dependenciesNode.appendNode('dependency') - dependencyNode.appendNode('groupId', it.group) - dependencyNode.appendNode('artifactId', it.name) - dependencyNode.appendNode('version', it.version) - } - } - } - } - } - - repositories { - maven { - name = "sonatype" - url = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - credentials { - username = getProperty("nexus.username") - password = getProperty("nexus.password") - } - } - } -} - -signing { - sign publishing.publications -} - -nexusStaging { - packageGroup = pom_info.group - username = getProperty("nexus.username") - password = getProperty("nexus.password") -} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index d67a56c..0000000 --- a/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include ':beziercurve' diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..dcc6a4f --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,17 @@ +pluginManagement { + repositories { + google() + gradlePluginPortal() + mavenCentral() + } +} + +dependencyResolutionManagement { + repositories { + google() + mavenCentral() + } +} + +includeBuild("convention-plugins") +rootProject.name = "beziercurve" diff --git a/src/commonMain/kotlin/ru/ztrap/bezier/curve/BezierCurve.kt b/src/commonMain/kotlin/ru/ztrap/bezier/curve/BezierCurve.kt new file mode 100644 index 0000000..bca4389 --- /dev/null +++ b/src/commonMain/kotlin/ru/ztrap/bezier/curve/BezierCurve.kt @@ -0,0 +1,62 @@ +package ru.ztrap.bezier.curve + +import kotlin.math.pow + +private val APPLICABLE_VALUES = 0f..1f + +public data class BezierCurve( + val start: Point, + val end: Point, + val controls: List, +) { + + /** + * @param start point in format `[x, y]` + * @param end point in format `[x, y]` + * @param controls points in format `[x, y]` + */ + public constructor( + start: Pair, + end: Pair, + controls: List>, + ) : this( + start = Point(start.x, start.y), + end = Point(end.x, end.y), + controls = controls.map { Point(it.x, it.y) }, + ) + + /** Calculates linear Bezier curve for presented [t]. Acceptable value for [t] in `[0,1]` */ + public fun calculate(t: Float): Point { + require(t in APPLICABLE_VALUES) { "Wrong t value = $t. Applicable values in [0,1]" } + return when (controls.size) { + 0 -> Point( + x = (1 - t) * start.x + t * end.x, + y = (1 - t) * start.y + t * end.y, + ) + + else -> { + var x = 0f + var y = 0f + + controls.forEachIndexed { index, control -> + val polynomial = bernstein(t, controls.size - 1, index + 1) + x += polynomial * control.x + y += polynomial * control.y + } + + Point(x = x, y = y) + } + } + } + + /** @return factorial of [n] */ + private fun fact(n: Int): Int = (1..n).reduce { acc, i -> acc * i } + + /** + * @return Bernstein polynomial + * @see Wikipedia + */ + private fun bernstein(t: Float, n: Int, i: Int): Float { + return fact(n) / (fact(i) * fact(n - i)) * (1 - t).pow(n - i) * t.pow(i) + } +} \ No newline at end of file diff --git a/beziercurve/src/main/kotlin/ru/ztrap/beziercurve/BezierScene.kt b/src/commonMain/kotlin/ru/ztrap/bezier/curve/BezierScene.kt similarity index 91% rename from beziercurve/src/main/kotlin/ru/ztrap/beziercurve/BezierScene.kt rename to src/commonMain/kotlin/ru/ztrap/bezier/curve/BezierScene.kt index 3871b3d..772fe80 100644 --- a/beziercurve/src/main/kotlin/ru/ztrap/beziercurve/BezierScene.kt +++ b/src/commonMain/kotlin/ru/ztrap/bezier/curve/BezierScene.kt @@ -1,9 +1,6 @@ -package ru.ztrap.beziercurve +package ru.ztrap.bezier.curve -/** - * @author pa.gulko zTrap (17.04.2019) - */ -data class BezierScene( +public data class BezierScene( val left: Float, val top: Float, val right: Float, diff --git a/src/commonMain/kotlin/ru/ztrap/bezier/curve/Point.kt b/src/commonMain/kotlin/ru/ztrap/bezier/curve/Point.kt new file mode 100644 index 0000000..9e52457 --- /dev/null +++ b/src/commonMain/kotlin/ru/ztrap/bezier/curve/Point.kt @@ -0,0 +1,59 @@ +package ru.ztrap.bezier.curve + +import kotlin.jvm.JvmInline + +/** + * Constructs a [Point] from [x] and [y] position values + */ +public fun Point(x: Float, y: Float): Point = Point(packFloats(x, y)) + +/** + * A two-dimensional point using [Float] for units + */ +@JvmInline +public value class Point internal constructor(@PublishedApi internal val packedValue: Long) { + + /** + * The horizontal aspect of the point + */ + public val x: Float + get() = unpackFloat1(packedValue) + + /** + * The vertical aspect of the point + */ + public val y: Float + get() = unpackFloat2(packedValue) + + /** + * Returns a copy of this [Point] instance optionally overriding the + * x or y parameter + */ + public fun copy(x: Float = this.x, y: Float = this.y): Point = Point(x, y) + + override fun toString(): String = if (isSpecified) { + "($x, $y)" + } else { + "Point.Unspecified" + } + + public companion object { + /** + * A [Point] with 0 [x] and 0 [y] values. + */ + public val Zero: Point = Point(0f, 0f) + + /** + * Represents an offset whose [x] and [y] are unspecified. This is usually a replacement for + * `null` when a primitive value is desired. + * Access to [x] or [y] on an unspecified offset is not allowed. + */ + public val Unspecified: Point = Point(Float.NaN, Float.NaN) + } +} + +public inline val Point.isSpecified: Boolean + get() = packedValue != Point.Unspecified.packedValue + +public inline val Point.isUnspecified: Boolean + get() = packedValue == Point.Unspecified.packedValue \ No newline at end of file diff --git a/src/commonMain/kotlin/ru/ztrap/bezier/curve/utils.kt b/src/commonMain/kotlin/ru/ztrap/bezier/curve/utils.kt new file mode 100644 index 0000000..681770b --- /dev/null +++ b/src/commonMain/kotlin/ru/ztrap/bezier/curve/utils.kt @@ -0,0 +1,30 @@ +package ru.ztrap.bezier.curve + +/** + * Packs two Float values into one Long value for use in inline classes. + */ +internal inline fun packFloats(val1: Float, val2: Float): Long { + val v1 = val1.toRawBits().toLong() + val v2 = val2.toRawBits().toLong() + return v1.shl(32) or (v2 and 0xFFFFFFFF) +} + +/** + * Unpacks the first Float value in [packFloats] from its returned Long. + */ +internal inline fun unpackFloat1(value: Long): Float { + return Float.fromBits(value.shr(32).toInt()) +} + +/** + * Unpacks the second Float value in [packFloats] from its returned Long. + */ +internal inline fun unpackFloat2(value: Long): Float { + return Float.fromBits(value.and(0xFFFFFFFF).toInt()) +} + +internal inline val Pair.x: Float + get() = first + +internal inline val Pair.y: Float + get() = second \ No newline at end of file