diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 19cb1112..efe2b716 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -13,7 +13,7 @@ jobs: gradle_build: strategy: matrix: - os: [ macos-13, macos-14, windows-2022 ] + os: [ macos-15-intel, macos-15, windows-2022 ] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/gradle_package.yml b/.github/workflows/gradle_package.yml index 31846d34..cab733dc 100644 --- a/.github/workflows/gradle_package.yml +++ b/.github/workflows/gradle_package.yml @@ -23,8 +23,8 @@ jobs: strategy: matrix: configuration: [ - { runner: "macos-13", path: "build/dist/*" }, - { runner: "macos-14", path: "build/dist/*" }, + { runner: "macos-15-intel", path: "build/dist/*" }, + { runner: "macos-15", path: "build/dist/*" }, { runner: "windows-2022", path: "build/dist/*" } ] runs-on: ${{ matrix.configuration.runner }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9bfeeb30..9365dcd4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,8 +24,8 @@ jobs: strategy: matrix: configuration: [ - { runner: "macos-13", path: "build/dist" }, - { runner: "macos-14", path: "build/dist" }, + { runner: "macos-15-intel", path: "build/dist" }, + { runner: "macos-15", path: "build/dist" }, { runner: "windows-2022", path: "build/dist" } ] runs-on: ${{ matrix.configuration.runner }} diff --git a/README.md b/README.md index 0d140d03..ab504449 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,8 @@ ## Сборка дистрибутива -Задача `:jpackage` в `build.gradle` Запускает утилиту [**jpackage -**](https://docs.oracle.com/en/java/javase/21/docs/specs/man/jpackage.html). +Задача `:jpackage` в `build.gradle` Запускает утилиту +[jpackage](https://docs.oracle.com/en/java/javase/21/docs/specs/man/jpackage.html). ```shell ./gradlew jpackage diff --git a/build.gradle b/build.gradle index 036b8cf6..148668dd 100644 --- a/build.gradle +++ b/build.gradle @@ -11,6 +11,7 @@ plugins { id "org.jetbrains.kotlin.jvm" version "$kotlinVersion" id "org.openjfx.javafxplugin" version "0.1.0" id "org.jetbrains.dokka" version "2.0.0" + id "me.champeau.jmh" version "0.7.3" } group "ru.nucodelabs" @@ -100,6 +101,7 @@ dependencies { "$projectDir/lib/${System.mapLibraryName("MathVES")}" ) + /* Slf4j Logging */ implementation("org.slf4j:slf4j-api:${slf4jVersion}") implementation("ch.qos.logback:logback-classic:$logbackVersion") implementation project(":app-logback-appender") @@ -114,11 +116,8 @@ dependencies { implementation "org.codehaus.groovy:groovy-jsr223:3.0.25" implementation group: "com.fasterxml.jackson.core", name: "jackson-databind", version: jacksonVersion - implementation group: "org.apache.commons", name: "commons-math3", version: "3.6.1" - implementation group: "com.google.inject", name: "guice", version: guiceVersion implementation "com.fasterxml.jackson.module:jackson-module-kotlin:$jacksonVersion" - implementation "org.apache.commons:commons-collections4:4.4" /* Math Libraries */ implementation "org.glassfish.expressly:expressly:5.0.0" @@ -127,6 +126,7 @@ dependencies { implementation "org.bytedeco:javacpp:1.5.12:$platform" implementation "org.bytedeco:arpack-ng:3.9.1-1.5.12:$platform" implementation "org.bytedeco:arpack-ng:3.9.1-1.5.12" + implementation group: "org.apache.commons", name: "commons-math3", version: "3.6.1" /* Test Dependencies */ testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion" @@ -134,6 +134,8 @@ dependencies { testAnnotationProcessor "org.mapstruct:mapstruct-processor:$mapstructVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlinTestVersion" testImplementation "org.openjfx:javafx:${javafx.version}" + + jmh "org.apache.commons:commons-lang3:3.18.0" } /* Setup Runtime */ @@ -164,7 +166,7 @@ tasks.register("cleanRunDir", Delete) { delete fileTree(runDir) { exclude "err-trace*.txt" } } -tasks.withType(JavaExec).configureEach { +run { dependsOn copyClrToRunDir, copyDataToRunDir, copyLibsToRunDir jvmArgs = moduleExportsJvmArgs systemProperty("app.gem.log.stdout", true) diff --git a/common-utils/src/main/kotlin/ru/nucodelabs/util/Equals.kt b/common-utils/src/main/kotlin/ru/nucodelabs/util/Equals.kt new file mode 100644 index 00000000..1585309b --- /dev/null +++ b/common-utils/src/main/kotlin/ru/nucodelabs/util/Equals.kt @@ -0,0 +1,35 @@ +package ru.nucodelabs.util + +import java.util.Objects +import kotlin.reflect.KClass + +class Equals( + val thisRef: T, + val other: Any? +) { + var isEqual = thisRef === other || other != null && thisRef::class == other::class + + inline fun by(getter: (o: T) -> Any?): Equals { + if (!isEqual) return this + @Suppress("unchecked_cast") + isEqual = isEqual && getter(thisRef) == getter(other as T) + return this + } + + inline fun and(condition: (it: T, other: T) -> Boolean): Equals { + if (!isEqual) return this + @Suppress("unchecked_cast") + isEqual = isEqual && condition(thisRef, other as T) + return this + } + + inline fun and(condition: () -> Boolean): Equals { + if (!isEqual) return this + isEqual = isEqual && condition() + return this + } +} + +fun hash(vararg values: Any?): Int { + return Objects.hash(*values) +} \ No newline at end of file diff --git a/common-utils/src/main/kotlin/ru/nucodelabs/util/std/Lists.kt b/common-utils/src/main/kotlin/ru/nucodelabs/util/Lists.kt similarity index 90% rename from common-utils/src/main/kotlin/ru/nucodelabs/util/std/Lists.kt rename to common-utils/src/main/kotlin/ru/nucodelabs/util/Lists.kt index 94fd0597..ff272409 100644 --- a/common-utils/src/main/kotlin/ru/nucodelabs/util/std/Lists.kt +++ b/common-utils/src/main/kotlin/ru/nucodelabs/util/Lists.kt @@ -1,4 +1,4 @@ -package ru.nucodelabs.util.std +package ru.nucodelabs.util fun MutableList.swap(index1: Int, index2: Int) { val tmp = this[index1] diff --git a/common-utils/src/main/kotlin/ru/nucodelabs/util/std/Math.kt b/common-utils/src/main/kotlin/ru/nucodelabs/util/Math.kt similarity index 95% rename from common-utils/src/main/kotlin/ru/nucodelabs/util/std/Math.kt rename to common-utils/src/main/kotlin/ru/nucodelabs/util/Math.kt index ce66923e..234b34e5 100644 --- a/common-utils/src/main/kotlin/ru/nucodelabs/util/std/Math.kt +++ b/common-utils/src/main/kotlin/ru/nucodelabs/util/Math.kt @@ -1,4 +1,4 @@ -package ru.nucodelabs.util.std +package ru.nucodelabs.util import java.text.DecimalFormat import kotlin.math.pow diff --git a/common-utils/src/main/kotlin/ru/nucodelabs/util/Result.kt b/common-utils/src/main/kotlin/ru/nucodelabs/util/Result.kt new file mode 100644 index 00000000..4ee6d4a2 --- /dev/null +++ b/common-utils/src/main/kotlin/ru/nucodelabs/util/Result.kt @@ -0,0 +1,50 @@ +package ru.nucodelabs.util + +sealed interface Result + +@JvmInline +value class Ok(val value: T) : Result + +@JvmInline +value class Err(val error: E) : Result + +fun T.toOkResult(): Result = Ok(this) +fun E.toErrorResult(): Result = Err(this) + +@Suppress("unused") +inline fun Result.okOrThrow( + mapError: (E) -> Throwable = { IllegalStateException(it.toString()) } +): T { + return when (this) { + is Ok -> value + is Err -> throw mapError(error) + } +} + +@Suppress("unused") +fun Result.okOrNull(): T? { + return when (this) { + is Ok -> value + is Err -> null + } +} + +@Suppress("unused") +fun Result.errorOrNull(): E? { + return when (this) { + is Err -> error + is Ok -> null + } +} + +@Suppress("unused") +inline fun Result.ifError(action: (E) -> Unit): Result { + if (this is Err) action(error) + return this +} + +@Suppress("unused") +inline fun Result.ifOk(action: (T) -> Unit): Result { + if (this is Ok) action(value) + return this +} \ No newline at end of file diff --git a/common-utils/src/main/kotlin/ru/nucodelabs/util/Validation.kt b/common-utils/src/main/kotlin/ru/nucodelabs/util/Validation.kt new file mode 100644 index 00000000..cc70b50a --- /dev/null +++ b/common-utils/src/main/kotlin/ru/nucodelabs/util/Validation.kt @@ -0,0 +1,9 @@ +package ru.nucodelabs.util + +/** + * Return null if valid else error object + */ +inline fun validate(condition: Boolean, lazyError: () -> T): T? { + if (condition) return null + return lazyError() +} \ No newline at end of file diff --git a/common-utils/src/test/kotlin/ru/nucodelabs/util/EqualsTest.kt b/common-utils/src/test/kotlin/ru/nucodelabs/util/EqualsTest.kt new file mode 100644 index 00000000..6ee8e672 --- /dev/null +++ b/common-utils/src/test/kotlin/ru/nucodelabs/util/EqualsTest.kt @@ -0,0 +1,81 @@ +package ru.nucodelabs.util + +import org.junit.jupiter.api.Test + +class EqualsTest { + class Some( + val a: Int, + val b: String, + val c: Double, + val d: List + ) + + var objA: Some = Some(1, "12345", 1234.5678, listOf("Some", "String", "Content")) + var objB: Some = Some(1, "12345", 1234.5678, listOf("Some", "String", "Content")) + + @Test + fun isEqual() { + assert(objA !== objB) + assert(objA != objB) + val result = Equals(objA, objB) + .by { it.a } + .by { it.b } + .by { it.c } + .by { it.d } + .isEqual + assert(result) + } + + @Test + fun isEqual_same() { + val result = Equals(objA, objB) + .by { it.a } + .by { it.b } + .by { it.c } + .by { it.d } + .isEqual + assert(result) + } + + @Test + fun isEqual_not() { + objB = Some(2, "123", 123.32, emptyList()) + assert(objA !== objB) + assert(objA != objB) + val result = Equals(objA, objB) + .by { it.a } + .by { it.b } + .by { it.c } + .by { it.d } + .isEqual + assert(!result) + } + + @Test + fun and() { + val a = doubleArrayOf(.1, .2, .3) + val b = doubleArrayOf(.1, .2, .3) + val result = Equals(objA, objB) + .by { it.a } + .by { it.b } + .by { it.c } + .by { it.d } + .and { a contentEquals b } + .isEqual + assert(result) + } + + @Test + fun and_false() { + val a = doubleArrayOf(.1, .2, .3) + val b = doubleArrayOf(.1, .2, .3, .4) + val result = Equals(objA, objB) + .by { it.a } + .by { it.b } + .by { it.c } + .by { it.d } + .and { a contentEquals b } + .isEqual + assert(!result) + } +} \ No newline at end of file diff --git a/data/gem_json_examples/burm.section.json b/data/gem_json_examples/burm.section.json index da37cb19..94063ec2 100644 --- a/data/gem_json_examples/burm.section.json +++ b/data/gem_json_examples/burm.section.json @@ -8,8 +8,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 2148.8, - "resistanceApparent": 135.01, - "errorResistanceApparent": 5.0, + "resistivityApparent": 135.01, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -17,8 +17,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 1106.0, - "resistanceApparent": 130.3, - "errorResistanceApparent": 5.0, + "resistivityApparent": 130.3, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -26,8 +26,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 550.0, - "resistanceApparent": 151.19, - "errorResistanceApparent": 5.0, + "resistivityApparent": 151.19, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -35,8 +35,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 320.0, - "resistanceApparent": 158.34, - "errorResistanceApparent": 5.0, + "resistivityApparent": 158.34, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -44,8 +44,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 218.04, - "resistanceApparent": 169.54, - "errorResistanceApparent": 5.0, + "resistivityApparent": 169.54, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -53,8 +53,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 104.28, - "resistanceApparent": 159.71, - "errorResistanceApparent": 5.0, + "resistivityApparent": 159.71, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -62,8 +62,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 56.0, - "resistanceApparent": 142.06, - "errorResistanceApparent": 5.0, + "resistivityApparent": 142.06, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -71,8 +71,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 31.6, - "resistanceApparent": 142.71, - "errorResistanceApparent": 5.0, + "resistivityApparent": 142.71, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -80,8 +80,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 17.69, - "resistanceApparent": 124.9, - "errorResistanceApparent": 5.0, + "resistivityApparent": 124.9, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -89,8 +89,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 107.44, - "resistanceApparent": 125.4, - "errorResistanceApparent": 5.0, + "resistivityApparent": 125.4, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -98,8 +98,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 11.38, - "resistanceApparent": 142.92, - "errorResistanceApparent": 5.0, + "resistivityApparent": 142.92, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -107,8 +107,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 61.0, - "resistanceApparent": 128.77, - "errorResistanceApparent": 5.0, + "resistivityApparent": 128.77, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -116,8 +116,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 35.0, - "resistanceApparent": 116.78, - "errorResistanceApparent": 5.0, + "resistivityApparent": 116.78, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -125,8 +125,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 21.17, - "resistanceApparent": 116.4, - "errorResistanceApparent": 5.0, + "resistivityApparent": 116.4, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -134,8 +134,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 12.32, - "resistanceApparent": 106.52, - "errorResistanceApparent": 5.0, + "resistivityApparent": 106.52, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -143,8 +143,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 7.6, - "resistanceApparent": 103.02, - "errorResistanceApparent": 5.0, + "resistivityApparent": 103.02, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -152,8 +152,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 4.5, - "resistanceApparent": 103.23, - "errorResistanceApparent": 5.0, + "resistivityApparent": 103.23, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -161,8 +161,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 18.0, - "resistanceApparent": 96.156, - "errorResistanceApparent": 5.0, + "resistivityApparent": 96.156, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -170,8 +170,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 3.09, - "resistanceApparent": 107.29, - "errorResistanceApparent": 5.0, + "resistivityApparent": 107.29, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -179,8 +179,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 12.3, - "resistanceApparent": 100.73, - "errorResistanceApparent": 5.0, + "resistivityApparent": 100.73, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -188,8 +188,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 8.8, - "resistanceApparent": 113.53, - "errorResistanceApparent": 5.0, + "resistivityApparent": 113.53, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -197,8 +197,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 6.4, - "resistanceApparent": 125.54, - "errorResistanceApparent": 5.0, + "resistivityApparent": 125.54, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -206,8 +206,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 4.9, - "resistanceApparent": 143.39, - "errorResistanceApparent": 5.0, + "resistivityApparent": 143.39, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -215,8 +215,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 3.9, - "resistanceApparent": 164.67, - "errorResistanceApparent": 5.0, + "resistivityApparent": 164.67, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -224,8 +224,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 9.9, - "resistanceApparent": 164.67, - "errorResistanceApparent": 5.0, + "resistivityApparent": 164.67, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -233,8 +233,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 3.0, - "resistanceApparent": 189.5, - "errorResistanceApparent": 5.0, + "resistivityApparent": 189.5, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -242,8 +242,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 7.7, - "resistanceApparent": 193.8, - "errorResistanceApparent": 5.0, + "resistivityApparent": 193.8, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -251,8 +251,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 5.7, - "resistanceApparent": 226.33, - "errorResistanceApparent": 5.0, + "resistivityApparent": 226.33, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -260,8 +260,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 4.4, - "resistanceApparent": 268.94, - "errorResistanceApparent": 5.0, + "resistivityApparent": 268.94, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -269,8 +269,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 3.5, - "resistanceApparent": 312.53, - "errorResistanceApparent": 5.0, + "resistivityApparent": 312.53, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -278,53 +278,53 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 2.91, - "resistanceApparent": 357.27, - "errorResistanceApparent": 5.0, + "resistivityApparent": 357.27, + "errorResistivityApparent": 5.0, "isHidden": false } ], "modelData": [ { "power": 0.66, - "resistance": 161.05, + "resistivity": 161.05, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 0.59, - "resistance": 80.53, + "resistivity": 80.53, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 2.63, - "resistance": 233.44, + "resistivity": 233.44, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 21.44, - "resistance": 111.0, + "resistivity": 111.0, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 23.1, - "resistance": 56.37, + "resistivity": 56.37, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 96.8, - "resistance": 200.0, + "resistivity": 200.0, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { - "power": "NaN", - "resistance": 1414.69, + "power": "0.0", + "resistivity": 1414.69, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false } ], "offsetX": 100.0, @@ -339,8 +339,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 3400.0, - "resistanceApparent": 221.09, - "errorResistanceApparent": 5.0, + "resistivityApparent": 221.09, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -348,8 +348,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 1327.0, - "resistanceApparent": 163.79, - "errorResistanceApparent": 5.0, + "resistivityApparent": 163.79, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -357,8 +357,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 580.0, - "resistanceApparent": 166.89, - "errorResistanceApparent": 5.0, + "resistivityApparent": 166.89, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -366,8 +366,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 330.0, - "resistanceApparent": 170.74, - "errorResistanceApparent": 5.0, + "resistivityApparent": 170.74, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -375,8 +375,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 221.2, - "resistanceApparent": 179.45, - "errorResistanceApparent": 5.0, + "resistivityApparent": 179.45, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -384,8 +384,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 110.6, - "resistanceApparent": 176.85, - "errorResistanceApparent": 5.0, + "resistivityApparent": 176.85, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -393,8 +393,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 63.0, - "resistanceApparent": 167.28, - "errorResistanceApparent": 5.0, + "resistivityApparent": 167.28, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -402,8 +402,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 30.02, - "resistanceApparent": 143.03, - "errorResistanceApparent": 5.0, + "resistivityApparent": 143.03, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -411,8 +411,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 17.38, - "resistanceApparent": 130.18, - "errorResistanceApparent": 5.0, + "resistivityApparent": 130.18, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -420,8 +420,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 126.4, - "resistanceApparent": 130.5, - "errorResistanceApparent": 5.0, + "resistivityApparent": 130.5, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -429,8 +429,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 9.2, - "resistanceApparent": 123.0, - "errorResistanceApparent": 5.0, + "resistivityApparent": 123.0, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -438,8 +438,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 66.0, - "resistanceApparent": 122.67, - "errorResistanceApparent": 5.0, + "resistivityApparent": 122.67, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -447,8 +447,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 38.0, - "resistanceApparent": 110.11, - "errorResistanceApparent": 5.0, + "resistivityApparent": 110.11, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -456,8 +456,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 22.12, - "resistanceApparent": 105.11, - "errorResistanceApparent": 5.0, + "resistivityApparent": 105.11, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -465,8 +465,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 12.96, - "resistanceApparent": 95.513, - "errorResistanceApparent": 5.0, + "resistivityApparent": 95.513, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -474,8 +474,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 8.3, - "resistanceApparent": 95.813, - "errorResistanceApparent": 5.0, + "resistivityApparent": 95.813, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -483,8 +483,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 4.9, - "resistanceApparent": 95.723, - "errorResistanceApparent": 5.0, + "resistivityApparent": 95.723, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -492,8 +492,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 18.96, - "resistanceApparent": 95.723, - "errorResistanceApparent": 5.0, + "resistivityApparent": 95.723, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -501,8 +501,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 3.3, - "resistanceApparent": 97.983, - "errorResistanceApparent": 5.0, + "resistivityApparent": 97.983, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -510,8 +510,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 12.96, - "resistanceApparent": 100.57, - "errorResistanceApparent": 5.0, + "resistivityApparent": 100.57, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -519,8 +519,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 9.3, - "resistanceApparent": 114.42, - "errorResistanceApparent": 5.0, + "resistivityApparent": 114.42, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -528,8 +528,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 7.0, - "resistanceApparent": 131.75, - "errorResistanceApparent": 5.0, + "resistivityApparent": 131.75, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -537,8 +537,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 5.2, - "resistanceApparent": 146.61, - "errorResistanceApparent": 5.0, + "resistivityApparent": 146.61, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -546,8 +546,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 4.2, - "resistanceApparent": 171.78, - "errorResistanceApparent": 5.0, + "resistivityApparent": 171.78, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -555,8 +555,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 10.0, - "resistanceApparent": 170.94, - "errorResistanceApparent": 5.0, + "resistivityApparent": 170.94, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -564,8 +564,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 3.3, - "resistanceApparent": 202.89, - "errorResistanceApparent": 5.0, + "resistivityApparent": 202.89, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -573,8 +573,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 8.0, - "resistanceApparent": 206.08, - "errorResistanceApparent": 5.0, + "resistivityApparent": 206.08, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -582,8 +582,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 6.0, - "resistanceApparent": 243.04, - "errorResistanceApparent": 5.0, + "resistivityApparent": 243.04, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -591,8 +591,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 4.6, - "resistanceApparent": 285.93, - "errorResistanceApparent": 5.0, + "resistivityApparent": 285.93, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -600,8 +600,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 3.7, - "resistanceApparent": 335.21, - "errorResistanceApparent": 5.0, + "resistivityApparent": 335.21, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -609,53 +609,53 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 3.07, - "resistanceApparent": 381.73, - "errorResistanceApparent": 5.0, + "resistivityApparent": 381.73, + "errorResistivityApparent": 5.0, "isHidden": false } ], "modelData": [ { "power": 0.53, - "resistance": 459.49, + "resistivity": 459.49, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 0.59, - "resistance": 80.53, + "resistivity": 80.53, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 2.89, - "resistance": 233.44, + "resistivity": 233.44, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 19.3, - "resistance": 111.0, + "resistivity": 111.0, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 25.41, - "resistance": 56.37, + "resistivity": 56.37, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 87.12, - "resistance": 200.0, + "resistivity": 200.0, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { - "power": "NaN", - "resistance": 1882.95, + "power": "0.0", + "resistivity": 1882.95, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false } ], "offsetX": 100.0, @@ -670,8 +670,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 2212.0, - "resistanceApparent": 138.98, - "errorResistanceApparent": 5.0, + "resistivityApparent": 138.98, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -679,8 +679,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 1169.2, - "resistanceApparent": 137.74, - "errorResistanceApparent": 5.0, + "resistivityApparent": 137.74, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -688,8 +688,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 590.0, - "resistanceApparent": 162.18, - "errorResistanceApparent": 5.0, + "resistivityApparent": 162.18, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -697,8 +697,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 350.0, - "resistanceApparent": 173.18, - "errorResistanceApparent": 5.0, + "resistivityApparent": 173.18, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -706,8 +706,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 230.68, - "resistanceApparent": 179.36, - "errorResistanceApparent": 5.0, + "resistivityApparent": 179.36, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -715,8 +715,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 110.6, - "resistanceApparent": 169.39, - "errorResistanceApparent": 5.0, + "resistivityApparent": 169.39, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -724,8 +724,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 63.0, - "resistanceApparent": 159.82, - "errorResistanceApparent": 5.0, + "resistivityApparent": 159.82, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -733,8 +733,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 30.968, - "resistanceApparent": 139.85, - "errorResistanceApparent": 5.0, + "resistivityApparent": 139.85, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -742,8 +742,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 17.064, - "resistanceApparent": 120.48, - "errorResistanceApparent": 5.0, + "resistivityApparent": 120.48, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -751,8 +751,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 104.28, - "resistanceApparent": 117.94, - "errorResistanceApparent": 5.0, + "resistivityApparent": 117.94, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -760,8 +760,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 8.7, - "resistanceApparent": 109.26, - "errorResistanceApparent": 5.0, + "resistivityApparent": 109.26, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -769,8 +769,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 48.0, - "resistanceApparent": 98.269, - "errorResistanceApparent": 5.0, + "resistivityApparent": 98.269, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -778,8 +778,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 29.39, - "resistanceApparent": 94.793, - "errorResistanceApparent": 5.0, + "resistivityApparent": 94.793, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -787,8 +787,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 17.38, - "resistanceApparent": 92.366, - "errorResistanceApparent": 5.0, + "resistivityApparent": 92.366, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -796,8 +796,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 11.06, - "resistanceApparent": 92.135, - "errorResistanceApparent": 5.0, + "resistivityApparent": 92.135, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -805,8 +805,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 7.4, - "resistanceApparent": 96.517, - "errorResistanceApparent": 5.0, + "resistivityApparent": 96.517, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -814,8 +814,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 4.5, - "resistanceApparent": 99.337, - "errorResistanceApparent": 5.0, + "resistivityApparent": 99.337, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -823,8 +823,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 19.908, - "resistanceApparent": 99.337, - "errorResistanceApparent": 5.0, + "resistivityApparent": 99.337, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -832,8 +832,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 3.7, - "resistanceApparent": 123.81, - "errorResistanceApparent": 5.0, + "resistivityApparent": 123.81, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -841,8 +841,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 16.432, - "resistanceApparent": 127.55, - "errorResistanceApparent": 5.0, + "resistivityApparent": 127.55, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -850,8 +850,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 11.38, - "resistanceApparent": 139.81, - "errorResistanceApparent": 5.0, + "resistivityApparent": 139.81, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -859,8 +859,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 8.6, - "resistanceApparent": 161.68, - "errorResistanceApparent": 5.0, + "resistivityApparent": 161.68, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -868,8 +868,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 7.5, - "resistanceApparent": 212.47, - "errorResistanceApparent": 5.0, + "resistivityApparent": 212.47, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -877,8 +877,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 4.5, - "resistanceApparent": 182.99, - "errorResistanceApparent": 5.0, + "resistivityApparent": 182.99, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -886,8 +886,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 20.856, - "resistanceApparent": 356.51, - "errorResistanceApparent": 5.0, + "resistivityApparent": 356.51, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -895,8 +895,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 0.0, - "resistanceApparent": 1310.4, - "errorResistanceApparent": 5.0, + "resistivityApparent": 1310.4, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -904,8 +904,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 0.0, - "resistanceApparent": 243.04, - "errorResistanceApparent": 5.0, + "resistivityApparent": 243.04, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -913,8 +913,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 0.0, - "resistanceApparent": 285.93, - "errorResistanceApparent": 5.0, + "resistivityApparent": 285.93, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -922,8 +922,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 0.0, - "resistanceApparent": 335.21, - "errorResistanceApparent": 5.0, + "resistivityApparent": 335.21, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -931,53 +931,53 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 0.0, - "resistanceApparent": 381.73, - "errorResistanceApparent": 5.0, + "resistivityApparent": 381.73, + "errorResistivityApparent": 5.0, "isHidden": false } ], "modelData": [ { "power": 0.35, - "resistance": 372.19, + "resistivity": 372.19, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 0.59, - "resistance": 80.53, + "resistivity": 80.53, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 3.18, - "resistance": 233.44, + "resistivity": 233.44, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 11.4, - "resistance": 99.9, + "resistivity": 99.9, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 20.58, - "resistance": 60.0, + "resistivity": 60.0, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 87.12, - "resistance": 220.0, + "resistivity": 220.0, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { - "power": "NaN", - "resistance": 1882.95, + "power": "0.0", + "resistivity": 1882.95, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false } ], "offsetX": 100.0, @@ -992,8 +992,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 1264.0, - "resistanceApparent": 79.419, - "errorResistanceApparent": 5.0, + "resistivityApparent": 79.419, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -1001,8 +1001,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 620.0, - "resistanceApparent": 73.042, - "errorResistanceApparent": 5.0, + "resistivityApparent": 73.042, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -1010,8 +1010,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 281.24, - "resistanceApparent": 77.31, - "errorResistanceApparent": 5.0, + "resistivityApparent": 77.31, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -1019,8 +1019,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 158.0, - "resistanceApparent": 78.178, - "errorResistanceApparent": 5.0, + "resistivityApparent": 78.178, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -1028,8 +1028,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 101.12, - "resistanceApparent": 78.625, - "errorResistanceApparent": 5.0, + "resistivityApparent": 78.625, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -1037,8 +1037,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 48.0, - "resistanceApparent": 73.513, - "errorResistanceApparent": 5.0, + "resistivityApparent": 73.513, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -1046,8 +1046,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 25.59, - "resistanceApparent": 64.918, - "errorResistanceApparent": 5.0, + "resistivityApparent": 64.918, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -1055,8 +1055,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 12.96, - "resistanceApparent": 58.528, - "errorResistanceApparent": 5.0, + "resistivityApparent": 58.528, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -1064,8 +1064,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 7.3, - "resistanceApparent": 51.543, - "errorResistanceApparent": 5.0, + "resistivityApparent": 51.543, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -1073,8 +1073,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 41.0, - "resistanceApparent": 51.806, - "errorResistanceApparent": 20.0, + "resistivityApparent": 51.806, + "errorResistivityApparent": 20.0, "isHidden": false }, { @@ -1082,8 +1082,8 @@ "mn2": 0.5, "amperage": 100.0, "voltage": 4.8, - "resistanceApparent": 60.281, - "errorResistanceApparent": 5.0, + "resistivityApparent": 60.281, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -1091,8 +1091,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 29.7, - "resistanceApparent": 66.24, - "errorResistanceApparent": 20.8, + "resistivityApparent": 66.24, + "errorResistivityApparent": 20.8, "isHidden": false }, { @@ -1100,8 +1100,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 18.01, - "resistanceApparent": 63.525, - "errorResistanceApparent": 20.0, + "resistivityApparent": 63.525, + "errorResistivityApparent": 20.0, "isHidden": false }, { @@ -1109,8 +1109,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 9.1, - "resistanceApparent": 53.799, - "errorResistanceApparent": 20.0, + "resistivityApparent": 53.799, + "errorResistivityApparent": 20.0, "isHidden": false }, { @@ -1118,8 +1118,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 6.9, - "resistanceApparent": 62.916, - "errorResistanceApparent": 20.0, + "resistivityApparent": 62.916, + "errorResistivityApparent": 20.0, "isHidden": false }, { @@ -1127,8 +1127,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 4.4, - "resistanceApparent": 62.825, - "errorResistanceApparent": 5.0, + "resistivityApparent": 62.825, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -1136,8 +1136,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 3.04, - "resistanceApparent": 72.544, - "errorResistanceApparent": 5.0, + "resistivityApparent": 72.544, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -1145,8 +1145,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 13.27, - "resistanceApparent": 70.889, - "errorResistanceApparent": 5.0, + "resistivityApparent": 70.889, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -1154,8 +1154,8 @@ "mn2": 3.0, "amperage": 100.0, "voltage": 2.34, - "resistanceApparent": 83.74, - "errorResistanceApparent": 5.0, + "resistivityApparent": 83.74, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -1163,8 +1163,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 10.428, - "resistanceApparent": 85.396, - "errorResistanceApparent": 5.0, + "resistivityApparent": 85.396, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -1172,8 +1172,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 8.0, - "resistanceApparent": 103.21, - "errorResistanceApparent": 5.0, + "resistivityApparent": 103.21, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -1181,8 +1181,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 6.0, - "resistanceApparent": 117.69, - "errorResistanceApparent": 5.0, + "resistivityApparent": 117.69, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -1190,8 +1190,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 4.7, - "resistanceApparent": 137.54, - "errorResistanceApparent": 5.0, + "resistivityApparent": 137.54, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -1199,8 +1199,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 4.6, - "resistanceApparent": 194.23, - "errorResistanceApparent": 99.9, + "resistivityApparent": 194.23, + "errorResistivityApparent": 99.9, "isHidden": true }, { @@ -1208,8 +1208,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 12.32, - "resistanceApparent": 210.6, - "errorResistanceApparent": 99.9, + "resistivityApparent": 210.6, + "errorResistivityApparent": 99.9, "isHidden": false }, { @@ -1217,8 +1217,8 @@ "mn2": 12.0, "amperage": 100.0, "voltage": 3.002, - "resistanceApparent": 189.63, - "errorResistanceApparent": 5.0, + "resistivityApparent": 189.63, + "errorResistivityApparent": 5.0, "isHidden": true }, { @@ -1226,8 +1226,8 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 7.8, - "resistanceApparent": 200.93, - "errorResistanceApparent": 5.0, + "resistivityApparent": 200.93, + "errorResistivityApparent": 5.0, "isHidden": false }, { @@ -1235,47 +1235,47 @@ "mn2": 29.0, "amperage": 100.0, "voltage": 6.0, - "resistanceApparent": 243.04, - "errorResistanceApparent": 5.0, + "resistivityApparent": 243.04, + "errorResistivityApparent": 5.0, "isHidden": false } ], "modelData": [ { "power": 0.66, - "resistance": 100.0, + "resistivity": 100.0, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 0.73, - "resistance": 50.0, + "resistivity": 50.0, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 2.92, - "resistance": 108.9, + "resistivity": 108.9, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 21.0, - "resistance": 35.0, + "resistivity": 35.0, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { "power": 40.0, - "resistance": 102.4, + "resistivity": 102.4, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false }, { - "power": "NaN", - "resistance": 1062.88, + "power": "0.0", + "resistivity": 1062.88, "isFixedPower": false, - "isFixedResistance": false + "isFixedResistivity": false } ], "offsetX": 100.0, diff --git a/files/src/main/java/ru/nucodelabs/files/sonet/EXPFile.java b/files/src/main/java/ru/nucodelabs/files/sonet/EXPFile.java index cec69345..1904b044 100644 --- a/files/src/main/java/ru/nucodelabs/files/sonet/EXPFile.java +++ b/files/src/main/java/ru/nucodelabs/files/sonet/EXPFile.java @@ -16,8 +16,8 @@ public class EXPFile { private ArrayList amperage; // Ток, мА private ArrayList voltage; // Напряжение, мВ - private ArrayList resistanceApparent; // Сопротивление кажущееся, Ом * м - private ArrayList errorResistanceApparent; // Погрешность, % + private ArrayList resistivityApparent; // Сопротивление кажущееся, Ом * м + private ArrayList errorResistivityApparent; // Погрешность, % private ArrayList polarizationApparent; // Поляризация кажущаяся, % private ArrayList errorPolarizationApparent; // Погрешность, % @@ -31,8 +31,8 @@ public EXPFile() { checked = ""; amperage = new ArrayList<>(); voltage = new ArrayList<>(); - resistanceApparent = new ArrayList<>(); - errorResistanceApparent = new ArrayList<>(); + resistivityApparent = new ArrayList<>(); + errorResistivityApparent = new ArrayList<>(); polarizationApparent = new ArrayList<>(); errorPolarizationApparent = new ArrayList<>(); } @@ -98,12 +98,12 @@ public ArrayList getVoltage() { return voltage; } - public ArrayList getResistanceApparent() { - return resistanceApparent; + public ArrayList getResistivityApparent() { + return resistivityApparent; } - public ArrayList getErrorResistanceApparent() { - return errorResistanceApparent; + public ArrayList getErrorResistivityApparent() { + return errorResistivityApparent; } public ArrayList getPolarizationApparent() { @@ -134,12 +134,12 @@ public void setVoltage(ArrayList voltage) { this.voltage = voltage; } - public void setResistanceApparent(ArrayList resistanceApparent) { - this.resistanceApparent = resistanceApparent; + public void setResistivityApparent(ArrayList resistivityApparent) { + this.resistivityApparent = resistivityApparent; } - public void setErrorResistanceApparent(ArrayList errorResistanceApparent) { - this.errorResistanceApparent = errorResistanceApparent; + public void setErrorResistivityApparent(ArrayList errorResistivityApparent) { + this.errorResistivityApparent = errorResistivityApparent; } public void setPolarizationApparent(ArrayList polarizationApparent) { diff --git a/files/src/main/java/ru/nucodelabs/files/sonet/MODFile.java b/files/src/main/java/ru/nucodelabs/files/sonet/MODFile.java index 0c969970..cad200ae 100644 --- a/files/src/main/java/ru/nucodelabs/files/sonet/MODFile.java +++ b/files/src/main/java/ru/nucodelabs/files/sonet/MODFile.java @@ -6,12 +6,12 @@ public class MODFile { private File file; - private ArrayList resistance; // Сопротивление, Ом*м + private ArrayList resistivity; // Сопротивление, Ом*м private ArrayList polarization; // Поляризация, % private ArrayList power; // Мощность, м public MODFile() { - resistance = new ArrayList<>(0); + resistivity = new ArrayList<>(0); polarization = new ArrayList<>(0); power = new ArrayList<>(0); } @@ -20,8 +20,8 @@ public int getColumnCnt() { return 3; } - public ArrayList getResistance() { - return resistance; + public ArrayList getResistivity() { + return resistivity; } public ArrayList getPolarization() { @@ -36,8 +36,8 @@ public void setPolarization(ArrayList polarization) { this.polarization = polarization; } - public void setResistance(ArrayList resistance) { - this.resistance = resistance; + public void setResistivity(ArrayList resistivity) { + this.resistivity = resistivity; } public void setPower(ArrayList power) { diff --git a/files/src/main/java/ru/nucodelabs/files/sonet/SonetImportUtils.java b/files/src/main/java/ru/nucodelabs/files/sonet/SonetImportUtils.java index a0c4ea50..84806db7 100644 --- a/files/src/main/java/ru/nucodelabs/files/sonet/SonetImportUtils.java +++ b/files/src/main/java/ru/nucodelabs/files/sonet/SonetImportUtils.java @@ -42,9 +42,9 @@ private SonetImportUtils() { numbers.stream().map(s -> s.get(0)).toList()); res.getVoltage().addAll( numbers.stream().map(s -> s.get(1)).toList()); - res.getResistanceApparent().addAll( + res.getResistivityApparent().addAll( numbers.stream().map(s -> s.get(2)).toList()); - res.getErrorResistanceApparent().addAll( + res.getErrorResistivityApparent().addAll( numbers.stream().map(s -> s.get(3)).toList()); res.getPolarizationApparent().addAll( numbers.stream().map(s -> s.get(4)).toList()); @@ -60,7 +60,7 @@ private SonetImportUtils() { try (Scanner sc = new Scanner(file).useLocale(Locale.US)) { ArrayList> numbers = columnReader(sc, new MODFile().getColumnCnt()); - res.getResistance().addAll( + res.getResistivity().addAll( numbers.stream().map(s -> s.get(0)).toList()); res.getPower().addAll( numbers.stream().map(s -> s.get(1)).toList()); diff --git a/files/src/test/java/ru/nucodelabs/files/sonet/SonetImportUtilsTest.java b/files/src/test/java/ru/nucodelabs/files/sonet/SonetImportUtilsTest.java index e60f0e74..ea87da45 100644 --- a/files/src/test/java/ru/nucodelabs/files/sonet/SonetImportUtilsTest.java +++ b/files/src/test/java/ru/nucodelabs/files/sonet/SonetImportUtilsTest.java @@ -41,12 +41,12 @@ void readEXP_test() throws Exception { System.out.println(exp.getOperator()); System.out.println(exp.getInterpreter()); System.out.println(exp.getChecked()); - for (int i = 0; i < exp.getResistanceApparent().size(); i++) { + for (int i = 0; i < exp.getResistivityApparent().size(); i++) { System.out.println( checkNull.apply(exp.getAmperage().get(i)) + " " + checkNull.apply(exp.getVoltage().get(i)) + " " - + checkNull.apply(exp.getResistanceApparent().get(i)) + " " - + checkNull.apply(exp.getErrorResistanceApparent().get(i)) + " " + + checkNull.apply(exp.getResistivityApparent().get(i)) + " " + + checkNull.apply(exp.getErrorResistivityApparent().get(i)) + " " + checkNull.apply(exp.getPolarizationApparent().get(i)) + " " + checkNull.apply(exp.getErrorPolarizationApparent().get(i)) ); @@ -64,8 +64,8 @@ void readEXP_test() throws Exception { } assertEquals(31, exp.getAmperage().size()); - assertEquals(31, exp.getResistanceApparent().size()); - assertEquals(31, exp.getErrorResistanceApparent().size()); + assertEquals(31, exp.getResistivityApparent().size()); + assertEquals(31, exp.getErrorResistivityApparent().size()); } @Test @@ -73,16 +73,16 @@ void readMOD_test() throws Exception { System.out.println("SonetTest.readMOD_test"); File file = new File("data/sonet_examples/KAZAN.MOD"); MODFile mod = SonetImportUtils.readMOD(file); - for (int i = 0; i < mod.getResistance().size(); i++) { + for (int i = 0; i < mod.getResistivity().size(); i++) { System.out.println( - checkNull.apply(mod.getResistance().get(i)) + " " + checkNull.apply(mod.getResistivity().get(i)) + " " + checkNull.apply(mod.getPower().get(i)) + " " + checkNull.apply(mod.getPolarization().get(i)) ); } assertEquals(3, mod.getPower().size()); - assertEquals(3, mod.getResistance().size()); + assertEquals(3, mod.getResistivity().size()); } @Test @@ -93,7 +93,7 @@ void readEXP_test1() throws Exception { System.out.println("SonetTest.readEXP_test"); assertEquals(28, exp.getAmperage().size()); - assertEquals(28, exp.getResistanceApparent().size()); - assertEquals(28, exp.getErrorResistanceApparent().size()); + assertEquals(28, exp.getResistivityApparent().size()); + assertEquals(28, exp.getErrorResistivityApparent().size()); } } diff --git a/kfx-utils/src/main/kotlin/ru/nucodelabs/kfx/core/AbstractViewController.kt b/kfx-utils/src/main/kotlin/ru/nucodelabs/kfx/core/AbstractViewController.kt index 1e6468b6..68a87a69 100644 --- a/kfx-utils/src/main/kotlin/ru/nucodelabs/kfx/core/AbstractViewController.kt +++ b/kfx-utils/src/main/kotlin/ru/nucodelabs/kfx/core/AbstractViewController.kt @@ -4,21 +4,15 @@ import javafx.fxml.FXML import javafx.fxml.Initializable import javafx.scene.Node import javafx.stage.Stage -import java.net.URL -import java.util.* /** * Abstract JavaFX controller which already implements `Initializable`. - * It runs fxScriptInit which can be defined in related FXML file using `fx:script` tag. * To use this controller you have to set `fx:id` attribute to `"root"` in root node of corresponding FXML-view. * Then you can obtain root node via property `root` and you can try to obtain stage via `stage` property. * @param N type of root node */ abstract class AbstractViewController : Initializable { - @FXML - protected var fxScriptInit: Runnable = Runnable {} - /** * Root node FXML-injected */ @@ -28,13 +22,12 @@ abstract class AbstractViewController : Initializable { /** * Current window */ + @Deprecated("Use stage() method", replaceWith = ReplaceWith("rootStage()")) protected val stage: Stage? get() = root.scene?.window as Stage? - - override fun initialize(location: URL, resources: ResourceBundle) { - fxScriptInit() - } - - private fun fxScriptInit() = fxScriptInit.run() + /** + * Window that contains the controller root node + */ + protected fun rootStage(): Stage? = root.scene?.window as? Stage } \ No newline at end of file diff --git a/kfx-utils/src/main/kotlin/ru/nucodelabs/kfx/ext/FX.kt b/kfx-utils/src/main/kotlin/ru/nucodelabs/kfx/ext/FX.kt index 1a0e0185..d206bc03 100644 --- a/kfx-utils/src/main/kotlin/ru/nucodelabs/kfx/ext/FX.kt +++ b/kfx-utils/src/main/kotlin/ru/nucodelabs/kfx/ext/FX.kt @@ -12,6 +12,7 @@ import javafx.collections.FXCollections import javafx.collections.ObservableList import javafx.embed.swing.SwingFXUtils import javafx.scene.Node +import javafx.scene.Parent import javafx.scene.SnapshotParameters import javafx.scene.canvas.Canvas import javafx.scene.chart.XYChart @@ -210,7 +211,7 @@ fun Tooltip.noAutoHide() = apply { showDuration = Duration.INDEFINITE } fun Tooltip.noHideDelay() = apply { hideDelay = Duration.ZERO } -fun Tooltip.forCharts() = this.noDelay().noAutoHide().noHideDelay() +fun Tooltip.shownOnHover() = this.noDelay().noAutoHide().noHideDelay() /** * As PNG @@ -250,7 +251,8 @@ infix fun Property.bindTo(observable: ObservableValue) { bind(observable) } -fun currentWindow(): Stage = Stage.getWindows().find { it.isFocused } as Stage +fun currentWindow(): Stage = Stage.getWindows().filterIsInstance().find { it.isFocused } + ?: throw IllegalStateException("No window focused") fun saveInitialDirectory( preferences: Preferences, @@ -271,4 +273,21 @@ fun unfocus(node: Node) { if (node.isFocused) { node.parent.requestFocus() } +} + +fun switch(from: Parent, to: Parent) { + hide(from) + show(to) + to.requestLayout() + to.layout() +} + +fun hide(node: Node) { + node.isVisible = false + node.isManaged = false +} + +fun show(node: Node) { + node.isManaged = true + node.isVisible = true } \ No newline at end of file diff --git a/kfx-utils/src/main/kotlin/ru/nucodelabs/kfx/observable/Constrained.kt b/kfx-utils/src/main/kotlin/ru/nucodelabs/kfx/observable/Constrained.kt new file mode 100644 index 00000000..80f39086 --- /dev/null +++ b/kfx-utils/src/main/kotlin/ru/nucodelabs/kfx/observable/Constrained.kt @@ -0,0 +1,25 @@ +package ru.nucodelabs.kfx.observable + +import javafx.beans.property.SimpleDoubleProperty +import javafx.beans.property.SimpleObjectProperty + + +class ConstrainedObjectProperty( + value: T?, + val isValid: (T?) -> Boolean +) : SimpleObjectProperty(value) { + + override fun set(value: T?) { + if (isValid(value)) super.set(value) + } +} + +class ConstrainedDoubleProperty( + value: Double, + val isValid: (Double) -> Boolean +) : SimpleDoubleProperty(value) { + + override fun set(value: Double) { + if (isValid(value)) super.set(value) + } +} \ No newline at end of file diff --git a/kfx-utils/src/main/kotlin/ru/nucodelabs/kfx/snapshot/Snapshot.kt b/kfx-utils/src/main/kotlin/ru/nucodelabs/kfx/snapshot/Snapshot.kt index aa7bea3d..1974e346 100644 --- a/kfx-utils/src/main/kotlin/ru/nucodelabs/kfx/snapshot/Snapshot.kt +++ b/kfx-utils/src/main/kotlin/ru/nucodelabs/kfx/snapshot/Snapshot.kt @@ -15,7 +15,8 @@ interface Snapshot { } } - private data class SnapshotImpl(override val value: T) : Snapshot + @JvmInline + private value class SnapshotImpl(override val value: T) : Snapshot } fun snapshotOf(value: T) = Snapshot.of(value) \ No newline at end of file diff --git a/src/jmh/kotlin/ru/nucodelabs/equals/EqualsBenchmark.kt b/src/jmh/kotlin/ru/nucodelabs/equals/EqualsBenchmark.kt new file mode 100644 index 00000000..f8a1e79b --- /dev/null +++ b/src/jmh/kotlin/ru/nucodelabs/equals/EqualsBenchmark.kt @@ -0,0 +1,50 @@ +package ru.nucodelabs.equals + +import org.apache.commons.lang3.builder.EqualsBuilder +import org.openjdk.jmh.annotations.* +import ru.nucodelabs.util.Equals + +@Suppress("unused") +@Warmup(iterations = 0) +@Measurement(iterations = 2) +@State(Scope.Thread) +open class EqualsBenchmark { + class Some( + val a: Int, + val b: String, + val c: Double, + val d: List, + val e: DoubleArray + ) + + lateinit var objA: Some + lateinit var objB: Some + + @Setup + fun setup() { + objA = Some(1, "12345", 1234.5678, listOf("Some", "String", "Content"), doubleArrayOf(.1, .2, .3)) + objB = Some(1, "12345", 1234.5678, listOf("Some", "String", "Content"), doubleArrayOf(.1, .2, .3)) + } + + @Benchmark + fun commonUtilsEqualsKt(): Boolean { + return Equals(objA, objB) + .by { it.a } + .by { it.b } + .by { it.c } + .by { it.d } + .and { it, other -> it.e contentEquals other.e } + .isEqual + } + + @Benchmark + fun apacheCommonsEqualsBuilderJava(): Boolean { + return EqualsBuilder() + .append(objA.a, objB.a) + .append(objA.b, objB.b) + .append(objA.c, objB.c) + .append(objA.d, objB.d) + .append(objA.e, objB.e) + .isEquals + } +} diff --git a/src/main/java/ru/nucodelabs/gem/app/GemApplication.kt b/src/main/java/ru/nucodelabs/gem/app/GemApplication.kt index 185470d5..7f5429e3 100644 --- a/src/main/java/ru/nucodelabs/gem/app/GemApplication.kt +++ b/src/main/java/ru/nucodelabs/gem/app/GemApplication.kt @@ -25,7 +25,7 @@ class GemApplication : GuiceApplication(AppModule()) { private val macOSHandledFiles: MutableList = mutableListOf() - val log = slf4j(this) + val log = slf4j() @Inject lateinit var alertsFactory: AlertsFactory diff --git a/src/main/java/ru/nucodelabs/gem/app/UncaughtExceptionHandler.kt b/src/main/java/ru/nucodelabs/gem/app/UncaughtExceptionHandler.kt index e2ee9f06..c4b0b21f 100644 --- a/src/main/java/ru/nucodelabs/gem/app/UncaughtExceptionHandler.kt +++ b/src/main/java/ru/nucodelabs/gem/app/UncaughtExceptionHandler.kt @@ -9,12 +9,16 @@ class UncaughtExceptionHandler( private val alertsFactory: AlertsFactory, ) : UncaughtExceptionHandler { - val log = slf4j(this) + val log = slf4j() override fun uncaughtException(t: Thread, e: Throwable) { log.error("Uncaught exception", e) if (Platform.isFxApplicationThread()) { - alertsFactory.uncaughtExceptionAlert(e).show() + if (e is UnsatisfiedLinkError) { + alertsFactory.unsatisfiedLinkErrorAlert(e).show() + } else { + alertsFactory.uncaughtExceptionAlert(e).show() + } } } } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/app/io/SonetImportManagerImpl.kt b/src/main/java/ru/nucodelabs/gem/app/io/SonetImportManagerImpl.kt index b3181ae7..8a11af99 100644 --- a/src/main/java/ru/nucodelabs/gem/app/io/SonetImportManagerImpl.kt +++ b/src/main/java/ru/nucodelabs/gem/app/io/SonetImportManagerImpl.kt @@ -24,8 +24,8 @@ internal class SonetImportManagerImpl : SonetImportManager { sttParsed.mN_2, expParsed.amperage, expParsed.voltage, - expParsed.resistanceApparent, - expParsed.errorResistanceApparent + expParsed.resistivityApparent, + expParsed.errorResistivityApparent ).minOf { it.size } val expData: MutableList = mutableListOf() @@ -33,8 +33,8 @@ internal class SonetImportManagerImpl : SonetImportManager { expData += ExperimentalData( ab2 = sttParsed.aB_2[i], mn2 = sttParsed.mN_2[i], - resistanceApparent = expParsed.resistanceApparent[i], - errorResistanceApparent = expParsed.errorResistanceApparent[i], + resistivityApparent = expParsed.resistivityApparent[i], + errorResistivityApparent = expParsed.errorResistivityApparent[i], amperage = expParsed.amperage[i], voltage = expParsed.voltage[i] ) @@ -75,14 +75,14 @@ internal class SonetImportManagerImpl : SonetImportManager { val minSize = listOf( modParsed.power, - modParsed.resistance + modParsed.resistivity ).minOf { it.size } val modelData: MutableList = mutableListOf() for (i in 0 until minSize) { modelData += ModelLayer( power = modParsed.power[i], - resistance = modParsed.resistance[i] + resistivity = modParsed.resistivity[i] ) } return modelData diff --git a/src/main/java/ru/nucodelabs/gem/config/AppModule.java b/src/main/java/ru/nucodelabs/gem/config/AppModule.java index d821e2e7..fe6c689a 100644 --- a/src/main/java/ru/nucodelabs/gem/config/AppModule.java +++ b/src/main/java/ru/nucodelabs/gem/config/AppModule.java @@ -186,7 +186,7 @@ public String toString(Double object) { try { return decimalFormat.format(object); } catch (Exception e) { - return ""; + return null; } } @@ -195,7 +195,7 @@ public Double fromString(String string) { try { return decimalFormat.parse(string).doubleValue(); } catch (ParseException e) { - return Double.NaN; + return null; } } }; diff --git a/src/main/java/ru/nucodelabs/gem/config/Logging.kt b/src/main/java/ru/nucodelabs/gem/config/Logging.kt index 7c8a1271..218a490f 100644 --- a/src/main/java/ru/nucodelabs/gem/config/Logging.kt +++ b/src/main/java/ru/nucodelabs/gem/config/Logging.kt @@ -1,5 +1,6 @@ package ru.nucodelabs.gem.config +import org.slf4j.Logger import org.slf4j.LoggerFactory -fun slf4j(instance: Any) = LoggerFactory.getLogger(instance::class.java)!! \ No newline at end of file +inline fun T.slf4j(): Logger = LoggerFactory.getLogger(T::class.java)!! \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/file/dto/anisotropy/ModelLayerDto.kt b/src/main/java/ru/nucodelabs/gem/file/dto/anisotropy/ModelLayerDto.kt index baf7ee44..4f58a54f 100644 --- a/src/main/java/ru/nucodelabs/gem/file/dto/anisotropy/ModelLayerDto.kt +++ b/src/main/java/ru/nucodelabs/gem/file/dto/anisotropy/ModelLayerDto.kt @@ -5,7 +5,7 @@ import com.fasterxml.jackson.annotation.JsonInclude @JsonInclude(JsonInclude.Include.NON_NULL) data class ModelLayerDto( val power: FixableDoubleValueDto, - val resistance: FixableDoubleValueDto, + val resistivity: FixableDoubleValueDto, var verticalAnisotropyCoefficient: FixableDoubleValueDto, var azimuth: FixableDoubleValueDto, var azimuthAnisotropyCoefficient: FixableDoubleValueDto, diff --git a/src/main/java/ru/nucodelabs/gem/file/dto/anisotropy/SignalDto.kt b/src/main/java/ru/nucodelabs/gem/file/dto/anisotropy/SignalDto.kt index 8fd92d0b..2060d9b9 100644 --- a/src/main/java/ru/nucodelabs/gem/file/dto/anisotropy/SignalDto.kt +++ b/src/main/java/ru/nucodelabs/gem/file/dto/anisotropy/SignalDto.kt @@ -8,7 +8,7 @@ data class SignalDto( var mn2: Double, var amperage: Double?, var voltage: Double?, - var resistanceApparent: Double?, - var errorResistanceApparent: Double?, + var resistivityApparent: Double?, + var errorResistivityApparent: Double?, var isHidden: Boolean? ) diff --git a/src/main/java/ru/nucodelabs/gem/file/dto/mapper/DtoMapper.java b/src/main/java/ru/nucodelabs/gem/file/dto/mapper/DtoMapper.java index eb79f101..0d3528ea 100644 --- a/src/main/java/ru/nucodelabs/gem/file/dto/mapper/DtoMapper.java +++ b/src/main/java/ru/nucodelabs/gem/file/dto/mapper/DtoMapper.java @@ -4,23 +4,23 @@ import ru.nucodelabs.gem.file.dto.anisotropy.*; import ru.nucodelabs.geo.anisotropy.*; +import java.util.Collections; import java.util.List; -import static org.apache.commons.collections4.ListUtils.emptyIfNull; @Mapper( componentModel = MappingConstants.ComponentModel.JSR330, - unmappedSourcePolicy = ReportingPolicy.ERROR, - unmappedTargetPolicy = ReportingPolicy.ERROR, - nullValueIterableMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT + unmappedSourcePolicy = ReportingPolicy.ERROR, + unmappedTargetPolicy = ReportingPolicy.ERROR, + nullValueIterableMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT ) public abstract class DtoMapper { @Mapping( - target = "resistanceApparent", - defaultExpression = "java(ru.nucodelabs.geo.ves.calc.VesKt.rhoA(dto.getAb2(), dto.getMn2(), dto.getAmperage(), dto.getVoltage()))" + target = "resistivityApparent", + defaultExpression = "java(ru.nucodelabs.geo.ves.calc.VesFunctions.rhoA(dto.getAb2(), dto.getMn2(), dto.getAmperage(), dto.getVoltage()))" ) - @Mapping(target = "errorResistanceApparent", defaultExpression = "java(ru.nucodelabs.geo.anisotropy.DefaultValues.DEFAULT_ERROR)") + @Mapping(target = "errorResistivityApparent", defaultExpression = "java(ru.nucodelabs.geo.anisotropy.DefaultValues.DEFAULT_ERROR)") @Mapping(target = "isHidden", source = "hidden", defaultValue = "false") protected abstract Signal fromDto(SignalDto dto); @@ -32,7 +32,7 @@ public abstract class DtoMapper { protected abstract FixableValue fromDto(FixableDoubleValueDto fixableDoubleValueDto); protected Signals mapSignals(List dto) { - return new Signals(emptyIfNull(dto).stream().map(this::fromDto).toList()); + return new Signals((dto != null ? dto : Collections.emptyList()).stream().map(this::fromDto).toList()); } @Mapping(target = "isFixed", source = "fixed") diff --git a/src/main/java/ru/nucodelabs/gem/fxmodel/anisotropy/ObservableModelLayer.kt b/src/main/java/ru/nucodelabs/gem/fxmodel/anisotropy/ObservableModelLayer.kt index 4229b2b3..16bcaabd 100644 --- a/src/main/java/ru/nucodelabs/gem/fxmodel/anisotropy/ObservableModelLayer.kt +++ b/src/main/java/ru/nucodelabs/gem/fxmodel/anisotropy/ObservableModelLayer.kt @@ -7,7 +7,7 @@ import tornadofx.setValue class ObservableModelLayer( power: ObservableFixableValue, - resistance: ObservableFixableValue, + resistivity: ObservableFixableValue, verticalAnisotropyCoefficient: ObservableFixableValue, azimuth: ObservableFixableValue, azimuthAnisotropyCoefficient: ObservableFixableValue, @@ -16,9 +16,9 @@ class ObservableModelLayer( fun powerProperty() = powerProperty var power: ObservableFixableValue by powerProperty - private val resistanceProperty: ObjectProperty> = SimpleObjectProperty(resistance) - fun resistanceProperty() = resistanceProperty - var resistance: ObservableFixableValue by resistanceProperty + private val resistivityProperty: ObjectProperty> = SimpleObjectProperty(resistivity) + fun resistivityProperty() = resistivityProperty + var resistivity: ObservableFixableValue by resistivityProperty private val verticalAnisotropyCoefficientProperty: ObjectProperty> = SimpleObjectProperty(verticalAnisotropyCoefficient) diff --git a/src/main/java/ru/nucodelabs/gem/fxmodel/anisotropy/ObservableSignal.kt b/src/main/java/ru/nucodelabs/gem/fxmodel/anisotropy/ObservableSignal.kt index 827fdc61..9e3806b6 100644 --- a/src/main/java/ru/nucodelabs/gem/fxmodel/anisotropy/ObservableSignal.kt +++ b/src/main/java/ru/nucodelabs/gem/fxmodel/anisotropy/ObservableSignal.kt @@ -10,8 +10,8 @@ class ObservableSignal( mn2: Double, amperage: Double, voltage: Double, - resistanceApparent: Double, - errorResistanceApparent: Double, + resistivityApparent: Double, + errorResistivityApparent: Double, isHidden: Boolean ) { private val ab2Property = SimpleDoubleProperty(ab2) @@ -30,13 +30,13 @@ class ObservableSignal( fun voltageProperty() = voltageProperty var voltage by voltageProperty - private val resistanceApparentProperty = SimpleDoubleProperty(resistanceApparent) - fun resistanceApparentProperty() = resistanceApparentProperty - var resistanceApparent by resistanceApparentProperty + private val resistivityApparentProperty = SimpleDoubleProperty(resistivityApparent) + fun resistivityApparentProperty() = resistivityApparentProperty + var resistivityApparent by resistivityApparentProperty - private val errorResistanceApparentProperty = SimpleDoubleProperty(errorResistanceApparent) - fun errorResistanceApparentProperty() = errorResistanceApparentProperty - var errorResistanceApparent by errorResistanceApparentProperty + private val errorResistivityApparentProperty = SimpleDoubleProperty(errorResistivityApparent) + fun errorResistivityApparentProperty() = errorResistivityApparentProperty + var errorResistivityApparent by errorResistivityApparentProperty private val hiddenProperty = SimpleBooleanProperty(isHidden) fun hiddenProperty() = hiddenProperty diff --git a/src/main/java/ru/nucodelabs/gem/fxmodel/anisotropy/app/AnisotropyFxAppModel.kt b/src/main/java/ru/nucodelabs/gem/fxmodel/anisotropy/app/AnisotropyFxAppModel.kt index bc6bb208..708ac9eb 100644 --- a/src/main/java/ru/nucodelabs/gem/fxmodel/anisotropy/app/AnisotropyFxAppModel.kt +++ b/src/main/java/ru/nucodelabs/gem/fxmodel/anisotropy/app/AnisotropyFxAppModel.kt @@ -134,7 +134,7 @@ class AnisotropyFxAppModel @Inject constructor( fun upperErrorBoundSignals(): List { val selectedSignals = selectedSignals() return selectedSignals?.signals?.effectiveSignals?.map { - it.copy(resistanceApparent = it.resistanceApparentUpperBoundByError) + it.copy(resistivityApparent = it.resistivityApparentUpperBoundByError) }?.map { fxModelMapper.toObservable(it) } ?: emptyList() @@ -143,7 +143,7 @@ class AnisotropyFxAppModel @Inject constructor( fun lowerErrorBoundSignals(): List { val selectedSignals = selectedSignals() return selectedSignals?.signals?.effectiveSignals?.map { - it.copy(resistanceApparent = it.resistanceApparentLowerBoundByError) + it.copy(resistivityApparent = it.resistivityApparentLowerBoundByError) }?.map { fxModelMapper.toObservable(it) } ?: emptyList() @@ -170,7 +170,7 @@ class AnisotropyFxAppModel @Inject constructor( return exp.mapIndexed { aIdx, azimuthSignals -> azimuthSignals.copy( signals = Signals(azimuthSignals.signals.sortedSignals.mapIndexed { index, signal -> - signal.copy(resistanceApparent = theor[aIdx].signals.sortedSignals[index].resistanceApparent / signal.resistanceApparent) + signal.copy(resistivityApparent = theor[aIdx].signals.sortedSignals[index].resistivityApparent / signal.resistivityApparent) }) ) }.map { diff --git a/src/main/java/ru/nucodelabs/gem/fxmodel/ves/ObservableExperimentalData.kt b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/ObservableExperimentalData.kt index 9b377eac..cb6fa4e2 100644 --- a/src/main/java/ru/nucodelabs/gem/fxmodel/ves/ObservableExperimentalData.kt +++ b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/ObservableExperimentalData.kt @@ -1,7 +1,10 @@ package ru.nucodelabs.gem.fxmodel.ves import javafx.beans.property.SimpleBooleanProperty -import javafx.beans.property.SimpleDoubleProperty +import ru.nucodelabs.geo.ves.ExperimentalData +import ru.nucodelabs.geo.ves.MutableExperimentalSignal +import ru.nucodelabs.geo.ves.ReadOnlyExperimentalSignal +import ru.nucodelabs.kfx.observable.ConstrainedDoubleProperty import tornadofx.getValue import tornadofx.setValue @@ -10,35 +13,71 @@ class ObservableExperimentalData( mn2: Double, amperage: Double, voltage: Double, - resistanceApparent: Double, - errorResistanceApparent: Double, + resistivityApparent: Double, + errorResistivityApparent: Double, isHidden: Boolean -) { - private val ab2Property = SimpleDoubleProperty(ab2) +) : MutableExperimentalSignal { + private val ab2Property = ConstrainedDoubleProperty( + ab2, + ExperimentalData::isValidDistance + ) + fun ab2Property() = ab2Property - var ab2 by ab2Property + override var ab2 by ab2Property + + private val mn2Property = ConstrainedDoubleProperty( + mn2, + ExperimentalData::isValidDistance + ) - private val mn2Property = SimpleDoubleProperty(mn2) fun mn2Property() = mn2Property - var mn2 by mn2Property + override var mn2 by mn2Property + + private val amperageProperty = ConstrainedDoubleProperty( + amperage, + ExperimentalData::isValidAmperage + ) - private val amperageProperty = SimpleDoubleProperty(amperage) fun amperageProperty() = amperageProperty - var amperage by amperageProperty + override var amperage by amperageProperty + + private val voltageProperty = ConstrainedDoubleProperty( + voltage, + ExperimentalData::isValidVoltage + ) - private val voltageProperty = SimpleDoubleProperty(voltage) fun voltageProperty() = voltageProperty - var voltage by voltageProperty + override var voltage by voltageProperty - private val resistanceApparentProperty = SimpleDoubleProperty(resistanceApparent) - fun resistanceApparentProperty() = resistanceApparentProperty - var resistanceApparent by resistanceApparentProperty + private val resistivityApparentProperty = ConstrainedDoubleProperty( + resistivityApparent, + ExperimentalData::isValidResistApparent + ) - private val errorResistanceApparentProperty = SimpleDoubleProperty(errorResistanceApparent) - fun errorResistanceApparentProperty() = errorResistanceApparentProperty - var errorResistanceApparent by errorResistanceApparentProperty + fun resistivityApparentProperty() = resistivityApparentProperty + override var resistivityApparent by resistivityApparentProperty + + private val errorResistivityApparentProperty = ConstrainedDoubleProperty( + errorResistivityApparent, + ExperimentalData::isValidErrResistApparent + ) + + fun errorResistivityApparentProperty() = errorResistivityApparentProperty + override var errorResistivityApparent by errorResistivityApparentProperty private val hiddenProperty = SimpleBooleanProperty(isHidden) fun hiddenProperty() = hiddenProperty - var isHidden by hiddenProperty -} \ No newline at end of file + override var isHidden by hiddenProperty +} + +inline fun T.toObservable(): ObservableExperimentalData = + if (T::class == ObservableExperimentalData::class) this as ObservableExperimentalData + else ObservableExperimentalData( + ab2, + mn2, + amperage, + voltage, + resistivityApparent, + errorResistivityApparent, + isHidden + ) \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/fxmodel/ves/ObservableModelLayer.kt b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/ObservableModelLayer.kt index 7ee38089..94d6f5f2 100644 --- a/src/main/java/ru/nucodelabs/gem/fxmodel/ves/ObservableModelLayer.kt +++ b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/ObservableModelLayer.kt @@ -1,29 +1,41 @@ package ru.nucodelabs.gem.fxmodel.ves import javafx.beans.property.SimpleBooleanProperty -import javafx.beans.property.SimpleDoubleProperty +import ru.nucodelabs.geo.ves.ModelLayer +import ru.nucodelabs.geo.ves.MutableModelLayer +import ru.nucodelabs.geo.ves.ReadOnlyModelLayer +import ru.nucodelabs.kfx.observable.ConstrainedDoubleProperty import tornadofx.getValue import tornadofx.setValue class ObservableModelLayer( power: Double, - resistance: Double, + resistivity: Double, isFixedPower: Boolean, - isFixedResistance: Boolean -) { - private val powerProperty = SimpleDoubleProperty(power) + isFixedResistivity: Boolean +) : MutableModelLayer { + private val powerProperty = ConstrainedDoubleProperty(power, ModelLayer::isValidPower) fun powerProperty() = powerProperty - var power by powerProperty + override var power by powerProperty - private val resistanceProperty = SimpleDoubleProperty(resistance) - fun resistanceProperty() = resistanceProperty - var resistance by resistanceProperty + private val resistivityProperty = ConstrainedDoubleProperty(resistivity, ModelLayer::isValidResistivity) + fun resistivityProperty() = resistivityProperty + override var resistivity by resistivityProperty private val fixedPowerProperty = SimpleBooleanProperty(isFixedPower) fun fixedPowerProperty() = fixedPowerProperty - var isFixedPower by fixedPowerProperty + override var isFixedPower by fixedPowerProperty - private val fixedResistanceProperty = SimpleBooleanProperty(isFixedResistance) - fun fixedResistanceProperty() = fixedResistanceProperty - var isFixedResistance by fixedResistanceProperty -} \ No newline at end of file + private val fixedResistivityProperty = SimpleBooleanProperty(isFixedResistivity) + fun fixedResistivityProperty() = fixedResistivityProperty + override var isFixedResistivity by fixedResistivityProperty +} + +inline fun T.toObservable(): ObservableModelLayer = + if (T::class == ObservableModelLayer::class) this as ObservableModelLayer + else ObservableModelLayer( + power, + resistivity, + isFixedPower, + isFixedResistivity + ) \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/fxmodel/ves/app/InitialModelService.kt b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/app/InitialModelService.kt index 6b94f760..efd0985f 100644 --- a/src/main/java/ru/nucodelabs/gem/fxmodel/ves/app/InitialModelService.kt +++ b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/app/InitialModelService.kt @@ -3,8 +3,8 @@ package ru.nucodelabs.gem.fxmodel.ves.app import jakarta.inject.Inject import ru.nucodelabs.geo.forward.ForwardSolver import ru.nucodelabs.geo.target.RelativeErrorAwareTargetFunction -import ru.nucodelabs.geo.ves.ExperimentalData import ru.nucodelabs.geo.ves.ModelLayer +import ru.nucodelabs.geo.ves.ReadOnlyExperimentalSignal import ru.nucodelabs.geo.ves.calc.initialModel.SimpleInitialModel.threeLayersInitialModel import ru.nucodelabs.geo.ves.calc.initialModel.multiLayerInitialModel import ru.nucodelabs.geo.ves.calc.inverse.InverseSolver @@ -15,7 +15,7 @@ class InitialModelService @Inject constructor( private val targetFunction: RelativeErrorAwareTargetFunction, ) { fun arbitraryInitialModel( - signals: List, + signals: List, minTargetFunctionValue: Double, maxLayersCount: Int, ): List { @@ -29,7 +29,7 @@ class InitialModelService @Inject constructor( ) } - fun simpleInitialModel(signals: List): List { + fun simpleInitialModel(signals: List): List { return threeLayersInitialModel(signals) } } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/fxmodel/ves/app/MetricsService.kt b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/app/MetricsService.kt index 063594e3..ffe34a11 100644 --- a/src/main/java/ru/nucodelabs/gem/fxmodel/ves/app/MetricsService.kt +++ b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/app/MetricsService.kt @@ -3,8 +3,8 @@ package ru.nucodelabs.gem.fxmodel.ves.app import jakarta.inject.Inject import ru.nucodelabs.geo.forward.ForwardSolver import ru.nucodelabs.geo.target.RelativeErrorAwareTargetFunction -import ru.nucodelabs.geo.ves.ExperimentalData -import ru.nucodelabs.geo.ves.ModelLayer +import ru.nucodelabs.geo.ves.ReadOnlyExperimentalSignal +import ru.nucodelabs.geo.ves.ReadOnlyModelLayer import ru.nucodelabs.geo.ves.calc.adapter.invoke import ru.nucodelabs.geo.ves.calc.graph.MisfitsFunction import kotlin.math.abs @@ -15,32 +15,32 @@ class MetricsService @Inject constructor( private val misfitsFunction: MisfitsFunction ) { - fun targetFunctionValue(signals: List, model: List): Double { + fun targetFunctionValue(signals: List, model: List): Double { return targetFunction( forwardSolver(signals, model), - signals.map { it.resistanceApparent }, - signals.map { it.errorResistanceApparent } + signals.map { it.resistivityApparent }, + signals.map { it.errorResistivityApparent } ) } - fun errorValue(signals: List, model: List): List { + fun errorValue(signals: List, model: List): List { return misfitsFunction(signals, model) } - fun errorAvgMax(signals: List, model: List): AvgMax { + fun errorAvgMax(signals: List, model: List): AvgMax { val error = errorValue(signals, model) val avg = error.map { abs(it) }.average() val max = error.maxOfOrNull { abs(it) } ?: 0.0 return AvgMax(avg, max) } - fun misfitsValue(signals: List, model: List): List { + fun misfitsValue(signals: List, model: List): List { val theor = forwardSolver(signals, model) - val exp = signals.map { it.resistanceApparent } + val exp = signals.map { it.resistivityApparent } return exp.mapIndexed { idx, resApp -> ((resApp - theor[idx]) / resApp) * 100 } } - fun misfitsAvgMax(signals: List, model: List): AvgMax { + fun misfitsAvgMax(signals: List, model: List): AvgMax { val misfits = misfitsValue(signals, model) val avg = misfits.map { abs(it) }.average() val max = misfits.maxOfOrNull { abs(it) } ?: 0.0 diff --git a/src/main/java/ru/nucodelabs/gem/fxmodel/ves/app/VesFxAppModel.kt b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/app/VesFxAppModel.kt index 9d2b05a6..de3b20ef 100644 --- a/src/main/java/ru/nucodelabs/gem/fxmodel/ves/app/VesFxAppModel.kt +++ b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/app/VesFxAppModel.kt @@ -17,7 +17,7 @@ class VesFxAppModel @Inject constructor( private val observableSection: ObservableSection, private val historyManager: HistoryManager
, private val initialModelService: InitialModelService, - private val metricsService: MetricsService, + private val metricsService: MetricsService ) { private val selectedIndex: Int by selectedIndexObservable::value @@ -64,7 +64,7 @@ class VesFxAppModel @Inject constructor( return metricsService.errorAvgMax(picket.effectiveExperimentalData, picket.modelData) } - fun targetFunction(): Double { + fun targetFunctionValue(): Double { return metricsService.targetFunctionValue(picket.effectiveExperimentalData, picket.modelData) } diff --git a/src/main/java/ru/nucodelabs/gem/fxmodel/ves/mapper/VesFxModelMapper.java b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/mapper/VesFxModelMapper.java index 1c08dce2..a10c7b7c 100644 --- a/src/main/java/ru/nucodelabs/gem/fxmodel/ves/mapper/VesFxModelMapper.java +++ b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/mapper/VesFxModelMapper.java @@ -19,11 +19,11 @@ public abstract class VesFxModelMapper { @Mapping(target = "isHidden", source = "hidden") public abstract ExperimentalData toModel(ObservableExperimentalData experimentalData); - @Mapping(target = "isFixedResistance", source = "fixedResistance") + @Mapping(target = "isFixedResistivity", source = "fixedResistivity") @Mapping(target = "isFixedPower", source = "fixedPower") public abstract ObservableModelLayer toObservable(ModelLayer modelLayer); - @Mapping(target = "isFixedResistance", source = "fixedResistance") + @Mapping(target = "isFixedResistivity", source = "fixedResistivity") @Mapping(target = "isFixedPower", source = "fixedPower") public abstract ModelLayer toModel(ObservableModelLayer modelLayer); } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/fxmodel/ves/observable/ObservablePicket.kt b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/observable/ObservablePicket.kt new file mode 100644 index 00000000..ffc6905e --- /dev/null +++ b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/observable/ObservablePicket.kt @@ -0,0 +1,101 @@ +package ru.nucodelabs.gem.fxmodel.ves.observable + +import javafx.beans.property.DoubleProperty +import javafx.beans.property.SimpleDoubleProperty +import javafx.beans.property.SimpleStringProperty +import javafx.beans.property.StringProperty +import javafx.collections.FXCollections +import javafx.collections.ListChangeListener +import javafx.collections.ObservableList +import ru.nucodelabs.gem.fxmodel.ves.ObservableExperimentalData +import ru.nucodelabs.gem.fxmodel.ves.ObservableModelLayer +import ru.nucodelabs.geo.ves.* +import ru.nucodelabs.geo.ves.calc.orderByDistances +import ru.nucodelabs.kfx.observable.ConstrainedDoubleProperty +import tornadofx.getValue +import tornadofx.setValue + +class ObservablePicket : MutableExperimentalDataSet, ModelDataSet { + val nameProperty: StringProperty = SimpleStringProperty(Picket.DEFAULT_NAME) + var name by nameProperty + fun nameProperty() = nameProperty + + val rawExperimentalData: ObservableList = + FXCollections.observableArrayList { experimentalData -> + arrayOf( + experimentalData.ab2Property(), + experimentalData.mn2Property(), + experimentalData.amperageProperty(), + experimentalData.voltageProperty(), + experimentalData.resistivityApparentProperty(), + experimentalData.errorResistivityApparentProperty() + ) + } + + override val modelData: ObservableList = + FXCollections.observableArrayList().apply { + addListener(ListChangeListener { change -> + while (change.next()) { + if (change.wasAdded() && !Picket.isValidModelDataSize(change.list.size)) { + throw InvalidPropertiesException( + listOf( + InvalidPropertyValue("modelData.size", "", change.list.size) + ) + ) + } + } + }) + } + + val offsetXProperty: DoubleProperty = ConstrainedDoubleProperty(Picket.DEFAULT_X_OFFSET, Picket::isValidOffsetX) + override var offsetX by offsetXProperty + fun offsetXProperty() = offsetXProperty + + val modelZProperty: DoubleProperty = SimpleDoubleProperty(Picket.DEFAULT_Z) + override var modelZ by modelZProperty + fun modelZProperty() = modelZProperty + + val commentProperty: StringProperty = SimpleStringProperty(Picket.DEFAULT_COMMENT) + var comment by commentProperty + fun commentProperty() = commentProperty + + override val sortedExperimentalData: List = + rawExperimentalData.sorted(orderByDistances()).apply { + addListener(ListChangeListener { change -> + while (change.next()) { + when { + change.wasUpdated() -> handleExperimentalDataUpdate(change.list) + change.wasAdded() -> handleExperimentalDataUpdate(change.list) + change.wasReplaced() -> handleExperimentalDataUpdate(change.list) + } + } + }) + } + + private fun handleExperimentalDataUpdate(list: List) { + hideExtraSignalsInPlace(list) + } + + override val effectiveExperimentalData: List + get() = sortedExperimentalData.filter { !it.isHidden } + + override fun addSignal(signal: ObservableExperimentalData) { + rawExperimentalData.add(signal) + } + + override fun addSignals(signals: Iterable) { + rawExperimentalData.addAll(signals) + } + + override fun removeSignal(signal: ObservableExperimentalData) { + rawExperimentalData.remove(signal) + } + + override fun removeSignals(signals: Iterable) { + rawExperimentalData.removeAll(signals) + } + + override fun edit(index: Int, mutate: MutableExperimentalSignal.() -> Unit) { + rawExperimentalData[index].mutate() + } +} \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/fxmodel/ves/observable/ObservableSection.kt b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/observable/ObservableSection.kt new file mode 100644 index 00000000..bdff8c67 --- /dev/null +++ b/src/main/java/ru/nucodelabs/gem/fxmodel/ves/observable/ObservableSection.kt @@ -0,0 +1,10 @@ +package ru.nucodelabs.gem.fxmodel.ves.observable + +import javafx.collections.FXCollections +import javafx.collections.ObservableList +import ru.nucodelabs.geo.ves.SectionExperimentalDataSet + +class ObservableSection : SectionExperimentalDataSet { + val pickets: ObservableList = FXCollections.observableArrayList() + override fun pickets(): ObservableList = pickets +} \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/view/AlertsFactory.kt b/src/main/java/ru/nucodelabs/gem/view/AlertsFactory.kt index 691a4309..4ff3df86 100644 --- a/src/main/java/ru/nucodelabs/gem/view/AlertsFactory.kt +++ b/src/main/java/ru/nucodelabs/gem/view/AlertsFactory.kt @@ -4,29 +4,31 @@ import jakarta.inject.Inject import jakarta.validation.ConstraintViolation import javafx.scene.control.Alert import javafx.stage.Stage +import ru.nucodelabs.gem.config.slf4j import ru.nucodelabs.kfx.ext.currentWindow import ru.nucodelabs.kfx.ext.get import java.util.* class AlertsFactory @Inject constructor(private val uiProperties: ResourceBundle) { + val log = slf4j() + fun simpleAlert( title: String = uiProperties["error"], headerText: String = "", text: String, owner: Stage? = currentWindow() - ) = - Alert(Alert.AlertType.ERROR, text).apply { - this.title = title - this.headerText = headerText - initOwner(owner) - } + ) = Alert(Alert.AlertType.ERROR, text).apply { + this.title = title + this.headerText = headerText + initOwner(owner) + } fun uncaughtExceptionAlert(e: Throwable) = Alert(Alert.AlertType.ERROR, e.message).apply { title = uiProperties["error"] + headerText = uiProperties["saveAndRestart"] initOwner(currentWindow()) - headerText = "Сохраните важные данные и перезапустите программу" - } + }.also { log.warn("Uncaught exception alert", e) } @JvmOverloads fun simpleExceptionAlert(e: Throwable, owner: Stage? = currentWindow()): Alert = @@ -34,28 +36,35 @@ class AlertsFactory @Inject constructor(private val uiProperties: ResourceBundle title = uiProperties["error"] headerText = title initOwner(owner) - } + }.also { log.warn("Simple exception alert", e) } @JvmOverloads fun unsatisfiedLinkErrorAlert(e: UnsatisfiedLinkError, owner: Stage? = currentWindow()): Alert = Alert(Alert.AlertType.ERROR, e.message).apply { title = uiProperties["noLib"] - headerText = uiProperties["unableToDrawChart"] + headerText = uiProperties["saveAndRestart"] initOwner(owner) - } + }.also { log.warn("Unsatisfied link error", e) } @JvmOverloads fun incorrectFileAlert(e: Exception, owner: Stage? = currentWindow()): Alert = simpleExceptionAlert(e, owner).apply { headerText = uiProperties["fileError"] - } + }.also { log.warn("Incorrect file alert", e) } @JvmOverloads fun violationsAlert(violations: Set>, owner: Stage? = currentWindow()): Alert { val message = violations.joinToString("\n") { it.message } return Alert(Alert.AlertType.ERROR, message).apply { initOwner(owner) + }.also { log.warn("Validation violations alert: $message") } + } + + fun invalidInputAlert(message: String, owner: Stage? = currentWindow()): Alert { + return Alert(Alert.AlertType.WARNING, message).apply { + title = uiProperties["invalidInput"] + initOwner(owner) } } } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/view/color/ColorPalette.java b/src/main/java/ru/nucodelabs/gem/view/color/ColorPalette.java index 1d71ce77..88e5583b 100644 --- a/src/main/java/ru/nucodelabs/gem/view/color/ColorPalette.java +++ b/src/main/java/ru/nucodelabs/gem/view/color/ColorPalette.java @@ -5,7 +5,7 @@ import org.jetbrains.annotations.NotNull; import ru.nucodelabs.files.clr.ColorNode; import ru.nucodelabs.files.clr.RgbaColor; -import ru.nucodelabs.util.std.MathKt; +import ru.nucodelabs.util.MathKt; import java.util.ArrayList; import java.util.Arrays; @@ -143,10 +143,10 @@ private Segment blockFor(double percentage) { return segmentList.get((int) Math.floor(percentage / (1.0 / segmentList.size()))); } - private double percentageFor(double resistance) { - if (resistance < minValue) return 0.0; - if (resistance > maxValue) return 1.0; - return (resistance - minValue) / (maxValue - minValue); + private double percentageFor(double value) { + if (value < minValue) return 0.0; + if (value > maxValue) return 1.0; + return (value - minValue) / (maxValue - minValue); } private void checkLog() { diff --git a/src/main/java/ru/nucodelabs/gem/view/control/chart/AbstractMap.kt b/src/main/java/ru/nucodelabs/gem/view/control/chart/AbstractMap.kt index 07439d97..d9eed5a7 100644 --- a/src/main/java/ru/nucodelabs/gem/view/control/chart/AbstractMap.kt +++ b/src/main/java/ru/nucodelabs/gem/view/control/chart/AbstractMap.kt @@ -1,26 +1,53 @@ package ru.nucodelabs.gem.view.control.chart import javafx.beans.NamedArg +import javafx.beans.property.SimpleObjectProperty import javafx.scene.canvas.Canvas import javafx.scene.chart.ScatterChart import javafx.scene.chart.ValueAxis import javafx.scene.layout.Region +import ru.nucodelabs.gem.view.color.ColorMapper abstract class AbstractMap( @NamedArg("xAxis") xAxis: ValueAxis, - @NamedArg("yAxis") yAxis: ValueAxis + @NamedArg("yAxis") yAxis: ValueAxis, + @NamedArg("colorMapper") colorMapper: ColorMapper? = null ) : ScatterChart(xAxis, yAxis) { - private val plotArea = this.lookup(".chart-plot-background") as Region + private val _colorMapper = SimpleObjectProperty(colorMapper) + fun colorMapperProperty() = _colorMapper + var colorMapper: ColorMapper? + set(value) = _colorMapper.set(value) + get() = _colorMapper.get() - protected val canvas: Canvas = Canvas(plotArea.width, plotArea.height) + init { + colorMapperProperty().addListener { _, _, new -> + startListening(new) + onColorMapperChange() + } + startListening(colorMapper) + } + + private fun startListening(colorMapper: ColorMapper?) { + colorMapper?.minValueProperty()?.addListener { _, _, _ -> onColorMapperChange() } + colorMapper?.maxValueProperty()?.addListener { _, _, _ -> onColorMapperChange() } + colorMapper?.numberOfSegmentsProperty()?.addListener { _, _, _ -> onColorMapperChange() } + colorMapper?.logScaleProperty()?.addListener { _, _, _ -> onColorMapperChange() } + } + + protected val plotBackground = this.lookup(".chart-plot-background") as Region + + protected val backgroundCanvas: Canvas = Canvas(plotBackground.width, plotBackground.height) init { - plotChildren += canvas - canvas.layoutX = 0.0 - canvas.layoutY = 0.0 - canvas.widthProperty().bind(plotArea.widthProperty()) - canvas.heightProperty().bind(plotArea.heightProperty()) - canvas.viewOrder = 1.0 + plotChildren += backgroundCanvas + backgroundCanvas.layoutX = 0.0 + backgroundCanvas.layoutY = 0.0 + backgroundCanvas.widthProperty().bind(plotBackground.widthProperty()) + backgroundCanvas.heightProperty().bind(plotBackground.heightProperty()) + backgroundCanvas.managedProperty().bind(this.managedProperty()) + backgroundCanvas.viewOrder = 1.0 } + + protected abstract fun onColorMapperChange() } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/view/control/chart/CanvasRenderPolygonChart.kt b/src/main/java/ru/nucodelabs/gem/view/control/chart/CanvasRenderPolygonChart.kt new file mode 100644 index 00000000..48fea451 --- /dev/null +++ b/src/main/java/ru/nucodelabs/gem/view/control/chart/CanvasRenderPolygonChart.kt @@ -0,0 +1,73 @@ +package ru.nucodelabs.gem.view.control.chart + +import javafx.beans.NamedArg +import javafx.beans.property.BooleanProperty +import javafx.beans.property.ObjectProperty +import javafx.beans.property.SimpleBooleanProperty +import javafx.beans.property.SimpleObjectProperty +import javafx.scene.canvas.Canvas +import javafx.scene.chart.ValueAxis +import javafx.scene.paint.Color +import javafx.util.StringConverter +import ru.nucodelabs.gem.view.color.ColorMapper +import ru.nucodelabs.kfx.ext.clear +import tornadofx.getValue +import tornadofx.setValue + +class CanvasRenderPolygonChart @JvmOverloads constructor( + @NamedArg("xAxis") xAxis: ValueAxis, + @NamedArg("yAxis") yAxis: ValueAxis, + @NamedArg("colorMapper") colorMapper: ColorMapper? = null, +) : AbstractMap(xAxis, yAxis, colorMapper) { + + init { + animated = false + } + + private val extraValueFormatterProperty = SimpleObjectProperty?>(null).apply { + addListener { _, old, new -> render(backgroundCanvas) } + } + var extraValueFormatter: StringConverter? by extraValueFormatterProperty + + @Suppress("unused") + fun extraValueFormatterProperty(): ObjectProperty?> = extraValueFormatterProperty + + private val extraValueVisibleProperty = SimpleBooleanProperty(false).apply { + addListener { _, old, new -> render(backgroundCanvas) } + } + var extraValueVisible by extraValueVisibleProperty + fun extraValueVisibleProperty(): BooleanProperty = extraValueVisibleProperty + + override fun onColorMapperChange() = render(backgroundCanvas) + + override fun layoutPlotChildren() { + super.layoutPlotChildren() + render(backgroundCanvas) + } + + private fun render(canvas: Canvas) { + val graphics = canvas.graphicsContext2D + canvas.clear() + data.forEach { series -> + if (series.data.isEmpty()) return@forEach + val (xPoints, yPoints) = toPolygon(series) + val extraValue = series.data.first().extraValue as Number + val color = colorMapper?.colorFor(extraValue.toDouble()) ?: Color.WHITE + graphics.fill = color + graphics.fillPolygon(xPoints, yPoints, xPoints.size) + if (extraValueVisible) { + val text = extraValueFormatter?.toString(extraValue) ?: extraValue.toString() + val textX = xPoints.min() + val textY = yPoints.max() + graphics.fill = color.invert() + graphics.fillText(text, textX, textY) + } + } + } + + private fun toPolygon(series: Series): Pair { + val xPoints = series.data.map { xAxis.getDisplayPosition(it.xValue) }.toDoubleArray() + val yPoints = series.data.map { yAxis.getDisplayPosition(it.yValue) }.toDoubleArray() + return Pair(xPoints, yPoints) + } +} \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/view/control/chart/InterpolationMap.kt b/src/main/java/ru/nucodelabs/gem/view/control/chart/InterpolationMap.kt index 6cfa16ee..48d05f8b 100644 --- a/src/main/java/ru/nucodelabs/gem/view/control/chart/InterpolationMap.kt +++ b/src/main/java/ru/nucodelabs/gem/view/control/chart/InterpolationMap.kt @@ -2,7 +2,6 @@ package ru.nucodelabs.gem.view.control.chart import javafx.beans.NamedArg import javafx.beans.property.SimpleIntegerProperty -import javafx.beans.property.SimpleObjectProperty import javafx.scene.canvas.Canvas import javafx.scene.chart.ValueAxis import javafx.scene.effect.BlendMode @@ -20,9 +19,9 @@ class InterpolationMap @JvmOverloads constructor( @NamedArg("xAxis") xAxis: ValueAxis, @NamedArg("yAxis") yAxis: ValueAxis, @NamedArg("colorMapper") colorMapper: ColorMapper? = null -) : AbstractMap(xAxis, yAxis) { +) : AbstractMap(xAxis, yAxis, colorMapper) { - var canvasBlendMode: BlendMode by canvas.blendModeProperty() + var canvasBlendMode: BlendMode by backgroundCanvas.blendModeProperty() private val _interpolateSeriesIndex = SimpleIntegerProperty(0) @@ -46,27 +45,6 @@ class InterpolationMap @JvmOverloads constructor( } } - private val _colorMapper = SimpleObjectProperty(colorMapper) - fun colorMapperProperty() = _colorMapper - var colorMapper: ColorMapper? - set(value) = _colorMapper.set(value) - get() = _colorMapper.get() - - init { - colorMapperProperty().addListener { _, _, new -> - startListening(new) - redrawSnapshot() - } - startListening(colorMapper) - } - - private fun startListening(colorMapper: ColorMapper?) { - colorMapper?.minValueProperty()?.addListener { _, _, _ -> redrawSnapshot() } - colorMapper?.maxValueProperty()?.addListener { _, _, _ -> redrawSnapshot() } - colorMapper?.numberOfSegmentsProperty()?.addListener { _, _, _ -> redrawSnapshot() } - colorMapper?.logScaleProperty()?.addListener { _, _, _ -> redrawSnapshot() } - } - private lateinit var interpolator: Interpolator private var preparedData: List> = mutableListOf() @@ -75,6 +53,8 @@ class InterpolationMap @JvmOverloads constructor( if (needRedraw) redrawSnapshot() else layoutSnapshot() } + override fun onColorMapperChange() = redrawSnapshot() + private fun redrawSnapshot() { initInterpolator() needRedraw = false @@ -85,7 +65,13 @@ class InterpolationMap @JvmOverloads constructor( } private fun layoutSnapshot() { - canvas.graphicsContext2D.drawImage(snapshot, 0.0, 0.0, canvas.width, canvas.height) + backgroundCanvas.graphicsContext2D.drawImage( + snapshot, + 0.0, + 0.0, + backgroundCanvas.width, + backgroundCanvas.height + ) } override fun dataItemAdded(series: Series?, itemIndex: Int, item: Data?) { diff --git a/src/main/java/ru/nucodelabs/gem/view/control/chart/PolygonChart.kt b/src/main/java/ru/nucodelabs/gem/view/control/chart/PolygonChart.kt index 857113aa..667786f2 100644 --- a/src/main/java/ru/nucodelabs/gem/view/control/chart/PolygonChart.kt +++ b/src/main/java/ru/nucodelabs/gem/view/control/chart/PolygonChart.kt @@ -9,6 +9,10 @@ import javafx.scene.shape.Polygon * Draws polygons using points of each series. * To get polygons references use `seriesPolygons` map view. */ +@Deprecated( + "Use CanvasRenderPolygonChart", + ReplaceWith("CanvasRenderPolygonChart(xAxis, yAxis)") +) open class PolygonChart( @NamedArg("xAxis") xAxis: ValueAxis, @NamedArg("yAxis") yAxis: ValueAxis diff --git a/src/main/java/ru/nucodelabs/gem/view/control/chart/PolygonWithNamesChart.kt b/src/main/java/ru/nucodelabs/gem/view/control/chart/PolygonWithNamesChart.kt deleted file mode 100644 index a701e8cd..00000000 --- a/src/main/java/ru/nucodelabs/gem/view/control/chart/PolygonWithNamesChart.kt +++ /dev/null @@ -1,85 +0,0 @@ -package ru.nucodelabs.gem.view.control.chart - -import javafx.beans.NamedArg -import javafx.beans.property.BooleanProperty -import javafx.beans.property.SimpleBooleanProperty -import javafx.scene.chart.ValueAxis -import javafx.scene.effect.DropShadow -import javafx.scene.paint.Color -import javafx.scene.text.Font -import javafx.scene.text.Text -import tornadofx.getValue -import tornadofx.setValue - -class PolygonWithNamesChart( - @NamedArg("xAxis") xAxis: ValueAxis, - @NamedArg("yAxis") yAxis: ValueAxis -) : PolygonChart(xAxis, yAxis) { - - private val namesVisibleProperty = SimpleBooleanProperty(false) - var namesVisible by namesVisibleProperty - fun namesVisibleProperty(): BooleanProperty = namesVisibleProperty - - /** - * Maps series to corresponding Text node - */ - val seriesText: Map, Text> - get() = _seriesText - - private val _seriesText = mutableMapOf, Text>() - - private fun removeTextGroup(series: Series) { - plotChildren -= _seriesText[series] - _seriesText -= series - } - - override fun layoutPlotChildren() { - super.layoutPlotChildren() - setupTextAll() - } - - override fun seriesRemoved(series: Series) { - super.seriesRemoved(series) - removeTextGroup(series) - } - - override fun seriesAdded(series: Series, seriesIndex: Int) { - super.seriesAdded(series, seriesIndex) - setupText(series) - } - - private fun setupTextAll() { - for (series in data) { - setupText(series) - } - } - - private fun setupText(series: Series) { - val polygon = seriesPolygons[series] ?: return - - val xCoord = polygon.points[0] + 3 - val yCoord = polygon.points[1] + 10 - - val text = _seriesText[series] - if (text != null) { - text.x = xCoord - text.y = yCoord - } else { - val newText = Text(xCoord, yCoord, series.name ?: "").apply { - font = Font(11.0) - fill = Color.WHITE - effect = DropShadow(2.0, Color.BLACK) - textProperty().bind(series.nameProperty()) - managedProperty().bind(visibleProperty()) - isVisible = namesVisible - visibleProperty().bind(namesVisibleProperty) - } - plotChildren += newText - _seriesText[series] = newText - } - } -} - - - - diff --git a/src/main/java/ru/nucodelabs/gem/view/control/chart/SmartInterpolationMap.kt b/src/main/java/ru/nucodelabs/gem/view/control/chart/SmartInterpolationMap.kt index dd5818f0..c09656a8 100644 --- a/src/main/java/ru/nucodelabs/gem/view/control/chart/SmartInterpolationMap.kt +++ b/src/main/java/ru/nucodelabs/gem/view/control/chart/SmartInterpolationMap.kt @@ -1,37 +1,24 @@ package ru.nucodelabs.gem.view.control.chart import javafx.beans.NamedArg -import javafx.beans.property.ObjectProperty -import javafx.beans.property.SimpleObjectProperty import javafx.scene.chart.ValueAxis import ru.nucodelabs.gem.view.color.ColorMapper import ru.nucodelabs.geo.ves.calc.interpolation.ApacheInterpolator2D import ru.nucodelabs.geo.ves.calc.interpolation.RBFSpatialInterpolator import ru.nucodelabs.geo.ves.calc.interpolation.SmartInterpolator +// TODO: Optimize like InterpolationMap class SmartInterpolationMap( @NamedArg("xAxis") xAxis: ValueAxis, @NamedArg("yAxis") yAxis: ValueAxis, @NamedArg("colorMapper") colorMapper: ColorMapper? = null -) : AbstractMap(xAxis, yAxis) { +) : AbstractMap(xAxis, yAxis, colorMapper) { - private val _colorMapper = SimpleObjectProperty(colorMapper) private var interpolatorIsInitialized = false - fun colorMapperProperty(): ObjectProperty = _colorMapper - var colorMapper: ColorMapper? - set(value) = _colorMapper.set(value) - get() = _colorMapper.get() - - init { - colorMapperProperty().addListener { _, _, new -> - startListening(new) { draw() } - draw() - } - startListening(colorMapper) { draw() } - } - private val interpolator2D = SmartInterpolator(RBFSpatialInterpolator(), ApacheInterpolator2D()) + override fun onColorMapperChange() = draw() + override fun layoutPlotChildren() { super.layoutPlotChildren() if (!interpolatorIsInitialized) { @@ -61,6 +48,6 @@ class SmartInterpolationMap( } private fun draw() { - draw(canvas, xAxis, yAxis, interpolator2D, colorMapper) + draw(backgroundCanvas, xAxis, yAxis, interpolator2D, colorMapper) } } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/view/control/chart/log/LogarithmicAxis.kt b/src/main/java/ru/nucodelabs/gem/view/control/chart/log/LogarithmicAxis.kt index 96ef78f1..8ee600ea 100644 --- a/src/main/java/ru/nucodelabs/gem/view/control/chart/log/LogarithmicAxis.kt +++ b/src/main/java/ru/nucodelabs/gem/view/control/chart/log/LogarithmicAxis.kt @@ -9,7 +9,7 @@ import javafx.beans.property.DoubleProperty import javafx.beans.property.SimpleDoubleProperty import javafx.util.Duration import ru.nucodelabs.gem.view.control.chart.InvertibleValueAxis -import ru.nucodelabs.util.std.exp10 +import ru.nucodelabs.util.exp10 import kotlin.math.ceil import kotlin.math.floor import kotlin.math.log10 @@ -88,8 +88,10 @@ open class LogarithmicAxis @JvmOverloads constructor( tickMarksTextNodes.forEach { (mark, node) -> node.isVisible = mark.isTextVisible } } - private fun checkBounds(lowerBound: Double, upperBound: Double) = - require(lowerBound > 0 && upperBound > 0 && lowerBound <= upperBound) { "Lower: $lowerBound; Upper: $upperBound" } + /* + private fun checkBounds(lowerBound: Double, upperBound: Double) = + require(lowerBound > 0 && upperBound > 0 && lowerBound <= upperBound) { "Lower: $lowerBound; Upper: $upperBound" } + */ override fun calculateMinorTickMarks(): List { @@ -185,7 +187,7 @@ open class LogarithmicAxis @JvmOverloads constructor( ) lowerRangeTimeline.play() upperRangeTimeline.play() - } catch (e: Exception) { + } catch (_: Exception) { lowerBoundProperty().set(lowerBound.toDouble()) upperBoundProperty().set(upperBound.toDouble()) } diff --git a/src/main/java/ru/nucodelabs/gem/view/control/chart/log/LogarithmicChartNavigationSupport.kt b/src/main/java/ru/nucodelabs/gem/view/control/chart/log/LogarithmicChartNavigationSupport.kt index d90c834d..957145fe 100644 --- a/src/main/java/ru/nucodelabs/gem/view/control/chart/log/LogarithmicChartNavigationSupport.kt +++ b/src/main/java/ru/nucodelabs/gem/view/control/chart/log/LogarithmicChartNavigationSupport.kt @@ -2,7 +2,7 @@ package ru.nucodelabs.gem.view.control.chart.log import javafx.scene.chart.ValueAxis import ru.nucodelabs.kfx.ext.length -import ru.nucodelabs.util.std.exp10 +import ru.nucodelabs.util.exp10 import kotlin.math.log10 import kotlin.math.max import kotlin.math.min diff --git a/src/main/java/ru/nucodelabs/gem/view/control/chart/log/PseudoLogarithmicAxis.kt b/src/main/java/ru/nucodelabs/gem/view/control/chart/log/PseudoLogarithmicAxis.kt index 998d5f0b..b99b826a 100644 --- a/src/main/java/ru/nucodelabs/gem/view/control/chart/log/PseudoLogarithmicAxis.kt +++ b/src/main/java/ru/nucodelabs/gem/view/control/chart/log/PseudoLogarithmicAxis.kt @@ -1,7 +1,7 @@ package ru.nucodelabs.gem.view.control.chart.log import javafx.beans.NamedArg -import ru.nucodelabs.util.std.exp10 +import ru.nucodelabs.util.exp10 import kotlin.math.* class PseudoLogarithmicAxis @JvmOverloads constructor( @@ -16,8 +16,10 @@ class PseudoLogarithmicAxis @JvmOverloads constructor( // checkBounds(lowerBound, upperBound) } - private fun checkBounds(lowerBound: Double, upperBound: Double) = - require(upperBound >= lowerBound) + /* + private fun checkBounds(lowerBound: Double, upperBound: Double) = + require(upperBound >= lowerBound) + */ @Suppress("UNCHECKED_CAST") override fun calculateTickValues(length: Double, range: Any?): List { diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/AbstractController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/AbstractController.kt index 2d898e92..43a68b2c 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/AbstractController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/AbstractController.kt @@ -1,10 +1,7 @@ package ru.nucodelabs.gem.view.controller -import javafx.fxml.FXML import javafx.fxml.Initializable import javafx.stage.Stage -import java.net.URL -import java.util.* /** * Контроллер, который не только инициализируется FXML-загрузчиком, но и знает как добыть свою сцену @@ -18,13 +15,4 @@ import java.util.* ) abstract class AbstractController : Initializable { protected abstract val stage: Stage? - - @FXML - protected var fxScriptInit: Runnable = Runnable {} - - override fun initialize(location: URL, resources: ResourceBundle) { - fxScriptInit() - } - - protected fun fxScriptInit() = fxScriptInit.run() } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/anisotropy/main/AnisotropyMainViewController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/anisotropy/main/AnisotropyMainViewController.kt index 90003207..0a0a3189 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/anisotropy/main/AnisotropyMainViewController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/anisotropy/main/AnisotropyMainViewController.kt @@ -37,7 +37,7 @@ import ru.nucodelabs.gem.view.mapping.mapSignals import ru.nucodelabs.gem.view.mapping.mapSignalsRelations import ru.nucodelabs.kfx.core.AbstractViewController import ru.nucodelabs.kfx.ext.* -import ru.nucodelabs.util.std.toDoubleOrNullBy +import ru.nucodelabs.util.toDoubleOrNullBy import java.io.File import java.net.URL import java.text.DecimalFormat @@ -93,7 +93,7 @@ class AnisotropyMainViewController @Inject constructor( private lateinit var zCol: TableColumn @FXML - private lateinit var resistanceCol: TableColumn + private lateinit var resistivityCol: TableColumn @FXML private lateinit var powerCol: TableColumn @@ -126,7 +126,7 @@ class AnisotropyMainViewController @Inject constructor( private lateinit var vesCurvesAxisY: NucodeNumberAxis @FXML - lateinit var azimuthDropdown: ComboBox + private lateinit var azimuthDropdown: ComboBox @FXML private lateinit var transparencySlider: Slider @@ -143,10 +143,10 @@ class AnisotropyMainViewController @Inject constructor( private lateinit var amperageCol: TableColumn @FXML - private lateinit var errorResistanceCol: TableColumn + private lateinit var errorResistivityCol: TableColumn @FXML - private lateinit var resistanceApparentCol: TableColumn + private lateinit var resistivityApparentCol: TableColumn @FXML private lateinit var mn2Col: TableColumn @@ -184,7 +184,6 @@ class AnisotropyMainViewController @Inject constructor( lateinit var signalsInterpolation: SmartInterpolationMap override fun initialize(location: URL, resources: ResourceBundle) { - super.initialize(location, resources) initControls() initAndSetupListeners() } @@ -332,7 +331,7 @@ class AnisotropyMainViewController @Inject constructor( ) modelIndexCol.cellFactory = indexCellFactory() powerCol.cellValueFactory = Callback { features -> features.value.power.valueProperty() } - resistanceCol.cellValueFactory = Callback { features -> features.value.resistance.valueProperty() } + resistivityCol.cellValueFactory = Callback { features -> features.value.resistivity.valueProperty() } verticalAnisotropyCoefCol.cellValueFactory = Callback { features -> features.value.verticalAnisotropyCoefficient.valueProperty() } azimuthAnisotropyCoefCol.cellValueFactory = @@ -361,7 +360,7 @@ class AnisotropyMainViewController @Inject constructor( val editableColumns = listOf( powerCol, - resistanceCol, + resistivityCol, verticalAnisotropyCoefCol, azimuthAnisotropyCoefCol, azimuthCol @@ -380,9 +379,9 @@ class AnisotropyMainViewController @Inject constructor( } } - resistanceCol -> indexProperty().addListener { _, _, _ -> + resistivityCol -> indexProperty().addListener { _, _, _ -> if (index >= 0 && index <= appModel.observablePoint.model.lastIndex) { - style = if (appModel.observablePoint.model[index].resistance.isFixed) { + style = if (appModel.observablePoint.model[index].resistivity.isFixed) { STYLE_FOR_FIXED } else { "" @@ -451,10 +450,10 @@ class AnisotropyMainViewController @Inject constructor( isHiddenCol.cellValueFactory = Callback { features -> features.value.hiddenProperty().bidirectionalNot() } ab2Col.cellValueFactory = Callback { features -> features.value.ab2Property().asObject() } mn2Col.cellValueFactory = Callback { features -> features.value.mn2Property().asObject() } - resistanceApparentCol.cellValueFactory = - Callback { features -> features.value.resistanceApparentProperty().asObject() } - errorResistanceCol.cellValueFactory = - Callback { features -> features.value.errorResistanceApparentProperty().asObject() } + resistivityApparentCol.cellValueFactory = + Callback { features -> features.value.resistivityApparentProperty().asObject() } + errorResistivityCol.cellValueFactory = + Callback { features -> features.value.errorResistivityApparentProperty().asObject() } amperageCol.cellValueFactory = Callback { features -> features.value.amperageProperty().asObject() } voltageCol.cellValueFactory = Callback { features -> features.value.voltageProperty().asObject() } } @@ -467,8 +466,8 @@ class AnisotropyMainViewController @Inject constructor( val editableColumns = listOf( ab2Col, mn2Col, - resistanceApparentCol, - errorResistanceCol, + resistivityApparentCol, + errorResistivityCol, amperageCol, voltageCol ) @@ -524,7 +523,7 @@ class AnisotropyMainViewController @Inject constructor( val index = pointIndex / 2 val ab2 = appModel.observablePoint.azimuthSignals[seriesIndex].signals.effectiveSignals[index].ab2 val mn2 = appModel.observablePoint.azimuthSignals[seriesIndex].signals.effectiveSignals[index].mn2 - val resistance = point.extraValue as Double + val resistivity = point.extraValue as Double val azimuth: Double = if (pointIndex % 2 == 0) { appModel.observablePoint.azimuthSignals[seriesIndex].azimuth } else { @@ -534,10 +533,10 @@ class AnisotropyMainViewController @Inject constructor( № ${index + 1} AB/2 = ${df.format(ab2)} m MN/2 = ${df.format(mn2)} m - ρₐ = ${df.format(resistance)} Ω‧m + ρₐ = ${df.format(resistivity)} Ω‧m Азимут = ${df.format(azimuth)} ° """.trimIndent() - return Tooltip(tooltipText).forCharts() + return Tooltip(tooltipText).shownOnHover() } @Suppress("unused") @@ -553,7 +552,7 @@ class AnisotropyMainViewController @Inject constructor( AB/2 = ${df.format(point.xValue)} m Отношение = ${df.format(point.yValue)} """.trimIndent() - ).forCharts() + ).shownOnHover() } @Suppress("unused") @@ -566,21 +565,21 @@ class AnisotropyMainViewController @Inject constructor( val signal = point.extraValue as ObservableSignal val ab2 = signal.ab2 val mn2 = signal.mn2 - val resistance = signal.resistanceApparent + val resistivity = signal.resistivityApparent return Tooltip( """ № ${pointIndex + 1} AB/2 = ${df.format(ab2)} m MN/2 = ${df.format(mn2)} m - ρₐ = ${df.format(resistance)} Ω‧m + ρₐ = ${df.format(resistivity)} Ω‧m """.trimIndent() - ).forCharts() + ).shownOnHover() } @FXML private fun loadProject() { - val file: File? = fileChooser.showOpenDialog(stage) + val file: File? = fileChooser.showOpenDialog(rootStage()) if (file != null) { saveInitialDirectory(preferences, JSON_FILES_DIR, fileChooser, file) validation(alertsFactory) { @@ -592,7 +591,7 @@ class AnisotropyMainViewController @Inject constructor( @FXML private fun saveProject() { - val file: File? = fileChooser.showSaveDialog(stage) + val file: File? = fileChooser.showSaveDialog(rootStage()) if (file != null) { saveInitialDirectory(preferences, JSON_FILES_DIR, fileChooser, file) appModel.saveProject(file) diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/charts/ColorAxisController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/charts/ColorAxisController.kt index 232136e2..15781f21 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/charts/ColorAxisController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/charts/ColorAxisController.kt @@ -26,7 +26,7 @@ import ru.nucodelabs.gem.view.control.chart.log.LogarithmicAxis import ru.nucodelabs.kfx.core.AbstractViewController import ru.nucodelabs.kfx.ext.* import ru.nucodelabs.kfx.pref.FXPreferences -import ru.nucodelabs.util.std.toDoubleOrNullBy +import ru.nucodelabs.util.toDoubleOrNullBy import tornadofx.div import tornadofx.minus import java.net.URL diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/charts/CurvesPseudoSectionController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/charts/CurvesPseudoSectionController.kt index 68bbe0bf..b8d0206b 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/charts/CurvesPseudoSectionController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/charts/CurvesPseudoSectionController.kt @@ -12,8 +12,8 @@ import ru.nucodelabs.gem.fxmodel.ves.ObservableSection import ru.nucodelabs.geo.ves.ExperimentalData import ru.nucodelabs.geo.ves.calc.effectiveToSortedIndicesMapping import ru.nucodelabs.geo.ves.calc.graph.CurvesSectionGraphContext -import ru.nucodelabs.kfx.ext.forCharts import ru.nucodelabs.kfx.ext.installTooltips +import ru.nucodelabs.kfx.ext.shownOnHover import ru.nucodelabs.kfx.ext.toObservableList import java.net.URL import java.text.DecimalFormat @@ -67,13 +67,13 @@ class CurvesPseudoSectionController @Inject constructor( val pair = pointMap[point] val n = pair?.first?.plus(1) val ab2 = decimalFormat.format(pair?.second?.ab2) - val res = decimalFormat.format(pair?.second?.resistanceApparent) + val res = decimalFormat.format(pair?.second?.resistivityApparent) return Tooltip( """ №$n AB/2 = $ab2 m ρₐ = $res Ω‧m """.trimIndent() - ).forCharts() + ).shownOnHover() } } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/charts/MapPseudoSectionController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/charts/MapPseudoSectionController.kt index 92985b5a..85f7f4d6 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/charts/MapPseudoSectionController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/charts/MapPseudoSectionController.kt @@ -14,8 +14,8 @@ import ru.nucodelabs.gem.view.color.ColorMapper import ru.nucodelabs.gem.view.control.chart.InterpolationMap import ru.nucodelabs.geo.ves.calc.effectiveToSortedIndicesMapping import ru.nucodelabs.geo.ves.calc.xOfPicket -import ru.nucodelabs.kfx.ext.forCharts import ru.nucodelabs.kfx.ext.installTooltips +import ru.nucodelabs.kfx.ext.shownOnHover import ru.nucodelabs.kfx.ext.toObservableList import java.net.URL import java.text.DecimalFormat @@ -52,14 +52,14 @@ class MapPseudoSectionController @Inject constructor( val section = observableSection.asSection() val data: MutableList> = mutableListOf() - for (picket in section.pickets) { + for ((picketIdx, picket) in section.pickets.withIndex()) { val indexMapping = picket.effectiveToSortedIndicesMapping() for ((index, expData) in picket.effectiveExperimentalData.withIndex()) { data.add( Data( - section.xOfPicket(picket) as Number, + section.xOfPicket(picketIdx) as Number, expData.ab2 as Number, - expData.resistanceApparent + expData.resistivityApparent ).also { pointMap += it to indexMapping[index] } ) } @@ -81,6 +81,6 @@ class MapPseudoSectionController @Inject constructor( AB/2 = ${decimalFormat.format(point.yValue)} m ρₐ = ${decimalFormat.format(point.extraValue)} Ω‧m """.trimIndent() - ).forCharts() + ).shownOnHover() } } diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/charts/MisfitStacksController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/charts/MisfitStacksController.kt index 14dd248b..b8b0c600 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/charts/MisfitStacksController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/charts/MisfitStacksController.kt @@ -1,11 +1,7 @@ package ru.nucodelabs.gem.view.controller.charts import jakarta.inject.Inject -import javafx.beans.property.ObjectProperty -import javafx.beans.property.SimpleObjectProperty import javafx.beans.value.ObservableObjectValue -import javafx.collections.FXCollections -import javafx.collections.ObservableList import javafx.fxml.FXML import javafx.scene.chart.LineChart import javafx.scene.chart.NumberAxis @@ -17,15 +13,13 @@ import javafx.scene.image.Image import javafx.scene.image.ImageView import javafx.scene.layout.VBox import ru.nucodelabs.gem.fxmodel.ves.app.VesFxAppModel -import ru.nucodelabs.gem.view.AlertsFactory import ru.nucodelabs.gem.view.control.chart.log.LogarithmicAxis import ru.nucodelabs.geo.ves.Picket import ru.nucodelabs.geo.ves.calc.graph.experimentalCurve import ru.nucodelabs.kfx.core.AbstractViewController import ru.nucodelabs.kfx.ext.Point -import ru.nucodelabs.kfx.ext.forCharts import ru.nucodelabs.kfx.ext.line -import ru.nucodelabs.kfx.ext.observableListOf +import ru.nucodelabs.kfx.ext.shownOnHover import java.math.RoundingMode import java.net.URL import java.text.DecimalFormat @@ -48,11 +42,9 @@ const val ERROR_FORMULA_IMAGE_PATH = "/img/error.png" class MisfitStacksController @Inject constructor( private val picketObservable: ObservableObjectValue, - private val alertsFactory: AlertsFactory, private val decimalFormat: DecimalFormat, private val appModel: VesFxAppModel, ) : AbstractViewController() { - private val dataProperty = emptyData() @FXML private lateinit var targetFunctionText: Label @@ -75,65 +67,53 @@ class MisfitStacksController @Inject constructor( private val picket: Picket get() = picketObservable.get()!! + private val format4FracDigits = DecimalFormat("#.####").apply { roundingMode = RoundingMode.HALF_UP } + override fun initialize(location: URL, resources: ResourceBundle) { picketObservable.addListener { _, _, newValue: Picket? -> if (newValue != null) { update() } } - lineChart.dataProperty().bind(dataProperty) installTooltipForTerms() } private fun update() { - var misfitStacksSeriesList: MutableList> = ArrayList() - try { - val misfits = appModel.misfits() - val expPoints = experimentalCurve(picket) - - misfitStacksSeriesList = observableListOf() - - if (picket.effectiveExperimentalData.isNotEmpty() && picket.modelData.isNotEmpty()) { - check(misfits.size == expPoints.size) - - for ((index, expPoint) in expPoints.withIndex()) { - misfitStacksSeriesList += line( - Point(expPoint.x as Number, 0.0 as Number), - Point(expPoint.x as Number, misfits[index] as Number) - ) - } - - val targetFunction = appModel.targetFunction() - val (misfitsAvg, misfitsMax) = appModel.misfitsAvgMax() - val (errorAvg, errorMax) = appModel.errorAvgMax() - - val dfTwo = DecimalFormat("#.##").apply { roundingMode = RoundingMode.HALF_UP } - val dfFour = DecimalFormat("#.####").apply { roundingMode = RoundingMode.HALF_UP } - - targetFunctionText.text = - "целевая функция: f = ${dfFour.format(targetFunction)}" - misfitText.text = - "отклонение: avg = ${dfTwo.format(misfitsAvg)}%, max = ${dfTwo.format(misfitsMax)}%" - errorText.text = - "погрешность: avg = ${dfTwo.format(errorAvg)}% , max = ${dfTwo.format(errorMax)}%" + val misfitStacksSeriesList: MutableList> = ArrayList() + val misfits = appModel.misfits() + val expPoints = experimentalCurve(picket) + + if (picket.effectiveExperimentalData.isNotEmpty() && picket.modelData.isNotEmpty()) { + check(misfits.size == expPoints.size) + + for ((index, expPoint) in expPoints.withIndex()) { + misfitStacksSeriesList += line( + Point(expPoint.x as Number, 0.0 as Number), + Point(expPoint.x as Number, misfits[index] as Number) + ) } - } catch (e: UnsatisfiedLinkError) { - alertsFactory.unsatisfiedLinkErrorAlert(e, stage).show() - } catch (e: IllegalStateException) { - alertsFactory.simpleExceptionAlert(e, stage).show() + val targetFunction = appModel.targetFunctionValue() + val (misfitsAvg, misfitsMax) = appModel.misfitsAvgMax() + val (errorAvg, errorMax) = appModel.errorAvgMax() + + targetFunctionText.text = + "целевая функция: f = ${format4FracDigits.format(targetFunction)}" + misfitText.text = + "отклонение: avg = ${decimalFormat.format(misfitsAvg)}%, max = ${decimalFormat.format(misfitsMax)}%" + errorText.text = + "погрешность: avg = ${decimalFormat.format(errorAvg)}% , max = ${decimalFormat.format(errorMax)}%" } - dataProperty.get().clear() - dataProperty.get() += misfitStacksSeriesList + lineChart.data.setAll(misfitStacksSeriesList) colorizeMisfitStacksSeries() installTooltips() } private fun installTooltips() { - dataProperty.get().forEach { + lineChart.data.forEach { val text = "${decimalFormat.format(it.data[1].yValue)}%" - Tooltip.install(it.node, Tooltip(text).forCharts()) - it.data.forEach { p -> Tooltip.install(p.node, Tooltip(text).forCharts()) } + Tooltip.install(it.node, Tooltip(text).shownOnHover()) + it.data.forEach { p -> Tooltip.install(p.node, Tooltip(text).shownOnHover()) } } } @@ -145,7 +125,7 @@ class MisfitStacksController @Inject constructor( tooltipForTargetFunction.text = TARGET_FUNCTION_DESCRIPTION tooltipForTargetFunction.graphic = ImageView(imageForTargetFunction) tooltipForTargetFunction.contentDisplay = ContentDisplay.BOTTOM - Tooltip.install(targetFunctionText, tooltipForTargetFunction.forCharts()) + Tooltip.install(targetFunctionText, tooltipForTargetFunction.shownOnHover()) val imageForMisfit = Image( javaClass.getResourceAsStream(MISFIT_FORMULA_IMAGE_PATH) @@ -154,7 +134,7 @@ class MisfitStacksController @Inject constructor( tooltipForMisfit.text = MISFIT_DESCRIPTION tooltipForMisfit.graphic = ImageView(imageForMisfit) tooltipForMisfit.contentDisplay = ContentDisplay.BOTTOM - Tooltip.install(misfitText, tooltipForMisfit.forCharts()) + Tooltip.install(misfitText, tooltipForMisfit.shownOnHover()) val imageForError = Image( javaClass.getResourceAsStream(ERROR_FORMULA_IMAGE_PATH) @@ -163,11 +143,11 @@ class MisfitStacksController @Inject constructor( tooltipForError.text = ERROR_DESCRIPTION tooltipForError.graphic = ImageView(imageForError) tooltipForError.contentDisplay = ContentDisplay.BOTTOM - Tooltip.install(errorText, tooltipForError.forCharts()) + Tooltip.install(errorText, tooltipForError.shownOnHover()) } private fun colorizeMisfitStacksSeries() { - val data = dataProperty.get() + val data = lineChart.data for (series in data) { val nonZeroPoint = series.data[1] if (abs(nonZeroPoint.yValue.toDouble()) < 100.0) { @@ -178,10 +158,4 @@ class MisfitStacksController @Inject constructor( } } } -} - -fun emptyData(): ObjectProperty>> = SimpleObjectProperty( - FXCollections.observableArrayList( - ArrayList() - ) -) +} \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/charts/ModelCurveDragger.kt b/src/main/java/ru/nucodelabs/gem/view/controller/charts/ModelCurveDragger.kt index 09957afa..a35e8146 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/charts/ModelCurveDragger.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/charts/ModelCurveDragger.kt @@ -29,7 +29,7 @@ class ModelCurveDragger val yAxis: ValueAxis ) { // mapping: point on chart --> index of the value in data model arrays - private lateinit var pointResistanceMap: MutableMap, Int> + private lateinit var pointResistMap: MutableMap, Int> private lateinit var pointPowerMap: MutableMap, Int> // ends of line to be dragged @@ -91,7 +91,7 @@ class ModelCurveDragger if (point1 != null && point2 != null) { val style = """ -fx-background-color: blue; - """ + """.trim() point1!!.node.lookup(".chart-line-symbol").style = style point2!!.node.lookup(".chart-line-symbol").style = style } @@ -147,11 +147,11 @@ class ModelCurveDragger } else if (point1!!.yValue == point2!!.yValue // горизонтальная линия && mouseY > lowerLimitY ) { - val index = pointResistanceMap[point1!!]!! + val index = pointResistMap[point1!!]!! point1!!.yValue = mouseY point2!!.yValue = mouseY - mutableModelData[index] = mutableModelData[index].copy(resistance = mouseY) + mutableModelData[index] = mutableModelData[index].copy(resistivity = mouseY) } } @@ -165,22 +165,22 @@ class ModelCurveDragger */ private fun mapModelData(modelData: List) { val errMsg = "ModelData array size: %d does not match mapping size: %d" - pointResistanceMap = HashMap() + pointResistMap = HashMap() val points = vesCurvesData.get()[modelCurveIndex].data run { var i = 0 var j = 0 while (i < points.size) { - pointResistanceMap[points[i]] = j - pointResistanceMap[points[i + 1]] = j + pointResistMap[points[i]] = j + pointResistMap[points[i + 1]] = j i += 2 j++ } } - require(pointResistanceMap.values.stream().distinct().count() == modelData.size.toLong()) { + require(pointResistMap.values.stream().distinct().count() == modelData.size.toLong()) { String.format( errMsg, - pointResistanceMap.values.stream().distinct().count(), + pointResistMap.values.stream().distinct().count(), modelData.size ) } diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/charts/ModelSectionController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/charts/ModelSectionController.kt index 7c829208..f2de092f 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/charts/ModelSectionController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/charts/ModelSectionController.kt @@ -10,9 +10,9 @@ import javafx.stage.Stage import javafx.util.StringConverter import ru.nucodelabs.gem.fxmodel.ves.ObservableSection import ru.nucodelabs.gem.view.color.ColorMapper +import ru.nucodelabs.gem.view.control.chart.CanvasRenderPolygonChart import ru.nucodelabs.gem.view.control.chart.InvertibleValueAxis import ru.nucodelabs.gem.view.control.chart.NucodeNumberAxis -import ru.nucodelabs.gem.view.control.chart.PolygonWithNamesChart import ru.nucodelabs.gem.view.controller.AbstractController import ru.nucodelabs.gem.view.controller.charts.ModelSectionController.PicketDependencies.Factory.dependenciesOf import ru.nucodelabs.geo.ves.ExperimentalData @@ -25,7 +25,6 @@ import ru.nucodelabs.kfx.ext.observableListOf import java.math.MathContext import java.math.RoundingMode import java.net.URL -import java.text.DecimalFormat import java.util.* import kotlin.math.abs @@ -34,8 +33,7 @@ private const val LAST_COEF = 0.5 class ModelSectionController @Inject constructor( private val observableSection: ObservableSection, private val colorMapper: ColorMapper, - private val formatter: StringConverter, - private val df: DecimalFormat + private val formatter: StringConverter ) : AbstractController() { /** @@ -67,12 +65,14 @@ class ModelSectionController @Inject constructor( private lateinit var xAxis: NucodeNumberAxis @FXML - private lateinit var chart: PolygonWithNamesChart + lateinit var chart: CanvasRenderPolygonChart override val stage: Stage? get() = chart.scene.window as Stage? override fun initialize(location: URL, resources: ResourceBundle) { + chart.colorMapper = this.colorMapper + chart.extraValueFormatter = formatter yAxis.tickLabelFormatter = formatter xAxis.tickLabelFormatter = formatter @@ -89,11 +89,6 @@ class ModelSectionController @Inject constructor( } } }) - - colorMapper.maxValueProperty().addListener { _, _, _ -> update() } - colorMapper.minValueProperty().addListener { _, _, _ -> update() } - colorMapper.numberOfSegmentsProperty().addListener { _, _, _ -> update() } - colorMapper.logScaleProperty().addListener { _, _, _ -> update() } } private fun update() { @@ -101,14 +96,14 @@ class ModelSectionController @Inject constructor( setupXAxisMarks() setupYAxisBounds() - chart.data.clear() - if (observableSection.pickets.isEmpty()) { + chart.data.clear() return } val lowerBoundZ = zWithVirtualLastLayers().minOfOrNull { it.minOrNull() ?: 0.0 } ?: 0.0 + val chartData = ArrayList>() for ((index, bounds) in observableSection.asSection().picketsBounds().withIndex()) { val picket = observableSection.pickets[index] if (picket.modelData.isEmpty()) { @@ -131,24 +126,21 @@ class ModelSectionController @Inject constructor( picket.modelData[i].power } + val resistivity = picket.modelData[i].resistivity val series: Series = Series( observableListOf( - Data(x, y), - Data(x + width, y), - Data(x + width, y - height), - Data(x, y - height) + Data(x, y, resistivity), + Data(x + width, y, resistivity), + Data(x + width, y - height, resistivity), + Data(x, y - height, resistivity) ) ) - chart.data += series - series.name = df.format(picket.modelData[i].resistance) - chart.seriesPolygons[series]?.apply { fill = colorMapper.colorFor(picket.modelData[i].resistance) } + chartData += series } } - } - fun setupNames(boolean: Boolean) { - chart.namesVisibleProperty().set(boolean) + chart.data.setAll(chartData) } private fun setupXAxisMarks() { diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/charts/ModelSectionSwitcherController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/charts/ModelSectionSwitcherController.kt index ddaab82b..3d8507f0 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/charts/ModelSectionSwitcherController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/charts/ModelSectionSwitcherController.kt @@ -9,12 +9,12 @@ import javafx.scene.control.ContextMenu import javafx.scene.control.MenuItem import javafx.scene.layout.VBox import javafx.stage.FileChooser -import javafx.stage.Stage import ru.nucodelabs.gem.app.pref.PNG_FILES_DIR import ru.nucodelabs.gem.config.Name -import ru.nucodelabs.gem.view.controller.AbstractController -import ru.nucodelabs.kfx.ext.bindTo +import ru.nucodelabs.kfx.core.AbstractViewController +import ru.nucodelabs.kfx.ext.hide import ru.nucodelabs.kfx.ext.saveSnapshotAsPng +import ru.nucodelabs.kfx.ext.switch import java.net.URL import java.util.* import java.util.prefs.Preferences @@ -22,7 +22,7 @@ import java.util.prefs.Preferences class ModelSectionSwitcherController @Inject constructor( @Named(Name.File.PNG) private val fc: FileChooser, private val prefs: Preferences -) : AbstractController() { +) : AbstractViewController() { @FXML private lateinit var logSectionBox: VBox @@ -35,30 +35,20 @@ class ModelSectionSwitcherController @Inject constructor( @FXML lateinit var linearSectionBoxController: ModelSectionController - override val stage: Stage? - get() = linearSectionBox.scene?.window as Stage? - override fun initialize(location: URL, resources: ResourceBundle) { - logSectionBox.managedProperty() bindTo logSectionBox.visibleProperty() - linearSectionBox.managedProperty() bindTo linearSectionBox.visibleProperty() - - logSectionBox.isVisible = false - logSectionBox.visibleProperty() bindTo linearSectionBox.visibleProperty().not() - linearSectionBox.isVisible = true + logSectionBoxController.chart.extraValueVisibleProperty() + .bindBidirectional(linearSectionBoxController.chart.extraValueVisibleProperty()) + hide(logSectionBox) logSectionBox.apply { val contextMenu = ContextMenu( MenuItem("Переключить на линейный масштаб").apply { - onAction = EventHandler { linearSectionBox.isVisible = true } + onAction = EventHandler { switch(logSectionBox, linearSectionBox) } }, - CheckMenuItem("Показывать сопротивления").apply{ + CheckMenuItem("Показывать сопротивления").apply { isSelected = false - onAction = if (!this.isSelected){ - EventHandler { logSectionBoxController.setupNames(this.isSelected)} - - }else { - EventHandler { logSectionBoxController.setupNames(this.isSelected) } - } + selectedProperty() + .bindBidirectional(logSectionBoxController.chart.extraValueVisibleProperty()) }, MenuItem("Сохранить как изображение").apply { onAction = EventHandler { @@ -77,16 +67,12 @@ class ModelSectionSwitcherController @Inject constructor( linearSectionBox.apply { val contextMenu = ContextMenu( MenuItem("Переключить на псевдо-логарифмический масштаб").apply { - onAction = EventHandler { linearSectionBox.isVisible = false } + onAction = EventHandler { switch(linearSectionBox, logSectionBox) } }, - CheckMenuItem("Показывать сопротивления").apply{ + CheckMenuItem("Показывать сопротивления").apply { isSelected = false - onAction = if (!this.isSelected){ - EventHandler { linearSectionBoxController.setupNames(this.isSelected)} - - }else { - EventHandler { linearSectionBoxController.setupNames(this.isSelected) } - } + selectedProperty() + .bindBidirectional(linearSectionBoxController.chart.extraValueVisibleProperty()) }, MenuItem("Сохранить как изображение").apply { onAction = EventHandler { diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/charts/VesCurvesController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/charts/VesCurvesController.kt index a0832cd8..bd0b4f60 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/charts/VesCurvesController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/charts/VesCurvesController.kt @@ -16,28 +16,27 @@ import javafx.scene.chart.XYChart.Series import javafx.scene.control.* import javafx.scene.input.MouseEvent import javafx.scene.input.ScrollEvent +import javafx.scene.layout.VBox import javafx.stage.FileChooser -import javafx.stage.Stage import javafx.util.StringConverter import ru.nucodelabs.gem.app.pref.PNG_FILES_DIR import ru.nucodelabs.gem.config.Name import ru.nucodelabs.gem.config.Style import ru.nucodelabs.gem.fxmodel.ves.ObservableSection -import ru.nucodelabs.gem.view.AlertsFactory import ru.nucodelabs.gem.view.control.chart.log.LogarithmicAxis import ru.nucodelabs.gem.view.control.chart.log.LogarithmicChartNavigationSupport -import ru.nucodelabs.gem.view.controller.AbstractController import ru.nucodelabs.geo.forward.ForwardSolver import ru.nucodelabs.geo.ves.Picket import ru.nucodelabs.geo.ves.Section import ru.nucodelabs.geo.ves.calc.effectiveToSortedIndicesMapping import ru.nucodelabs.geo.ves.calc.graph.* -import ru.nucodelabs.geo.ves.calc.resistanceApparentLowerBoundByError -import ru.nucodelabs.geo.ves.calc.resistanceApparentUpperBoundByError +import ru.nucodelabs.geo.ves.calc.resistivityApparentLowerBoundByError +import ru.nucodelabs.geo.ves.calc.resistivityApparentUpperBoundByError import ru.nucodelabs.geo.ves.calc.zOfModelLayers +import ru.nucodelabs.kfx.core.AbstractViewController import ru.nucodelabs.kfx.ext.* import ru.nucodelabs.kfx.snapshot.HistoryManager -import ru.nucodelabs.util.std.exp10 +import ru.nucodelabs.util.exp10 import java.lang.Double.max import java.lang.Double.min import java.net.URL @@ -53,7 +52,6 @@ private const val ZOOM_DELTA_LOG = 0.05 class VesCurvesController @Inject constructor( private val picketObservable: ObservableObjectValue, private val _picketIndex: IntegerProperty, - private val alertsFactory: AlertsFactory, private val observableSection: ObservableSection, private val historyManager: HistoryManager
, private val decimalFormat: DecimalFormat, @@ -61,7 +59,7 @@ class VesCurvesController @Inject constructor( private val forwardSolver: ForwardSolver, @Named(Name.File.PNG) private val fc: FileChooser, private val prefs: Preferences -) : AbstractController() { +) : AbstractViewController() { private val dataProperty: ObjectProperty>> = initData() @@ -80,9 +78,6 @@ class VesCurvesController @Inject constructor( @FXML private lateinit var yAxis: LogarithmicAxis - override val stage: Stage - get() = lineChart.scene.window as Stage - private val picket get() = picketObservable.get()!! @@ -249,12 +244,12 @@ class VesCurvesController @Inject constructor( || picket.sortedExperimentalData.isNotEmpty() ) { yAxis.lowerBound = min( - picket.modelData.minOfOrNull { it.resistance } ?: Double.MAX_VALUE, - picket.sortedExperimentalData.minOfOrNull { it.resistanceApparent } ?: Double.MAX_VALUE + picket.modelData.minOfOrNull { it.resistivity } ?: Double.MAX_VALUE, + picket.sortedExperimentalData.minOfOrNull { it.resistivityApparent } ?: Double.MAX_VALUE ) yAxis.upperBound = max( - picket.modelData.maxOfOrNull { it.resistance } ?: Double.MIN_VALUE, - picket.sortedExperimentalData.maxOfOrNull { it.resistanceApparent } ?: Double.MIN_VALUE + picket.modelData.maxOfOrNull { it.resistivity } ?: Double.MIN_VALUE, + picket.sortedExperimentalData.maxOfOrNull { it.resistivityApparent } ?: Double.MIN_VALUE ) } else { yAxis.lowerBound = 1.0 @@ -268,13 +263,11 @@ class VesCurvesController @Inject constructor( private fun updateTheoreticalCurve() { val theorCurveSeries = Series() - try { - theorCurveSeries.data.addAll( - theoreticalCurve(picket, forwardSolver).map { (x, y) -> Data(x as Number, y as Number) } - ) - } catch (e: UnsatisfiedLinkError) { - alertsFactory.unsatisfiedLinkErrorAlert(e, stage) - } + + theorCurveSeries.data.addAll( + theoreticalCurve(picket, picket, forwardSolver).map { (x, y) -> Data(x as Number, y as Number) } + ) + theorCurveSeries.name = uiProperties["theorCurve"] dataProperty.get()[THEOR_CURVE_SERIES_INDEX] = theorCurveSeries } @@ -370,12 +363,12 @@ class VesCurvesController @Inject constructor( EXP_CURVE_ERROR_UPPER_SERIES_INDEX -> { val x = decimalFormat.format(point.xValue) val yLower = decimalFormat.format( - picket.effectiveExperimentalData[pointIndex].resistanceApparentLowerBoundByError + picket.effectiveExperimentalData[pointIndex].resistivityApparentLowerBoundByError ) val yUpper = decimalFormat.format( - picket.effectiveExperimentalData[pointIndex].resistanceApparentUpperBoundByError + picket.effectiveExperimentalData[pointIndex].resistivityApparentUpperBoundByError ) - val y = decimalFormat.format(picket.effectiveExperimentalData[pointIndex].resistanceApparent) + val y = decimalFormat.format(picket.effectiveExperimentalData[pointIndex].resistivityApparent) Tooltip( """ №${effectiveToSortedMapping[pointIndex] + 1} @@ -384,19 +377,19 @@ class VesCurvesController @Inject constructor( min ρₐ = $yLower max ρₐ = $yUpper """.trimIndent() - ).forCharts() + ).shownOnHover() } THEOR_CURVE_SERIES_INDEX -> { val x = decimalFormat.format(point.xValue) val yLower = decimalFormat.format( - picket.sortedExperimentalData[pointIndex].resistanceApparentLowerBoundByError + picket.sortedExperimentalData[pointIndex].resistivityApparentLowerBoundByError ) val yUpper = decimalFormat.format( - picket.sortedExperimentalData[pointIndex].resistanceApparentUpperBoundByError + picket.sortedExperimentalData[pointIndex].resistivityApparentUpperBoundByError ) - val y = decimalFormat.format(picket.sortedExperimentalData[pointIndex].resistanceApparent) - val theorRes = theoreticalCurve(picket, forwardSolver).getOrNull(pointIndex)?.y + val y = decimalFormat.format(picket.sortedExperimentalData[pointIndex].resistivityApparent) + val theorRes = theoreticalCurve(picket, picket, forwardSolver).getOrNull(pointIndex)?.y Tooltip( """ №${pointIndex + 1} @@ -406,7 +399,7 @@ class VesCurvesController @Inject constructor( max ρₐ = $yUpper ρₐ (теор.) = ${decimalFormat.format(theorRes)} Ω‧m """.trimIndent() - ).forCharts() + ).shownOnHover() } else -> null diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/main/AddExperimentalDataController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/main/AddExperimentalDataController.kt index dcf336c4..a3d9eeaa 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/main/AddExperimentalDataController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/main/AddExperimentalDataController.kt @@ -1,29 +1,41 @@ package ru.nucodelabs.gem.view.controller.main -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.module.kotlin.readValue import jakarta.inject.Inject -import jakarta.validation.Validator +import javafx.beans.binding.Bindings import javafx.beans.property.IntegerProperty import javafx.fxml.FXML +import javafx.scene.control.Label import javafx.scene.control.TextField +import javafx.scene.control.TextFormatter import javafx.scene.layout.VBox -import javafx.stage.Stage +import javafx.util.StringConverter import ru.nucodelabs.gem.fxmodel.ves.ObservableSection import ru.nucodelabs.gem.view.AlertsFactory -import ru.nucodelabs.gem.view.controller.AbstractController import ru.nucodelabs.geo.ves.ExperimentalData +import ru.nucodelabs.geo.ves.InvalidPropertiesException +import ru.nucodelabs.geo.ves.InvalidPropertyValue import ru.nucodelabs.geo.ves.Section +import ru.nucodelabs.geo.ves.calc.rhoA +import ru.nucodelabs.kfx.core.AbstractViewController import ru.nucodelabs.kfx.snapshot.HistoryManager +import tornadofx.get +import java.net.URL +import java.text.DecimalFormat +import java.text.ParseException +import java.util.* class AddExperimentalDataController @Inject constructor( - private val objectMapper: ObjectMapper, private val alertsFactory: AlertsFactory, private val picketIndex: IntegerProperty, private val observableSection: ObservableSection, private val historyManager: HistoryManager
, - private val validator: Validator -) : AbstractController() { + private val decimalFormat: DecimalFormat, + private val uiProps: ResourceBundle +) : AbstractViewController() { + + @FXML + private lateinit var invalidMessageLabel: Label + @FXML private lateinit var amperageTextField: TextField @@ -42,63 +54,104 @@ class AddExperimentalDataController @Inject constructor( @FXML private lateinit var ab2TextField: TextField - @FXML - private lateinit var root: VBox - - override val stage: Stage? - get() = root.scene.window as Stage? + override fun initialize(location: URL, resources: ResourceBundle) { + val fields = listOf( + ab2TextField to ExperimentalData::validateAb2, + mn2TextField to ExperimentalData::validateMn2, + resAppTextField to ExperimentalData::validateResistApparent, + errResAppTextField to ExperimentalData::validateErrResistApparent, + voltageTextField to ExperimentalData::validateVoltage, + amperageTextField to ExperimentalData::validateAmperage + ) + val converter = object : StringConverter() { + override fun toString(value: Double?): String? = value?.let { + decimalFormat.format(it) + } - fun createJson( - ab2: String, - mn2: String, - amperage: String, - voltage: String, - errorResApp: String, - resApp: String - ): String { - return ("{" + - (if (ab2.isNotBlank()) "\"ab2\": $ab2," else "") + - (if (mn2.isNotBlank()) "\"mn2\": $mn2," else "") + - (if (amperage.isNotBlank()) "\"amperage\": $amperage," else "") + - (if (voltage.isNotBlank()) "\"voltage\": $voltage," else "") + - (if (errorResApp.isNotBlank()) "\"errorResistanceApparent\": $errorResApp," else "") + - (if (resApp.isNotBlank()) "\"resistanceApparent\": $resApp," else "") + - "}").let { - val idx = it.lastIndexOf(",") - it.removeRange(idx, idx + 1) + override fun fromString(value: String?): Double? { + if (value.isNullOrBlank()) return null + return try { + decimalFormat.parse(value).toDouble() + } catch (_: ParseException) { + null + } + } } + fields.forEach { (field, _) -> field.textFormatter = TextFormatter(converter) } + invalidMessageLabel.textProperty().bind( + Bindings.createStringBinding( + { validateAndFillDefaults(fields) }, + *fields.map { (field, _) -> field.textProperty() }.toTypedArray() + ) + ) + invalidMessageLabel.visibleProperty().bind(invalidMessageLabel.textProperty().map { it.isNotBlank() }) + } + + /** + * Returns error message + */ + private fun validateAndFillDefaults(fields: List InvalidPropertyValue?>>): String = + fields.map { (field, validate) -> + val value = field.textFormatter.value as Double? + return@map if (value == null) { + // Fill errorResistivityApparent default value if absent + if (field === errResAppTextField) { + @Suppress("unchecked_cast") + (field.textFormatter as TextFormatter).value = ExperimentalData.DEFAULT_ERROR + return@map "" + } + // Fill resistivityApparent formula calculated default value if absent + if (field === resAppTextField) { + val ab2 = ab2TextField.textFormatter.value as Double? + val mn2 = mn2TextField.textFormatter.value as Double? + val amperage = amperageTextField.textFormatter.value as Double? + val voltage = voltageTextField.textFormatter.value as Double? + if (ab2 != null && mn2 != null && amperage != null && voltage != null) { + @Suppress("unchecked_cast") + (field.textFormatter as TextFormatter) + .value = rhoA(ab2, mn2, amperage, voltage) + return@map "" + } + } + "${fullLabelForField(field)}: ${uiProps["invalidInput"]}" + } else { + validate(value)?.let { (prop, _, _) -> uiProps["invalid.exp.$prop"] } ?: "" + } + }.filter { it.isNotBlank() }.joinToString(separator = "\n") + + private fun fullLabelForField(field: TextField) = when (field) { + ab2TextField -> uiProps["ab2Full"] + mn2TextField -> uiProps["mn2Full"] + amperageTextField -> uiProps["amperageFull"] + voltageTextField -> uiProps["voltageFull"] + resAppTextField -> uiProps["resistivityApparentFull"] + errResAppTextField -> uiProps["errorResistivityApparentFull"] + else -> "Error" } @FXML private fun add() { val newExpDataItem = try { - objectMapper.readValue( - createJson( - ab2 = ab2TextField.text, - mn2 = mn2TextField.text, - amperage = amperageTextField.text, - voltage = voltageTextField.text, - errorResApp = errResAppTextField.text, - resApp = resAppTextField.text - ) + ExperimentalData( + ab2 = ab2TextField.textFormatter.value as Double, + mn2 = mn2TextField.textFormatter.value as Double, + amperage = amperageTextField.textFormatter.value as Double, + resistivityApparent = resAppTextField.textFormatter.value as Double, + voltage = voltageTextField.textFormatter.value as Double, + errorResistivityApparent = errResAppTextField.textFormatter.value as Double ) - } catch (e: Exception) { - alertsFactory.simpleExceptionAlert(e, stage).show() + } catch (e: InvalidPropertiesException) { + alertsFactory.simpleExceptionAlert(e, rootStage()).show() return } - val violations = validator.validate(newExpDataItem) - if (violations.isEmpty()) { - historyManager.snapshotAfter { - val picket = observableSection.pickets[picketIndex.value] - val expData = picket.sortedExperimentalData - observableSection.pickets[picketIndex.value] = - picket.copy(experimentalData = expData.toMutableList().apply { - add(newExpDataItem) - }) - } - } else { - alertsFactory.violationsAlert(violations, stage).show() + historyManager.snapshotAfter { + val picket = observableSection.pickets[picketIndex.value] + val expData = picket.sortedExperimentalData + observableSection.pickets[picketIndex.value] = + picket.copy(experimentalData = expData.toMutableList().apply { + add(newExpDataItem) + }) } } } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/main/CalculateErrorScreenController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/main/CalculateErrorScreenController.kt index b4ed408d..7c9a6188 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/main/CalculateErrorScreenController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/main/CalculateErrorScreenController.kt @@ -13,6 +13,7 @@ import javafx.scene.chart.XYChart.Series import javafx.scene.control.* import javafx.stage.Stage import javafx.util.Callback +import javafx.util.StringConverter import ru.nucodelabs.gem.config.Name import ru.nucodelabs.gem.fxmodel.ves.ObservableExperimentalData import ru.nucodelabs.gem.fxmodel.ves.ObservableSection @@ -24,6 +25,7 @@ import ru.nucodelabs.geo.ves.Picket import ru.nucodelabs.geo.ves.Section import ru.nucodelabs.geo.ves.calc.error.* import ru.nucodelabs.kfx.ext.DoubleValidationConverter +import ru.nucodelabs.kfx.ext.get import ru.nucodelabs.kfx.ext.observableListOf import ru.nucodelabs.kfx.ext.toObservableList import ru.nucodelabs.kfx.snapshot.HistoryManager @@ -49,7 +51,8 @@ class CalculateErrorScreenController @Inject constructor( private val historyManager: HistoryManager
, private val observablePicket: ObservableObjectValue, private val picketIndexProp: IntegerProperty, - private val vesFxModelMapper: VesFxModelMapper + private val vesFxModelMapper: VesFxModelMapper, + private val uiProps: ResourceBundle ) : AbstractController() { @FXML private lateinit var errorFormula: ComboBox @@ -61,7 +64,7 @@ class CalculateErrorScreenController @Inject constructor( private lateinit var chart: LineChart @FXML - private lateinit var errorResistanceCol: TableColumn + private lateinit var errorResCol: TableColumn @FXML private lateinit var resCol: TableColumn @@ -114,12 +117,8 @@ class CalculateErrorScreenController @Inject constructor( val data = observableListOf() private enum class ErrorFunctionType { - USING_VARIANCE { - override fun toString(): String = "По правилу трех сигма (по дисперсии)" - }, - USING_TRUST_INTERVALS { - override fun toString(): String = "По доверительным интервалам" - } + USING_VARIANCE, + USING_TRUST_INTERVALS } private lateinit var errorFunctionVersion: ErrorFunctionType @@ -148,25 +147,29 @@ class CalculateErrorScreenController @Inject constructor( private fun listenToItems() { table.items.forEach { item -> - item.resistanceApparentProperty().addListener { _, _, _ -> updateChart() } - item.errorResistanceApparentProperty().addListener { _, _, _ -> updateChart() } + item.resistivityApparentProperty().addListener { _, _, _ -> updateChart() } + item.errorResistivityApparentProperty().addListener { _, _, _ -> updateChart() } } } private fun Number.fmt(): String = df.format(this) private fun setupComboBox() { - errorFormula.items.setAll(ErrorFunctionType.USING_VARIANCE, ErrorFunctionType.USING_TRUST_INTERVALS) - errorFormula.selectionModel.selectedItemProperty().addListener { _, _, newValue: ErrorFunctionType -> - errorFunctionVersion = when (newValue) { - ErrorFunctionType.USING_VARIANCE -> { - ErrorFunctionType.USING_VARIANCE - } - - ErrorFunctionType.USING_TRUST_INTERVALS -> { - ErrorFunctionType.USING_TRUST_INTERVALS + errorFormula.items.setAll(ErrorFunctionType.entries) + errorFormula.converter = object : StringConverter() { + override fun toString(value: ErrorFunctionType?): String? { + return when (value) { + ErrorFunctionType.USING_VARIANCE -> uiProps["errorFunction.usingVariance"] + ErrorFunctionType.USING_TRUST_INTERVALS -> uiProps["errorFunction.usingTrustIntervals"] + null -> null } } + + override fun fromString(value: String?): ErrorFunctionType? = null + + } + errorFormula.selectionModel.selectedItemProperty().addListener { _, _, newValue: ErrorFunctionType -> + errorFunctionVersion = newValue } errorFormula.selectionModel.selectFirst() } @@ -269,7 +272,7 @@ class CalculateErrorScreenController @Inject constructor( createStringBinding( { val (_, _, _, avg, _) = resAppWithError(vesFxModelMapper.toModel(f.value)) - f.value.resistanceApparent = avg + f.value.resistivityApparent = avg avg.fmt() }, f.value.ab2Property(), @@ -282,11 +285,11 @@ class CalculateErrorScreenController @Inject constructor( errorFormula.selectionModel.selectedItemProperty() ) } - errorResistanceCol.cellValueFactory = Callback { f -> + errorResCol.cellValueFactory = Callback { f -> createStringBinding( { val (_, _, _, _, error) = resAppWithError(vesFxModelMapper.toModel(f.value)) - f.value.errorResistanceApparent = error + f.value.errorResistivityApparent = error error.fmt() }, f.value.ab2Property(), @@ -318,11 +321,11 @@ class CalculateErrorScreenController @Inject constructor( iAErrorTf.textFormatter.value as Double, iBErrorTf.textFormatter.value as Double ).withValue(data.amperage) - return resistanceApparentWithError(errorFunctionVersion == ErrorFunctionType.USING_VARIANCE, k, u, i) + return resistivityApparentWithError(errorFunctionVersion == ErrorFunctionType.USING_VARIANCE, k, u, i) } private fun resAppErrorForDist(data: ExperimentalData) = - resistanceApparentErrorForDistance( + resistivityApparentErrorForDistance( errorFunctionVersion == ErrorFunctionType.USING_VARIANCE, kWithError( data.ab2, @@ -335,7 +338,7 @@ class CalculateErrorScreenController @Inject constructor( ) private fun resAppErrorForVolt(data: ExperimentalData) = - resistanceApparentErrorForVoltage( + resistivityApparentErrorForVoltage( errorFunctionVersion == ErrorFunctionType.USING_VARIANCE, measureError( data.voltage, @@ -348,7 +351,7 @@ class CalculateErrorScreenController @Inject constructor( ) private fun resAppErrorForAmp(data: ExperimentalData) = - resistanceApparentErrorForAmperage( + resistivityApparentErrorForAmperage( errorFunctionVersion == ErrorFunctionType.USING_VARIANCE, measureError( data.amperage, @@ -412,8 +415,8 @@ class CalculateErrorScreenController @Inject constructor( val modifiedData = observablePicket.get().sortedExperimentalData.toMutableList().also { list -> list.replaceAll { if (it in data) it.copy( - resistanceApparent = table.items[data.indexOf(it)].resistanceApparent, - errorResistanceApparent = table.items[data.indexOf(it)].errorResistanceApparent + resistivityApparent = table.items[data.indexOf(it)].resistivityApparent, + errorResistivityApparent = table.items[data.indexOf(it)].errorResistivityApparent ) else it } } diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/main/InitialModelConfigurationViewController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/main/InitialModelConfigurationViewController.kt index 31ddd3e6..b30ac1dc 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/main/InitialModelConfigurationViewController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/main/InitialModelConfigurationViewController.kt @@ -8,8 +8,8 @@ import ru.nucodelabs.gem.fxmodel.ves.app.ArbitraryInitialModelParameters import ru.nucodelabs.gem.fxmodel.ves.app.VesFxAppModel import ru.nucodelabs.gem.view.AlertsFactory import ru.nucodelabs.kfx.core.AbstractViewController -import ru.nucodelabs.util.std.toDoubleOrNullBy -import ru.nucodelabs.util.std.toIntOrNullBy +import ru.nucodelabs.util.toDoubleOrNullBy +import ru.nucodelabs.util.toIntOrNullBy import java.net.URL import java.text.DecimalFormat import java.util.* @@ -28,7 +28,6 @@ class InitialModelConfigurationViewController @Inject constructor( private lateinit var minTargetFunctionValueTextField: TextField override fun initialize(location: URL, resources: ResourceBundle) { - super.initialize(location, resources) minTargetFunctionValueTextField.text = decimalFormat.format(parameters.minTargetFunctionValue) maxLayersCountTextField.text = decimalFormat.format(parameters.maxLayersCount) } @@ -39,7 +38,7 @@ class InitialModelConfigurationViewController @Inject constructor( val maxLayersCount = maxLayersCountTextField.text.toIntOrNullBy(decimalFormat) if (minTargetFunctionValue == null || maxLayersCount == null) { - alertsFactory.simpleAlert(text = "Неправильный ввод", owner = stage).show() + alertsFactory.simpleAlert(text = "Неправильный ввод", owner = rootStage()).show() return } @@ -48,6 +47,6 @@ class InitialModelConfigurationViewController @Inject constructor( maxLayersCount = maxLayersCount ) - stage?.close() + rootStage()?.close() } } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/main/MainViewController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/main/MainViewController.kt index 76a237b7..e7620eb5 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/main/MainViewController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/main/MainViewController.kt @@ -17,6 +17,7 @@ import javafx.scene.Scene import javafx.scene.control.* import javafx.scene.input.KeyCode import javafx.scene.input.KeyCodeCombination +import javafx.scene.input.KeyCombination import javafx.scene.layout.HBox import javafx.scene.layout.VBox import javafx.stage.FileChooser @@ -74,17 +75,22 @@ class MainViewController @Inject constructor( private val preferences: Preferences, private val decimalFormat: DecimalFormat, private val fxPreferences: FXPreferences, - private val inverseSolver: InverseSolver + private val inverseSolver: InverseSolver, + private val ui: ResourceBundle, ) : AbstractController(), FileImporter, FileOpener { private val windowTitle: StringProperty = SimpleStringProperty("GEM") private val dirtyAsterisk: StringProperty = SimpleStringProperty("") private val noFileOpenedProperty: BooleanProperty = SimpleBooleanProperty(true) + + @Suppress("unused") fun noFileOpenedProperty(): BooleanProperty = noFileOpenedProperty val noFileOpened: Boolean by noFileOpenedProperty private val vesNumberProperty: StringProperty = SimpleStringProperty() + + @Suppress("unused") fun vesNumberProperty(): StringProperty = vesNumberProperty val vesNumber: String? by vesNumberProperty @@ -166,14 +172,13 @@ class MainViewController @Inject constructor( get() = root override fun initialize(location: URL, resources: ResourceBundle) { - super.initialize(location, resources) stage.onCloseRequest = EventHandler { e -> if (!askToSave(e).isConsumed) { menuViewSectionInSeparateWindow.isSelected = false } } -// stage.scene.accelerators[KeyCodeCombination(KeyCode.Y, KeyCombination.SHORTCUT_DOWN)] = Runnable { redo() } + stage.scene.accelerators[KeyCodeCombination(KeyCode.Y, KeyCombination.SHORTCUT_DOWN)] = Runnable { redo() } macOS { val useSystemMenu = CheckMenuItem(resources["useSystemMenu"]) menuView.items.add(0, useSystemMenu) @@ -293,7 +298,7 @@ class MainViewController @Inject constructor( if (newValue != null) { picketOffsetX.text = decimalFormat.format(newValue.offsetX) picketZ.text = decimalFormat.format(newValue.z) - xCoordLbl.text = decimalFormat.format(observableSection.asSection().xOfPicket(picket)) + xCoordLbl.text = decimalFormat.format(observableSection.asSection().xOfPicket(picketIndex)) } } } @@ -677,11 +682,11 @@ class MainViewController @Inject constructor( private fun openAddExpData() { if (addExperimentalData.scene == null) { Stage().apply { - title = "Добавить измерение" + title = ui["addSignal"] initOwner(this@MainViewController.stage) addExperimentalData.stylesheets += Style.COMMON_STYLESHEET scene = Scene(addExperimentalData) - isResizable = false + isResizable = true }.show() } else { (addExperimentalData.scene.window as Stage).show() diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/main/NormalizationScreenController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/main/NormalizationScreenController.kt index 49a67444..1391d07e 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/main/NormalizationScreenController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/main/NormalizationScreenController.kt @@ -92,7 +92,6 @@ class NormalizationScreenController @Inject constructor( private lateinit var additiveResult: List override fun initialize(location: URL, resources: ResourceBundle) { - super.initialize(location, resources) xAxis.tickLabelFormatter = numberStringConverter yAxis.tickLabelFormatter = numberStringConverter @@ -211,7 +210,7 @@ class NormalizationScreenController @Inject constructor( }.map { (idxSrc, _) -> picket.sortedExperimentalData[idxSrc] }.map { - XYChart.Data(it.ab2 as Number, it.resistanceApparent as Number) + XYChart.Data(it.ab2 as Number, it.resistivityApparent as Number) }.toObservableList() ).also { it.name = decimalFormat.format(mn2) } } @@ -243,7 +242,7 @@ class NormalizationScreenController @Inject constructor( @FXML private fun apply() { val newExp = picket.sortedExperimentalData.mapIndexed { idx, exp -> - exp.copy(resistanceApparent = normalizationResult[idx]) + exp.copy(resistivityApparent = normalizationResult[idx]) } historyManager.snapshotAfter { diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/main/PicketsBarController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/main/PicketsBarController.kt index e862316c..59bb339b 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/main/PicketsBarController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/main/PicketsBarController.kt @@ -16,7 +16,7 @@ import ru.nucodelabs.geo.ves.Section import ru.nucodelabs.geo.ves.calc.length import ru.nucodelabs.geo.ves.calc.picketsBounds import ru.nucodelabs.kfx.snapshot.HistoryManager -import ru.nucodelabs.util.std.swap +import ru.nucodelabs.util.swap import java.net.URL import java.util.* diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/tables/ExperimentalTableController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/tables/ExperimentalTableController.kt index 094d7edd..d628c1e9 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/tables/ExperimentalTableController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/tables/ExperimentalTableController.kt @@ -2,7 +2,6 @@ package ru.nucodelabs.gem.view.controller.tables import jakarta.inject.Inject import jakarta.inject.Provider -import jakarta.validation.Validator import javafx.beans.property.IntegerProperty import javafx.beans.value.ObservableObjectValue import javafx.collections.ListChangeListener @@ -16,6 +15,7 @@ import javafx.scene.input.Clipboard import javafx.scene.input.DataFormat import javafx.scene.input.KeyCode import javafx.scene.input.KeyEvent +import javafx.scene.layout.VBox import javafx.stage.Stage import javafx.util.Callback import javafx.util.StringConverter @@ -23,26 +23,20 @@ import ru.nucodelabs.gem.config.Style import ru.nucodelabs.gem.fxmodel.ves.ObservableExperimentalData import ru.nucodelabs.gem.fxmodel.ves.ObservableSection import ru.nucodelabs.gem.fxmodel.ves.mapper.VesFxModelMapper +import ru.nucodelabs.gem.fxmodel.ves.toObservable import ru.nucodelabs.gem.view.AlertsFactory -import ru.nucodelabs.gem.view.controller.AbstractController import ru.nucodelabs.gem.view.controller.FileImporter import ru.nucodelabs.gem.view.controller.main.CalculateErrorScreenController import ru.nucodelabs.gem.view.controller.util.DEFAULT_FONT_SIZE import ru.nucodelabs.gem.view.controller.util.indexCellFactory -import ru.nucodelabs.geo.ves.ExperimentalData -import ru.nucodelabs.geo.ves.Picket -import ru.nucodelabs.geo.ves.Section +import ru.nucodelabs.geo.ves.* import ru.nucodelabs.geo.ves.calc.k import ru.nucodelabs.geo.ves.calc.u -import ru.nucodelabs.geo.ves.calc.withCalculatedResistanceApparent -import ru.nucodelabs.geo.ves.toTabulatedTable -import ru.nucodelabs.kfx.ext.DoubleValidationConverter -import ru.nucodelabs.kfx.ext.bidirectionalNot -import ru.nucodelabs.kfx.ext.decimalFilter -import ru.nucodelabs.kfx.ext.toObservableList +import ru.nucodelabs.geo.ves.calc.withCalculatedResistivityApparent +import ru.nucodelabs.kfx.core.AbstractViewController +import ru.nucodelabs.kfx.ext.* import ru.nucodelabs.kfx.snapshot.HistoryManager -import ru.nucodelabs.util.TextToTableParser -import ru.nucodelabs.util.std.toDoubleOrNullBy +import ru.nucodelabs.util.* import tornadofx.getValue import java.net.URL import java.text.DecimalFormat @@ -65,16 +59,16 @@ val EXP_HELP_PASTE = """ class ExperimentalTableController @Inject constructor( private val picketObservable: ObservableObjectValue, - private val validator: Validator, private val observableSection: ObservableSection, picketIndexProperty: IntegerProperty, private val historyManager: HistoryManager
, private val alertsFactory: AlertsFactory, - private val doubleStringConverter: StringConverter, + private val converter: StringConverter, private val decimalFormat: DecimalFormat, fileImporterProvider: Provider, - private val mapper: VesFxModelMapper -) : AbstractController(), FileImporter by fileImporterProvider.get() { + private val mapper: VesFxModelMapper, + private val uiProps: ResourceBundle +) : AbstractViewController(), FileImporter by fileImporterProvider.get() { @FXML private lateinit var calculateErrorScreen: Stage @@ -92,35 +86,33 @@ class ExperimentalTableController @Inject constructor( private lateinit var indexCol: TableColumn @FXML - private lateinit var ab2Col: TableColumn + private lateinit var ab2Col: TableColumn @FXML - private lateinit var mn2Col: TableColumn + private lateinit var mn2Col: TableColumn @FXML - private lateinit var resistanceApparentCol: TableColumn + private lateinit var resAppCol: TableColumn @FXML - private lateinit var errorResistanceCol: TableColumn + private lateinit var errorResCol: TableColumn @FXML - private lateinit var amperageCol: TableColumn + private lateinit var amperageCol: TableColumn @FXML - private lateinit var voltageCol: TableColumn + private lateinit var voltageCol: TableColumn @FXML private lateinit var table: TableView - override val stage: Stage - get() = table.scene.window as Stage - private val picket: Picket get() = picketObservable.get()!! private val picketIndex by picketIndexProperty override fun initialize(location: URL, resources: ResourceBundle) { + table.columnResizePolicy = TableView.CONSTRAINED_RESIZE_POLICY_LAST_COLUMN picketObservable.addListener { _, oldValue: Picket?, newValue: Picket? -> if (newValue != null) { if (oldValue != null @@ -189,24 +181,39 @@ class ExperimentalTableController @Inject constructor( isHiddenCol.cellValueFactory = Callback { features -> features.value.hiddenProperty().bidirectionalNot() } isHiddenCol.cellFactory = CheckBoxTableCell.forTableColumn(isHiddenCol) - ab2Col.cellValueFactory = Callback { features -> features.value.ab2Property().asObject() } - mn2Col.cellValueFactory = Callback { features -> features.value.mn2Property().asObject() } - resistanceApparentCol.cellValueFactory = - Callback { features -> features.value.resistanceApparentProperty().asObject() } - errorResistanceCol.cellValueFactory = - Callback { features -> features.value.errorResistanceApparentProperty().asObject() } - amperageCol.cellValueFactory = Callback { features -> features.value.amperageProperty().asObject() } - voltageCol.cellValueFactory = Callback { features -> features.value.voltageProperty().asObject() } + ab2Col.cellValueFactory = Callback { features -> features.value.ab2Property() } + mn2Col.cellValueFactory = Callback { features -> features.value.mn2Property() } + resAppCol.cellValueFactory = Callback { features -> features.value.resistivityApparentProperty() } + errorResCol.cellValueFactory = Callback { features -> features.value.errorResistivityApparentProperty() } + amperageCol.cellValueFactory = Callback { features -> features.value.amperageProperty() } + voltageCol.cellValueFactory = Callback { features -> features.value.voltageProperty() } val editableColumns = listOf( - ab2Col, - mn2Col, - resistanceApparentCol, - errorResistanceCol, - amperageCol, - voltageCol + ab2Col to ExperimentalData::validateAb2, + mn2Col to ExperimentalData::validateMn2, + resAppCol to ExperimentalData::validateResistApparent, + errorResCol to ExperimentalData::validateErrResistApparent, + amperageCol to ExperimentalData::validateAmperage, + voltageCol to ExperimentalData::validateVoltage, ) - editableColumns.forEach { it.cellFactory = TextFieldTableCell.forTableColumn(doubleStringConverter) } + + editableColumns.forEach { (col, validate) -> + col.cellFactory = Callback { _ -> TextFieldTableCell(converter) } + + val onEditCommitHandler = col.onEditCommit + col.onEditCommit = EventHandler { event -> + if (event.newValue == null) { + event.consume() + return@EventHandler + } + validate(event.newValue.toDouble())?.let { (prop, _) -> + alertsFactory.invalidInputAlert(uiProps["invalid.exp.$prop"]).show() + event.consume() + return@EventHandler + } + onEditCommitHandler.handle(event) + } + } } private fun setupRowFactory() { @@ -231,16 +238,11 @@ class ExperimentalTableController @Inject constructor( editor.also { tf -> tf.textFormatter = TextFormatter( DoubleValidationConverter(decimalFormat) { value -> - val violations = validator.validateValue( - ExperimentalData::class.java, - "errorResistanceApparent", - value - ) - violations.isEmpty().also { valid -> - if (!valid) { - alertsFactory.violationsAlert(violations, stage).show() - } + ExperimentalData.validateErrResistApparent(value)?.let { (prop, _, _) -> + alertsFactory.invalidInputAlert(uiProps["invalid.exp.$prop"]).show() + return@DoubleValidationConverter false } + true }, 5.0, decimalFilter(decimalFormat) @@ -261,7 +263,9 @@ class ExperimentalTableController @Inject constructor( style = "-fx-font-size: $DEFAULT_FONT_SIZE;" } - onContextMenuRequested = EventHandler { contextMenu.show(this, it.screenX, it.screenY) } + onContextMenuRequested = EventHandler { + if (item != null) contextMenu.show(this, it.screenX, it.screenY) + } } } } @@ -295,70 +299,12 @@ class ExperimentalTableController @Inject constructor( private fun listenToItemsProperties(items: List) { items.forEach { expData -> - expData.ab2Property().addListener { _, oldAb2, newAb2 -> - val violations = validator.validateValue(ExperimentalData::class.java, "ab2", newAb2) - if (violations.isEmpty()) { - commitChanges() - } else { - expData.ab2 = oldAb2.toDouble() - alertsFactory.violationsAlert(violations, stage).show() - } - } - expData.mn2Property().addListener { _, oldMn2, newMn2 -> - val violations = validator.validateValue(ExperimentalData::class.java, "mn2", newMn2) - if (violations.isEmpty()) { - commitChanges() - } else { - expData.mn2 = oldMn2.toDouble() - alertsFactory.violationsAlert(violations, stage).show() - } - } - expData.errorResistanceApparentProperty().addListener { _, oldErr, newErr -> - val violations = validator.validateValue( - ExperimentalData::class.java, - "errorResistanceApparent", - newErr - ) - if (violations.isEmpty() - ) { - commitChanges() - } else { - expData.errorResistanceApparent = oldErr.toDouble() - alertsFactory.violationsAlert(violations, stage).show() - } - } - expData.amperageProperty().addListener { _, oldAmp, newAmp -> - val violations = validator.validateValue(ExperimentalData::class.java, "amperage", newAmp) - if (violations.isEmpty()) { - commitChanges() - } else { - expData.amperage = oldAmp.toDouble() - alertsFactory.violationsAlert(violations, stage).show() - } - } - expData.voltageProperty().addListener { _, oldVolt, newVolt -> - val violations = validator.validateValue(ExperimentalData::class.java, "voltage", newVolt) - if (violations.isEmpty()) { - commitChanges() - } else { - expData.voltage = oldVolt.toDouble() - alertsFactory.violationsAlert(violations, stage).show() - } - } - expData.resistanceApparentProperty().addListener { _, oldRes, newRes -> - val violations = validator.validateValue( - ExperimentalData::class.java, - "resistanceApparent", - newRes - ) - if (violations.isEmpty() - ) { - commitChanges() - } else { - expData.resistanceApparent = oldRes.toDouble() - alertsFactory.violationsAlert(violations, stage).show() - } - } + expData.ab2Property().addListener { _, oldAb2, newAb2 -> commitChanges() } + expData.mn2Property().addListener { _, oldMn2, newMn2 -> commitChanges() } + expData.errorResistivityApparentProperty().addListener { _, oldErr, newErr -> commitChanges() } + expData.amperageProperty().addListener { _, oldAmp, newAmp -> commitChanges() } + expData.voltageProperty().addListener { _, oldVolt, newVolt -> commitChanges() } + expData.resistivityApparentProperty().addListener { _, oldRes, newRes -> commitChanges() } expData.hiddenProperty().addListener { _, _, isHidden -> if (table.selectionModel.selectedItems.isEmpty()) { toggleSingleHidden(expData, isHidden) @@ -396,7 +342,7 @@ class ExperimentalTableController @Inject constructor( if (calculateErrorScreen.owner == null) { calculateErrorScreen.initOwner(stage) } - calculateErrorScreen.icons.setAll(stage.icons) + calculateErrorScreen.icons.setAll(stage?.icons) } private fun setIsHiddenOnSelected(isHidden: Boolean) { @@ -429,7 +375,7 @@ class ExperimentalTableController @Inject constructor( private fun setErrorOnSelected(error: Double) { val items = table.items.map { mapper.toModel(it) }.toMutableList() for (i in table.selectionModel.selectedIndices) { - items[i] = items[i].copy(errorResistanceApparent = error) + items[i] = items[i].copy(errorResistivityApparent = error) } table.items.setAll(items.map { mapper.toObservable(it) }) } @@ -444,7 +390,7 @@ class ExperimentalTableController @Inject constructor( val experimentalData = table.items.map { mapper.toModel(it) }.toMutableList() for (i in table.selectionModel.selectedIndices) { - experimentalData[i] = experimentalData[i].withCalculatedResistanceApparent() + experimentalData[i] = experimentalData[i].withCalculatedResistivityApparent() } table.items.setAll(experimentalData.map { mapper.toObservable(it) }) @@ -455,46 +401,58 @@ class ExperimentalTableController @Inject constructor( val text = Clipboard.getSystemClipboard().string val parser = if (text != null) TextToTableParser(text) else return try { - val a = "abcdefghijklmnopqrstuvwxyz".uppercase().toCharArray() + val a = "abcdefghijksssddddmnopqrstuvwxyz".uppercase().toCharArray() val parsedTable = parser.parsedTable.filter { row -> row.none { it == null } } fun String?.process(expected: String, row: Int, col: Int) = this?.replace(',', '.')?.toDoubleOrNullBy(decimalFormat) ?: throw IllegalArgumentException("${a[col]}${row + 1} - Ожидалось $expected, было $this") - val pastedItems: List = when (parser.columnsCount) { + val pastedItems = when (parser.columnsCount) { 3 -> parsedTable.mapIndexed { rowIdx, row -> val ab2 = row[0].process("AB/2", rowIdx, 0) val mn2 = row[1].process("MN/2", rowIdx, 1) val resApp = row[2].process("ρₐ", rowIdx, 2) val amp = 100.0 val volt = u(resApp, 100.0, k(ab2, mn2)) - ExperimentalData( - ab2 = ab2, - mn2 = mn2, - resistanceApparent = resApp, - amperage = amp, - voltage = volt - ) + try { + ExperimentalData( + ab2 = ab2, + mn2 = mn2, + resistivityApparent = resApp, + amperage = amp, + voltage = volt + ).toOkResult() + } catch (e: InvalidPropertiesException) { + e.errors.toErrorResult() + } } 4 -> parsedTable.mapIndexed { rowIdx, row -> - ExperimentalData( - ab2 = row[0].process("AB/2", rowIdx, 0), - mn2 = row[1].process("MN/2", rowIdx, 1), - voltage = row[2].process("U", rowIdx, 2), - amperage = row[3].process("I", rowIdx, 3) - ) + try { + ExperimentalData( + ab2 = row[0].process("AB/2", rowIdx, 0), + mn2 = row[1].process("MN/2", rowIdx, 1), + voltage = row[2].process("U", rowIdx, 2), + amperage = row[3].process("I", rowIdx, 3) + ).toOkResult() + } catch (e: InvalidPropertiesException) { + e.errors.toErrorResult() + } } 5 -> parsedTable.mapIndexed { rowIdx, row -> - ExperimentalData( - ab2 = row[0].process("AB/2", rowIdx, 0), - mn2 = row[1].process("MN/2", rowIdx, 1), - voltage = row[2].process("U", rowIdx, 2), - amperage = row[3].process("I", rowIdx, 3), - resistanceApparent = row[4].process("ρₐ", rowIdx, 4) - ) + try { + ExperimentalData( + ab2 = row[0].process("AB/2", rowIdx, 0), + mn2 = row[1].process("MN/2", rowIdx, 1), + voltage = row[2].process("U", rowIdx, 2), + amperage = row[3].process("I", rowIdx, 3), + resistivityApparent = row[4].process("ρₐ", rowIdx, 4) + ).toOkResult() + } catch (e: InvalidPropertiesException) { + e.errors.toErrorResult() + } } else -> { @@ -509,14 +467,17 @@ class ExperimentalTableController @Inject constructor( ) } } - for (item in pastedItems) { - val violations = validator.validate(item) - if (violations.isNotEmpty()) { - alertsFactory.violationsAlert(violations, stage).show() - return - } + val invalidInputMessage = pastedItems.mapNotNull { it.errorOrNull() } + .flatten() + .map { it.property } + .distinct() + .joinToString(separator = "\n") { uiProps["invalid.exp.$it"] } + .takeIf { it.isNotBlank() } + if (invalidInputMessage != null) { + alertsFactory.invalidInputAlert(invalidInputMessage).show() + } else { + table.items.setAll(pastedItems.mapNotNull { it.okOrNull() }.map { it.toObservable() }) } - table.items += pastedItems.map { mapper.toObservable(it) } } catch (e: Exception) { alertsFactory.simpleExceptionAlert(e, stage).show() } diff --git a/src/main/java/ru/nucodelabs/gem/view/controller/tables/ModelTableController.kt b/src/main/java/ru/nucodelabs/gem/view/controller/tables/ModelTableController.kt index 55d071a0..377d52f3 100644 --- a/src/main/java/ru/nucodelabs/gem/view/controller/tables/ModelTableController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/controller/tables/ModelTableController.kt @@ -2,7 +2,6 @@ package ru.nucodelabs.gem.view.controller.tables import jakarta.inject.Inject import jakarta.inject.Provider -import jakarta.validation.Validator import javafx.beans.binding.Bindings.createBooleanBinding import javafx.beans.binding.Bindings.createStringBinding import javafx.beans.property.IntegerProperty @@ -15,30 +14,27 @@ import javafx.scene.control.* import javafx.scene.control.cell.TextFieldTableCell import javafx.scene.input.* import javafx.scene.layout.VBox -import javafx.stage.Stage import javafx.util.Callback import javafx.util.StringConverter import ru.nucodelabs.gem.fxmodel.ves.ObservableModelLayer import ru.nucodelabs.gem.fxmodel.ves.ObservableSection import ru.nucodelabs.gem.fxmodel.ves.app.VesFxAppModel import ru.nucodelabs.gem.fxmodel.ves.mapper.VesFxModelMapper +import ru.nucodelabs.gem.fxmodel.ves.toObservable import ru.nucodelabs.gem.view.AlertsFactory -import ru.nucodelabs.gem.view.controller.AbstractController import ru.nucodelabs.gem.view.controller.FileImporter import ru.nucodelabs.gem.view.controller.main.InitialModelConfigurationViewController import ru.nucodelabs.gem.view.controller.util.DEFAULT_FONT_SIZE import ru.nucodelabs.gem.view.controller.util.indexCellFactory -import ru.nucodelabs.geo.ves.ModelLayer -import ru.nucodelabs.geo.ves.Picket -import ru.nucodelabs.geo.ves.Section +import ru.nucodelabs.geo.ves.* import ru.nucodelabs.geo.ves.calc.divide import ru.nucodelabs.geo.ves.calc.join import ru.nucodelabs.geo.ves.calc.zOfModelLayers -import ru.nucodelabs.geo.ves.toTabulatedTable +import ru.nucodelabs.kfx.core.AbstractViewController +import ru.nucodelabs.kfx.ext.get import ru.nucodelabs.kfx.ext.toObservableList import ru.nucodelabs.kfx.snapshot.HistoryManager -import ru.nucodelabs.util.TextToTableParser -import ru.nucodelabs.util.std.toDoubleOrNullBy +import ru.nucodelabs.util.* import tornadofx.getValue import java.net.URL import java.text.DecimalFormat @@ -62,13 +58,13 @@ class ModelTableController @Inject constructor( private val alertsFactory: AlertsFactory, private val observableSection: ObservableSection, private val picketIndexProperty: IntegerProperty, - private val validator: Validator, private val historyManager: HistoryManager
, - private val doubleStringConverter: StringConverter, + private val converter: StringConverter, private val decimalFormat: DecimalFormat, private val mapper: VesFxModelMapper, - private val appModel: VesFxAppModel -) : AbstractController(), FileImporter by fileImporterProvider.get() { + private val appModel: VesFxAppModel, + private val uiProps: ResourceBundle +) : AbstractViewController(), FileImporter by fileImporterProvider.get() { @FXML private lateinit var copyFromRightBtn: Button @@ -77,16 +73,16 @@ class ModelTableController @Inject constructor( private lateinit var copyFromLeftBtn: Button @FXML - private lateinit var zCol: TableColumn + private lateinit var zCol: TableColumn @FXML private lateinit var indexCol: TableColumn @FXML - private lateinit var powerCol: TableColumn + private lateinit var powerCol: TableColumn @FXML - private lateinit var resistanceCol: TableColumn + private lateinit var resCol: TableColumn @FXML private lateinit var table: TableView @@ -97,16 +93,13 @@ class ModelTableController @Inject constructor( @FXML private lateinit var initialModelConfigurationViewController: InitialModelConfigurationViewController - override val stage: Stage? - get() = table.scene.window as Stage? - - private val picket: Picket get() = picketObservable.get()!! private val picketIndex by picketIndexProperty override fun initialize(location: URL, resources: ResourceBundle) { + table.columnResizePolicy = TableView.CONSTRAINED_RESIZE_POLICY_LAST_COLUMN picketObservable.addListener { _, oldValue, newValue -> newValue?.let { if (oldValue != null @@ -157,10 +150,10 @@ class ModelTableController @Inject constructor( table.items.setAll(modelData.map { mapper.toObservable(it) }) } - private fun fixResistanceForSelected() { + private fun fixResistivityForSelected() { val modelData = picket.modelData.toMutableList() for (index in table.selectionModel.selectedIndices) { - modelData[index] = modelData[index].copy(isFixedResistance = true) + modelData[index] = modelData[index].copy(isFixedResistivity = true) } table.items.setAll(modelData.map { mapper.toObservable(it) }) } @@ -173,10 +166,10 @@ class ModelTableController @Inject constructor( table.items.setAll(modelData.map { mapper.toObservable(it) }) } - private fun unfixResistanceForSelected() { + private fun unfixResistivityForSelected() { val modelData = picket.modelData.toMutableList() for (index in table.selectionModel.selectedIndices) { - modelData[index] = modelData[index].copy(isFixedResistance = false) + modelData[index] = modelData[index].copy(isFixedResistivity = false) } table.items.setAll(modelData.map { mapper.toObservable(it) }) } @@ -198,12 +191,12 @@ class ModelTableController @Inject constructor( ).apply { if (table.selectionModel.selectedItems.size == 1) { items += MenuItem().apply { - if (item.isFixedResistance) { + if (item.isFixedResistivity) { text = "Разблокировать сопротивление" - onAction = EventHandler { unfixResistanceForSelected() } + onAction = EventHandler { unfixResistivityForSelected() } } else { text = "Зафиксировать сопротивление" - onAction = EventHandler { fixResistanceForSelected() } + onAction = EventHandler { fixResistivityForSelected() } } } items += MenuItem().apply { @@ -221,10 +214,10 @@ class ModelTableController @Inject constructor( onAction = EventHandler { joinSelected() } }, MenuItem("Зафиксировать сопротивление").apply { - onAction = EventHandler { fixResistanceForSelected() } + onAction = EventHandler { fixResistivityForSelected() } }, MenuItem("Разблокировать сопротивление").apply { - onAction = EventHandler { unfixResistanceForSelected() } + onAction = EventHandler { unfixResistivityForSelected() } }, MenuItem("Зафиксировать мощность").apply { onAction = EventHandler { fixPowerForSelected() } @@ -238,7 +231,9 @@ class ModelTableController @Inject constructor( } } - onContextMenuRequested = EventHandler { createContextMenu().show(this, it.screenX, it.screenY) } + onContextMenuRequested = EventHandler { + if (item != null) createContextMenu().show(this, it.screenX, it.screenY) + } } } } @@ -270,7 +265,7 @@ class ModelTableController @Inject constructor( modelData.add(0, modelData[index].copy(power = 10.0)) } else { if (index == modelData.lastIndex) { - modelData.add(index, modelData[index - 1].copy(resistance = modelData.last().resistance)) + modelData.add(index, modelData[index - 1].copy(resistivity = modelData.last().resistivity)) } else { val (fst, snd) = modelData[index].divide() modelData[index] = fst @@ -278,15 +273,21 @@ class ModelTableController @Inject constructor( } } } + if (modelData.size > Picket.MAX_MODEL_DATA_SIZE) { + alertsFactory.simpleAlert( + text = "Количество слоев модели не должно превышать ${Picket.MAX_MODEL_DATA_SIZE}" + ).show() + return + } table.items.setAll(modelData.map { mapper.toObservable(it) }) } private fun setupCellFactories() { indexCol.cellFactory = indexCellFactory() - powerCol.cellValueFactory = Callback { features -> features.value.powerProperty().asObject() } - resistanceCol.cellValueFactory = Callback { features -> features.value.resistanceProperty().asObject() } + powerCol.cellValueFactory = Callback { features -> features.value.powerProperty() } + resCol.cellValueFactory = Callback { features -> features.value.resistivityProperty() } zCol.cellFactory = Callback { - TableCell().apply { + TableCell().apply { textProperty().bind( createStringBinding( { @@ -306,35 +307,42 @@ class ModelTableController @Inject constructor( } val editableColumns = listOf( - powerCol, - resistanceCol + powerCol to ModelLayer::validatePower, + resCol to ModelLayer::validateResistivity ) - editableColumns.forEach { - it.cellFactory = Callback { col -> - TextFieldTableCell.forTableColumn(doubleStringConverter).call(col).apply { + editableColumns.forEach { (col, validate) -> + col.cellFactory = Callback { _ -> + TextFieldTableCell(converter).apply { when (col) { - powerCol -> indexProperty().addListener { _, _, _ -> - if (index >= 0 && index <= picket.modelData.lastIndex) { - style = if (picket.modelData[index].isFixedPower) { - STYLE_FOR_FIXED - } else { - "" - } - } - } + powerCol -> tableRowProperty() + .flatMap { it.itemProperty() } + .flatMap { it.fixedPowerProperty() } + .addListener { _, _, isFixed -> style = if (isFixed ?: false) STYLE_FOR_FIXED else "" } + + + resCol -> tableRowProperty() + .flatMap { it.itemProperty() } + .flatMap { it.fixedResistivityProperty() } + .addListener { _, _, isFixed -> style = if (isFixed ?: false) STYLE_FOR_FIXED else "" } - resistanceCol -> indexProperty().addListener { _, _, _ -> - if (index >= 0 && index <= picket.modelData.lastIndex) { - style = if (picket.modelData[index].isFixedResistance) { - STYLE_FOR_FIXED - } else { - "" - } - } - } } + } } + + val onEditCommitHandler = col.onEditCommit + col.onEditCommit = EventHandler { event -> + if (event.newValue == null) { + event.consume() + return@EventHandler + } + validate(event.newValue.toDouble())?.let { (prop, _) -> + alertsFactory.invalidInputAlert(uiProps["invalid.model.$prop"]).show() + event.consume() + return@EventHandler + } + onEditCommitHandler.handle(event) + } } } @@ -383,35 +391,19 @@ class ModelTableController @Inject constructor( private fun listenToItemsProperties(items: List) { items.forEach { layer -> - layer.powerProperty().addListener { _, oldPow, newPow -> - val violations = validator.validateValue(ModelLayer::class.java, "power", newPow) - if (violations.isEmpty()) { - commitChanges() - update() - } else { - layer.power = oldPow.toDouble() - alertsFactory.violationsAlert(violations, stage).show() - } - } - layer.resistanceProperty().addListener { _, oldRes, newRes -> - val violations = validator.validateValue(ModelLayer::class.java, "resistance", newRes) - if (violations.isEmpty()) { - commitChanges() - } else { - layer.resistance = oldRes.toDouble() - alertsFactory.violationsAlert(violations, stage).show() - } - } + layer.powerProperty().addListener { _, oldPow, newPow -> commitChanges() } + layer.resistivityProperty().addListener { _, oldRes, newRes -> commitChanges() } layer.fixedPowerProperty().addListener { _, _, _ -> commitChanges() } - layer.fixedResistanceProperty().addListener { _, _, _ -> commitChanges() } + layer.fixedResistivityProperty().addListener { _, _, _ -> commitChanges() } } } private fun commitChanges() { - val modelDataInTable = table.items.map { mapper.toModel(it) } - if (modelDataInTable != picket.modelData) { + val mappedModel = table.items.map { mapper.toModel(it) } + if (mappedModel != picket.modelData) { + val update = picket.copy(modelData = mappedModel) historyManager.snapshotAfter { - observableSection.pickets[picketIndex] = picket.copy(modelData = modelDataInTable) + observableSection.pickets[picketIndex] = update } } } @@ -481,14 +473,18 @@ class ModelTableController @Inject constructor( ?.toDoubleOrNullBy(decimalFormat) ?: throw IllegalArgumentException("${a[col]}${row + 1} - Ожидалось $expected, было $this") - val pastedItems: List = when (parser.columnsCount) { + val pastedItems = when (parser.columnsCount) { 2 -> parsedTable.mapIndexed { rowIdx, row -> val pow = row[0].process("H", rowIdx, 0) val res = row[1].process("ρ", rowIdx, 1) - ModelLayer( - resistance = res, - power = pow - ) + try { + ModelLayer( + resistivity = res, + power = pow + ).toOkResult() + } catch (e: InvalidPropertiesException) { + e.errors.toErrorResult() + } } else -> { @@ -503,14 +499,18 @@ class ModelTableController @Inject constructor( ) } } - for (item in pastedItems) { - val violations = validator.validate(item) - if (violations.isNotEmpty()) { - alertsFactory.violationsAlert(violations, stage).show() - return - } + val invalidInputMessage = pastedItems + .mapNotNull { it.errorOrNull() } + .flatten() + .map { it.property } + .distinct() + .joinToString(separator = "\n") { uiProps["invalid.model.$it"] } + .takeIf { it.isNotBlank() } + if (invalidInputMessage != null) { + alertsFactory.invalidInputAlert(invalidInputMessage).show() + } else { + table.items.setAll(pastedItems.mapNotNull { it.okOrNull() }.map { it.toObservable() }) } - table.items += pastedItems.map { mapper.toObservable(it) } } catch (e: Exception) { alertsFactory.simpleExceptionAlert(e, stage).show() } diff --git a/src/main/java/ru/nucodelabs/gem/view/mapping/ViewMapping.kt b/src/main/java/ru/nucodelabs/gem/view/mapping/ViewMapping.kt index 3c90bb14..e8489412 100644 --- a/src/main/java/ru/nucodelabs/gem/view/mapping/ViewMapping.kt +++ b/src/main/java/ru/nucodelabs/gem/view/mapping/ViewMapping.kt @@ -22,12 +22,12 @@ fun mapAzimuthSignals(azimuthSignals: List): Observabl Data( xFromCenter(signal.ab2, observableAzimuthSignals.azimuth), yFromCenter(signal.ab2, observableAzimuthSignals.azimuth), - signal.resistanceApparent + signal.resistivityApparent ), Data( xFromCenter(signal.ab2, !observableAzimuthSignals.azimuth), yFromCenter(signal.ab2, !observableAzimuthSignals.azimuth), - signal.resistanceApparent + signal.resistivityApparent ) ) }.flatMap { it.toList() } @@ -41,9 +41,9 @@ fun mapAzimuthSignals(azimuthSignals: List): Observabl fun mapSignals(signals: List): Series { return Series( signals.map { - Data(it.ab2 as Number, it.resistanceApparent as Number, it).apply { + Data(it.ab2 as Number, it.resistivityApparent as Number, it).apply { XValueProperty().bind(it.ab2Property()) - YValueProperty().bind(it.resistanceApparentProperty()) + YValueProperty().bind(it.resistivityApparentProperty()) } }.toObservableList() ) diff --git a/src/main/java/ru/nucodelabs/geo/anisotropy/Constraints.kt b/src/main/java/ru/nucodelabs/geo/anisotropy/Constraints.kt index dbd54146..789d52fd 100644 --- a/src/main/java/ru/nucodelabs/geo/anisotropy/Constraints.kt +++ b/src/main/java/ru/nucodelabs/geo/anisotropy/Constraints.kt @@ -1,5 +1,5 @@ package ru.nucodelabs.geo.anisotropy const val MIN_POWER = 0.0 -const val MIN_RESISTANCE = 0.1 +const val MIN_RESISTIVITY = 0.1 const val MAX_LAYERS_COUNT = 40 \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/geo/anisotropy/ModelLayer.kt b/src/main/java/ru/nucodelabs/geo/anisotropy/ModelLayer.kt index e7ed20eb..f1658dda 100644 --- a/src/main/java/ru/nucodelabs/geo/anisotropy/ModelLayer.kt +++ b/src/main/java/ru/nucodelabs/geo/anisotropy/ModelLayer.kt @@ -3,14 +3,14 @@ package ru.nucodelabs.geo.anisotropy /** * Слой модели * @property power Мощность, м - * @property resistance Сопротивление, Ом * м + * @property resistivity Сопротивление, Ом * м * @property verticalAnisotropyCoefficient коэффициент анизотропии по оси Z * @property azimuth азимутальный угол анизотропии * @property azimuthAnisotropyCoefficient коэффициент анизотропии в азимутальной плоскости XY */ data class ModelLayer( var power: FixableValue, - var resistance: FixableValue, + var resistivity: FixableValue, var verticalAnisotropyCoefficient: FixableValue, var azimuth: FixableValue, var azimuthAnisotropyCoefficient: FixableValue, diff --git a/src/main/java/ru/nucodelabs/geo/anisotropy/Signal.kt b/src/main/java/ru/nucodelabs/geo/anisotropy/Signal.kt index 5b1b851f..3e1df3ae 100644 --- a/src/main/java/ru/nucodelabs/geo/anisotropy/Signal.kt +++ b/src/main/java/ru/nucodelabs/geo/anisotropy/Signal.kt @@ -14,8 +14,8 @@ import ru.nucodelabs.geo.ves.calc.u * @property mn2 MN/2, м * @property amperage Ток, мА * @property voltage Напряжение, мВ - * @property resistanceApparent Сопротивление кажущееся, Ом * м - * @property errorResistanceApparent Погрешность, % + * @property resistivityApparent Сопротивление кажущееся, Ом * м + * @property errorResistivityApparent Погрешность, % * @property isHidden Отключена для интерпретации */ data class Signal( @@ -23,25 +23,30 @@ data class Signal( @field:Positive val mn2: Double, @field:Min(0) var amperage: Double, @field:Min(0) var voltage: Double, - @field:DecimalMin(MIN_RESISTANCE.toString()) var resistanceApparent: Double = rhoA(ab2, mn2, amperage, voltage), - @field:Min(0) @field:Max(100) var errorResistanceApparent: Double = DEFAULT_ERROR, + @field:DecimalMin(MIN_RESISTIVITY.toString()) var resistivityApparent: Double = rhoA(ab2, mn2, amperage, voltage), + @field:Min(0) @field:Max(100) var errorResistivityApparent: Double = DEFAULT_ERROR, val isHidden: Boolean = false -) +) { + companion object Factory { + @Suppress("unused") + @JvmStatic + fun withCalculatedVoltage( + ab2: Double, + mn2: Double, + resistivityApparent: Double, + amperage: Double = DEFAULT_AMPERAGE, + voltage: Double = u(resistivityApparent, amperage, k(ab2, mn2)), + errorResistivityApparent: Double = DEFAULT_ERROR, + isHidden: Boolean = false + ) = Signal( + ab2 = ab2, + mn2 = mn2, + amperage = amperage, + voltage = voltage, + resistivityApparent = resistivityApparent, + errorResistivityApparent = errorResistivityApparent, + isHidden = isHidden + ) + } +} -fun signalWithOnlyRhoA( - ab2: Double, - mn2: Double, - resistanceApparent: Double, - amperage: Double = DEFAULT_AMPERAGE, - voltage: Double = u(resistanceApparent, amperage, k(ab2, mn2)), - errorResistanceApparent: Double = DEFAULT_ERROR, - isHidden: Boolean = false -) = Signal( - ab2 = ab2, - mn2 = mn2, - amperage = amperage, - voltage = voltage, - resistanceApparent = resistanceApparent, - errorResistanceApparent = errorResistanceApparent, - isHidden = isHidden -) diff --git a/src/main/java/ru/nucodelabs/geo/anisotropy/calc/AnisotropyFunctions.kt b/src/main/java/ru/nucodelabs/geo/anisotropy/calc/AnisotropyFunctions.kt index 19edbb0c..dee6d175 100644 --- a/src/main/java/ru/nucodelabs/geo/anisotropy/calc/AnisotropyFunctions.kt +++ b/src/main/java/ru/nucodelabs/geo/anisotropy/calc/AnisotropyFunctions.kt @@ -31,7 +31,7 @@ fun forwardSolve( signalsOut, model.size.toShort(), model.map { it.power.value }.toDoubleArray(), - model.map { it.resistance.value }.toDoubleArray(), + model.map { it.resistivity.value }.toDoubleArray(), model.map { it.verticalAnisotropyCoefficient.value }.toDoubleArray(), model.map { it.azimuth.value }.toDoubleArray(), model.map { it.azimuthAnisotropyCoefficient.value }.toDoubleArray() @@ -45,7 +45,7 @@ fun forwardSolve( it.copy( signals = Signals( it.signals.sortedSignals.map { signal -> - val new = signal.copy(resistanceApparent = signalsOut[i]) + val new = signal.copy(resistivityApparent = signalsOut[i]) i++ new } @@ -69,13 +69,13 @@ fun inverseSolveInPlace( }.toByteArray() val AB2 = signals.map { it.ab2 }.toDoubleArray() val MN2 = signals.map { it.mn2 }.toDoubleArray() - val rel_error = signals.map { it.errorResistanceApparent / 100.0 }.toDoubleArray() + val rel_error = signals.map { it.errorResistivityApparent / 100.0 }.toDoubleArray() val n_layers = model.size.toShort() val fix_h = model.map { if (it.power.isFixed) 1.toByte() else 0.toByte() }.toByteArray() val h = model.map { it.power.value }.toDoubleArray() - val fix_ro = model.map { if (it.resistance.isFixed) 1.toByte() else 0.toByte() }.toByteArray() - val ro_avg = model.map { it.resistance.value }.toDoubleArray() + val fix_ro = model.map { if (it.resistivity.isFixed) 1.toByte() else 0.toByte() }.toByteArray() + val ro_avg = model.map { it.resistivity.value }.toDoubleArray() val fix_kanisotropy_vert = model.map { if (it.verticalAnisotropyCoefficient.isFixed) 1.toByte() else 0.toByte() }.toByteArray() val kanisotropy_vert = model.map { it.verticalAnisotropyCoefficient.value }.toDoubleArray() @@ -92,7 +92,7 @@ fun inverseSolveInPlace( idx_azimuth, AB2, MN2, - signals.map { it.resistanceApparent }.toDoubleArray(), + signals.map { it.resistivityApparent }.toDoubleArray(), rel_error, n_layers, fix_h, @@ -113,7 +113,7 @@ fun inverseSolveInPlace( model.forEachIndexed { i, layer -> layer.power.value = h[i] - layer.resistance.value = ro_avg[i] + layer.resistivity.value = ro_avg[i] layer.verticalAnisotropyCoefficient.value = kanisotropy_vert[i] layer.azimuth.value = azimuth[i] layer.azimuthAnisotropyCoefficient.value = kanisotropy_azimuth[i] @@ -131,7 +131,7 @@ fun convertModel( val h = singleLayer.map { it.power }.toDoubleArray() val n_model = models.size val model_azimuth = azimuths.toDoubleArray() - val ro_isotrop = allLayers.map { it.resistance }.toDoubleArray() + val ro_isotrop = allLayers.map { it.resistivity }.toDoubleArray() val ro_avg = List(n_layers) { 0.0 }.toDoubleArray() val kanisotropy_vert = List(n_layers) { 0.0 }.toDoubleArray() @@ -159,7 +159,7 @@ fun convertModel( anizotropyModel.add( ModelLayer( power = FixableValue(h[i], false), - resistance = FixableValue(ro_avg[i], false), + resistivity = FixableValue(ro_avg[i], false), verticalAnisotropyCoefficient = FixableValue(kanisotropy_vert[i], false), azimuth = FixableValue(azimuth[i], false), azimuthAnisotropyCoefficient = FixableValue(kanisotropy_azimuth[i], false) diff --git a/src/main/java/ru/nucodelabs/geo/anisotropy/calc/SignalFunctions.kt b/src/main/java/ru/nucodelabs/geo/anisotropy/calc/SignalFunctions.kt index 4554905d..402e3fd2 100644 --- a/src/main/java/ru/nucodelabs/geo/anisotropy/calc/SignalFunctions.kt +++ b/src/main/java/ru/nucodelabs/geo/anisotropy/calc/SignalFunctions.kt @@ -33,8 +33,8 @@ fun processSignals(signals: List): List { return acc.sortedWith(orderSignalsByDistances()) } -val Signal.resistanceApparentUpperBoundByError - get() = (resistanceApparent + resistanceApparent * errorResistanceApparent / 100).coerceAtLeast(1.0) +val Signal.resistivityApparentUpperBoundByError + get() = (resistivityApparent + resistivityApparent * errorResistivityApparent / 100).coerceAtLeast(1.0) -val Signal.resistanceApparentLowerBoundByError - get() = (resistanceApparent - resistanceApparent * errorResistanceApparent / 100).coerceAtLeast(1.0) \ No newline at end of file +val Signal.resistivityApparentLowerBoundByError + get() = (resistivityApparent - resistivityApparent * errorResistivityApparent / 100).coerceAtLeast(1.0) \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/geo/anisotropy/calc/SignalRelation.kt b/src/main/java/ru/nucodelabs/geo/anisotropy/calc/SignalRelation.kt index 2b01007c..61fc24d3 100644 --- a/src/main/java/ru/nucodelabs/geo/anisotropy/calc/SignalRelation.kt +++ b/src/main/java/ru/nucodelabs/geo/anisotropy/calc/SignalRelation.kt @@ -22,7 +22,7 @@ fun signalsRelations(current: AzimuthSignals, all: List): List Relation( signal.ab2, - current.signals.effectiveSignals[index].resistanceApparent / signal.resistanceApparent + current.signals.effectiveSignals[index].resistivityApparent / signal.resistivityApparent ) }) } diff --git a/src/main/java/ru/nucodelabs/geo/forward/ForwardSolver.kt b/src/main/java/ru/nucodelabs/geo/forward/ForwardSolver.kt index 39dad63b..966e1f3c 100644 --- a/src/main/java/ru/nucodelabs/geo/forward/ForwardSolver.kt +++ b/src/main/java/ru/nucodelabs/geo/forward/ForwardSolver.kt @@ -5,6 +5,6 @@ interface ForwardSolver { experimentalAb2: List, experimentalMn2: List, modelPower: List, - modelResistance: List, + modelResistivity: List, ): List } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/geo/forward/impl/SonetForwardSolverAdapter.kt b/src/main/java/ru/nucodelabs/geo/forward/impl/SonetForwardSolverAdapter.kt index 44a54c24..c917efc5 100644 --- a/src/main/java/ru/nucodelabs/geo/forward/impl/SonetForwardSolverAdapter.kt +++ b/src/main/java/ru/nucodelabs/geo/forward/impl/SonetForwardSolverAdapter.kt @@ -10,10 +10,10 @@ class SonetForwardSolverAdapter : ForwardSolver { experimentalAb2: List, experimentalMn2: List, modelPower: List, - modelResistance: List + modelResistivity: List ): List { return solver.solve( - modelResistance.toDoubleArray(), + modelResistivity.toDoubleArray(), modelPower.toDoubleArray(), modelPower.size, experimentalAb2.toDoubleArray(), diff --git a/src/main/java/ru/nucodelabs/geo/target/impl/SquareDiffErrorAwareTargetFunction.kt b/src/main/java/ru/nucodelabs/geo/target/impl/SquareDiffErrorAwareTargetFunction.kt index 1f4f5186..be1d2029 100644 --- a/src/main/java/ru/nucodelabs/geo/target/impl/SquareDiffErrorAwareTargetFunction.kt +++ b/src/main/java/ru/nucodelabs/geo/target/impl/SquareDiffErrorAwareTargetFunction.kt @@ -1,7 +1,7 @@ package ru.nucodelabs.geo.target.impl import ru.nucodelabs.geo.target.RelativeErrorAwareTargetFunction -import ru.nucodelabs.util.std.fromPercent +import ru.nucodelabs.util.fromPercent import kotlin.math.pow /** diff --git a/src/main/java/ru/nucodelabs/geo/ves/ExperimentalData.kt b/src/main/java/ru/nucodelabs/geo/ves/ExperimentalData.kt index 33fe236f..6a8e2865 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/ExperimentalData.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/ExperimentalData.kt @@ -1,10 +1,27 @@ package ru.nucodelabs.geo.ves -import jakarta.validation.constraints.DecimalMin -import jakarta.validation.constraints.Max -import jakarta.validation.constraints.Min -import jakarta.validation.constraints.Positive import ru.nucodelabs.geo.ves.calc.rhoA +import ru.nucodelabs.util.validate + +interface ReadOnlyExperimentalSignal { + val ab2: Double + val mn2: Double + val amperage: Double + val voltage: Double + val resistivityApparent: Double + val errorResistivityApparent: Double + val isHidden: Boolean +} + +interface MutableExperimentalSignal : ReadOnlyExperimentalSignal { + override var ab2: Double + override var mn2: Double + override var amperage: Double + override var voltage: Double + override var resistivityApparent: Double + override var errorResistivityApparent: Double + override var isHidden: Boolean +} /** * Экспериментальное измерение @@ -12,20 +29,86 @@ import ru.nucodelabs.geo.ves.calc.rhoA * @property mn2 MN/2, м * @property amperage Ток, мА * @property voltage Напряжение, мВ - * @property resistanceApparent Сопротивление кажущееся, Ом * м - * @property errorResistanceApparent Погрешность, % + * @property resistivityApparent Сопротивление кажущееся, Ом * м + * @property errorResistivityApparent Погрешность, % * @property isHidden Отключена для интерпретации */ data class ExperimentalData( - @field:Positive val ab2: Double, - @field:Positive val mn2: Double, - @field:Min(0) val amperage: Double, - @field:Min(0) val voltage: Double, - @field:DecimalMin("0.1") val resistanceApparent: Double = rhoA(ab2, mn2, amperage, voltage), - @field:Min(0) @field:Max(100) val errorResistanceApparent: Double = DEFAULT_ERROR, - val isHidden: Boolean = false -) { - companion object Defaults { + override val ab2: Double, + override val mn2: Double, + override val amperage: Double, + override val voltage: Double, + override val resistivityApparent: Double = rhoA(ab2, mn2, amperage, voltage), + override val errorResistivityApparent: Double = DEFAULT_ERROR, + override val isHidden: Boolean = false +) : ReadOnlyExperimentalSignal { + + init { + val errors = listOfNotNull( + validateAb2(ab2), + validateMn2(mn2), + validateAmperage(amperage), + validateVoltage(voltage), + validateResistApparent(resistivityApparent), + validateErrResistApparent(errorResistivityApparent), + ) + if (errors.isNotEmpty()) throw InvalidPropertiesException(errors) + } + + companion object Meta { const val DEFAULT_ERROR = 5.0 + + const val MIN_DIST = .0 + const val MIN_AMP = .0 + const val MIN_VOLT = .0 + const val MIN_RESIST_APP = 0.1 + const val MIN_ERROR_RESIST_APP = .0 + const val MAX_ERROR_RESIST_APP = 100.0 + + const val AB2 = "ab2" + fun validateAb2(ab2: Double) = validate(isValidDistance(ab2)) { + InvalidPropertyValue(AB2, "AB/2 must be >= $MIN_DIST", ab2) + } + + const val MN2 = "mn2" + fun validateMn2(mn2: Double) = validate(isValidDistance(mn2)) { + InvalidPropertyValue(MN2, "MN/2 must be >= $MIN_DIST", mn2) + } + + fun isValidDistance(dist: Double) = dist >= MIN_DIST + + const val AMPERAGE = "amperage" + fun validateAmperage(amperage: Double) = validate(isValidAmperage(amperage)) { + InvalidPropertyValue(AMPERAGE, "Amperage must be >= $MIN_AMP", amperage) + } + + fun isValidAmperage(amperage: Double) = amperage >= MIN_AMP + + const val VOLTAGE = "voltage" + fun validateVoltage(voltage: Double) = validate(isValidVoltage(voltage)) { + InvalidPropertyValue(VOLTAGE, "Voltage must be >= $MIN_VOLT", voltage) + } + + fun isValidVoltage(voltage: Double) = voltage >= MIN_VOLT + + const val RESIST_APP = "resistivityApparent" + fun validateResistApparent(resistApparent: Double) = validate(isValidResistApparent(resistApparent)) { + InvalidPropertyValue(RESIST_APP, "Resistivity Apparent must be >= $MIN_RESIST_APP", resistApparent) + } + + fun isValidResistApparent(resistApparent: Double) = resistApparent >= MIN_RESIST_APP + + const val ERR_RESIST_APP = "errorResistivityApparent" + fun validateErrResistApparent(errResistApparent: Double) = + validate(isValidErrResistApparent(errResistApparent)) { + InvalidPropertyValue( + ERR_RESIST_APP, + "Error for Resist Apparent must be in range $MIN_ERROR_RESIST_APP - $MAX_ERROR_RESIST_APP %", + errResistApparent + ) + } + + fun isValidErrResistApparent(errResistApparent: Double) = + errResistApparent in MIN_ERROR_RESIST_APP..MAX_ERROR_RESIST_APP } } diff --git a/src/main/java/ru/nucodelabs/geo/ves/ExperimentalDataSet.kt b/src/main/java/ru/nucodelabs/geo/ves/ExperimentalDataSet.kt new file mode 100644 index 00000000..8ebfc9f4 --- /dev/null +++ b/src/main/java/ru/nucodelabs/geo/ves/ExperimentalDataSet.kt @@ -0,0 +1,57 @@ +package ru.nucodelabs.geo.ves + +import ru.nucodelabs.geo.ves.calc.orderByDistances + + +interface ExperimentalDataSet { + val sortedExperimentalData: List + val effectiveExperimentalData: List + val offsetX: Double +} + +interface MutableExperimentalDataSet : ExperimentalDataSet { + fun addSignal(signal: E) + fun addSignals(signals: Iterable) + fun removeSignal(signal: E) + fun removeSignals(signals: Iterable) + fun edit(index: Int, mutate: MutableExperimentalSignal.() -> Unit) +} + +fun toSortedExperimentalData(experimentalData: List): List { + val acc = mutableListOf() + + // Группируем по AB + val dupGroups = experimentalData.groupBy { it.ab2 } + for ((_, group) in dupGroups) { + // Если больше одного не отключенного дубликата в группе + acc += if (group.filter { !it.isHidden }.size > 1) { + val sortedGroup = group.sortedWith(orderByDistances()) + List(sortedGroup.size) { idx -> + // Отключаем все кроме последнего (с наиб. MN) + if (idx < sortedGroup.lastIndex) { + sortedGroup[idx].copy(isHidden = true) + } else { + sortedGroup[idx].copy(isHidden = false) + } + } + } else { + group + } + } + + return acc.sortedWith(orderByDistances()) +} + +fun hideExtraSignalsInPlace(sortedExperimentalData: List) { + val groupsByAb = sortedExperimentalData.groupBy { it.ab2 } + + for ((_, group) in groupsByAb) { + if (group.filter { !it.isHidden }.size <= 1) { + continue + } else { + group.sortedWith(orderByDistances()).forEachIndexed { idx, item -> + item.isHidden = idx != group.lastIndex + } + } + } +} \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/geo/ves/InvalidPropertiesException.kt b/src/main/java/ru/nucodelabs/geo/ves/InvalidPropertiesException.kt new file mode 100644 index 00000000..62b5e5ad --- /dev/null +++ b/src/main/java/ru/nucodelabs/geo/ves/InvalidPropertiesException.kt @@ -0,0 +1,11 @@ +package ru.nucodelabs.geo.ves + +class InvalidPropertiesException( + val errors: List +) : Exception(errors.joinToString()) + +data class InvalidPropertyValue( + val property: String, + val message: String, + val value: Any? +) \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/geo/ves/JavaApi.kt b/src/main/java/ru/nucodelabs/geo/ves/JavaApi.kt index 9ac9d5e6..263b5dd3 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/JavaApi.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/JavaApi.kt @@ -6,33 +6,33 @@ class ExperimentalDataBuilder(source: ExperimentalData) { private var mn2: Double = source.mn2 private var amperage: Double = source.amperage private var voltage: Double = source.voltage - private var resistanceApparent: Double = source.resistanceApparent - private var errorResistanceApparent: Double = source.errorResistanceApparent + private var resistivityApparent: Double = source.resistivityApparent + private var errorResistivityApparent: Double = source.errorResistivityApparent private var isHidden: Boolean = source.isHidden fun ab2(value: Double) = apply { ab2 = value } fun mn2(value: Double) = apply { mn2 = value } fun amperage(value: Double) = apply { amperage = value } fun voltage(value: Double) = apply { voltage = value } - fun resistanceApparent(value: Double) = apply { resistanceApparent = value } - fun errorResistanceApparent(value: Double) = apply { errorResistanceApparent = value } + fun resistivityApparent(value: Double) = apply { resistivityApparent = value } + fun errorResistivityApparent(value: Double) = apply { errorResistivityApparent = value } fun isHidden(value: Boolean) = apply { isHidden = value } - fun build() = ExperimentalData(ab2, mn2, amperage, voltage, resistanceApparent, errorResistanceApparent, isHidden) + fun build() = ExperimentalData(ab2, mn2, amperage, voltage, resistivityApparent, errorResistivityApparent, isHidden) } fun copy(source: ExperimentalData) = ExperimentalDataBuilder(source) class ModelLayerBuilder(source: ModelLayer) { private var power = source.power - private var resistance = source.resistance + private var resistivity = source.resistivity private var isFixedPower = source.isFixedPower - private var isFixedResistance = source.isFixedResistance + private var isFixedResistivity = source.isFixedResistivity fun power(value: Double) = apply { power = value } - fun resistance(value: Double) = apply { resistance = value } + fun resistivity(value: Double) = apply { resistivity = value } fun isFixedPower(value: Boolean) = apply { isFixedPower = value } - fun isFixedResistance(value: Boolean) = apply { isFixedResistance = value } - fun build() = ModelLayer(power, resistance, isFixedPower, isFixedResistance) + fun isFixedResistivity(value: Boolean) = apply { isFixedResistivity = value } + fun build() = ModelLayer(power, resistivity, isFixedPower, isFixedResistivity) } fun copy(source: ModelLayer) = ModelLayerBuilder(source) \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/geo/ves/ModelDataSet.kt b/src/main/java/ru/nucodelabs/geo/ves/ModelDataSet.kt new file mode 100644 index 00000000..d615c093 --- /dev/null +++ b/src/main/java/ru/nucodelabs/geo/ves/ModelDataSet.kt @@ -0,0 +1,6 @@ +package ru.nucodelabs.geo.ves + +interface ModelDataSet { + val modelData: List + val modelZ: Double +} diff --git a/src/main/java/ru/nucodelabs/geo/ves/ModelLayer.kt b/src/main/java/ru/nucodelabs/geo/ves/ModelLayer.kt index 5d58c31a..62400a88 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/ModelLayer.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/ModelLayer.kt @@ -1,18 +1,56 @@ package ru.nucodelabs.geo.ves -import jakarta.validation.constraints.DecimalMin -import jakarta.validation.constraints.Min +import ru.nucodelabs.util.validate + +interface ReadOnlyModelLayer { + val power: Double + val resistivity: Double + val isFixedPower: Boolean + val isFixedResistivity: Boolean +} + +interface MutableModelLayer : ReadOnlyModelLayer { + override var power: Double + override var resistivity: Double + override var isFixedPower: Boolean + override var isFixedResistivity: Boolean +} /** * Слой модели * @property power Мощность, м - * @property resistance Сопротивление, Ом * м + * @property resistivity Сопротивление, Ом * м * @property isFixedPower Значение зафиксировано для обратной задачи - * @property isFixedResistance Значение зафиксировано для обратной задачи + * @property isFixedResistivity Значение зафиксировано для обратной задачи */ data class ModelLayer( - @field:Min(0) val power: Double, - @field:DecimalMin("0.1") val resistance: Double, - val isFixedPower: Boolean = false, - val isFixedResistance: Boolean = false -) + override val power: Double, + override val resistivity: Double, + override val isFixedPower: Boolean = false, + override val isFixedResistivity: Boolean = false +) : ReadOnlyModelLayer { + init { + val errors = listOfNotNull( + validatePower(power), + validateResistivity(resistivity) + ) + if (errors.isNotEmpty()) throw InvalidPropertiesException(errors) + } + + companion object Meta { + const val MIN_POWER = .0 + const val MIN_RESIST = 0.1 + + fun validatePower(power: Double) = validate(isValidPower(power)) { + InvalidPropertyValue("power", "Power=$power must be >= $MIN_POWER", power) + } + + fun isValidPower(power: Double): Boolean = power >= MIN_POWER + + fun validateResistivity(resist: Double) = validate(isValidResistivity(resist)) { + InvalidPropertyValue("resistivity", "Resistivity=$resist must be >= $MIN_RESIST", resist) + } + + fun isValidResistivity(resist: Double) = resist >= MIN_RESIST + } +} diff --git a/src/main/java/ru/nucodelabs/geo/ves/Picket.kt b/src/main/java/ru/nucodelabs/geo/ves/Picket.kt index 12805ee6..6ff68329 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/Picket.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/Picket.kt @@ -2,10 +2,9 @@ package ru.nucodelabs.geo.ves import com.fasterxml.jackson.annotation.JsonGetter import com.fasterxml.jackson.annotation.JsonIgnore -import jakarta.validation.Valid -import jakarta.validation.constraints.Min -import jakarta.validation.constraints.Size -import ru.nucodelabs.geo.ves.calc.orderByDistances +import ru.nucodelabs.util.Equals +import ru.nucodelabs.util.hash +import ru.nucodelabs.util.validate import java.util.* /** @@ -15,75 +14,128 @@ import java.util.* * @property modelData Данные модели * @property offsetX Расстояние до пикета слева * @property z Координата Z + * @property comment Комментарий */ -data class Picket( - @JsonIgnore val id: UUID = UUID.randomUUID(), - val name: String = DEFAULT_NAME, - private var experimentalData: List<@Valid ExperimentalData> = emptyList(), - @field:Size(max = 40) var modelData: List<@Valid ModelLayer> = emptyList(), - @field:Min(0) val offsetX: Double = DEFAULT_OFFSET_X, - val z: Double = DEFAULT_Z, - val comment: String = DEFAULT_COMMENT -) { +class Picket private constructor( + val name: String, + experimentalData: List, + override val modelData: List, + override val offsetX: Double, + val z: Double, + val comment: String, + skipExperimentalDataProcessing: Boolean = false, +) : ExperimentalDataSet, ModelDataSet { + constructor( + name: String = DEFAULT_NAME, + experimentalData: List = emptyList(), + modelData: List = emptyList(), + offsetX: Double = DEFAULT_X_OFFSET, + z: Double = DEFAULT_Z, + comment: String = DEFAULT_COMMENT + ) : this( + name, + experimentalData, + modelData, + offsetX, + z, + comment, + skipExperimentalDataProcessing = false, + ) + init { - modelData = modelData.toMutableList().also { - if (it.isNotEmpty()) { - for (i in it.indices) { - if (it[i].power.isNaN()) { - it[i] = it[i].copy(power = 0.0) - } - } - it[it.lastIndex] = it.last().copy(power = Double.NaN) - } - } + val errors = listOfNotNull( + validate(isValidModelDataSize(modelData.size)) { + InvalidPropertyValue( + "modelData.size", + "Model layers count must be ≤ $MAX_MODEL_DATA_SIZE layers", + modelData.size + ) + }, + validate(isValidOffsetX(offsetX)) { + InvalidPropertyValue("offsetX", "X-Offset must be >= $MIN_OFFSET_X", offsetX) + }, + ) + if (errors.isNotEmpty()) throw InvalidPropertiesException(errors) } + + override val modelZ: Double = z + + @JsonIgnore + val id: UUID = UUID.randomUUID() // todo remove, make name unique + /** * Полевые(экспериментальные) данные, отсортированы по AB/2 затем по MN/2 */ @get:JsonGetter("experimentalData") - val sortedExperimentalData: List by lazy { - - val acc = mutableListOf() + override val sortedExperimentalData: List by lazy { + if (skipExperimentalDataProcessing) return@lazy experimentalData + toSortedExperimentalData(experimentalData) + } - // Группируем по AB - val dupGroups = experimentalData.groupBy { it.ab2 } - for ((_, group) in dupGroups) { - // Если больше одного не отключенного дубликата в группе - acc += if (group.filter { !it.isHidden }.size > 1) { - val sortedGroup = group.sortedWith(orderByDistances()) - List(sortedGroup.size) { - // Отключаем все кроме последнего (с наиб. MN) - if (it < sortedGroup.lastIndex) { - sortedGroup[it].copy(isHidden = true) - } else { - sortedGroup[it].copy(isHidden = false) - } - } - } else { - group - } - } + /** + * Без отключенных и если одинаковые AB/2, то с наибольшим MN/2 + */ + @get:JsonIgnore + override val effectiveExperimentalData: List by lazy { + this.sortedExperimentalData.filter { !it.isHidden } + } - acc.sortedWith(orderByDistances()) + override fun equals(other: Any?): Boolean { + return Equals(this, other) + .by { it.id } + .by { it.name } + .by { it.sortedExperimentalData } + .by { it.modelData } + .by { it.offsetX } + .by { it.z } + .by { it.comment } + .isEqual } - init { - experimentalData = sortedExperimentalData + override fun hashCode(): Int { + return hash( + id, + name, + sortedExperimentalData, + modelData, + offsetX, + z, + comment + ) } /** - * Без отключенных и если одинаковые AB/2, то с наибольшим MN/2 + * Slightly optimized copy */ - @get:JsonIgnore - val effectiveExperimentalData: List by lazy { - sortedExperimentalData.filter { !it.isHidden } - } + fun copy( + name: String = this.name, + experimentalData: List = this.sortedExperimentalData, + modelData: List = this.modelData, + offsetX: Double = this.offsetX, + z: Double = this.z, + comment: String = this.comment + ): Picket = Picket( + name, + experimentalData, + modelData, + offsetX, + z, + comment, + skipExperimentalDataProcessing = this.sortedExperimentalData == experimentalData, + ) - companion object Defaults { - const val DEFAULT_OFFSET_X = 100.0 + companion object Meta { + const val DEFAULT_X_OFFSET = 100.0 const val DEFAULT_NAME = "Пикет" const val DEFAULT_Z = 0.0 const val DEFAULT_COMMENT = "" + + const val MAX_MODEL_DATA_SIZE = 40 + const val MIN_OFFSET_X = 0.0 + + fun isValidOffsetX(offsetX: Double): Boolean = offsetX >= MIN_OFFSET_X + + fun isValidModelDataSize(modelDataSize: Int): Boolean = modelDataSize <= MAX_MODEL_DATA_SIZE } -} +} \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/geo/ves/Section.kt b/src/main/java/ru/nucodelabs/geo/ves/Section.kt index a3f6d462..0e7fea97 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/Section.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/Section.kt @@ -5,5 +5,7 @@ package ru.nucodelabs.geo.ves * @property pickets Список пикетов для данного разреза */ data class Section( - val pickets: List = listOf() -) + val pickets: List = emptyList() +) : SectionExperimentalDataSet { + override fun pickets(): List = pickets +} diff --git a/src/main/java/ru/nucodelabs/geo/ves/SectionExperimentalDataSet.kt b/src/main/java/ru/nucodelabs/geo/ves/SectionExperimentalDataSet.kt new file mode 100644 index 00000000..1b1ce35e --- /dev/null +++ b/src/main/java/ru/nucodelabs/geo/ves/SectionExperimentalDataSet.kt @@ -0,0 +1,5 @@ +package ru.nucodelabs.geo.ves + +interface SectionExperimentalDataSet { + fun pickets(): List +} \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/geo/ves/TableConversion.kt b/src/main/java/ru/nucodelabs/geo/ves/TableConversion.kt index 307a8755..9f83a114 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/TableConversion.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/TableConversion.kt @@ -1,11 +1,11 @@ package ru.nucodelabs.geo.ves -fun ModelLayer.toTabulatedRow() = "$power $resistance" +fun ModelLayer.toTabulatedRow() = "$power $resistivity" @JvmName("convertModelDataToTabulatedTable") fun List.toTabulatedTable() = joinToString(separator = "\n") { it.toTabulatedRow() } -fun ExperimentalData.toTabulatedRow() = "$ab2 $mn2 $voltage $amperage $resistanceApparent" +fun ExperimentalData.toTabulatedRow() = "$ab2 $mn2 $voltage $amperage $resistivityApparent" @JvmName("convertExperimentalDataToTabulatedTable") fun List.toTabulatedTable() = joinToString(separator = "\n") { it.toTabulatedRow() } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/ExperimentalDataFunctions.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/ExperimentalDataFunctions.kt index 44213297..5e67787b 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/ExperimentalDataFunctions.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/ExperimentalDataFunctions.kt @@ -1,16 +1,15 @@ package ru.nucodelabs.geo.ves.calc import ru.nucodelabs.geo.ves.ExperimentalData +import ru.nucodelabs.geo.ves.ReadOnlyExperimentalSignal -fun orderByDistances() = - compareBy { it.ab2 } - .thenBy { it.mn2 } +fun orderByDistances(): Comparator = compareBy { it.ab2 }.thenBy { it.mn2 } -fun ExperimentalData.withCalculatedResistanceApparent() = - this.copy(resistanceApparent = rhoA(ab2, mn2, amperage, voltage)) +fun ExperimentalData.withCalculatedResistivityApparent() = + this.copy(resistivityApparent = rhoA(ab2, mn2, amperage, voltage)) -val ExperimentalData.resistanceApparentUpperBoundByError - get() = (resistanceApparent + resistanceApparent * errorResistanceApparent / 100).coerceAtLeast(1.0) +val ReadOnlyExperimentalSignal.resistivityApparentUpperBoundByError + get() = (resistivityApparent + resistivityApparent * errorResistivityApparent / 100).coerceAtLeast(1.0) -val ExperimentalData.resistanceApparentLowerBoundByError - get() = (resistanceApparent - resistanceApparent * errorResistanceApparent / 100).coerceAtLeast(1.0) \ No newline at end of file +val ReadOnlyExperimentalSignal.resistivityApparentLowerBoundByError + get() = (resistivityApparent - resistivityApparent * errorResistivityApparent / 100).coerceAtLeast(1.0) \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/ModelLayerFunctions.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/ModelLayerFunctions.kt index f571c1b3..ba18ad2b 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/ModelLayerFunctions.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/ModelLayerFunctions.kt @@ -1,16 +1,15 @@ package ru.nucodelabs.geo.ves.calc import ru.nucodelabs.geo.ves.ModelLayer +import ru.nucodelabs.geo.ves.ReadOnlyModelLayer import ru.nucodelabs.mathves.ModelFunctions fun ModelLayer.divide(): Pair = copy(power = power / 2) to copy(power = power / 2) -fun List.join(): ModelLayer = +fun List.join(): ModelLayer = ModelFunctions.joinLayers( map { it.power }.toDoubleArray(), - map { it.resistance }.toDoubleArray() + map { it.resistivity }.toDoubleArray() ).let { - ModelLayer(power = it[0], resistance = it[1]) - } - -fun joinLayers(layers: List): ModelLayer = layers.join() \ No newline at end of file + ModelLayer(power = it[0], resistivity = it[1]) + } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/Normalization.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/Normalization.kt index 31a082bb..12115d48 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/Normalization.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/Normalization.kt @@ -1,16 +1,16 @@ package ru.nucodelabs.geo.ves.calc -import ru.nucodelabs.geo.ves.ExperimentalData +import ru.nucodelabs.geo.ves.ReadOnlyExperimentalSignal import ru.nucodelabs.mathves.Normalization -import ru.nucodelabs.util.std.fromPercent +import ru.nucodelabs.util.fromPercent data class FixableValue(val value: T, val isFixed: Boolean) /** - * @return normalized resistance and additive coefficients + * @return normalized resistivity and additive coefficients */ fun normalizeExperimentalData( - experimentalData: List, + experimentalData: List, distinctMn2: List>, idxMap: List ): Pair, List> { @@ -20,14 +20,14 @@ fun normalizeExperimentalData( distinctMn2.map { it.isFixed }.toBooleanArray(), experimentalData.map { it.ab2 }.toDoubleArray(), idxMap.map { it.toShort() }.toShortArray(), - experimentalData.map { it.resistanceApparent }.toDoubleArray(), - experimentalData.map { it.errorResistanceApparent.fromPercent() }.toDoubleArray(), + experimentalData.map { it.resistivityApparent }.toDoubleArray(), + experimentalData.map { it.errorResistivityApparent.fromPercent() }.toDoubleArray(), add ).toList() to add.toList() } @JvmName("distinctMn2ForExpData") -fun distinctMn2(experimentalData: List) = distinctMn2(experimentalData.map { it.mn2 }) +fun distinctMn2(experimentalData: List) = distinctMn2(experimentalData.map { it.mn2 }) fun distinctMn2(mn2: List): Pair, List> { val idx = ShortArray(mn2.size) diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/PicketFunctions.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/PicketFunctions.kt index 876b5cba..083145c9 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/PicketFunctions.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/PicketFunctions.kt @@ -1,11 +1,12 @@ package ru.nucodelabs.geo.ves.calc -import ru.nucodelabs.geo.ves.Picket +import ru.nucodelabs.geo.ves.ExperimentalDataSet +import ru.nucodelabs.geo.ves.ModelDataSet -fun Picket.zOfModelLayers(): List { +fun ModelDataSet.zOfModelLayers(): List { val heightList: MutableList = mutableListOf() val power = modelData.map { it.power } - var sum = z + var sum = modelZ for (p in power) { sum -= p heightList.add(sum) @@ -18,10 +19,10 @@ fun Picket.zOfModelLayers(): List { * * Тогда верно следующее: * - * `a[i] = j` `<=>` `effectiveExperimentalData[i] = sortedExperimentalData[j]` + * `a[i] = j <=> effectiveExperimentalData[i] = sortedExperimentalData[j]` */ -fun Picket.effectiveToSortedIndicesMapping(): IntArray { - return IntArray(effectiveExperimentalData.size) { i -> - sortedExperimentalData.indexOf(effectiveExperimentalData[i]) - } +fun ExperimentalDataSet.effectiveToSortedIndicesMapping(): IntArray { + val sorted = sortedExperimentalData + val effective = effectiveExperimentalData + return IntArray(effective.size) { i -> sorted.indexOf(effective[i]) } } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/SectionFunctions.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/SectionFunctions.kt index 350b473e..13386170 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/SectionFunctions.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/SectionFunctions.kt @@ -1,24 +1,16 @@ package ru.nucodelabs.geo.ves.calc -import ru.nucodelabs.geo.ves.Picket -import ru.nucodelabs.geo.ves.Section +import ru.nucodelabs.geo.ves.SectionExperimentalDataSet -fun Section.xOfPicket(picket: Picket): Double = xOfPicket(pickets.indexOf(picket)) - -fun Section.xOfPicket(index: Int): Double { - require(index >= 0) - if (index == 0) return 0.0 - - var x = 0.0 - for (i in 1..index) { - x += this.pickets[i].offsetX - } - return x +fun SectionExperimentalDataSet.xOfPicket(picketIndex: Int): Double { + if (picketIndex == 0) return 0.0 + return pickets().subList(1, picketIndex + 1).map { it.offsetX }.reduce(Double::plus) } data class Bounds(val leftX: Double, val rightX: Double) -fun Section.picketsBounds(): List { +fun SectionExperimentalDataSet.picketsBounds(): List { + val pickets = pickets() if (pickets.isEmpty()) { return emptyList() } @@ -44,7 +36,7 @@ fun Section.picketsBounds(): List { return res } -fun Section.length(): Double { +fun SectionExperimentalDataSet.length(): Double { val bounds = picketsBounds() return bounds.last().rightX - bounds.first().leftX } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/Ves.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/VesFunctions.kt similarity index 94% rename from src/main/java/ru/nucodelabs/geo/ves/calc/Ves.kt rename to src/main/java/ru/nucodelabs/geo/ves/calc/VesFunctions.kt index 3ecab934..c53c7b99 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/Ves.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/VesFunctions.kt @@ -1,3 +1,4 @@ +@file:JvmName("VesFunctions") package ru.nucodelabs.geo.ves.calc import kotlin.math.PI diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/adapter/ForwardSolverAdapter.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/adapter/ForwardSolverAdapter.kt index d5b9f8e2..99dbab52 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/adapter/ForwardSolverAdapter.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/adapter/ForwardSolverAdapter.kt @@ -1,14 +1,17 @@ package ru.nucodelabs.geo.ves.calc.adapter import ru.nucodelabs.geo.forward.ForwardSolver -import ru.nucodelabs.geo.ves.ExperimentalData -import ru.nucodelabs.geo.ves.ModelLayer +import ru.nucodelabs.geo.ves.ReadOnlyExperimentalSignal +import ru.nucodelabs.geo.ves.ReadOnlyModelLayer -operator fun ForwardSolver.invoke(experimentalData: List, modelData: List): List { +operator fun ForwardSolver.invoke( + experimentalData: List, + modelData: List +): List { return this( experimentalData.map { it.ab2 }, experimentalData.map { it.mn2 }, modelData.map { it.power }, - modelData.map { it.resistance }, + modelData.map { it.resistivity }, ) } diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/error/SchlumbergerErrorFunctions.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/error/SchlumbergerErrorFunctions.kt index 408198f5..6d4a5112 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/error/SchlumbergerErrorFunctions.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/error/SchlumbergerErrorFunctions.kt @@ -1,8 +1,8 @@ package ru.nucodelabs.geo.ves.calc.error import ru.nucodelabs.mathves.SchlumbergerErrorFunctions -import ru.nucodelabs.util.std.asPercent -import ru.nucodelabs.util.std.fromPercent +import ru.nucodelabs.util.asPercent +import ru.nucodelabs.util.fromPercent data class MinMax(val min: Double, val max: Double) @@ -28,7 +28,7 @@ data class ValueMinMaxAvgError( val error: Double, ) -fun resistanceApparentWithError( +fun resistivityApparentWithError( isNew: Boolean, k: ValueMinMax, u: ValueMinMax, @@ -87,10 +87,10 @@ fun resistanceApparentWithError( // // return ValueMinMaxAvgError(Rok, Rok_min, Rok_max, Rok_avg, Rok_err) -fun resistanceApparentErrorForDistance( +fun resistivityApparentErrorForDistance( isNew: Boolean, k: ValueMinMax, u: Double, i: Double ): Double { - return resistanceApparentWithError( + return resistivityApparentWithError( isNew, k, measureError(u, 0.0, 0.0).withValue(u), @@ -98,10 +98,10 @@ fun resistanceApparentErrorForDistance( ).error } -fun resistanceApparentErrorForAmperage( +fun resistivityApparentErrorForAmperage( isNew: Boolean, i: ValueMinMax, ab2: Double, mn2: Double, u: Double ): Double { - return resistanceApparentWithError( + return resistivityApparentWithError( isNew, kWithError(ab2, mn2, 0.0, 0.0), measureError(u, 0.0, 0.0).withValue(u), @@ -109,10 +109,10 @@ fun resistanceApparentErrorForAmperage( ).error } -fun resistanceApparentErrorForVoltage( +fun resistivityApparentErrorForVoltage( isNew: Boolean, u: ValueMinMax, ab2: Double, mn2: Double, i: Double ): Double { - return resistanceApparentWithError( + return resistivityApparentWithError( isNew, kWithError(ab2, mn2, 0.0, 0.0), u, diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/graph/CurvesSectionGraphContext.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/graph/CurvesSectionGraphContext.kt index e0e0b3e8..4db9f0c5 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/graph/CurvesSectionGraphContext.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/graph/CurvesSectionGraphContext.kt @@ -1,41 +1,39 @@ package ru.nucodelabs.geo.ves.calc.graph -import jakarta.inject.Inject -import ru.nucodelabs.geo.ves.Section +import ru.nucodelabs.geo.ves.SectionExperimentalDataSet import ru.nucodelabs.geo.ves.calc.Bounds import ru.nucodelabs.geo.ves.calc.picketsBounds import ru.nucodelabs.util.Point import kotlin.math.min -class CurvesSectionGraphContext @Inject constructor(inputSection: Section) { - - private val section = inputSection.copy() +class CurvesSectionGraphContext(private val section: SectionExperimentalDataSet) { private val rightK = 1.0 - private var resistanceK = 1.0 + private var resistivityK = 1.0 - private val resistances: MutableList> = arrayListOf() + private val resistivityValues: MutableList> = arrayListOf() init { - initResistances() - shiftResistances() + initResistivityValues() + shiftResistivityValues() setK() - recalculateResistances() + recalculateResistivityValues() addXValues() } fun getPoints(): List> { val pointsList: MutableList> = arrayListOf() - for (picketIdx in section.pickets.indices) { - if (section.pickets[picketIdx].effectiveExperimentalData.isEmpty()) { + val pickets = section.pickets() + for (picketIdx in pickets.indices) { + if (pickets[picketIdx].effectiveExperimentalData.isEmpty()) { pointsList.add(arrayListOf()) continue } pointsList.add(arrayListOf()) - for (abIdx in resistances[picketIdx].indices) { - val xValue = resistances[picketIdx][abIdx] - val yValue = section.pickets[picketIdx].effectiveExperimentalData[abIdx].ab2 + for (abIdx in resistivityValues[picketIdx].indices) { + val xValue = resistivityValues[picketIdx][abIdx] + val yValue = pickets[picketIdx].effectiveExperimentalData[abIdx].ab2 pointsList[picketIdx].add(Point(xValue, yValue)) } } @@ -43,51 +41,59 @@ class CurvesSectionGraphContext @Inject constructor(inputSection: Section) { } private fun addXValues() { - for (picketIdx in resistances.indices) { - resistances[picketIdx] = - resistances[picketIdx].map { e -> e + section.picketsBounds()[picketIdx].leftX } as MutableList + val bounds = section.picketsBounds() + for (picketIdx in resistivityValues.indices) { + val resistSrc = resistivityValues[picketIdx] + resistivityValues[picketIdx] = resistSrc.mapTo(ArrayList(resistSrc.size)) { e -> + e + bounds[picketIdx].leftX + } } } - private fun recalculateResistances() { - for (picketIdx in resistances.indices) { - resistances[picketIdx] = - resistances[picketIdx].map { e -> e * resistanceK * rightK } as MutableList + private fun recalculateResistivityValues() { + for (picketIdx in resistivityValues.indices) { + val resistSrc = resistivityValues[picketIdx] + resistivityValues[picketIdx] = resistSrc.mapTo(ArrayList(resistSrc.size)) { e -> + e * resistivityK * rightK + } } } - private fun initResistances() { - for (picketIdx in section.pickets.indices) { - if (section.pickets[picketIdx].effectiveExperimentalData.isEmpty()) { - resistances.add(arrayListOf()) + private fun initResistivityValues() { + val pickets = section.pickets() + for (picketIdx in pickets.indices) { + if (pickets[picketIdx].effectiveExperimentalData.isEmpty()) { + resistivityValues.add(arrayListOf()) continue } - resistances.add(arrayListOf()) - for (ab in section.pickets[picketIdx].effectiveExperimentalData) { - resistances[picketIdx].add(ab.resistanceApparent) + resistivityValues.add(arrayListOf()) + for (ab in pickets[picketIdx].effectiveExperimentalData) { + resistivityValues[picketIdx].add(ab.resistivityApparent) } } } - private fun shiftResistances() { - for (picketIdx in resistances.indices) { - if (resistances[picketIdx].isEmpty()) - continue - val minResistance = resistances[picketIdx].min() - resistances[picketIdx] = resistances[picketIdx].map { e -> e - minResistance } as MutableList + private fun shiftResistivityValues() { + for (picketIdx in resistivityValues.indices) { + val resistSrc = resistivityValues[picketIdx] + if (resistSrc.isEmpty()) continue + val minResist = resistSrc.min() + resistivityValues[picketIdx] = resistSrc.mapTo(ArrayList(resistSrc.size)) { e -> + e - minResist + } } } private fun setK() { - for (picketIdx in resistances.indices) { - if (resistances[picketIdx].isEmpty()) - continue - resistanceK = min(resistanceK, getKFor(resistances[picketIdx], section.picketsBounds()[picketIdx])) + val picketsBounds = section.picketsBounds() + for (picketIdx in resistivityValues.indices) { + if (resistivityValues[picketIdx].isEmpty()) continue + resistivityK = min(resistivityK, getKFor(resistivityValues[picketIdx], picketsBounds[picketIdx])) } } - private fun getKFor(resistances: List, bound: Bounds): Double { - val range = resistances.max() - resistances.min() + private fun getKFor(resistivity: List, bound: Bounds): Double { + val range = resistivity.max() - resistivity.min() val xSize = bound.rightX - bound.leftX return xSize / range } diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/graph/MathVesNativeMisfitsFunction.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/graph/MathVesNativeMisfitsFunction.kt index 64af54a6..92c83191 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/graph/MathVesNativeMisfitsFunction.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/graph/MathVesNativeMisfitsFunction.kt @@ -1,32 +1,35 @@ package ru.nucodelabs.geo.ves.calc.graph import ru.nucodelabs.geo.forward.ForwardSolver -import ru.nucodelabs.geo.ves.ExperimentalData -import ru.nucodelabs.geo.ves.ModelLayer +import ru.nucodelabs.geo.ves.ReadOnlyExperimentalSignal +import ru.nucodelabs.geo.ves.ReadOnlyModelLayer import ru.nucodelabs.geo.ves.calc.adapter.invoke import kotlin.math.abs import kotlin.math.sign internal class MathVesNativeMisfitsFunction(val forwardSolver: ForwardSolver) : MisfitsFunction { - override fun invoke(experimentalData: List, modelData: List): List { + override fun invoke( + experimentalData: List, + modelData: List + ): List { if (experimentalData.isEmpty() || modelData.isEmpty()) { return listOf() } - val resistanceApparent = experimentalData.map { it.resistanceApparent } - val errorResistanceApparent = experimentalData.map { it.errorResistanceApparent } + val resistivityApparent = experimentalData.map { it.resistivityApparent } + val errorResistivityApparent = experimentalData.map { it.errorResistivityApparent } - val solvedResistance = forwardSolver(experimentalData, modelData) + val solvedResistivity = forwardSolver(experimentalData, modelData) val res = ArrayList(experimentalData.size) for (i in experimentalData.indices) { val value = abs( ru.nucodelabs.mathves.MisfitFunctions.calculateRelativeDeviationWithError( - resistanceApparent[i], - errorResistanceApparent[i] / 100f, - solvedResistance[i] + resistivityApparent[i], + errorResistivityApparent[i] / 100f, + solvedResistivity[i] ) - ) * sign(solvedResistance[i] - resistanceApparent[i]) * 100f + ) * sign(solvedResistivity[i] - resistivityApparent[i]) * 100f res.add(value) } diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/graph/MisfitsFunction.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/graph/MisfitsFunction.kt index 2b49f9d5..f3ef6243 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/graph/MisfitsFunction.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/graph/MisfitsFunction.kt @@ -1,11 +1,14 @@ package ru.nucodelabs.geo.ves.calc.graph -import ru.nucodelabs.geo.ves.ExperimentalData -import ru.nucodelabs.geo.ves.ModelLayer +import ru.nucodelabs.geo.ves.ReadOnlyExperimentalSignal +import ru.nucodelabs.geo.ves.ReadOnlyModelLayer interface MisfitsFunction { /** * Returns list of misfits between experimental and theoretical curves */ - operator fun invoke(experimentalData: List, modelData: List): List + operator fun invoke( + experimentalData: List, + modelData: List + ): List } \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/graph/VesCurvesFunctions.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/graph/VesCurvesFunctions.kt index 91f5c2db..7c544083 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/graph/VesCurvesFunctions.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/graph/VesCurvesFunctions.kt @@ -1,39 +1,41 @@ package ru.nucodelabs.geo.ves.calc.graph import ru.nucodelabs.geo.forward.ForwardSolver -import ru.nucodelabs.geo.ves.Picket +import ru.nucodelabs.geo.ves.ExperimentalDataSet +import ru.nucodelabs.geo.ves.ModelDataSet import ru.nucodelabs.geo.ves.calc.adapter.invoke -import ru.nucodelabs.geo.ves.calc.resistanceApparentLowerBoundByError -import ru.nucodelabs.geo.ves.calc.resistanceApparentUpperBoundByError +import ru.nucodelabs.geo.ves.calc.resistivityApparentLowerBoundByError +import ru.nucodelabs.geo.ves.calc.resistivityApparentUpperBoundByError import ru.nucodelabs.util.Point -fun experimentalCurve(picket: Picket) = - picket.effectiveExperimentalData.map { Point(it.ab2, it.resistanceApparent) } +fun experimentalCurve(picket: ExperimentalDataSet) = + picket.effectiveExperimentalData.map { Point(it.ab2, it.resistivityApparent) } +fun experimentalCurveErrorUpperBound(picket: ExperimentalDataSet) = + picket.effectiveExperimentalData.map { Point(it.ab2, it.resistivityApparentUpperBoundByError) } -fun experimentalCurveErrorUpperBound(picket: Picket) = - picket.effectiveExperimentalData.map { Point(it.ab2, it.resistanceApparentUpperBoundByError) } +fun experimentalCurveErrorLowerBound(picket: ExperimentalDataSet) = + picket.effectiveExperimentalData.map { Point(it.ab2, it.resistivityApparentLowerBoundByError) } -fun experimentalCurveErrorLowerBound(picket: Picket) = - picket.effectiveExperimentalData.map { Point(it.ab2, it.resistanceApparentLowerBoundByError) } +fun experimentalHiddenPoints(picket: ExperimentalDataSet) = + picket.sortedExperimentalData.filter { it.isHidden }.map { Point(it.ab2, it.resistivityApparent) } -fun experimentalHiddenPoints(picket: Picket) = - picket.sortedExperimentalData.filter { it.isHidden }.map { Point(it.ab2, it.resistanceApparent) } - -fun theoreticalCurve(picket: Picket, forwardSolver: ForwardSolver): List { - if (picket.sortedExperimentalData.isEmpty() || picket.modelData.isEmpty()) { +fun theoreticalCurve( + experimental: ExperimentalDataSet, + modelDataSet: ModelDataSet, + forwardSolver: ForwardSolver +): List { + val sortedExp = experimental.sortedExperimentalData + if (sortedExp.isEmpty() || modelDataSet.modelData.isEmpty()) { return listOf() } - val solvedResistance = forwardSolver(picket.sortedExperimentalData, picket.modelData) - return List(picket.sortedExperimentalData.size) { i -> - Point(picket.sortedExperimentalData[i].ab2, solvedResistance[i]) + val solvedResist = forwardSolver(sortedExp, modelDataSet.modelData) + return List(sortedExp.size) { i -> + Point(sortedExp[i].ab2, solvedResist[i]) } } -fun misfits(picket: Picket, misfitsFunction: MisfitsFunction): List = - misfitsFunction(picket.effectiveExperimentalData, picket.modelData) - -fun modelStepGraph(picket: Picket, beginX: Double = 1e-3, endX: Double = 1e100): List { +fun modelStepGraph(picket: ModelDataSet, beginX: Double = 1e-3, endX: Double = 1e100): List { val modelData = picket.modelData if (modelData.isEmpty()) { @@ -42,22 +44,22 @@ fun modelStepGraph(picket: Picket, beginX: Double = 1e-3, endX: Double = 1e100): val points = mutableListOf() // first point - points += Point(beginX, modelData.first().resistance) + points += Point(beginX, modelData.first().resistivity) var prevSum = 0.0 for (i in 0 until modelData.size - 1) { - val currentResistance = modelData[i].resistance + val currentResist = modelData[i].resistivity val currentPower = modelData[i].power points += Point( currentPower + prevSum, - currentResistance + currentResist ) - val nextResistance = modelData[i + 1].resistance + val nextResist = modelData[i + 1].resistivity points += Point( currentPower + prevSum, - nextResistance + nextResist ) prevSum += currentPower } @@ -65,7 +67,7 @@ fun modelStepGraph(picket: Picket, beginX: Double = 1e-3, endX: Double = 1e100): // last point points += Point( endX, - modelData.last().resistance + modelData.last().resistivity ) return points diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/initialModel/MultiLayerInitialModel.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/initialModel/MultiLayerInitialModel.kt index 9dd016f0..33bb47d2 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/initialModel/MultiLayerInitialModel.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/initialModel/MultiLayerInitialModel.kt @@ -4,8 +4,8 @@ import ru.nucodelabs.geo.forward.ForwardSolver import ru.nucodelabs.geo.forward.impl.SonetForwardSolverAdapter import ru.nucodelabs.geo.target.RelativeErrorAwareTargetFunction import ru.nucodelabs.geo.target.impl.SquareDiffTargetFunction -import ru.nucodelabs.geo.ves.ExperimentalData import ru.nucodelabs.geo.ves.ModelLayer +import ru.nucodelabs.geo.ves.ReadOnlyExperimentalSignal import ru.nucodelabs.geo.ves.calc.adapter.invoke import ru.nucodelabs.geo.ves.calc.divide import ru.nucodelabs.geo.ves.calc.inverse.InverseSolver @@ -17,18 +17,18 @@ const val MAX_LAYERS_COUNT = 10 const val MAX_EVAL_INVERSE = 10_000_000 const val MIN_TARGET_FUNCTION_VALUE = 1.0 -private fun initialModel(signals: List): List = +private fun initialModel(signals: List): List = listOf( ModelLayer( power = 0.0, - resistance = 2.0.pow(signals.map { log2(it.ab2) }.average()) + resistivity = 2.0.pow(signals.map { log2(it.ab2) }.average()) ) ) // сопр среднее по логарифму, потом обратно в степень, с 1 слоем fun multiLayerInitialModel( - signals: List, + signals: List, initialModel: List = initialModel(signals), forwardSolver: ForwardSolver = SonetForwardSolverAdapter(), targetFunction: RelativeErrorAwareTargetFunction = SquareDiffTargetFunction(), @@ -54,8 +54,8 @@ fun multiLayerInitialModel( val targetFunctionValue = targetFunction( forwardSolver(signals, model), - signals.map { it.resistanceApparent }, - signals.map { it.errorResistanceApparent } + signals.map { it.resistivityApparent }, + signals.map { it.errorResistivityApparent } ) val isResult = targetFunctionValue <= minTargetFunctionValue && result == null diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/initialModel/SimpleInitialModel.java b/src/main/java/ru/nucodelabs/geo/ves/calc/initialModel/SimpleInitialModel.java index 7cc2979b..5a355c9c 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/initialModel/SimpleInitialModel.java +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/initialModel/SimpleInitialModel.java @@ -2,6 +2,7 @@ import ru.nucodelabs.geo.ves.ExperimentalData; import ru.nucodelabs.geo.ves.ModelLayer; +import ru.nucodelabs.geo.ves.ReadOnlyExperimentalSignal; import java.util.ArrayList; import java.util.List; @@ -13,17 +14,24 @@ public class SimpleInitialModel { private SimpleInitialModel() { } - public static List threeLayersInitialModel(List experimentalData) { + public static List threeLayersInitialModel(List experimentalData) { if (experimentalData.size() <= 3) { throw new IllegalStateException("Для построения стартовой модели требуется ≥ 4 измерений, было " + experimentalData.size()); } List logExperimentalData = experimentalData.stream() - .map(data -> copy(data).ab2(Math.log(data.getAb2())).build()) + .map(data -> new ExperimentalData( + Math.log(data.getAb2()), + data.getMn2(), + data.getAmperage(), + data.getVoltage(), + data.getResistivityApparent(), + data.getErrorResistivityApparent(), + data.isHidden() + )) .toList(); - int pointsCnt = logExperimentalData.size(); - double ab2min = logExperimentalData.get(0).getAb2(); - double ab2max = logExperimentalData.get(pointsCnt - 1).getAb2(); + double ab2min = logExperimentalData.getFirst().getAb2(); + double ab2max = logExperimentalData.getLast().getAb2(); double ab2range = ab2max - ab2min; List> logSplitData = new ArrayList<>(); logSplitData.add(logExperimentalData.stream() @@ -46,19 +54,19 @@ public static List threeLayersInitialModel(List ex double prevLast; List list = logSplitData.get(i); double avg = list.stream() - .map(ExperimentalData::getResistanceApparent) + .map(ExperimentalData::getResistivityApparent) .mapToDouble(Double::doubleValue) .average() .orElse(0); if (i > 0) { - prevLast = Math.exp(logSplitData.get(i - 1).get(logSplitData.get(i - 1).size() - 1).getAb2()); + prevLast = Math.exp(logSplitData.get(i - 1).getLast().getAb2()); } else { prevLast = 0; } //От последнего в этом слою отнимаем последний в прошлом - modelLayers.add(new ModelLayer(Math.exp(list.get(list.size() - 1).getAb2()) - prevLast, avg, false, false)); + modelLayers.add(new ModelLayer(Math.exp(list.getLast().getAb2()) - prevLast, avg, false, false)); } - modelLayers.set(modelLayers.size() - 1, copy(modelLayers.get(modelLayers.size() - 1)).power(0).build()); + modelLayers.set(modelLayers.size() - 1, copy(modelLayers.getLast()).power(0).build()); return modelLayers; } } diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/interpolation/Interpolator.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/interpolation/Interpolator.kt index a8f0dbf2..f4ebda6c 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/interpolation/Interpolator.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/interpolation/Interpolator.kt @@ -3,7 +3,7 @@ package ru.nucodelabs.geo.ves.calc.interpolation import org.apache.commons.math3.analysis.interpolation.BicubicInterpolatingFunction import org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction import ru.nucodelabs.util.Point -import ru.nucodelabs.util.std.exp10 +import ru.nucodelabs.util.exp10 class Interpolator( private var interpolatorContext: InterpolatorContext diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/interpolation/SmartInterpolator.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/interpolation/SmartInterpolator.kt index 4faffbea..c1bd0e7c 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/interpolation/SmartInterpolator.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/interpolation/SmartInterpolator.kt @@ -2,7 +2,7 @@ package ru.nucodelabs.geo.ves.calc.interpolation import org.apache.commons.math3.analysis.interpolation.BicubicInterpolatingFunction import ru.nucodelabs.util.Point -import ru.nucodelabs.util.std.exp10 +import ru.nucodelabs.util.exp10 import kotlin.math.log10 class SmartInterpolator( diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/InverseSolver.java b/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/InverseSolver.java index e86ef455..51d214a0 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/InverseSolver.java +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/InverseSolver.java @@ -11,8 +11,9 @@ import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer; import ru.nucodelabs.geo.forward.ForwardSolver; import ru.nucodelabs.geo.target.RelativeErrorAwareTargetFunction; -import ru.nucodelabs.geo.ves.ExperimentalData; import ru.nucodelabs.geo.ves.ModelLayer; +import ru.nucodelabs.geo.ves.ReadOnlyExperimentalSignal; +import ru.nucodelabs.geo.ves.ReadOnlyModelLayer; import ru.nucodelabs.geo.ves.calc.inverse.func.FunctionValue; import java.util.ArrayList; @@ -62,14 +63,14 @@ public InverseSolver( } private void setLimitValues( - List resistances, double minResistance, double maxResistance, + List resistivity, double minResistivity, double maxResistivity, List powers, double minPower, double maxPower ) { - for (int i = 0; i < resistances.size(); i++) { - if (resistances.get(i) < minResistance) - resistances.set(i, minResistance); - else if (resistances.get(i) > maxResistance) - resistances.set(i, maxResistance); + for (int i = 0; i < resistivity.size(); i++) { + if (resistivity.get(i) < minResistivity) + resistivity.set(i, minResistivity); + else if (resistivity.get(i) > maxResistivity) + resistivity.set(i, maxResistivity); } for (int i = 0; i < powers.size(); i++) { if (powers.get(i) != 0 && powers.get(i) < minPower) @@ -80,34 +81,34 @@ else if (powers.get(i) > maxPower) } public List getOptimizedModelData( - List experimentalData, - List modelData, + List experimentalData, + List modelData, final int maxEval ) { //Изменяемые сопротивления и мощности - List modelResistance = modelData.stream() - .filter(modelLayer -> !modelLayer.isFixedResistance()).map(ModelLayer::getResistance).collect(Collectors.toList()); + List modelResistivity = modelData.stream() + .filter(modelLayer -> !modelLayer.isFixedResistivity()).map(ReadOnlyModelLayer::getResistivity).collect(Collectors.toList()); List modelPower = modelData.stream() - .filter(modelLayer -> !modelLayer.isFixedPower()).map(ModelLayer::getPower).collect(Collectors.toList()); + .filter(modelLayer -> !modelLayer.isFixedPower()).map(ReadOnlyModelLayer::getPower).collect(Collectors.toList()); //Установка ограничений для адекватности обратной задачи double maxPower = experimentalData.stream() - .map(ExperimentalData::getAb2) + .map(ReadOnlyExperimentalSignal::getAb2) .mapToDouble(Double::doubleValue) .max() .orElseThrow(); setLimitValues( - modelResistance, 0.1, 1e5, + modelResistivity, 0.1, 1e5, modelPower, 0.1, maxPower ); //Неизменяемые сопротивления и мощности - List fixedModelResistance = modelData.stream() - .filter(ModelLayer::isFixedResistance).map(ModelLayer::getResistance).toList(); + List fixedModelResistivity = modelData.stream() + .filter(ReadOnlyModelLayer::isFixedResistivity).map(ReadOnlyModelLayer::getResistivity).toList(); List fixedModelPower = modelData.stream() - .filter(ModelLayer::isFixedPower).map(ModelLayer::getPower).toList(); + .filter(ReadOnlyModelLayer::isFixedPower).map(ReadOnlyModelLayer::getPower).toList(); SimplexOptimizer optimizer = new SimplexOptimizer(relativeThreshold, absoluteThreshold); @@ -118,16 +119,16 @@ public List getOptimizedModelData( forwardSolver ); - //anyArray = resistance.size...(model.size - 1) - int dimension = modelResistance.size() + modelPower.size() - 1; // -1 - мощность последнего слоя не передается как параметр + //anyArray = resistivity.size...(model.size - 1) + int dimension = modelResistivity.size() + modelPower.size() - 1; // -1 - мощность последнего слоя не передается как параметр NelderMeadSimplex nelderMeadSimplex = new NelderMeadSimplex(dimension, sideLength); double[] startPoint = new double[dimension]; //res_1, ..., res_n, power_1, ..., power_n-1 - for (int i = 0; i < modelResistance.size(); i++) { - startPoint[i] = Math.log(modelResistance.get(i)); + for (int i = 0; i < modelResistivity.size(); i++) { + startPoint[i] = Math.log(modelResistivity.get(i)); } - for (int i = modelResistance.size(); i < dimension; i++) { - startPoint[i] = Math.log(modelPower.get(i - modelResistance.size())); + for (int i = modelResistivity.size(); i < dimension; i++) { + startPoint[i] = Math.log(modelPower.get(i - modelResistivity.size())); } InitialGuess initialGuess = new InitialGuess(startPoint); @@ -144,25 +145,25 @@ public List getOptimizedModelData( double[] key = pointValuePair.getKey(); List newModelPower = new ArrayList<>(); - List newModelResistance = new ArrayList<>(); - - int cntFixedResistances = 0; - int cntUnfixedResistances = 0; - for (ModelLayer modelLayer : modelData) { - if (modelLayer.isFixedResistance()) { - newModelResistance.add(fixedModelResistance.get(cntFixedResistances)); - cntFixedResistances++; + List newModelResistivity = new ArrayList<>(); + + int cntFixedResistivity = 0; + int cntUnfixedResistivity = 0; + for (var modelLayer : modelData) { + if (modelLayer.isFixedResistivity()) { + newModelResistivity.add(fixedModelResistivity.get(cntFixedResistivity)); + cntFixedResistivity++; } else { - newModelResistance.add(Math.exp(key[cntUnfixedResistances])); - cntUnfixedResistances++; + newModelResistivity.add(Math.exp(key[cntUnfixedResistivity])); + cntUnfixedResistivity++; } } int cntFixedPowers = 0; int cntUnfixedPowers = 0; for (int i = 0; i < modelData.size() - 1; i++) { - ModelLayer modelLayer = modelData.get(i); - int shift = modelResistance.size(); + var modelLayer = modelData.get(i); + int shift = modelResistivity.size(); if (modelLayer.isFixedPower()) { newModelPower.add(fixedModelPower.get(cntFixedPowers)); cntFixedPowers++; @@ -178,9 +179,9 @@ public List getOptimizedModelData( for (int i = 0; i < modelData.size(); i++) { resultModel.add(new ModelLayer( newModelPower.get(i), - newModelResistance.get(i), + newModelResistivity.get(i), modelData.get(i).isFixedPower(), - modelData.get(i).isFixedResistance()) + modelData.get(i).isFixedResistivity()) ); } diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/InverseSolverAdapter.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/InverseSolverAdapter.kt index 1fbaaad6..e5d5749b 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/InverseSolverAdapter.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/InverseSolverAdapter.kt @@ -1,10 +1,11 @@ package ru.nucodelabs.geo.ves.calc.inverse -import ru.nucodelabs.geo.ves.ExperimentalData import ru.nucodelabs.geo.ves.ModelLayer +import ru.nucodelabs.geo.ves.ReadOnlyExperimentalSignal +import ru.nucodelabs.geo.ves.ReadOnlyModelLayer operator fun InverseSolver.invoke( - experimentalSignals: List, - initialModel: List, + experimentalSignals: List, + initialModel: List, maxEval: Int = InverseSolver.MAX_EVAL_DEFAULT ): List = getOptimizedModelData(experimentalSignals, initialModel, maxEval) \ No newline at end of file diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/func/FunctionValue.java b/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/func/FunctionValue.java index 71465f6e..172071e2 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/func/FunctionValue.java +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/func/FunctionValue.java @@ -3,8 +3,9 @@ import org.apache.commons.math3.analysis.MultivariateFunction; import ru.nucodelabs.geo.forward.ForwardSolver; import ru.nucodelabs.geo.target.RelativeErrorAwareTargetFunction; -import ru.nucodelabs.geo.ves.ExperimentalData; import ru.nucodelabs.geo.ves.ModelLayer; +import ru.nucodelabs.geo.ves.ReadOnlyExperimentalSignal; +import ru.nucodelabs.geo.ves.ReadOnlyModelLayer; import ru.nucodelabs.geo.ves.calc.adapter.ForwardSolverAdapterKt; import java.util.ArrayList; @@ -12,18 +13,18 @@ public class FunctionValue implements MultivariateFunction { //Экспериментальные точки для FS - private final List experimentalData; + private final List experimentalData; //Функция для вычисления разности между exp и theoretical точками private final RelativeErrorAwareTargetFunction targetFunction; //Исходная модель - private final List modelLayers; + private final List modelLayers; private final ForwardSolver forwardSolver; private double diffMinValue = Double.MAX_VALUE; - public FunctionValue(List experimentalData, + public FunctionValue(List experimentalData, RelativeErrorAwareTargetFunction targetFunction, - List modelLayers, + List modelLayers, ForwardSolver forwardSolver) { this.experimentalData = experimentalData; this.targetFunction = targetFunction; @@ -34,37 +35,37 @@ public FunctionValue(List experimentalData, @Override public double value(double[] variables) { //Изменяемые сопротивления и мощности - List currentModelResistance = new ArrayList<>(); + List currentModelResistivity = new ArrayList<>(); List currentModelPower = new ArrayList<>(); - int unfixedResistancesCnt = (int) modelLayers.stream() - .filter(modelLayer -> !modelLayer.isFixedResistance()).count(); + int unfixedResistivityCnt = (int) modelLayers.stream() + .filter(modelLayer -> !modelLayer.isFixedResistivity()).count(); //Восстановление изменяемых слоев до нормальной формы - for (int i = 0; i < unfixedResistancesCnt; i++) { - currentModelResistance.add(Math.exp(variables[i])); + for (int i = 0; i < unfixedResistivityCnt; i++) { + currentModelResistivity.add(Math.exp(variables[i])); } - for (int i = unfixedResistancesCnt; i < variables.length; i++) { + for (int i = unfixedResistivityCnt; i < variables.length; i++) { currentModelPower.add(Math.exp(variables[i])); } currentModelPower.add(0.0); //Объединение изменяемых и неизменяемых слоев (в нормальной форме) - List newModelResistance = new ArrayList<>(); + List newModelResistivity = new ArrayList<>(); List newModelPower = new ArrayList<>(); - int cntUnfixedResistances = 0; - for (ModelLayer modelLayer : modelLayers) { - if (modelLayer.isFixedResistance()) { - newModelResistance.add(modelLayer.getResistance()); + int cntUnfixedResistivity = 0; + for (var modelLayer : modelLayers) { + if (modelLayer.isFixedResistivity()) { + newModelResistivity.add(modelLayer.getResistivity()); } else { - newModelResistance.add(currentModelResistance.get(cntUnfixedResistances)); - cntUnfixedResistances++; + newModelResistivity.add(currentModelResistivity.get(cntUnfixedResistivity)); + cntUnfixedResistivity++; } } int cntUnfixedPowers = 0; - for (ModelLayer modelLayer : modelLayers) { + for (var modelLayer : modelLayers) { if (modelLayer.isFixedPower()) { newModelPower.add(modelLayer.getPower()); } else { @@ -75,24 +76,24 @@ public double value(double[] variables) { List newModelLayers = new ArrayList<>(); for (int i = 0; i < modelLayers.size(); i++) { - newModelLayers.add(new ModelLayer(newModelPower.get(i), newModelResistance.get(i), false, false)); + newModelLayers.add(new ModelLayer(newModelPower.get(i), newModelResistivity.get(i), false, false)); } - List solvedResistance = ForwardSolverAdapterKt.invoke(forwardSolver, experimentalData, newModelLayers); + List solvedResistivity = ForwardSolverAdapterKt.invoke(forwardSolver, experimentalData, newModelLayers); double diffValue = targetFunction.invoke( - solvedResistance, - experimentalData.stream().map(ExperimentalData::getResistanceApparent).toList(), - experimentalData.stream().map(ExperimentalData::getErrorResistanceApparent).toList() + solvedResistivity, + experimentalData.stream().map(ReadOnlyExperimentalSignal::getResistivityApparent).toList(), + experimentalData.stream().map(ReadOnlyExperimentalSignal::getErrorResistivityApparent).toList() ); boolean flag = false; for (ModelLayer modelLayer : newModelLayers) { - if (modelLayer.getResistance() < 0.1 || - modelLayer.getResistance() > 1e5 || + if (modelLayer.getResistivity() < 0.1 || + modelLayer.getResistivity() > 1e5 || (modelLayer.getPower() != 0.0 && modelLayer.getPower() < 0.1) || - modelLayer.getPower() > experimentalData.get(experimentalData.size() - 1).getAb2()) { + modelLayer.getPower() > experimentalData.getLast().getAb2()) { diffValue = Math.max(diffMinValue * (1.1 + 0.1 * Math.random()), diffValue); flag = true; break; diff --git a/src/main/resources/ru/nucodelabs/gem/view/controller/anisotropy/main/AnisotropyMainView.fxml b/src/main/resources/ru/nucodelabs/gem/view/controller/anisotropy/main/AnisotropyMainView.fxml index 093fc956..98958bfe 100644 --- a/src/main/resources/ru/nucodelabs/gem/view/controller/anisotropy/main/AnisotropyMainView.fxml +++ b/src/main/resources/ru/nucodelabs/gem/view/controller/anisotropy/main/AnisotropyMainView.fxml @@ -118,20 +118,20 @@ - + - - + - @@ -240,12 +240,12 @@ - - diff --git a/src/main/resources/ru/nucodelabs/gem/view/controller/charts/LinearModelSection.fxml b/src/main/resources/ru/nucodelabs/gem/view/controller/charts/LinearModelSection.fxml index 89adbce5..88fe08f2 100644 --- a/src/main/resources/ru/nucodelabs/gem/view/controller/charts/LinearModelSection.fxml +++ b/src/main/resources/ru/nucodelabs/gem/view/controller/charts/LinearModelSection.fxml @@ -3,10 +3,9 @@ + - - - + @@ -34,5 +33,5 @@ - + \ No newline at end of file diff --git a/src/main/resources/ru/nucodelabs/gem/view/controller/charts/LogarithmicModelSection.fxml b/src/main/resources/ru/nucodelabs/gem/view/controller/charts/LogarithmicModelSection.fxml index 2aa93bf5..a2f0dc4c 100644 --- a/src/main/resources/ru/nucodelabs/gem/view/controller/charts/LogarithmicModelSection.fxml +++ b/src/main/resources/ru/nucodelabs/gem/view/controller/charts/LogarithmicModelSection.fxml @@ -3,9 +3,9 @@ + - \ No newline at end of file diff --git a/src/main/resources/ru/nucodelabs/gem/view/controller/charts/ModelSectionSwitcher.fxml b/src/main/resources/ru/nucodelabs/gem/view/controller/charts/ModelSectionSwitcher.fxml index 7dbacc16..215697ef 100644 --- a/src/main/resources/ru/nucodelabs/gem/view/controller/charts/ModelSectionSwitcher.fxml +++ b/src/main/resources/ru/nucodelabs/gem/view/controller/charts/ModelSectionSwitcher.fxml @@ -4,7 +4,7 @@ + maxWidth="Infinity" maxHeight="Infinity" fx:id="root"> diff --git a/src/main/resources/ru/nucodelabs/gem/view/controller/charts/VesCurves.fxml b/src/main/resources/ru/nucodelabs/gem/view/controller/charts/VesCurves.fxml index ed467c56..89b04170 100644 --- a/src/main/resources/ru/nucodelabs/gem/view/controller/charts/VesCurves.fxml +++ b/src/main/resources/ru/nucodelabs/gem/view/controller/charts/VesCurves.fxml @@ -13,6 +13,7 @@ maxWidth="Infinity" stylesheets="/css/common.css, @VesCurves.css" VBox.vgrow="ALWAYS" + fx:id="root" fx:controller="ru.nucodelabs.gem.view.controller.charts.VesCurvesController">