diff --git a/app/build.gradle b/app/build.gradle index ab742b0b8..b1648dca6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -42,8 +42,8 @@ android { minSdkVersion 16 compileSdk compileSdkVersionCode targetSdkVersion 34 - versionCode 336 - versionName "3.3.6" + versionCode 338 + versionName "3.3.8" vectorDrawables.useSupportLibrary true javaCompileOptions { annotationProcessorOptions { diff --git a/app/src/main/java/de/dreier/mytargets/base/db/dao/ImageDAO.kt b/app/src/main/java/de/dreier/mytargets/base/db/dao/ImageDAO.kt index 472057ac4..036df80e3 100644 --- a/app/src/main/java/de/dreier/mytargets/base/db/dao/ImageDAO.kt +++ b/app/src/main/java/de/dreier/mytargets/base/db/dao/ImageDAO.kt @@ -15,8 +15,12 @@ package de.dreier.mytargets.base.db.dao +import android.content.Context +import android.database.sqlite.SQLiteException import androidx.room.Dao import androidx.room.Query +import androidx.room.Transaction +import java.io.File @Dao interface ImageDAO { @@ -29,4 +33,38 @@ interface ImageDAO { "UNION SELECT `fileName` FROM `ArrowImage`" ) fun loadAllFileNames(): List + + @Transaction + fun removeAllPhotos(context: Context) { + try { + // 1. Delete entries from the database tables + deleteBowImages() + deleteEndImages() + deleteArrowImages() + } catch (e: SQLiteException) { + // Handle exceptions if tables don't exist (e.g., log a warning) + } + + // 2. Delete the corresponding files from storage + val fileNames = try { + loadAllFileNames() + } catch (e: SQLiteException) { + // Handle exceptions if the database hasn't been initialized (e.g., return an empty list) + emptyList() + } + + for (fileName in fileNames) { + val file = File(context.filesDir, fileName) + file.delete() + } + } + + @Query("DELETE FROM BowImage") + fun deleteBowImages() + + @Query("DELETE FROM EndImage") + fun deleteEndImages() + + @Query("DELETE FROM ArrowImage") + fun deleteArrowImages() } diff --git a/app/src/main/java/de/dreier/mytargets/features/scoreboard/ScoreboardConfiguration.kt b/app/src/main/java/de/dreier/mytargets/features/scoreboard/ScoreboardConfiguration.kt index 8a69d7318..fa32d1ae6 100644 --- a/app/src/main/java/de/dreier/mytargets/features/scoreboard/ScoreboardConfiguration.kt +++ b/app/src/main/java/de/dreier/mytargets/features/scoreboard/ScoreboardConfiguration.kt @@ -22,5 +22,6 @@ data class ScoreboardConfiguration( var showStatistics: Boolean = false, var showComments: Boolean = false, var showPointsColored: Boolean = false, - var showSignature: Boolean = false + var showSignature: Boolean = false, + var showTimeRange: Boolean = false ) diff --git a/app/src/main/java/de/dreier/mytargets/features/scoreboard/layout/DefaultScoreboardLayout.kt b/app/src/main/java/de/dreier/mytargets/features/scoreboard/layout/DefaultScoreboardLayout.kt index 27b04971c..ad2650dc6 100644 --- a/app/src/main/java/de/dreier/mytargets/features/scoreboard/layout/DefaultScoreboardLayout.kt +++ b/app/src/main/java/de/dreier/mytargets/features/scoreboard/layout/DefaultScoreboardLayout.kt @@ -35,7 +35,7 @@ import de.dreier.mytargets.shared.models.db.Shot import de.dreier.mytargets.shared.models.db.Training import de.dreier.mytargets.shared.targets.scoringstyle.ScoringStyle import de.dreier.mytargets.utils.ScoreUtils -import java.util.* +import java.util.Locale class DefaultScoreboardLayout( private val context: Context, @@ -100,6 +100,8 @@ class DefaultScoreboardLayout( if (configuration.showSignature) { appendSignature(training) } + val legendText = context.getString(R.string.legend_text) + builder.title(legendText) } private fun getTrainingInfoTable( @@ -251,7 +253,7 @@ class DefaultScoreboardLayout( var arrowDiameter = Dimension(0.714f, Dimension.Unit.CENTIMETER) if (training.arrowId != null) { val arrow = arrowDAO.loadArrow(training.arrowId!!) - if (arrow.diameter != null){ + if (arrow.diameter != null) { arrowDiameter = arrow.diameter } } @@ -284,10 +286,12 @@ class DefaultScoreboardLayout( val table = Table(false) appendTableHeader(table, round.shotsPerEnd) var carry = 0 - for (end in roundDAO.loadEnds(round.id)) { + val ends = roundDAO.loadEnds(round.id) + + for ((index, end) in ends.withIndex()) { val row = table.startRow() - row.addCell(end.index + 1) - var sum = 0 + row.addCell(index + 1) // Display the calculated end number (1-based) + var sum = 0 // Reset sum for each end val shots = ArrayList(endDAO.loadShots(end.id)) if (SettingsManager.shouldSortTarget(round.target)) { shots.sort() @@ -296,10 +300,10 @@ class DefaultScoreboardLayout( appendPointsCell(row, shot, round.target) val points = round.target.getScoreByZone(shot.scoringRing, shot.index) sum += points - carry += points + carry += points // Update the carry value } - row.addCell(sum) - row.addCell(carry) + row.addCell(sum) // End total + row.addCell(carry) // Display carry value } return table } diff --git a/app/src/main/java/de/dreier/mytargets/features/settings/SettingsManager.kt b/app/src/main/java/de/dreier/mytargets/features/settings/SettingsManager.kt index 0b61ba7ee..6edb19621 100644 --- a/app/src/main/java/de/dreier/mytargets/features/settings/SettingsManager.kt +++ b/app/src/main/java/de/dreier/mytargets/features/settings/SettingsManager.kt @@ -356,6 +356,7 @@ object SettingsManager { config.showComments = preferences["scoreboard_comments", true] config.showPointsColored = preferences["scoreboard_points_colored", true] config.showSignature = preferences["scoreboard_signature", true] + config.showTimeRange = preferences["scoreboard_time_range", true] return config } diff --git a/app/src/main/java/de/dreier/mytargets/features/settings/about/AboutFragment.kt b/app/src/main/java/de/dreier/mytargets/features/settings/about/AboutFragment.kt index c71bb33e9..ae106fe2f 100644 --- a/app/src/main/java/de/dreier/mytargets/features/settings/about/AboutFragment.kt +++ b/app/src/main/java/de/dreier/mytargets/features/settings/about/AboutFragment.kt @@ -36,11 +36,7 @@ class AboutFragment : Fragment() { BuildConfig.VERSION_NAME ) + " (${BuildConfig.VERSION_CODE})" - private val crowdinElement: Element - get() = WebElement( - R.string.translate_crowdin, R.drawable.about_icon_crowdin, - URL_CROWDIN - ) + private val betaTesterElement: Element get() = WebElement(R.string.test_beta, R.drawable.about_icon_beta_test, URL_PLAY_STORE) @@ -51,11 +47,6 @@ class AboutFragment : Fragment() { URL_SLACK ) - private val linkedInItem: Element - get() = WebElement( - R.string.network_linkedin, R.drawable.about_icon_linkedin, - URL_LINKEDIN - ) private val shareElement: Element get() { @@ -83,14 +74,10 @@ class AboutFragment : Fragment() { .setDescription(getString(R.string.my_targets) + "\n" + version) .addGroup(getString(R.string.contribute)) .addItem(shareElement) - .addItem(crowdinElement) .addItem(betaTesterElement) .addGroup(getString(R.string.connect)) - .addEmail("dreier.florian@gmail.com") .addPlayStore("de.dreier.mytargets") .addItem(slackElement) - .addGitHub("DreierF") - .addItem(linkedInItem) .addGroup(getString(R.string.special_thanks_to)) .addItem(Element(getString(R.string.all_beta_testers), null)) .addItem( @@ -134,8 +121,5 @@ class AboutFragment : Fragment() { "https://join.slack.com/t/mytargets/shared_invite/enQtNjk2NTE0MzU5NzE0LTc3NjAwYmZiNTcxMDA1NTI0M2UzYWY4ZGQwMjVhYjEyODQ0MDE2MjlhZjZiZTUwODg2YTE5YjhkN2FmZTQ2Njc" private const val URL_PLAY_STORE = "http://play.google.com/store/apps/details?id=de.dreier.mytargets" - private const val URL_PAYPAL = "https://www.paypal.me/floriandreier" - private const val URL_CROWDIN = "https://crowdin.com/project/mytargets" - private const val URL_LINKEDIN = "https://de.linkedin.com/in/florian-dreier-b056a1113" } } diff --git a/app/src/main/java/de/dreier/mytargets/features/settings/backup/BackupSettingsFragment.kt b/app/src/main/java/de/dreier/mytargets/features/settings/backup/BackupSettingsFragment.kt index d48da9b29..6a46e6969 100644 --- a/app/src/main/java/de/dreier/mytargets/features/settings/backup/BackupSettingsFragment.kt +++ b/app/src/main/java/de/dreier/mytargets/features/settings/backup/BackupSettingsFragment.kt @@ -29,12 +29,19 @@ import android.os.Build import android.os.Bundle import android.os.Handler import android.text.format.DateUtils -import android.view.* +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View import android.view.View.GONE import android.view.View.VISIBLE +import android.view.ViewGroup +import android.widget.Toast import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatActivity import androidx.databinding.DataBindingUtil +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL import com.afollestad.materialdialogs.MaterialDialog @@ -50,6 +57,9 @@ import de.dreier.mytargets.features.settings.backup.synchronization.GenericAccou import de.dreier.mytargets.features.settings.backup.synchronization.SyncUtils import de.dreier.mytargets.utils.ToolbarUtils import de.dreier.mytargets.utils.Utils +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import permissions.dispatcher.NeedsPermission import permissions.dispatcher.OnNeverAskAgain import permissions.dispatcher.OnPermissionDenied @@ -57,7 +67,9 @@ import permissions.dispatcher.RuntimePermissions import timber.log.Timber import java.io.FileNotFoundException import java.text.SimpleDateFormat -import java.util.* +import java.util.Locale +import java.util.Timer +import java.util.TimerTask @RuntimePermissions class BackupSettingsFragment : SettingsFragmentBase(), IAsyncBackupRestore.OnLoadFinishedListener { @@ -157,10 +169,25 @@ class BackupSettingsFragment : SettingsFragmentBase(), IAsyncBackupRestore.OnLoa } else if (item.itemId == R.id.action_fix_db) { DatabaseFixer.fix(ApplicationInstance.db) return true + } else if (item.itemId == R.id.action_remove_photos) { + deleteAllPhotos() + } return super.onOptionsItemSelected(item) } + private fun deleteAllPhotos() { + lifecycleScope.launch(Dispatchers.IO) { // Launch coroutine on IO dispatcher (background thread) + ApplicationInstance.db.imageDAO().removeAllPhotos(requireContext()) + + // Back on the main thread for UI updates (Toast) + withContext(Dispatchers.Main) { + Toast.makeText(requireContext(), "All photos removed", Toast.LENGTH_SHORT) + .show() + } + } + } + override fun onResume() { super.onResume() if (!isLeaving) { diff --git a/app/src/main/java/de/dreier/mytargets/features/statistics/StatisticsActivity.kt b/app/src/main/java/de/dreier/mytargets/features/statistics/StatisticsActivity.kt index f40754a41..9c2b4f4a6 100644 --- a/app/src/main/java/de/dreier/mytargets/features/statistics/StatisticsActivity.kt +++ b/app/src/main/java/de/dreier/mytargets/features/statistics/StatisticsActivity.kt @@ -20,19 +20,19 @@ import android.app.LoaderManager import android.content.AsyncTaskLoader import android.content.Intent import android.content.Loader -import androidx.databinding.DataBindingUtil import android.net.Uri import android.os.AsyncTask import android.os.Bundle -import com.google.android.material.snackbar.Snackbar +import android.view.Menu +import android.view.MenuItem +import androidx.core.view.GravityCompat.END +import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentStatePagerAdapter -import androidx.core.view.GravityCompat.END -import android.view.Menu -import android.view.MenuItem import com.afollestad.materialdialogs.MaterialDialog import com.evernote.android.state.State +import com.google.android.material.snackbar.Snackbar import de.dreier.mytargets.R import de.dreier.mytargets.app.ApplicationInstance import de.dreier.mytargets.base.activities.ChildActivityBase @@ -46,7 +46,8 @@ import de.dreier.mytargets.utils.toUri import java.io.File import java.io.IOException import java.text.SimpleDateFormat -import java.util.* +import java.util.Date +import java.util.Locale class StatisticsActivity : ChildActivityBase(), LoaderManager.LoaderCallbacks>> { @@ -165,6 +166,7 @@ class StatisticsActivity : ChildActivityBase(), export() true } + R.id.action_filter -> { if (!binding.drawerLayout.isDrawerOpen(END)) { binding.drawerLayout.openDrawer(END) @@ -173,6 +175,7 @@ class StatisticsActivity : ChildActivityBase(), } true } + else -> super.onOptionsItemSelected(item) } } @@ -206,8 +209,10 @@ class StatisticsActivity : ChildActivityBase(), .map { value1 -> Pair(value1.value[0].target, value1.value) } .sortedByDescending { it.second.size } val animate = binding.viewPager.adapter == null + val environment = + if (trainingDAO.loadTrainings().first().environment.indoor) "Indoor" else "Outdoor" val adapter = StatisticsPagerAdapter( - supportFragmentManager, filteredRounds!!, animate + supportFragmentManager, filteredRounds!!, animate, environment ) binding.viewPager.adapter = adapter } @@ -308,7 +313,8 @@ class StatisticsActivity : ChildActivityBase(), inner class StatisticsPagerAdapter internal constructor( fm: FragmentManager, private val targets: List>>, - private val animate: Boolean + private val animate: Boolean, + private val environment: String ) : FragmentStatePagerAdapter(fm) { override fun getItem(position: Int): Fragment { @@ -321,8 +327,8 @@ class StatisticsActivity : ChildActivityBase(), return targets.size } - override fun getPageTitle(position: Int): CharSequence? { - return targets[position].first.toString() + override fun getPageTitle(position: Int): CharSequence { + return targets[position].first.toString() + " - " + environment } } diff --git a/app/src/main/res/menu/settings_backup.xml b/app/src/main/res/menu/settings_backup.xml index 44b3b9e93..909e38468 100644 --- a/app/src/main/res/menu/settings_backup.xml +++ b/app/src/main/res/menu/settings_backup.xml @@ -26,5 +26,9 @@ android:id="@+id/action_fix_db" android:title="@string/fix_db" app:showAsAction="never"/> + diff --git a/app/src/main/res/raw/help.html b/app/src/main/res/raw/help.html index 58f31b66b..397d99ef1 100644 --- a/app/src/main/res/raw/help.html +++ b/app/src/main/res/raw/help.html @@ -128,6 +128,16 @@

Statistics

  • https://www.mckinley.biz/
  • https://www.canfordmagnabowmen.co.uk/
  • +

    Official Handicap Tables and Related Documents(Updated)

    +
    Analysis scope diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c5c9dad61..b1ce48b8e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -113,11 +113,12 @@ Scoreboard Arrows Score - R.Total + Running Total Print Average - Ø - + Ø + + Legend for Ø = Hits and Average ∑ = Handicap in App Comment @@ -394,4 +395,6 @@ Permission required Apps > MyTargets > Permissions and enable the entry \'Storage\'.]]> Attempt to fix database + Time range + Remove All Photos diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 226420d4c..4a72f8b52 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -245,6 +245,10 @@ android:defaultValue="true" android:key="scoreboard_signature" android:title="@string/show_signature"/> + + + + , + groupRadiusSquared: BigDecimal, + handicap: Int + ): BigDecimal { + // Implementation based on Australian handicap system tables and formulas + var expectedScore = BigDecimal.ZERO + val theta = calculateTheta(handicap) // Use your existing theta calculation + val xValues = calculateXValues(zoneMap) // Convert zone radii to x values (see below) + + for (i in xValues.indices) { + val zoneScore = + BigDecimal(zoneMap.keys.elementAt(i)) // Assuming scores are keys in zoneMap + val hitProbability = calculateHitProbability( + xValues[i], + theta + ) // Calculate hit probability for this zone + expectedScore += zoneScore * hitProbability } + + return expectedScore } - private fun metricCalc(zoneMap: Map, groupRadiusSquared: BigDecimal, bestArrowScore: BigDecimal): BigDecimal { - var exponentTotals = BigDecimal(0) - for ((index, radius) in zoneMap.iterator()) { - var zoneRadiusSquared = (radius + arrowRadius).pow(2) - exponentTotals += BigDecimal.valueOf(exp(-(zoneRadiusSquared / groupRadiusSquared).toDouble())) - } - return (bestArrowScore - exponentTotals) + private fun calculateTheta(handicap: Int): Double { + // This is a rough approximation based on the relationship between handicap and theta described in the article. + // It assumes a linear relationship, which may not be accurate for the actual Australian system. + val baseTheta = 0.05 // Example starting point for theta at handicap 0 + val thetaIncrementPerHandicap = 0.005 // Example increment (needs to be adjusted) + return baseTheta + (handicap * thetaIncrementPerHandicap) } - private fun imperialCalc(zoneMap: Map, groupRadiusSquared: BigDecimal, bestArrowScore: BigDecimal, zoneScoreStep: Int): BigDecimal { - var exponentTotals = BigDecimal(0) - var lastEntry = zoneMap.entries.last() - for ((index, radius) in zoneMap.iterator()) { - var zoneRadiusSquared = (radius + arrowRadius).pow(2) - if (radius == lastEntry.value) { - exponentTotals -= BigDecimal.valueOf(exp(-(zoneRadiusSquared / groupRadiusSquared).toDouble())) - } else { - exponentTotals += BigDecimal.valueOf(zoneScoreStep * exp(-(zoneRadiusSquared / groupRadiusSquared).toDouble())) - } + private fun calculateXValues(zoneMap: Map): List { + // Convert zone radii to x values based on target face size and arrow radius + return zoneMap.values.map { radius -> + (radius + arrowRadius).toDouble() / (targetSize.value.toDouble() / 2) } - return (bestArrowScore - exponentTotals) } + private fun calculateHitProbability(xValue: Double, theta: Double): BigDecimal { + // Calculate the probability of hitting a zone using the normal distribution approximation + val zScore = xValue / theta + val probability = + BigDecimal(0.5 * (1 + erf(zScore / sqrt(2.0)))) // Using error function (erf) + return probability + } + + fun handicapScoresList(rounded: Boolean = true): List { val decimalPlaces: Int = if (rounded) 0 else 2 - var handicapList = ArrayList() - for (handicap: Int in handicapLowerBound()..handicapUpperBound()) { + val handicapList = ArrayList() + for (handicap: Int in handicapLowerBound()..handicapUpperBound()) { // handicapList.add((BigDecimal(arrowCount) * averageArrowScoreForHandicap(handicap).setScale(2, RoundingMode.HALF_UP)).setScale(0, RoundingMode.UP).toInt()) - var average = averageArrowScoreForHandicap(handicap) - var roundScore = (BigDecimal(arrowCount) * average) + val average = averageArrowScoreForHandicap(handicap) + val roundScore = (BigDecimal(arrowCount) * average) handicapList.add(roundScore.setScale(decimalPlaces, RoundingMode.HALF_UP)) } return handicapList } - fun getHandicapForScore(totalScore: Int): Int { - val score = BigDecimal(totalScore.toString()) - var scoreList = handicapScoresList() - for (handicap: Int in handicapLowerBound()..handicapUpperBound()) { - if (score >= scoreList.get(handicap)) { - return handicap - } - } - return 101 - } + private fun erf(x: Double): Double { + // This is a basic approximation of the error function + // You can find more accurate implementations online + val a1 = 0.254829592 + val a2 = -0.284496736 + val a3 = 1.421413741 + val a4 = -1.453152027 + val a5 = 1.061405429 + val p = 0.3275911 + + val sign = if (x < 0) -1 else 1 + val xAbs = abs(x) - fun getHandicap(): Int { - return getHandicapForScore(this.reachedScore) + val t = 1.0 / (1.0 + p * xAbs) + val y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * exp(-xAbs * xAbs) + return sign * y } -//arrowDiameterCm=arrow_diameter_cm (0.357cm) 18/64 -//targetSizeCm=target_size_cm (122) -//targetDistanceMetres=distance_m (70) -// - -//15y=13.716m - -//SizeOfZone = 1*targetSizeCm/20..... - - //10-zone-Average_Arrow_Score=10 - ( - // EXP(-(((1*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + - // EXP(-(((2*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + - // EXP(-(((3*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + - // EXP(-(((4*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + - // EXP(-(((5*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + - // EXP(-(((6*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + - // EXP(-(((7*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + - // EXP(-(((8*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + - // EXP(-(((9*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + - // EXP(-(((10*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2)) - -//5-zone-avg-arrow= =9 - -// 2*( -// EXP(-(((1*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2) + -// EXP(-(((2*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2) + -// EXP(-(((3*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2) + -// EXP(-(((4*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2)) - -// EXP(-(((5*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2) - -//10-zone-compound-wa-pmoth =10 - (EXP(-(((1*targetSizeCm/40)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((2*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((3*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((4*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((5*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((6*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((7*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((8*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((9*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((10*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2)) -//10-zone-Average_Arrow_Score=10 - (EXP(-(((1*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((2*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((3*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((4*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((5*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((6*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((7*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((8*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((9*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((10*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2)) -//10-zone-compound-wa-pmoth =10 - (EXP(-(((1*targetSizeCm/40)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((2*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((3*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((4*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((5*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((6*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((7*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((8*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((9*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((10*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2)) -//5-zone-avg-arrow= =9 - 2*(EXP(-(((1*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((2*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((3*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((4*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2)) - EXP(-(((5*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2) -//10-zone-trispot==10 - (EXP(-(((1*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((2*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((3*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((4*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2)) - 6* EXP(-(((5*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) -//6-zone-fita=10 - (EXP(-(((1*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((2*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((3*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((4*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((5*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2)) - 5* EXP(-(((6*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) -//worcester=5 - (EXP(-(((1*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((2*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((3*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((4*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((5*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2)) -//wa-field=6 - EXP(-(((1*targetSizeCm/20)+arrowDiameterCm)^2)/groupRadiusCm^2) - (EXP(-(((2*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((3*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((4*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2) + EXP(-(((5*targetSizeCm/10)+arrowDiameterCm)^2)/groupRadiusCm^2)) -//beiter-hit-miss=1 - EXP(-(((1*targetSizeCm/2)+arrowDiameterCm)^2)/groupRadiusCm^2) } diff --git a/shared/src/main/java/de/dreier/mytargets/shared/models/Target.kt b/shared/src/main/java/de/dreier/mytargets/shared/models/Target.kt index 516acaad5..53b6c0538 100644 --- a/shared/src/main/java/de/dreier/mytargets/shared/models/Target.kt +++ b/shared/src/main/java/de/dreier/mytargets/shared/models/Target.kt @@ -31,7 +31,7 @@ import kotlinx.parcelize.Parcelize * scoring style and diameter. */ @Parcelize -data class Target( +data class Target( @ColumnInfo(name = "targetId") override var id: Long = 0, @ColumnInfo(name = "targetScoringStyleIndex")