diff --git a/src/main/java/ru/nucodelabs/files/sonet/EXPFile.java b/src/main/java/ru/nucodelabs/files/sonet/EXPFile.java deleted file mode 100644 index cec69345..00000000 --- a/src/main/java/ru/nucodelabs/files/sonet/EXPFile.java +++ /dev/null @@ -1,156 +0,0 @@ -package ru.nucodelabs.files.sonet; - -import java.io.File; -import java.util.ArrayList; - -public class EXPFile { - private String STTFileName; - private File file; - - private String number; // Номер установки - private String date; // Дата - private String weather; // Погода - private String operator; // Оператор - private String interpreter; // Интерпретатор - private String checked; // Проверил - - private ArrayList amperage; // Ток, мА - private ArrayList voltage; // Напряжение, мВ - private ArrayList resistanceApparent; // Сопротивление кажущееся, Ом * м - private ArrayList errorResistanceApparent; // Погрешность, % - private ArrayList polarizationApparent; // Поляризация кажущаяся, % - private ArrayList errorPolarizationApparent; // Погрешность, % - - public EXPFile() { - STTFileName = ""; - interpreter = ""; - number = ""; - date = ""; - weather = ""; - operator = ""; - checked = ""; - amperage = new ArrayList<>(); - voltage = new ArrayList<>(); - resistanceApparent = new ArrayList<>(); - errorResistanceApparent = new ArrayList<>(); - polarizationApparent = new ArrayList<>(); - errorPolarizationApparent = new ArrayList<>(); - } - - public int getColumnCnt() { - return 6; - } - - public String getNumber() { - return number; - } - - public String getDate() { - return date; - } - - public String getWeather() { - return weather; - } - - public String getOperator() { - return operator; - } - - public String getInterpreter() { - return interpreter; - } - - public String getChecked() { - return checked; - } - - public void setNumber(String number) { - this.number = number; - } - - public void setDate(String date) { - this.date = date; - } - - public void setOperator(String operator) { - this.operator = operator; - } - - public void setWeather(String weather) { - this.weather = weather; - } - - public void setInterpreter(String interpreter) { - this.interpreter = interpreter; - } - - public void setChecked(String checked) { - this.checked = checked; - } - - - public ArrayList getAmperage() { - return amperage; - } - - public ArrayList getVoltage() { - return voltage; - } - - public ArrayList getResistanceApparent() { - return resistanceApparent; - } - - public ArrayList getErrorResistanceApparent() { - return errorResistanceApparent; - } - - public ArrayList getPolarizationApparent() { - return polarizationApparent; - } - - public ArrayList getErrorPolarizationApparent() { - return errorPolarizationApparent; - } - - public String getSTTFileName() { - return STTFileName; - } - - public File getFile() { - return file; - } - - public void setFile(File file) { - this.file = file; - } - - public void setAmperage(ArrayList amperage) { - this.amperage = amperage; - } - - public void setVoltage(ArrayList voltage) { - this.voltage = voltage; - } - - public void setResistanceApparent(ArrayList resistanceApparent) { - this.resistanceApparent = resistanceApparent; - } - - public void setErrorResistanceApparent(ArrayList errorResistanceApparent) { - this.errorResistanceApparent = errorResistanceApparent; - } - - public void setPolarizationApparent(ArrayList polarizationApparent) { - this.polarizationApparent = polarizationApparent; - } - - public void setErrorPolarizationApparent(ArrayList errorPolarizationApparent) { - this.errorPolarizationApparent = errorPolarizationApparent; - } - - public void setSTTFileName(String STTFileName) { - this.STTFileName = STTFileName; - } -} diff --git a/src/main/java/ru/nucodelabs/files/sonet/EXPFile.kt b/src/main/java/ru/nucodelabs/files/sonet/EXPFile.kt new file mode 100644 index 00000000..eed2100e --- /dev/null +++ b/src/main/java/ru/nucodelabs/files/sonet/EXPFile.kt @@ -0,0 +1,25 @@ +package ru.nucodelabs.files.sonet + +import java.io.File + +class EXPFile { + var STTFileName: String = "" + var file: File? = null + + var number: String = "" + var date: String = "" + var weather: String = "" + var operator: String = "" + var interpreter: String = "" + var checked: String = "" + + var amperage: MutableList = mutableListOf() + var voltage: MutableList = mutableListOf() + var resistanceApparent: MutableList = mutableListOf() + var errorResistanceApparent: MutableList = mutableListOf() + var polarizationApparent: MutableList = mutableListOf() + var errorPolarizationApparent: MutableList = mutableListOf() + + val columnCnt: Int + get() = 6 +} diff --git a/src/main/java/ru/nucodelabs/files/sonet/EXPFileParser.java b/src/main/java/ru/nucodelabs/files/sonet/EXPFileParser.java deleted file mode 100644 index 4c13c218..00000000 --- a/src/main/java/ru/nucodelabs/files/sonet/EXPFileParser.java +++ /dev/null @@ -1,15 +0,0 @@ -package ru.nucodelabs.files.sonet; - -import java.io.File; - -public final class EXPFileParser { - private final File expFile; - - public EXPFileParser(File expFile) { - this.expFile = expFile; - } - - public EXPFile parse() throws Exception { - return SonetImportUtils.readEXP(expFile); - } -} diff --git a/src/main/java/ru/nucodelabs/files/sonet/EXPFileParser.kt b/src/main/java/ru/nucodelabs/files/sonet/EXPFileParser.kt new file mode 100644 index 00000000..3851ecc3 --- /dev/null +++ b/src/main/java/ru/nucodelabs/files/sonet/EXPFileParser.kt @@ -0,0 +1,8 @@ +package ru.nucodelabs.files.sonet + +import java.io.File + +class EXPFileParser(private val expFile: File) { + @Throws(Exception::class) + fun parse(): EXPFile = SonetImportUtils.readEXP(expFile) +} diff --git a/src/main/java/ru/nucodelabs/files/sonet/MODFile.java b/src/main/java/ru/nucodelabs/files/sonet/MODFile.java deleted file mode 100644 index 0c969970..00000000 --- a/src/main/java/ru/nucodelabs/files/sonet/MODFile.java +++ /dev/null @@ -1,54 +0,0 @@ -package ru.nucodelabs.files.sonet; - -import java.io.File; -import java.util.ArrayList; - -public class MODFile { - private File file; - - private ArrayList resistance; // Сопротивление, Ом*м - private ArrayList polarization; // Поляризация, % - private ArrayList power; // Мощность, м - - public MODFile() { - resistance = new ArrayList<>(0); - polarization = new ArrayList<>(0); - power = new ArrayList<>(0); - } - - public int getColumnCnt() { - return 3; - } - - public ArrayList getResistance() { - return resistance; - } - - public ArrayList getPolarization() { - return polarization; - } - - public ArrayList getPower() { - return power; - } - - public void setPolarization(ArrayList polarization) { - this.polarization = polarization; - } - - public void setResistance(ArrayList resistance) { - this.resistance = resistance; - } - - public void setPower(ArrayList power) { - this.power = power; - } - - public File getFile() { - return file; - } - - public void setFile(File file) { - this.file = file; - } -} diff --git a/src/main/java/ru/nucodelabs/files/sonet/MODFile.kt b/src/main/java/ru/nucodelabs/files/sonet/MODFile.kt new file mode 100644 index 00000000..ffd5295b --- /dev/null +++ b/src/main/java/ru/nucodelabs/files/sonet/MODFile.kt @@ -0,0 +1,14 @@ +package ru.nucodelabs.files.sonet + +import java.io.File + +class MODFile { + var file: File? = null + + var resistance: MutableList = mutableListOf() + var polarization: MutableList = mutableListOf() + var power: MutableList = mutableListOf() + + val columnCnt: Int + get() = 3 +} diff --git a/src/main/java/ru/nucodelabs/files/sonet/MODFileParser.java b/src/main/java/ru/nucodelabs/files/sonet/MODFileParser.java deleted file mode 100644 index 7c3a0118..00000000 --- a/src/main/java/ru/nucodelabs/files/sonet/MODFileParser.java +++ /dev/null @@ -1,15 +0,0 @@ -package ru.nucodelabs.files.sonet; - -import java.io.File; - -public final class MODFileParser { - private final File modFile; - - public MODFileParser(File modFile) { - this.modFile = modFile; - } - - public MODFile parse() throws Exception { - return SonetImportUtils.readMOD(modFile); - } -} diff --git a/src/main/java/ru/nucodelabs/files/sonet/MODFileParser.kt b/src/main/java/ru/nucodelabs/files/sonet/MODFileParser.kt new file mode 100644 index 00000000..5d50a63e --- /dev/null +++ b/src/main/java/ru/nucodelabs/files/sonet/MODFileParser.kt @@ -0,0 +1,8 @@ +package ru.nucodelabs.files.sonet + +import java.io.File + +class MODFileParser(private val modFile: File) { + @Throws(Exception::class) + fun parse(): MODFile = SonetImportUtils.readMOD(modFile) +} diff --git a/src/main/java/ru/nucodelabs/files/sonet/STTFile.java b/src/main/java/ru/nucodelabs/files/sonet/STTFile.java deleted file mode 100644 index c434e4bd..00000000 --- a/src/main/java/ru/nucodelabs/files/sonet/STTFile.java +++ /dev/null @@ -1,44 +0,0 @@ -package ru.nucodelabs.files.sonet; - -import java.io.File; -import java.util.ArrayList; - -public class STTFile { - private File file; - - private ArrayList AB_2; // AB/2, м - private ArrayList MN_2; // MN/2, м - - public STTFile() { - AB_2 = new ArrayList<>(0); - MN_2 = new ArrayList<>(0); - } - - public int getColumnCnt() { - return 2; - } - - public ArrayList getAB_2() { - return AB_2; - } - - public ArrayList getMN_2() { - return MN_2; - } - - public void setAB_2(ArrayList AB_2) { - this.AB_2 = AB_2; - } - - public void setMN_2(ArrayList MN_2) { - this.MN_2 = MN_2; - } - - public File getFile() { - return file; - } - - public void setFile(File file) { - this.file = file; - } -} diff --git a/src/main/java/ru/nucodelabs/files/sonet/STTFile.kt b/src/main/java/ru/nucodelabs/files/sonet/STTFile.kt new file mode 100644 index 00000000..ef958542 --- /dev/null +++ b/src/main/java/ru/nucodelabs/files/sonet/STTFile.kt @@ -0,0 +1,11 @@ +package ru.nucodelabs.files.sonet + +import java.io.File + +class STTFile { + var file: File? = null + var AB_2: MutableList = mutableListOf() + var MN_2: MutableList = mutableListOf() + val columnCnt: Int + get() = 2 +} diff --git a/src/main/java/ru/nucodelabs/files/sonet/STTFileParser.java b/src/main/java/ru/nucodelabs/files/sonet/STTFileParser.java deleted file mode 100644 index 2cc22fc2..00000000 --- a/src/main/java/ru/nucodelabs/files/sonet/STTFileParser.java +++ /dev/null @@ -1,15 +0,0 @@ -package ru.nucodelabs.files.sonet; - -import java.io.File; - -public final class STTFileParser { - private final File sttFile; - - public STTFileParser(File sttFile) { - this.sttFile = sttFile; - } - - public STTFile parse() throws Exception { - return SonetImportUtils.readSTT(sttFile); - } -} diff --git a/src/main/java/ru/nucodelabs/files/sonet/STTFileParser.kt b/src/main/java/ru/nucodelabs/files/sonet/STTFileParser.kt new file mode 100644 index 00000000..12bccbcc --- /dev/null +++ b/src/main/java/ru/nucodelabs/files/sonet/STTFileParser.kt @@ -0,0 +1,8 @@ +package ru.nucodelabs.files.sonet + +import java.io.File + +class STTFileParser(private val sttFile: File) { + @Throws(Exception::class) + fun parse(): STTFile = SonetImportUtils.readSTT(sttFile) +} diff --git a/src/main/java/ru/nucodelabs/files/sonet/SonetImportUtils.java b/src/main/java/ru/nucodelabs/files/sonet/SonetImportUtils.java deleted file mode 100644 index abf7a679..00000000 --- a/src/main/java/ru/nucodelabs/files/sonet/SonetImportUtils.java +++ /dev/null @@ -1,110 +0,0 @@ -package ru.nucodelabs.files.sonet; - -import java.io.File; -import java.util.ArrayList; -import java.util.Locale; -import java.util.Scanner; - -final class SonetImportUtils { - private SonetImportUtils() { - } // чтобы нельзя было создать экземпляр класса Sonet - - static STTFile readSTT(File file) throws Exception { - STTFile res = new STTFile(); - Scanner sc = new Scanner(file).useLocale(Locale.US); - - ArrayList> numbers = columnReader(sc, new STTFile().getColumnCnt()); - - res.getAB_2().addAll( - numbers.stream().map(s -> s.get(0)).toList()); - res.getMN_2().addAll( - numbers.stream().map(s -> s.get(1)).toList()); - - sc.close(); - res.setFile(file); - return res; - } - - static EXPFile readEXP(File file) throws Exception { - EXPFile res = new EXPFile(); - Scanner sc = new Scanner(file, "Cp866").useLocale(Locale.US); - res.setSTTFileName(sc.nextLine()); - readPassport(sc, res); - ArrayList> numbers = null; - if (sc.hasNext("\\$")) { - sc.next(); - numbers = columnReader(sc, new EXPFile().getColumnCnt()); - } - assert numbers != null; - - res.getAmperage().addAll( - numbers.stream().map(s -> s.get(0)).toList()); - res.getVoltage().addAll( - numbers.stream().map(s -> s.get(1)).toList()); - res.getResistanceApparent().addAll( - numbers.stream().map(s -> s.get(2)).toList()); - res.getErrorResistanceApparent().addAll( - numbers.stream().map(s -> s.get(3)).toList()); - res.getPolarizationApparent().addAll( - numbers.stream().map(s -> s.get(4)).toList()); - res.getErrorPolarizationApparent().addAll( - numbers.stream().map(s -> s.get(5)).toList()); - - sc.close(); - res.setFile(file); - return res; - } - - static MODFile readMOD(File file) throws Exception { - MODFile res = new MODFile(); - Scanner sc = new Scanner(file).useLocale(Locale.US); - - ArrayList> numbers = columnReader(sc, new MODFile().getColumnCnt()); - - res.getResistance().addAll( - numbers.stream().map(s -> s.get(0)).toList()); - res.getPower().addAll( - numbers.stream().map(s -> s.get(1)).toList()); - res.getPolarization().addAll( - numbers.stream().map(s -> s.get(2)).toList()); - - sc.close(); - res.setFile(file); - return res; - } - - private static void readPassport(Scanner sc, EXPFile res) { - ArrayList strList = new ArrayList<>(); - while (sc.hasNextLine() && !sc.hasNext("\\$") && strList.size() < 6) { - strList.add(sc.nextLine()); - } - if (strList.size() > 0) res.setNumber(strList.get(0)); - if (strList.size() > 1) res.setDate(strList.get(1)); - if (strList.size() > 2) res.setWeather(strList.get(2)); - if (strList.size() > 3) res.setOperator(strList.get(3)); - if (strList.size() > 4) res.setInterpreter(strList.get(4)); - if (strList.size() > 5) res.setChecked(strList.get(5)); - } - - private static ArrayList> columnReader(Scanner sc, int colCnt) { - ArrayList> res = new ArrayList<>(); - while (sc.hasNextLine() && !sc.hasNext("\\$") && !sc.hasNext("-1.0")) { - String str = sc.nextLine(); - if (str.isBlank()) { - continue; - } - Scanner strSc = new Scanner(str).useLocale(Locale.US); - ArrayList numList = new ArrayList<>(); - for (int i = 0; i < colCnt; i++) { - if (strSc.hasNext()) { - numList.add(strSc.nextDouble()); - } else { - numList.add(0d); - } - } - res.add(numList); - strSc.close(); - } - return res; - } -} diff --git a/src/main/java/ru/nucodelabs/files/sonet/SonetImportUtils.kt b/src/main/java/ru/nucodelabs/files/sonet/SonetImportUtils.kt new file mode 100644 index 00000000..9fece882 --- /dev/null +++ b/src/main/java/ru/nucodelabs/files/sonet/SonetImportUtils.kt @@ -0,0 +1,81 @@ +package ru.nucodelabs.files.sonet + +import java.io.File +import java.util.* + +internal object SonetImportUtils { + @JvmStatic + @Throws(Exception::class) + fun readSTT(file: File): STTFile { + val res = STTFile() + Scanner(file).useLocale(Locale.US).use { sc -> + val numbers = columnReader(sc, STTFile().columnCnt) + res.AB_2.addAll(numbers.map { it[0] }) + res.MN_2.addAll(numbers.map { it[1] }) + } + res.file = file + return res + } + + @JvmStatic + @Throws(Exception::class) + fun readEXP(file: File): EXPFile { + val res = EXPFile() + Scanner(file, "Cp866").useLocale(Locale.US).use { sc -> + res.STTFileName = sc.nextLine() + readPassport(sc, res) + val numbers = if (sc.hasNext("\\$") ) { + sc.next(); columnReader(sc, EXPFile().columnCnt) + } else null + requireNotNull(numbers) + res.amperage.addAll(numbers.map { it[0] }) + res.voltage.addAll(numbers.map { it[1] }) + res.resistanceApparent.addAll(numbers.map { it[2] }) + res.errorResistanceApparent.addAll(numbers.map { it[3] }) + res.polarizationApparent.addAll(numbers.map { it[4] }) + res.errorPolarizationApparent.addAll(numbers.map { it[5] }) + } + res.file = file + return res + } + + @JvmStatic + @Throws(Exception::class) + fun readMOD(file: File): MODFile { + val res = MODFile() + Scanner(file).useLocale(Locale.US).use { sc -> + val numbers = columnReader(sc, MODFile().columnCnt) + res.resistance.addAll(numbers.map { it[0] }) + res.power.addAll(numbers.map { it[1] }) + res.polarization.addAll(numbers.map { it[2] }) + } + res.file = file + return res + } + + private fun readPassport(sc: Scanner, res: EXPFile) { + val strList = ArrayList() + while (sc.hasNextLine() && !sc.hasNext("\\$") && strList.size < 6) { + strList.add(sc.nextLine()) + } + if (strList.size > 0) res.number = strList[0] + if (strList.size > 1) res.date = strList[1] + if (strList.size > 2) res.weather = strList[2] + if (strList.size > 3) res.operator = strList[3] + if (strList.size > 4) res.interpreter = strList[4] + if (strList.size > 5) res.checked = strList[5] + } + + private fun columnReader(sc: Scanner, colCnt: Int): MutableList> { + val res = mutableListOf>() + while (sc.hasNextLine() && !sc.hasNext("\\$") && !sc.hasNext("-1.0")) { + val line = sc.nextLine() + if (line.isBlank()) continue + Scanner(line).useLocale(Locale.US).use { rowScanner -> + val row = MutableList(colCnt) { if (rowScanner.hasNextDouble()) rowScanner.nextDouble() else 0.0 } + res.add(row) + } + } + return res + } +} diff --git a/src/main/java/ru/nucodelabs/gem/app/AppModule.java b/src/main/java/ru/nucodelabs/gem/app/AppModule.java deleted file mode 100644 index f8787b1d..00000000 --- a/src/main/java/ru/nucodelabs/gem/app/AppModule.java +++ /dev/null @@ -1,203 +0,0 @@ -package ru.nucodelabs.gem.app; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.google.inject.AbstractModule; -import com.google.inject.Injector; -import com.google.inject.Provides; -import com.google.inject.Singleton; -import com.google.inject.name.Named; -import jakarta.validation.Validation; -import jakarta.validation.Validator; -import javafx.fxml.FXMLLoader; -import javafx.stage.Stage; -import javafx.util.StringConverter; -import ru.nucodelabs.geo.ves.calc.forward.ForwardSolver; -import ru.nucodelabs.files.clr.ClrParser; -import ru.nucodelabs.files.clr.ColorNode; -import ru.nucodelabs.gem.app.io.JacksonJsonFileManager; -import ru.nucodelabs.gem.app.io.JsonFileManager; -import ru.nucodelabs.gem.app.io.SonetImportManager; -import ru.nucodelabs.gem.view.FileChoosersModule; -import ru.nucodelabs.gem.view.color.ColorMapper; -import ru.nucodelabs.gem.view.color.ColorPalette; -import ru.nucodelabs.gem.view.main.MainViewController; -import ru.nucodelabs.gem.view.main.MainViewModule; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.math.RoundingMode; -import java.net.URL; -import java.nio.file.Paths; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.text.ParseException; -import java.util.List; -import java.util.Locale; -import java.util.ResourceBundle; -import java.util.prefs.Preferences; - -import static com.fasterxml.jackson.module.kotlin.ExtensionsKt.jacksonObjectMapper; - -/** - * Зависимости приложения, которое, по сути, создает MainView - */ -public class AppModule extends AbstractModule { - - @Override - protected void configure() { - install(new FileChoosersModule()); - } - - @Provides - @Singleton - private ResourceBundle provideUIProperties() { - return ResourceBundle.getBundle("ru/nucodelabs/gem/UI", new Locale("ru")); - } - - @Provides - @Named("CSS") - @Singleton - private String provideStylesheet() { - return "ru/nucodelabs/gem/view/common.css"; - } - - @Provides - @Named("MainView") - private URL provideMainViewFXML() { - return MainViewController.class.getResource("MainSplitLayoutView.fxml"); - } - - @Provides - @Named("MainView") - private FXMLLoader provideFXMLLoader(ResourceBundle uiProperties, Injector injector, @Named("MainView") URL url) { - FXMLLoader fxmlLoader = new FXMLLoader(url, uiProperties); - fxmlLoader.setControllerFactory(injector.createChildInjector(new MainViewModule())::getInstance); - return fxmlLoader; - } - - @Provides - @Named("MainView") - private Stage create(@Named("MainView") FXMLLoader loader) throws IOException { - return loader.load(); - } - - @Provides - private Validator provideValidator() { - try (var factory = Validation.buildDefaultValidatorFactory()) { - return factory.getValidator(); - } - } - - @Provides - @Singleton - private JsonFileManager provideJsonFileManager(ObjectMapper objectMapper) { - return new JacksonJsonFileManager(objectMapper); - } - - @Provides - @Singleton - private SonetImportManager provideSonetImportManager() { - return SonetImportManager.create(); - } - - @Provides - private Preferences preferences() { - return Preferences.userNodeForPackage(GemApplication.class); - } - - @Provides - @Named("Precise") - DecimalFormat preciseFormat() { - DecimalFormat decimalFormat = new DecimalFormat(); - decimalFormat.setRoundingMode(RoundingMode.HALF_UP); - decimalFormat.setMaximumFractionDigits(16); - var dfs = new DecimalFormatSymbols(); - dfs.setDecimalSeparator('.'); - dfs.setGroupingSeparator(' '); - decimalFormat.setDecimalFormatSymbols(dfs); - - return decimalFormat; - } - - @Provides - private DecimalFormat decimalFormat() { - DecimalFormat decimalFormat = new DecimalFormat(); - decimalFormat.setRoundingMode(RoundingMode.HALF_UP); - decimalFormat.setMaximumFractionDigits(2); - decimalFormat.setGroupingSize(3); - var dfs = new DecimalFormatSymbols(); - dfs.setDecimalSeparator('.'); - dfs.setGroupingSeparator(' '); - decimalFormat.setDecimalFormatSymbols(dfs); - - return decimalFormat; - } - - @Provides - @Singleton - private StringConverter doubleStringConverter(DecimalFormat decimalFormat) { - return new StringConverter<>() { - @Override - public String toString(Double object) { - try { - return decimalFormat.format(object); - } catch (Exception e) { - return ""; - } - } - - @Override - public Double fromString(String string) { - try { - return decimalFormat.parse(string).doubleValue(); - } catch (ParseException e) { - throw new RuntimeException(e); - } - } - }; - } - - @Provides - @Singleton - StringConverter numberStringConverter(StringConverter doubleStringConverter) { - return new StringConverter<>() { - @Override - public String toString(Number object) { - return doubleStringConverter.toString(object.doubleValue()); - } - - @Override - public Number fromString(String string) { - return doubleStringConverter.fromString(string); - } - }; - } - - @Provides - @Named("CLR") - File clrFile() { - return Paths.get("colormap/default.clr").toFile(); - } - - @Provides - @Singleton - ColorMapper colorMapper(@Named("CLR") File clrFile) throws FileNotFoundException { - ClrParser clrParser = new ClrParser(clrFile); - System.out.println(clrFile.getAbsolutePath()); - List valueColorList = clrParser.getColorNodes(); - return new ColorPalette(valueColorList, 0, 1500, 15); - } - - @Provides - @Singleton - ForwardSolver forwardSolver() { - return ForwardSolver.createDefault(); - } - - @Provides - ObjectMapper objectMapper() { - return jacksonObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); - } -} diff --git a/src/main/java/ru/nucodelabs/gem/app/AppModule.kt b/src/main/java/ru/nucodelabs/gem/app/AppModule.kt new file mode 100644 index 00000000..00a1d61a --- /dev/null +++ b/src/main/java/ru/nucodelabs/gem/app/AppModule.kt @@ -0,0 +1,166 @@ +package ru.nucodelabs.gem.app + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.SerializationFeature +import com.google.inject.AbstractModule +import com.google.inject.Injector +import com.google.inject.Provides +import com.google.inject.Singleton +import com.google.inject.name.Named +import jakarta.validation.Validation +import jakarta.validation.Validator +import javafx.fxml.FXMLLoader +import javafx.stage.Stage +import javafx.util.StringConverter +import javafx.util.Callback +import ru.nucodelabs.geo.ves.calc.forward.ForwardSolver +import ru.nucodelabs.files.clr.ClrParser +import ru.nucodelabs.files.clr.ColorNode +import ru.nucodelabs.gem.app.io.JacksonJsonFileManager +import ru.nucodelabs.gem.app.io.JsonFileManager +import ru.nucodelabs.gem.app.io.SonetImportManager +import ru.nucodelabs.gem.view.FileChoosersModule +import ru.nucodelabs.gem.view.color.ColorMapper +import ru.nucodelabs.gem.view.color.ColorPalette +import ru.nucodelabs.gem.view.main.MainViewController +import ru.nucodelabs.gem.view.main.MainViewModule +import java.io.File +import java.io.FileNotFoundException +import java.io.IOException +import java.math.RoundingMode +import java.net.URL +import java.nio.file.Paths +import java.text.DecimalFormat +import java.text.DecimalFormatSymbols +import java.text.ParseException +import java.util.* +import java.util.prefs.Preferences + +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper + +/** + * Application dependencies configuration. + */ +class AppModule : AbstractModule() { + override fun configure() { + install(FileChoosersModule()) + } + + @Provides + @Singleton + private fun provideUIProperties(): ResourceBundle = + ResourceBundle.getBundle("ru/nucodelabs/gem/UI", Locale("ru")) + + @Provides + @Named("CSS") + @Singleton + private fun provideStylesheet(): String = "ru/nucodelabs/gem/view/common.css" + + @Provides + @Named("MainView") + private fun provideMainViewFXML(): URL = + MainViewController::class.java.getResource("MainSplitLayoutView.fxml")!! + + @Provides + @Named("MainView") + private fun provideFXMLLoader( + uiProperties: ResourceBundle, + injector: Injector, + @Named("MainView") url: URL + ): FXMLLoader = FXMLLoader(url, uiProperties).apply { + val child = injector.createChildInjector(MainViewModule()) + controllerFactory = Callback { clazz: Class<*>? -> child.getInstance(clazz) } + } + + @Provides + @Named("MainView") + @Throws(IOException::class) + private fun create(@Named("MainView") loader: FXMLLoader): Stage = loader.load() + + @Provides + private fun provideValidator(): Validator = + Validation.buildDefaultValidatorFactory().use { it.validator } + + @Provides + @Singleton + private fun provideJsonFileManager(objectMapper: ObjectMapper): JsonFileManager = + JacksonJsonFileManager(objectMapper) + + @Provides + @Singleton + private fun provideSonetImportManager(): SonetImportManager = SonetImportManager.create() + + @Provides + private fun preferences(): Preferences = Preferences.userNodeForPackage(GemApplication::class.java) + + @Provides + @Named("Precise") + fun preciseFormat(): DecimalFormat = DecimalFormat().apply { + roundingMode = RoundingMode.HALF_UP + maximumFractionDigits = 16 + decimalFormatSymbols = DecimalFormatSymbols().apply { + decimalSeparator = '.' + groupingSeparator = ' ' + } + } + + @Provides + fun decimalFormat(): DecimalFormat = DecimalFormat().apply { + roundingMode = RoundingMode.HALF_UP + maximumFractionDigits = 2 + groupingSize = 3 + decimalFormatSymbols = DecimalFormatSymbols().apply { + decimalSeparator = '.' + groupingSeparator = ' ' + } + } + + @Provides + @Singleton + fun doubleStringConverter(decimalFormat: DecimalFormat): StringConverter = object : StringConverter() { + override fun toString(obj: Double?): String = try { + decimalFormat.format(obj) + } catch (e: Exception) { + "" + } + + override fun fromString(string: String?): Double = try { + decimalFormat.parse(string).toDouble() + } catch (e: ParseException) { + throw RuntimeException(e) + } + } + + @Provides + @Singleton + fun numberStringConverter(doubleStringConverter: StringConverter): StringConverter = + object : StringConverter() { + override fun toString(obj: Number?): String = + doubleStringConverter.toString(obj?.toDouble()) + + override fun fromString(string: String?): Number = + doubleStringConverter.fromString(string) + } + + @Provides + @Named("CLR") + fun clrFile(): File = Paths.get("colormap/default.clr").toFile() + + @Provides + @Singleton + @Throws(FileNotFoundException::class) + fun colorMapper(@Named("CLR") clrFile: File): ColorMapper { + val clrParser = ClrParser(clrFile) + println(clrFile.absolutePath) + val valueColorList: List = clrParser.colorNodes + return ColorPalette(valueColorList, 0.0, 1500.0, 15) + } + + @Provides + @Singleton + fun forwardSolver(): ForwardSolver = ForwardSolver.createDefault() + + @Provides + fun objectMapper(): ObjectMapper = + jacksonObjectMapper().enable(SerializationFeature.INDENT_OUTPUT) +} diff --git a/src/main/java/ru/nucodelabs/gem/app/StartGemApplication.java b/src/main/java/ru/nucodelabs/gem/app/StartGemApplication.java deleted file mode 100644 index 83c3bc8c..00000000 --- a/src/main/java/ru/nucodelabs/gem/app/StartGemApplication.java +++ /dev/null @@ -1,17 +0,0 @@ -package ru.nucodelabs.gem.app; - -import javafx.application.Application; - -/** - * Main, запускает приложение JavaFX - */ -public class StartGemApplication { - - public static void main(String[] args) { - try { - Application.launch(GemApplication.class, args); - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/src/main/java/ru/nucodelabs/gem/app/StartGemApplication.kt b/src/main/java/ru/nucodelabs/gem/app/StartGemApplication.kt new file mode 100644 index 00000000..3e4aadfa --- /dev/null +++ b/src/main/java/ru/nucodelabs/gem/app/StartGemApplication.kt @@ -0,0 +1,17 @@ +package ru.nucodelabs.gem.app + +import javafx.application.Application + +/** + * Main entry point launching JavaFX application. + */ +object StartGemApplication { + @JvmStatic + fun main(args: Array) { + try { + Application.launch(GemApplication::class.java, *args) + } catch (e: Exception) { + e.printStackTrace() + } + } +} 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..d72617da 100644 --- a/src/main/java/ru/nucodelabs/gem/app/io/SonetImportManagerImpl.kt +++ b/src/main/java/ru/nucodelabs/gem/app/io/SonetImportManagerImpl.kt @@ -12,7 +12,7 @@ internal class SonetImportManagerImpl : SonetImportManager { val expParsed = EXPFileParser(expFile).parse() val expFilePath = expFile.toPath() return expParsed to STTFileParser( - File("${expFilePath.parent}${File.separator}${expParsed.sttFileName}") + File("${expFilePath.parent}${File.separator}${expParsed.STTFileName}") ).parse() } @@ -20,8 +20,8 @@ internal class SonetImportManagerImpl : SonetImportManager { val (expParsed, sttParsed) = parseExpWithStt(expFile) val minSize = listOf( - sttParsed.aB_2, - sttParsed.mN_2, + sttParsed.AB_2, + sttParsed.MN_2, expParsed.amperage, expParsed.voltage, expParsed.resistanceApparent, @@ -31,8 +31,8 @@ internal class SonetImportManagerImpl : SonetImportManager { val expData: MutableList = mutableListOf() for (i in 0 until minSize) { expData += ExperimentalData( - ab2 = sttParsed.aB_2[i], - mn2 = sttParsed.mN_2[i], + ab2 = sttParsed.AB_2[i], + mn2 = sttParsed.MN_2[i], resistanceApparent = expParsed.resistanceApparent[i], errorResistanceApparent = expParsed.errorResistanceApparent[i], amperage = expParsed.amperage[i], diff --git a/src/main/java/ru/nucodelabs/gem/util/fx/FXUtils.java b/src/main/java/ru/nucodelabs/gem/util/fx/FXUtils.java deleted file mode 100644 index 94da2412..00000000 --- a/src/main/java/ru/nucodelabs/gem/util/fx/FXUtils.java +++ /dev/null @@ -1,66 +0,0 @@ -package ru.nucodelabs.gem.util.fx; - -import javafx.fxml.FXMLLoader; -import javafx.scene.Node; -import javafx.scene.paint.Color; - -import java.io.IOException; -import java.util.Locale; -import java.util.ResourceBundle; - -/** - * Static methods for initializing user controls and view - */ -public class FXUtils { - - private FXUtils() { - } - - /** - * Load FXML file with name equals to {@code root} class name and sets the {@code root} as the controller of loaded FXML. - * - * @param root object that inherits class of root node of FXML - * @param class of root - * @param locale locale - */ - public static void initFXMLControl(N root, Locale locale) { - ResourceBundle bundle = ResourceBundle.getBundle("ru/nucodelabs/gem/UI", locale); - initFXMLControl(root, bundle); - } - - public static void initFXMLControl(N root) { - ResourceBundle bundle = ResourceBundle.getBundle("ru/nucodelabs/gem/UI"); - initFXMLControl(root, bundle); - } - - private static void initFXMLControl(N root, ResourceBundle bundle) { - String fxmlFileName = root.getClass().getSimpleName() + ".fxml"; - FXMLLoader loader = new FXMLLoader(root.getClass().getResource(fxmlFileName), bundle); - loader.setRoot(root); - loader.setController(root); - try { - loader.load(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public static void unfocus(Node... nodes) { - for (var node : nodes) { - if (node.isFocused()) { - node.getParent().requestFocus(); - } - } - } - - /** - * @return "rgba(%d, %d, %d, %f)" - */ - public static String toWeb(Color color) { - return String.format("rgba(%d, %d, %d, %f)", - (int) Math.ceil(color.getRed() * 255), - (int) Math.ceil(color.getGreen() * 255), - (int) Math.ceil(color.getBlue() * 255), - color.getOpacity()); - } -} diff --git a/src/main/java/ru/nucodelabs/gem/util/fx/FXUtils.kt b/src/main/java/ru/nucodelabs/gem/util/fx/FXUtils.kt new file mode 100644 index 00000000..d8a1fe62 --- /dev/null +++ b/src/main/java/ru/nucodelabs/gem/util/fx/FXUtils.kt @@ -0,0 +1,47 @@ +package ru.nucodelabs.gem.util.fx + +import javafx.fxml.FXMLLoader +import javafx.scene.Node +import javafx.scene.paint.Color +import java.io.IOException +import java.util.* + +/** + * Utility functions for initializing controls and manipulating colors. + */ +object FXUtils { + + @JvmStatic + fun initFXMLControl(root: N, locale: Locale = Locale.getDefault()) { + val bundle = ResourceBundle.getBundle("ru/nucodelabs/gem/UI", locale) + val fxmlFileName = root.javaClass.simpleName + ".fxml" + val loader = FXMLLoader(root.javaClass.getResource(fxmlFileName), bundle) + loader.setRoot(root) + loader.setController(root) + try { + loader.load() + } catch (e: IOException) { + e.printStackTrace() + } + } + + @JvmStatic + fun unfocus(vararg nodes: Node) { + nodes.filter(Node::isFocused).forEach { it.parent.requestFocus() } + } + + /** + * @return string in format "rgba(%d, %d, %d, %f)". + */ + @JvmStatic + fun toWeb(color: Color): String = with(color) { + String.format( + Locale.US, + "rgba(%d, %d, %d, %f)", + kotlin.math.round(red * 255).toInt(), + kotlin.math.round(green * 255).toInt(), + kotlin.math.round(blue * 255).toInt(), + opacity + ) + } +} diff --git a/src/main/java/ru/nucodelabs/gem/view/DialogsModule.java b/src/main/java/ru/nucodelabs/gem/view/DialogsModule.java deleted file mode 100644 index 8b62b490..00000000 --- a/src/main/java/ru/nucodelabs/gem/view/DialogsModule.java +++ /dev/null @@ -1,23 +0,0 @@ -package ru.nucodelabs.gem.view; - -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import com.google.inject.name.Named; -import javafx.scene.control.ButtonType; -import javafx.scene.control.Dialog; - -public class DialogsModule extends AbstractModule { - @Provides - @Named("Save") - private Dialog provideSaveDialog(@Named("CSS") String stylesheet) { - Dialog saveDialog = new Dialog<>(); - saveDialog.setTitle("Сохранение"); - saveDialog.setContentText("Сохранить изменения?"); - saveDialog.getDialogPane().getButtonTypes() - .addAll(ButtonType.YES, - ButtonType.NO, - ButtonType.CANCEL); - saveDialog.getDialogPane().getStylesheets().add(stylesheet); - return saveDialog; - } -} diff --git a/src/main/java/ru/nucodelabs/gem/view/DialogsModule.kt b/src/main/java/ru/nucodelabs/gem/view/DialogsModule.kt new file mode 100644 index 00000000..a07d0f60 --- /dev/null +++ b/src/main/java/ru/nucodelabs/gem/view/DialogsModule.kt @@ -0,0 +1,19 @@ +package ru.nucodelabs.gem.view + +import com.google.inject.AbstractModule +import com.google.inject.Provides +import com.google.inject.name.Named +import javafx.scene.control.ButtonType +import javafx.scene.control.Dialog + +class DialogsModule : AbstractModule() { + @Provides + @Named("Save") + fun provideSaveDialog(@Named("CSS") stylesheet: String): Dialog = + Dialog().apply { + title = "Сохранение" + contentText = "Сохранить изменения?" + dialogPane.buttonTypes.addAll(ButtonType.YES, ButtonType.NO, ButtonType.CANCEL) + dialogPane.stylesheets.add(stylesheet) + } +} diff --git a/src/main/java/ru/nucodelabs/gem/view/FileChoosersModule.java b/src/main/java/ru/nucodelabs/gem/view/FileChoosersModule.java deleted file mode 100644 index 736c8247..00000000 --- a/src/main/java/ru/nucodelabs/gem/view/FileChoosersModule.java +++ /dev/null @@ -1,84 +0,0 @@ -package ru.nucodelabs.gem.view; - -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import com.google.inject.Singleton; -import com.google.inject.name.Named; -import javafx.stage.FileChooser; - -import java.io.File; -import java.util.ResourceBundle; -import java.util.prefs.Preferences; - -import static ru.nucodelabs.gem.app.pref.AppPreferencesKt.*; - -public class FileChoosersModule extends AbstractModule { - - private static final FileChooser.ExtensionFilter allFilesFilter = new FileChooser.ExtensionFilter("Все файлы", "*.*"); - - @Provides - @Singleton - @Named("EXP") - private FileChooser provideEXPFileChooser(ResourceBundle ui, Preferences preferences) { - FileChooser chooser = new FileChooser(); - chooser.getExtensionFilters().addAll( - new FileChooser.ExtensionFilter(ui.getString("expData"), "*.exp"), - allFilesFilter - ); - File initDir = new File(preferences.get(EXP_FILES_DIR.getKey(), EXP_FILES_DIR.getDef())); - if (initDir.exists()) { - chooser.setInitialDirectory(initDir); - } - return chooser; - } - - @Provides - @Singleton - @Named("JSON") - private FileChooser provideJSONFileChooser(ResourceBundle ui, Preferences preferences) { - FileChooser chooser = new FileChooser(); - chooser.getExtensionFilters().addAll( - new FileChooser.ExtensionFilter(ui.getString("section") + "/" + ui.getString("picket"), "*.json"), - new FileChooser.ExtensionFilter(ui.getString("picket"), "*.point.json"), - new FileChooser.ExtensionFilter(ui.getString("section"), "*.section.json"), - allFilesFilter - ); - File initDir = new File(preferences.get(JSON_FILES_DIR.getKey(), JSON_FILES_DIR.getDef())); - if (initDir.exists()) { - chooser.setInitialDirectory(initDir); - } - return chooser; - } - - @Provides - @Singleton - @Named("MOD") - private FileChooser provideMODFileChooser(ResourceBundle ui, Preferences preferences) { - FileChooser chooser = new FileChooser(); - chooser.getExtensionFilters().addAll( - new FileChooser.ExtensionFilter(ui.getString("modData"), "*.mod"), - allFilesFilter - ); - File initDir = new File(preferences.get(MOD_FILES_DIR.getKey(), MOD_FILES_DIR.getDef())); - if (initDir.exists()) { - chooser.setInitialDirectory(initDir); - } - return chooser; - } - - @Provides - @Singleton - @Named("PNG") - private FileChooser pngFileChooser(Preferences preferences) { - FileChooser chooser = new FileChooser(); - chooser.getExtensionFilters().addAll( - new FileChooser.ExtensionFilter("Изображение", "*.png", "*.PNG"), - allFilesFilter - ); - File initDir = new File(preferences.get(PNG_FILES_DIR.getKey(), PNG_FILES_DIR.getDef())); - if (initDir.exists()) { - chooser.setInitialDirectory(initDir); - } - return chooser; - } -} diff --git a/src/main/java/ru/nucodelabs/gem/view/FileChoosersModule.kt b/src/main/java/ru/nucodelabs/gem/view/FileChoosersModule.kt new file mode 100644 index 00000000..7fe67367 --- /dev/null +++ b/src/main/java/ru/nucodelabs/gem/view/FileChoosersModule.kt @@ -0,0 +1,72 @@ +package ru.nucodelabs.gem.view + +import com.google.inject.AbstractModule +import com.google.inject.Provides +import com.google.inject.Singleton +import com.google.inject.name.Named +import javafx.stage.FileChooser +import java.io.File +import java.util.ResourceBundle +import java.util.prefs.Preferences +import ru.nucodelabs.gem.app.pref.EXP_FILES_DIR +import ru.nucodelabs.gem.app.pref.JSON_FILES_DIR +import ru.nucodelabs.gem.app.pref.MOD_FILES_DIR +import ru.nucodelabs.gem.app.pref.PNG_FILES_DIR + +class FileChoosersModule : AbstractModule() { + private val allFilesFilter = FileChooser.ExtensionFilter("Все файлы", "*.*") + + @Provides + @Singleton + @Named("EXP") + fun provideEXPFileChooser(ui: ResourceBundle, preferences: Preferences): FileChooser = + FileChooser().apply { + extensionFilters.addAll( + FileChooser.ExtensionFilter(ui.getString("expData"), "*.exp"), + allFilesFilter + ) + val initDir = File(preferences.get(EXP_FILES_DIR.key, EXP_FILES_DIR.def)) + if (initDir.exists()) initialDirectory = initDir + } + + @Provides + @Singleton + @Named("JSON") + fun provideJSONFileChooser(ui: ResourceBundle, preferences: Preferences): FileChooser = + FileChooser().apply { + extensionFilters.addAll( + FileChooser.ExtensionFilter("${ui.getString("section")}/${ui.getString("picket")}", "*.json"), + FileChooser.ExtensionFilter(ui.getString("picket"), "*.point.json"), + FileChooser.ExtensionFilter(ui.getString("section"), "*.section.json"), + allFilesFilter + ) + val initDir = File(preferences.get(JSON_FILES_DIR.key, JSON_FILES_DIR.def)) + if (initDir.exists()) initialDirectory = initDir + } + + @Provides + @Singleton + @Named("MOD") + fun provideMODFileChooser(ui: ResourceBundle, preferences: Preferences): FileChooser = + FileChooser().apply { + extensionFilters.addAll( + FileChooser.ExtensionFilter(ui.getString("modData"), "*.mod"), + allFilesFilter + ) + val initDir = File(preferences.get(MOD_FILES_DIR.key, MOD_FILES_DIR.def)) + if (initDir.exists()) initialDirectory = initDir + } + + @Provides + @Singleton + @Named("PNG") + fun pngFileChooser(preferences: Preferences): FileChooser = + FileChooser().apply { + extensionFilters.addAll( + FileChooser.ExtensionFilter("Изображение", "*.png", "*.PNG"), + allFilesFilter + ) + val initDir = File(preferences.get(PNG_FILES_DIR.key, PNG_FILES_DIR.def)) + if (initDir.exists()) initialDirectory = initDir + } +} diff --git a/src/main/java/ru/nucodelabs/gem/view/PowerOf10Formatter.java b/src/main/java/ru/nucodelabs/gem/view/PowerOf10Formatter.java deleted file mode 100644 index 012872ac..00000000 --- a/src/main/java/ru/nucodelabs/gem/view/PowerOf10Formatter.java +++ /dev/null @@ -1,66 +0,0 @@ -package ru.nucodelabs.gem.view; - -import javafx.util.StringConverter; - -import javax.naming.OperationNotSupportedException; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.ArrayList; -import java.util.stream.Collectors; - -/** - * Formats number to ten with power of this number, only if its integer - */ -public class PowerOf10Formatter extends StringConverter { - - private static String toUpperIndex(String doubleString) { - ArrayList resChars = new ArrayList<>(); - for (int i = 0; i < doubleString.length(); i++) { - char c = doubleString.charAt(i); - switch (c) { - case '1' -> resChars.add('¹'); - case '2' -> resChars.add('²'); - case '3' -> resChars.add('³'); - case '4' -> resChars.add('⁴'); - case '5' -> resChars.add('⁵'); - case '6' -> resChars.add('⁶'); - case '7' -> resChars.add('⁷'); - case '8' -> resChars.add('⁸'); - case '9' -> resChars.add('⁹'); - case '0' -> resChars.add('⁰'); - case '.' -> resChars.add('\u0387'); - case '-' -> resChars.add('\u207b'); - default -> resChars.add(c); - } - } - return resChars - .stream() - .map(String::valueOf) - .collect(Collectors.joining()); - } - - @Override - public String toString(Number object) { - DecimalFormat format = new DecimalFormat(); - DecimalFormatSymbols formatSymbols = new DecimalFormatSymbols(); - formatSymbols.setDecimalSeparator('.'); - format.setDecimalFormatSymbols(formatSymbols); - if (object.doubleValue() == 0) { - return "1"; - } else if (object.doubleValue() - Math.ceil(object.doubleValue()) == 0) { - return ("10" + toUpperIndex(format.format(object.doubleValue()))); - } else { - return ""; - } - } - - @Override - public Number fromString(String string) { - try { - throw new OperationNotSupportedException(); - } catch (OperationNotSupportedException e) { - e.printStackTrace(); - } - return null; - } -} diff --git a/src/main/java/ru/nucodelabs/gem/view/PowerOf10Formatter.kt b/src/main/java/ru/nucodelabs/gem/view/PowerOf10Formatter.kt new file mode 100644 index 00000000..88b38cda --- /dev/null +++ b/src/main/java/ru/nucodelabs/gem/view/PowerOf10Formatter.kt @@ -0,0 +1,52 @@ +package ru.nucodelabs.gem.view + +import javafx.util.StringConverter +import java.text.DecimalFormat +import java.text.DecimalFormatSymbols +import java.util.Locale + +/** + * Formats numbers as powers of ten when the value is integer. + */ +class PowerOf10Formatter : StringConverter() { + + private fun toUpperIndex(value: String): String = buildString { + value.forEach { c -> + append( + when (c) { + '1' -> '¹' + '2' -> '²' + '3' -> '³' + '4' -> '⁴' + '5' -> '⁵' + '6' -> '⁶' + '7' -> '⁷' + '8' -> '⁸' + '9' -> '⁹' + '0' -> '⁰' + '.' -> '\u0387' + '-' -> '\u207b' + else -> c + } + ) + } + } + + override fun toString(number: Number): String { + val format = DecimalFormat().apply { + decimalFormatSymbols = DecimalFormatSymbols(Locale.US).apply { + decimalSeparator = '.' + } + } + return when { + number.toDouble() == 0.0 -> "1" + number.toDouble() - Math.ceil(number.toDouble()) == 0.0 -> + "10" + toUpperIndex(format.format(number.toDouble())) + else -> "" + } + } + + override fun fromString(string: String?): Number? { + throw UnsupportedOperationException() + } +} diff --git a/src/main/java/ru/nucodelabs/gem/view/charts/ChartsModule.java b/src/main/java/ru/nucodelabs/gem/view/charts/ChartsModule.java deleted file mode 100644 index 51801e49..00000000 --- a/src/main/java/ru/nucodelabs/gem/view/charts/ChartsModule.java +++ /dev/null @@ -1,40 +0,0 @@ -package ru.nucodelabs.gem.view.charts; - -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import com.google.inject.name.Named; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.scene.chart.XYChart; -import ru.nucodelabs.geo.ves.calc.graph.MisfitsFunction; -import ru.nucodelabs.geo.ves.calc.forward.ForwardSolver; - -import java.util.ArrayList; - -import static ru.nucodelabs.gem.view.charts.VesCurvesController.TOTAL_COUNT; - -public class ChartsModule extends AbstractModule { - @Provides - private ObjectProperty>> emptyChartData() { - return new SimpleObjectProperty<>( - FXCollections.observableArrayList(new ArrayList<>())); - } - - @Provides - @Named("VESCurves") - private ObjectProperty>> provideVESCurvesData() { - ObjectProperty>> dataProperty = - new SimpleObjectProperty<>(FXCollections.observableArrayList()); - for (int i = 0; i < TOTAL_COUNT; i++) { - dataProperty.get().add(new XYChart.Series<>()); - } - return dataProperty; - } - - @Provides - MisfitsFunction misfitValuesFactory(ForwardSolver forwardSolver) { - return MisfitsFunction.createDefault(forwardSolver); - } -} diff --git a/src/main/java/ru/nucodelabs/gem/view/charts/ChartsModule.kt b/src/main/java/ru/nucodelabs/gem/view/charts/ChartsModule.kt new file mode 100644 index 00000000..a66ccf77 --- /dev/null +++ b/src/main/java/ru/nucodelabs/gem/view/charts/ChartsModule.kt @@ -0,0 +1,29 @@ +package ru.nucodelabs.gem.view.charts + +import com.google.inject.AbstractModule +import com.google.inject.Provides +import com.google.inject.name.Named +import javafx.beans.property.ObjectProperty +import javafx.beans.property.SimpleObjectProperty +import javafx.collections.FXCollections +import javafx.collections.ObservableList +import javafx.scene.chart.XYChart +import ru.nucodelabs.geo.ves.calc.graph.MisfitsFunction +import ru.nucodelabs.geo.ves.calc.forward.ForwardSolver + +class ChartsModule : AbstractModule() { + @Provides + fun emptyChartData(): ObjectProperty>> = + SimpleObjectProperty(FXCollections.observableArrayList()) + + @Provides + @Named("VESCurves") + fun provideVESCurvesData(): ObjectProperty>> = + SimpleObjectProperty(FXCollections.observableArrayList>().apply { + repeat(VesCurvesController.TOTAL_COUNT) { add(XYChart.Series()) } + }) + + @Provides + fun misfitValuesFactory(forwardSolver: ForwardSolver): MisfitsFunction = + MisfitsFunction.createDefault(forwardSolver) +} diff --git a/src/main/java/ru/nucodelabs/gem/view/charts/MisfitStacksController.kt b/src/main/java/ru/nucodelabs/gem/view/charts/MisfitStacksController.kt index 27209aa8..81ab2739 100644 --- a/src/main/java/ru/nucodelabs/gem/view/charts/MisfitStacksController.kt +++ b/src/main/java/ru/nucodelabs/gem/view/charts/MisfitStacksController.kt @@ -115,7 +115,7 @@ class MisfitStacksController @Inject constructor( val dfTwo = DecimalFormat("#.##").apply { roundingMode = RoundingMode.HALF_UP } val dfFour = DecimalFormat("#.####").apply { roundingMode = RoundingMode.HALF_UP } val targetFun = SquaresDiff() - val targetFunValue = targetFun.apply( + val targetFunValue = targetFun( forwardSolver(picket.effectiveExperimentalData, picket.modelData), picket.effectiveExperimentalData.map { it.resistanceApparent } ) diff --git a/src/main/java/ru/nucodelabs/gem/view/color/ColorPalette.java b/src/main/java/ru/nucodelabs/gem/view/color/ColorPalette.java deleted file mode 100644 index a2454680..00000000 --- a/src/main/java/ru/nucodelabs/gem/view/color/ColorPalette.java +++ /dev/null @@ -1,267 +0,0 @@ -package ru.nucodelabs.gem.view.color; - -import javafx.beans.property.*; -import javafx.scene.paint.Color; -import org.jetbrains.annotations.NotNull; -import ru.nucodelabs.files.clr.ColorNode; -import ru.nucodelabs.gem.util.std.MathKt; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -public class ColorPalette implements ColorMapper { - - private final List valueColorList; - private final DoubleProperty minValueProperty = new SimpleDoubleProperty(); - private Double minValue; - private final DoubleProperty maxValueProperty = new SimpleDoubleProperty(); - private Double maxValue; - private final IntegerProperty blocksCount = new SimpleIntegerProperty(); - - private final BooleanProperty logScaleProperty = new SimpleBooleanProperty(false); - - private final List segmentList = new ArrayList<>(); - - public ColorPalette(List valueColorList, double minValue, double maxValue, int blocksCount) { - this.valueColorList = valueColorList; - setMinValue(minValue); - setMaxValue(maxValue); - setNumberOfSegments(blocksCount); - if (blocksCount < 2) throw new RuntimeException("Число блоков меньше 2"); - checkLog(); - blocksInit(); - this.logScaleProperty.addListener((observable, oldValue, newValue) -> { - segmentList.clear(); - checkLog(); - blocksInit(); - }); - this.blocksCount.addListener((observable, oldValue, newValue) -> { - if (newValue.intValue() < 2) throw new RuntimeException("Число блоков меньше 2"); - segmentList.clear(); - checkLog(); - blocksInit(); - }); - this.minValueProperty.addListener((observable, oldValue, newValue) -> { - segmentList.clear(); - checkLog(); - blocksInit(); - }); - this.maxValueProperty.addListener((observable, oldValue, newValue) -> { - segmentList.clear(); - checkLog(); - blocksInit(); - }); - } - - /** - * @param c1 Первый цвет - * @param c2 Второй цвет - * @param percentage Процент отступа от c1 - * @return Возвращает цвет - */ - private Color colorInterpolate(Color c1, Color c2, double percentage) { - double r1 = c1.getRed(); - double g1 = c1.getGreen(); - double b1 = c1.getBlue(); - - double r2 = c2.getRed(); - double g2 = c2.getGreen(); - double b2 = c2.getBlue(); - - double r = r1 + (r2 - r1) * percentage; - double g = g1 + (g2 - g1) * percentage; - double b = b1 + (b2 - b1) * percentage; - double a = 1.0; - - return new Color(r, g, b, a); - } - - /** - * Ищет цвет в точке интерполяции между vc1 и vc2 - * - * @param vc1 vc1.position() < vc2.position() - * @param vc2 vc2.position() > vc1.position() - * @param percentage vc1.position() < position < vc2.position() - * @return Interpolated rgba color between vc1.color() and vc2.color() - */ - private Color vcInterpolate(ColorNode vc1, ColorNode vc2, double percentage) { - Color c1 = vc1.getColor(); - Color c2 = vc2.getColor(); - double diff = (percentage - vc1.getPosition()) / (vc2.getPosition() - vc1.getPosition()); - - return colorInterpolate(c1, c2, diff); - } - - private Color blockColor(double from, double to) { - List vcsFrom = findNearestVCs(from); - List vcsTo = findNearestVCs(to); - - Color colorFrom = vcInterpolate(vcsFrom.get(0), vcsFrom.get(1), from); - Color colorTo = vcInterpolate(vcsTo.get(0), vcsTo.get(1), to); - - return colorInterpolate(colorFrom, colorTo, 0.5); - } - - private List findNearestVCs(double percentage) { - for (int i = 0; i < valueColorList.size() - 1; i++) { - double vcPercentage1 = valueColorList.get(i).getPosition(); - double vcPercentage2 = valueColorList.get(i + 1).getPosition(); - if (vcPercentage1 <= percentage && vcPercentage2 >= percentage) - return new ArrayList<>(Arrays.asList(valueColorList.get(i), valueColorList.get(i + 1))); - } - throw new RuntimeException("Цвет не найден"); - } - - private void blocksInit() { - Color firstColor = valueColorList.get(0).getColor(); - Color lastColor = valueColorList.get(valueColorList.size() - 1).getColor(); - - double blockSize = 1.0 / blocksCount.get(); - double currentFrom = 0; - double currentTo = blockSize; - - //Первый блок - segmentList.add(new Segment(currentFrom, blockSize, firstColor)); - currentFrom += blockSize; - currentTo += blockSize; - - for (int i = 1; i < blocksCount.get() - 1; i++) { - segmentList.add(new Segment(currentFrom, currentTo, blockColor(currentFrom, currentTo))); - currentFrom += blockSize; - currentTo += blockSize; - } - - //Последний блок - segmentList.add(new Segment(currentFrom, 1.0, lastColor)); - } - - private Segment blockFor(double percentage) { - if (percentage == 1.0) return segmentList.get(segmentList.size() - 1); - 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 void checkLog() { - if (minValueProperty.get() < 0.1) minValue = 0.1; - if (logScaleProperty.get()) { - minValue = Math.log10(minValueProperty.get()); - maxValue = Math.log10(maxValueProperty.get()); - } else { - minValue = minValueProperty.get(); - maxValue = maxValueProperty.get(); - } - } - - @NotNull - @Override - public Color colorFor(double value) { - double percentage; - if (logScaleProperty.get()) percentage = percentageFor(Math.log10(value)); - else percentage = percentageFor(value); - Segment block = blockFor(percentage); - return block.getColor(); - } - - @Override - public double getMinValue() { - return minValueProperty.get(); - } - - @Override - public void setMinValue(double value) { - this.minValueProperty.set(value); - } - - @Override - public double getMaxValue() { - return maxValueProperty.get(); - } - - @Override - public void setMaxValue(double value) { - this.maxValueProperty.set(value); - } - - @NotNull - @Override - public DoubleProperty minValueProperty() { - return minValueProperty; - } - - @NotNull - @Override - public DoubleProperty maxValueProperty() { - return maxValueProperty; - } - - @NotNull - @Override - public IntegerProperty numberOfSegmentsProperty() { - return blocksCount; - } - - @Override - public int getNumberOfSegments() { - return blocksCount.get(); - } - - @Override - public void setNumberOfSegments(int value) { - blocksCount.set(value); - } - - @NotNull - @Override - public List getSegments() { - if (!logScaleProperty.get()) return segmentList - .stream() - .map(s -> new Segment( - s.getFrom() * (maxValue - minValue) + minValue, - s.getTo() * (maxValue - minValue) + minValue, - s.getColor() - )).collect(Collectors.toList()); - else return segmentList - .stream() - .map(s -> new Segment( - logValue(valueFor(s.getFrom(), getMinValue(), getMaxValue()), getMinValue(), getMaxValue()), - logValue(valueFor(s.getTo(), getMinValue(), getMaxValue()), getMinValue(), getMaxValue()), - s.getColor() - )).collect(Collectors.toList()); - } - - private Double valueFor(double percentage, double minValue, double maxValue) { - return percentage * (maxValue - minValue) + minValue; - } - - private Double logValue(double value, double minValue, double maxValue) { - double logRange = Math.log10(maxValue) - Math.log10(minValue); - double range = maxValue - minValue; - double rDiv = range / logRange; - double logValue = (value - minValue) / rDiv + Math.log10(minValue); - return MathKt.exp10(logValue); - } - - @NotNull - @Override - public BooleanProperty logScaleProperty() { - return logScaleProperty; - } - - @Override - public boolean isLogScale() { - return logScaleProperty.get(); - } - - @Override - public void setLogScale(boolean value) { - logScaleProperty.set(value); - } -} - diff --git a/src/main/java/ru/nucodelabs/gem/view/color/ColorPalette.kt b/src/main/java/ru/nucodelabs/gem/view/color/ColorPalette.kt new file mode 100644 index 00000000..08184485 --- /dev/null +++ b/src/main/java/ru/nucodelabs/gem/view/color/ColorPalette.kt @@ -0,0 +1,167 @@ +package ru.nucodelabs.gem.view.color + +import javafx.beans.property.* +import javafx.scene.paint.Color +import ru.nucodelabs.files.clr.ColorNode +import ru.nucodelabs.gem.util.std.exp10 + +class ColorPalette( + private val valueColorList: List, + minValue: Double, + maxValue: Double, + blocksCount: Int +) : ColorMapper { + private val minValueProperty = SimpleDoubleProperty() + private val maxValueProperty = SimpleDoubleProperty() + private val blocksCountProperty = SimpleIntegerProperty() + private val logScaleProperty = SimpleBooleanProperty(false) + private val segmentList: MutableList = mutableListOf() + + private var minValueInternal: Double = 0.0 + private var maxValueInternal: Double = 0.0 + + init { + minValueProperty.set(minValue) + maxValueProperty.set(maxValue) + blocksCountProperty.set(blocksCount) + require(blocksCount >= 2) { "Число блоков меньше 2" } + updateSegments() + this.logScaleProperty.addListener { _, _, _ -> updateSegments() } + this.blocksCountProperty.addListener { _, _, new -> + require(new.toInt() >= 2) { "Число блоков меньше 2" } + updateSegments() + } + this.minValueProperty.addListener { _, _, _ -> updateSegments() } + this.maxValueProperty.addListener { _, _, _ -> updateSegments() } + } + + private fun updateSegments() { + segmentList.clear() + checkLog() + blocksInit() + } + + private fun colorInterpolate(c1: Color, c2: Color, percentage: Double): Color { + val r = c1.red + (c2.red - c1.red) * percentage + val g = c1.green + (c2.green - c1.green) * percentage + val b = c1.blue + (c2.blue - c1.blue) * percentage + return Color(r, g, b, 1.0) + } + + private fun vcInterpolate(vc1: ColorNode, vc2: ColorNode, percentage: Double): Color { + val diff = (percentage - vc1.position) / (vc2.position - vc1.position) + return colorInterpolate(vc1.color, vc2.color, diff) + } + + private fun blockColor(from: Double, to: Double): Color { + val vcsFrom = findNearestVCs(from) + val vcsTo = findNearestVCs(to) + val colorFrom = vcInterpolate(vcsFrom[0], vcsFrom[1], from) + val colorTo = vcInterpolate(vcsTo[0], vcsTo[1], to) + return colorInterpolate(colorFrom, colorTo, 0.5) + } + + private fun findNearestVCs(percentage: Double): List { + for (i in 0 until valueColorList.size - 1) { + val vcPercentage1 = valueColorList[i].position + val vcPercentage2 = valueColorList[i + 1].position + if (vcPercentage1 <= percentage && vcPercentage2 >= percentage) { + return listOf(valueColorList[i], valueColorList[i + 1]) + } + } + error("Цвет не найден") + } + + private fun blocksInit() { + val firstColor = valueColorList.first().color + val lastColor = valueColorList.last().color + + val blockSize = 1.0 / blocksCountProperty.get() + var currentFrom = 0.0 + var currentTo = blockSize + segmentList.add(ColorMapper.Segment(currentFrom, blockSize, firstColor)) + currentFrom += blockSize + currentTo += blockSize + for (i in 1 until blocksCountProperty.get() - 1) { + segmentList.add(ColorMapper.Segment(currentFrom, currentTo, blockColor(currentFrom, currentTo))) + currentFrom += blockSize + currentTo += blockSize + } + segmentList.add(ColorMapper.Segment(currentFrom, 1.0, lastColor)) + } + + private fun blockFor(percentage: Double): ColorMapper.Segment { + if (percentage == 1.0) return segmentList.last() + return segmentList[(percentage / (1.0 / segmentList.size)).toInt()] + } + + private fun percentageFor(resistance: Double): Double = when { + resistance < minValueInternal -> 0.0 + resistance > maxValueInternal -> 1.0 + else -> (resistance - minValueInternal) / (maxValueInternal - minValueInternal) + } + + private fun checkLog() { + if (minValueProperty.get() < 0.1) minValueInternal = 0.1 else minValueInternal = minValueProperty.get() + if (logScaleProperty.get()) { + minValueInternal = kotlin.math.log10(minValueProperty.get()) + maxValueInternal = kotlin.math.log10(maxValueProperty.get()) + } else { + minValueInternal = minValueProperty.get() + maxValueInternal = maxValueProperty.get() + } + } + + override fun colorFor(value: Double): Color { + val percentage = if (logScaleProperty.get()) percentageFor(kotlin.math.log10(value)) else percentageFor(value) + return blockFor(percentage).color + } + + override var minValue: Double + get() = minValueProperty.get() + set(value) { minValueProperty.set(value) } + + override var maxValue: Double + get() = maxValueProperty.get() + set(value) { maxValueProperty.set(value) } + + override var numberOfSegments: Int + get() = blocksCountProperty.get() + set(value) { blocksCountProperty.set(value) } + + override fun minValueProperty(): DoubleProperty = minValueProperty + override fun maxValueProperty(): DoubleProperty = maxValueProperty + override fun numberOfSegmentsProperty(): IntegerProperty = blocksCountProperty + + override val segments: List + get() = + if (!logScaleProperty.get()) segmentList.map { + ColorMapper.Segment( + it.from * (maxValueInternal - minValueInternal) + minValueInternal, + it.to * (maxValueInternal - minValueInternal) + minValueInternal, + it.color + ) + } else segmentList.map { + ColorMapper.Segment( + logValue(valueFor(it.from, minValue, maxValue), minValue, maxValue), + logValue(valueFor(it.to, minValue, maxValue), minValue, maxValue), + it.color + ) + } + + private fun valueFor(percentage: Double, minValue: Double, maxValue: Double) = + percentage * (maxValue - minValue) + minValue + + private fun logValue(value: Double, minValue: Double, maxValue: Double): Double { + val logRange = kotlin.math.log10(maxValue) - kotlin.math.log10(minValue) + val range = maxValue - minValue + val rDiv = range / logRange + val logValue = (value - minValue) / rDiv + kotlin.math.log10(minValue) + return exp10(logValue) + } + + override fun logScaleProperty(): BooleanProperty = logScaleProperty + override var isLogScale: Boolean + get() = logScaleProperty.get() + set(value) { logScaleProperty.set(value) } +} diff --git a/src/main/java/ru/nucodelabs/gem/view/control/Placeholder.java b/src/main/java/ru/nucodelabs/gem/view/control/Placeholder.java deleted file mode 100644 index d4200aa4..00000000 --- a/src/main/java/ru/nucodelabs/gem/view/control/Placeholder.java +++ /dev/null @@ -1,22 +0,0 @@ -package ru.nucodelabs.gem.view.control; - -import javafx.beans.property.StringProperty; -import javafx.fxml.FXML; -import javafx.scene.control.Label; - -public class Placeholder extends VBUserControl { - @FXML - private Label text; - - public String getText() { - return text.textProperty().get(); - } - - public void setText(String text) { - this.text.textProperty().set(text); - } - - public StringProperty textProperty() { - return text.textProperty(); - } -} diff --git a/src/main/java/ru/nucodelabs/gem/view/control/Placeholder.kt b/src/main/java/ru/nucodelabs/gem/view/control/Placeholder.kt new file mode 100644 index 00000000..1e8bd739 --- /dev/null +++ b/src/main/java/ru/nucodelabs/gem/view/control/Placeholder.kt @@ -0,0 +1,19 @@ +package ru.nucodelabs.gem.view.control + +import javafx.beans.property.StringProperty +import javafx.fxml.FXML +import javafx.scene.control.Label + +class Placeholder : VBUserControl() { + + @FXML + private lateinit var text: Label + + var textValue: String + get() = text.text + set(value) { + text.text = value + } + + fun textProperty(): StringProperty = text.textProperty() +} diff --git a/src/main/java/ru/nucodelabs/gem/view/control/VBUserControl.java b/src/main/java/ru/nucodelabs/gem/view/control/VBUserControl.java deleted file mode 100644 index 7f36d2d8..00000000 --- a/src/main/java/ru/nucodelabs/gem/view/control/VBUserControl.java +++ /dev/null @@ -1,15 +0,0 @@ -package ru.nucodelabs.gem.view.control; - -import javafx.scene.layout.VBox; -import ru.nucodelabs.gem.util.fx.FXUtils; - -/** - * Abstract class of user control which have VBox as root container. - * You must create same named FXML-file in same package in resources folder. - */ -public abstract class VBUserControl extends VBox { - - public VBUserControl() { - FXUtils.initFXMLControl(this); - } -} diff --git a/src/main/java/ru/nucodelabs/gem/view/control/VBUserControl.kt b/src/main/java/ru/nucodelabs/gem/view/control/VBUserControl.kt new file mode 100644 index 00000000..7b411129 --- /dev/null +++ b/src/main/java/ru/nucodelabs/gem/view/control/VBUserControl.kt @@ -0,0 +1,14 @@ +package ru.nucodelabs.gem.view.control + +import javafx.scene.layout.VBox +import ru.nucodelabs.gem.util.fx.FXUtils + +/** + * Abstract user control which has VBox as a root container. + * The FXML file must have the same name and be located in the same package. + */ +abstract class VBUserControl : VBox() { + init { + FXUtils.initFXMLControl(this) + } +} diff --git a/src/main/java/ru/nucodelabs/gem/view/main/MainViewModule.java b/src/main/java/ru/nucodelabs/gem/view/main/MainViewModule.java deleted file mode 100644 index ebe86086..00000000 --- a/src/main/java/ru/nucodelabs/gem/view/main/MainViewModule.java +++ /dev/null @@ -1,52 +0,0 @@ -package ru.nucodelabs.gem.view.main; - -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import com.google.inject.Singleton; -import ru.nucodelabs.gem.fxmodel.ObservableSection; -import ru.nucodelabs.geo.ves.Section; -import ru.nucodelabs.gem.app.io.StorageManager; -import ru.nucodelabs.gem.app.snapshot.HistoryManager; -import ru.nucodelabs.gem.app.snapshot.Snapshot; -import ru.nucodelabs.gem.view.DialogsModule; -import ru.nucodelabs.gem.view.charts.ChartsModule; - -import static com.google.inject.Scopes.SINGLETON; - -/** - * Зависимости в пределах одного главного окна - * (при создании нового используются новые синглтоны, разделяемые контроллерами) - */ -public class MainViewModule extends AbstractModule { - @Override - protected void configure() { - bind(MainViewController.class).in(SINGLETON); - bind(StorageManager.class).in(SINGLETON); - bind(ObservableSection.class).in(SINGLETON); - - install(new DialogsModule()); - install(new ObservableDataModule()); - install(new ChartsModule()); - } - - @Provides - @Singleton - private HistoryManager
sectionHistoryManager(Snapshot.Originator
sectionOriginator) { - return new HistoryManager<>(sectionOriginator); - } - - @Provides - private Snapshot.Originator
sectionOriginator(ObservableSection observableSection) { - return observableSection; - } - - @Provides - private FileImporter fileImporter(MainViewController mainViewController) { - return mainViewController; - } - - @Provides - private FileOpener fileOpener(MainViewController mainViewController) { - return mainViewController; - } -} diff --git a/src/main/java/ru/nucodelabs/gem/view/main/MainViewModule.kt b/src/main/java/ru/nucodelabs/gem/view/main/MainViewModule.kt new file mode 100644 index 00000000..4d5f3eaa --- /dev/null +++ b/src/main/java/ru/nucodelabs/gem/view/main/MainViewModule.kt @@ -0,0 +1,38 @@ +package ru.nucodelabs.gem.view.main + +import com.google.inject.AbstractModule +import com.google.inject.Provides +import com.google.inject.Singleton +import ru.nucodelabs.gem.fxmodel.ObservableSection +import ru.nucodelabs.geo.ves.Section +import ru.nucodelabs.gem.app.io.StorageManager +import ru.nucodelabs.gem.app.snapshot.HistoryManager +import ru.nucodelabs.gem.app.snapshot.Snapshot +import ru.nucodelabs.gem.view.DialogsModule +import ru.nucodelabs.gem.view.charts.ChartsModule + +class MainViewModule : AbstractModule() { + override fun configure() { + bind(MainViewController::class.java).`in`(Singleton::class.java) + bind(StorageManager::class.java).`in`(Singleton::class.java) + bind(ObservableSection::class.java).`in`(Singleton::class.java) + + install(DialogsModule()) + install(ObservableDataModule()) + install(ChartsModule()) + } + + @Provides + @Singleton + fun sectionHistoryManager(sectionOriginator: Snapshot.Originator
): HistoryManager
= + HistoryManager(sectionOriginator) + + @Provides + fun sectionOriginator(observableSection: ObservableSection): Snapshot.Originator
= observableSection + + @Provides + fun fileImporter(mainViewController: MainViewController): FileImporter = mainViewController + + @Provides + fun fileOpener(mainViewController: MainViewController): FileOpener = mainViewController +} diff --git a/src/main/java/ru/nucodelabs/gem/view/main/ObservableDataModule.java b/src/main/java/ru/nucodelabs/gem/view/main/ObservableDataModule.java deleted file mode 100644 index 51ea7eb6..00000000 --- a/src/main/java/ru/nucodelabs/gem/view/main/ObservableDataModule.java +++ /dev/null @@ -1,54 +0,0 @@ -package ru.nucodelabs.gem.view.main; - -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import com.google.inject.Singleton; -import javafx.beans.property.IntegerProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleIntegerProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.value.ObservableObjectValue; -import ru.nucodelabs.gem.fxmodel.ObservableSection; -import ru.nucodelabs.geo.ves.Picket; - -import static javafx.beans.binding.Bindings.createObjectBinding; - -/** - * Используются для коммуникации между контроллерами и удобного отслеживания изменений в данных. - */ -public class ObservableDataModule extends AbstractModule { - /** - * Индекс текущего отображаемого пикета для контроллеров, которые с ним взаимодействуют - */ - @Provides - @Singleton - private IntegerProperty providePicketIndex() { - return new SimpleIntegerProperty(0); - } - - /** - * Текущий отображаемый пикет, привязан к списку пикетов и индексу, потому его нельзя модифицировать - * (вызвать set извне) - */ - @Provides - @Singleton - private ObservableObjectValue provideBoundCurrentPicket( - IntegerProperty picketIndex, - ObservableSection section) { - ObjectProperty picket = new SimpleObjectProperty<>(); - picket.bind(createObjectBinding( - () -> { - if (section.getPickets().isEmpty()) { - return null; - } else { - if (picketIndex.get() >= section.getPickets().size()) { - picketIndex.set(section.getPickets().size() - 1); - } - return section.getPickets().get(picketIndex.get()); - } - }, - picketIndex, section.getPickets() - )); - return picket; - } -} diff --git a/src/main/java/ru/nucodelabs/gem/view/main/ObservableDataModule.kt b/src/main/java/ru/nucodelabs/gem/view/main/ObservableDataModule.kt new file mode 100644 index 00000000..eab58d42 --- /dev/null +++ b/src/main/java/ru/nucodelabs/gem/view/main/ObservableDataModule.kt @@ -0,0 +1,36 @@ +package ru.nucodelabs.gem.view.main + +import com.google.inject.AbstractModule +import com.google.inject.Provides +import com.google.inject.Singleton +import javafx.beans.property.IntegerProperty +import javafx.beans.property.ObjectProperty +import javafx.beans.property.SimpleIntegerProperty +import javafx.beans.property.SimpleObjectProperty +import javafx.beans.value.ObservableObjectValue +import ru.nucodelabs.gem.fxmodel.ObservableSection +import ru.nucodelabs.geo.ves.Picket +import javafx.beans.binding.Bindings + +class ObservableDataModule : AbstractModule() { + @Provides + @Singleton + fun providePicketIndex(): IntegerProperty = SimpleIntegerProperty(0) + + @Provides + @Singleton + fun provideBoundCurrentPicket(picketIndex: IntegerProperty, section: ObservableSection): ObservableObjectValue { + val picket: ObjectProperty = SimpleObjectProperty() + picket.bind(Bindings.createObjectBinding( + { + if (section.pickets.isEmpty()) null else { + if (picketIndex.get() >= section.pickets.size) { + picketIndex.set(section.pickets.size - 1) + } + section.pickets[picketIndex.get()] + } + }, picketIndex, section.pickets + )) + return picket + } +} diff --git a/src/main/java/ru/nucodelabs/geo/ves/JavaApi.kt b/src/main/java/ru/nucodelabs/geo/ves/JavaApi.kt index 9ac9d5e6..b8c1d4cd 100644 --- a/src/main/java/ru/nucodelabs/geo/ves/JavaApi.kt +++ b/src/main/java/ru/nucodelabs/geo/ves/JavaApi.kt @@ -35,4 +35,4 @@ class ModelLayerBuilder(source: ModelLayer) { fun build() = ModelLayer(power, resistance, isFixedPower, isFixedResistance) } -fun copy(source: ModelLayer) = ModelLayerBuilder(source) \ No newline at end of file +fun copy(source: ModelLayer) = ModelLayerBuilder(source) 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 deleted file mode 100644 index c7f45b1d..00000000 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/InverseSolver.java +++ /dev/null @@ -1,188 +0,0 @@ -package ru.nucodelabs.geo.ves.calc.inverse; - -import org.apache.commons.math3.analysis.MultivariateFunction; -import org.apache.commons.math3.optim.InitialGuess; -import org.apache.commons.math3.optim.MaxEval; -import org.apache.commons.math3.optim.PointValuePair; -import org.apache.commons.math3.optim.nonlinear.scalar.GoalType; -import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction; -import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex; -import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer; -import ru.nucodelabs.geo.ves.calc.forward.ForwardSolver; -import ru.nucodelabs.geo.ves.calc.inverse.inverse_functions.FunctionValue; -import ru.nucodelabs.geo.ves.calc.inverse.inverse_functions.SquaresDiff; -import ru.nucodelabs.geo.ves.ExperimentalData; -import ru.nucodelabs.geo.ves.ModelLayer; -import ru.nucodelabs.geo.ves.Picket; - -import javax.inject.Inject; -import java.util.ArrayList; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.stream.Collectors; - -public class InverseSolver { - - //Размер симплекса (по каждому измерению) - private static final double SIDE_LENGTH_DEFAULT = 1.0; - - //Какие-то константы для SimplexOptimize - private static final double RELATIVE_THRESHOLD_DEFAULT = 1e-10; - private static final double ABSOLUTE_THRESHOLD_DEFAULT = 1e-30; - - private Picket picket; - private final double sideLength; - private final double relativeThreshold; - private final double absoluteThreshold; - private final ForwardSolver forwardSolver; - - @Inject - public InverseSolver(ForwardSolver forwardSolver) { - this( - SIDE_LENGTH_DEFAULT, - RELATIVE_THRESHOLD_DEFAULT, - ABSOLUTE_THRESHOLD_DEFAULT, - forwardSolver - ); - } - - public InverseSolver( - double sideLength, - double relativeThreshold, - double absoluteThreshold, - ForwardSolver forwardSolver - ) { - this.sideLength = sideLength; - this.relativeThreshold = relativeThreshold; - this.absoluteThreshold = absoluteThreshold; - this.forwardSolver = forwardSolver; - } - - private void setLimitValues( - List resistances, double minResistance, double maxResistance, - 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 < powers.size(); i++) { - if (powers.get(i) != 0 && powers.get(i) < minPower) - powers.set(i, minPower); - else if (powers.get(i) > maxPower) - powers.set(i, maxPower); - } - } - - public List getOptimizedModelData(Picket inputPicket) { - final int MAX_EVAL = 100000; - this.picket = inputPicket; - - List modelData = picket.getModelData(); - - //Изменяемые сопротивления и мощности - List modelResistance = modelData.stream() - .filter(modelLayer -> !modelLayer.isFixedResistance()).map(ModelLayer::getResistance).collect(Collectors.toList()); - List modelPower = modelData.stream() - .filter(modelLayer -> !modelLayer.isFixedPower()).map(ModelLayer::getPower).collect(Collectors.toList()); - - //Установка ограничений для адекватности обратной задачи - double minPower = picket.getEffectiveExperimentalData().stream() - .map(ExperimentalData::getAb2) - .mapToDouble(Double::doubleValue) - .min() - .orElseThrow(NoSuchElementException::new); - double maxPower = picket.getEffectiveExperimentalData().stream() - .map(ExperimentalData::getAb2) - .mapToDouble(Double::doubleValue) - .max() - .orElseThrow(NoSuchElementException::new); - - setLimitValues( - modelResistance, 0.1, 1e5, - modelPower, 0.1, maxPower - ); - - //Неизменяемые сопротивления и мощности - List fixedModelResistance = modelData.stream() - .filter(ModelLayer::isFixedResistance).map(ModelLayer::getResistance).toList(); - List fixedModelPower = modelData.stream() - .filter(ModelLayer::isFixedPower).map(ModelLayer::getPower).toList(); - - SimplexOptimizer optimizer = new SimplexOptimizer(relativeThreshold, absoluteThreshold); - - MultivariateFunction multivariateFunction = new FunctionValue( - picket.getEffectiveExperimentalData(), new SquaresDiff(), modelData, forwardSolver - ); - - //anyArray = resistance.size...(model.size - 1) - int dimension = modelResistance.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 = modelResistance.size(); i < dimension; i++) { - startPoint[i] = Math.log(modelPower.get(i - modelResistance.size())); - } - - InitialGuess initialGuess = new InitialGuess(startPoint); - - //Передавать только изменяемые параметры - PointValuePair pointValuePair = optimizer.optimize( - new MaxEval(MAX_EVAL), - new ObjectiveFunction(multivariateFunction), - GoalType.MINIMIZE, - initialGuess, - nelderMeadSimplex - ); - - 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++; - } else { - newModelResistance.add(Math.exp(key[cntUnfixedResistances])); - cntUnfixedResistances++; - } - } - - int cntFixedPowers = 0; - int cntUnfixedPowers = 0; - for (int i = 0; i < modelData.size() - 1; i++) { - ModelLayer modelLayer = modelData.get(i); - int shift = modelResistance.size(); - if (modelLayer.isFixedPower()) { - newModelPower.add(fixedModelPower.get(cntFixedPowers)); - cntFixedPowers++; - } else { - newModelPower.add(Math.exp(key[cntUnfixedPowers + shift])); - cntUnfixedPowers++; - } - } - newModelPower.add(0.0); //Для последнего слоя - - List resultModel = new ArrayList<>(); - - for (int i = 0; i < modelData.size(); i++) { - resultModel.add(new ModelLayer( - newModelPower.get(i), - newModelResistance.get(i), - modelData.get(i).isFixedPower(), - modelData.get(i).isFixedResistance()) - ); - } - - return resultModel; - } -} diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/InverseSolver.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/InverseSolver.kt new file mode 100644 index 00000000..f7de0d20 --- /dev/null +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/InverseSolver.kt @@ -0,0 +1,132 @@ +package ru.nucodelabs.geo.ves.calc.inverse + +import org.apache.commons.math3.analysis.MultivariateFunction +import org.apache.commons.math3.optim.InitialGuess +import org.apache.commons.math3.optim.MaxEval +import org.apache.commons.math3.optim.PointValuePair +import org.apache.commons.math3.optim.nonlinear.scalar.GoalType +import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction +import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex +import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer +import ru.nucodelabs.geo.ves.calc.forward.ForwardSolver +import ru.nucodelabs.geo.ves.calc.inverse.inverse_functions.FunctionValue +import ru.nucodelabs.geo.ves.calc.inverse.inverse_functions.SquaresDiff +import ru.nucodelabs.geo.ves.ExperimentalData +import ru.nucodelabs.geo.ves.ModelLayer +import ru.nucodelabs.geo.ves.Picket +import javax.inject.Inject + +class InverseSolver @Inject constructor(private val forwardSolver: ForwardSolver) { + private var picket: Picket? = null + + private val sideLength: Double = SIDE_LENGTH_DEFAULT + private val relativeThreshold: Double = RELATIVE_THRESHOLD_DEFAULT + private val absoluteThreshold: Double = ABSOLUTE_THRESHOLD_DEFAULT + + fun getOptimizedModelData(inputPicket: Picket): List { + val MAX_EVAL = 100000 + this.picket = inputPicket + val modelData = picket!!.modelData + val modelResistance = modelData.filter { !it.isFixedResistance }.map { it.resistance }.toMutableList() + val modelPower = modelData.filter { !it.isFixedPower }.map { it.power }.toMutableList() + + val minPower = picket!!.effectiveExperimentalData.minOf { it.ab2 } + val maxPower = picket!!.effectiveExperimentalData.maxOf { it.ab2 } + + setLimitValues(modelResistance, 0.1, 1e5, modelPower, 0.1, maxPower) + + val fixedModelResistance = modelData.filter { it.isFixedResistance }.map { it.resistance } + val fixedModelPower = modelData.filter { it.isFixedPower }.map { it.power } + + val optimizer = SimplexOptimizer(relativeThreshold, absoluteThreshold) + val multivariateFunction: MultivariateFunction = FunctionValue(picket!!.effectiveExperimentalData, SquaresDiff(), modelData, forwardSolver) + + val dimension = modelResistance.size + modelPower.size - 1 + val nelderMeadSimplex = NelderMeadSimplex(dimension, sideLength) + val startPoint = DoubleArray(dimension) + for (i in modelResistance.indices) { + startPoint[i] = kotlin.math.ln(modelResistance[i]) + } + for (i in modelResistance.size until dimension) { + startPoint[i] = kotlin.math.ln(modelPower[i - modelResistance.size]) + } + + val initialGuess = InitialGuess(startPoint) + val pointValuePair: PointValuePair = optimizer.optimize( + MaxEval(MAX_EVAL), + ObjectiveFunction(multivariateFunction), + GoalType.MINIMIZE, + initialGuess, + nelderMeadSimplex + ) + + val key = pointValuePair.key + + val newModelPower = mutableListOf() + val newModelResistance = mutableListOf() + + var cntFixedResistances = 0 + var cntUnfixedResistances = 0 + for (modelLayer in modelData) { + if (modelLayer.isFixedResistance) { + newModelResistance.add(fixedModelResistance[cntFixedResistances]) + cntFixedResistances++ + } else { + newModelResistance.add(kotlin.math.exp(key[cntUnfixedResistances])) + cntUnfixedResistances++ + } + } + + var cntFixedPowers = 0 + var cntUnfixedPowers = 0 + for (i in 0 until modelData.size - 1) { + val modelLayer = modelData[i] + val shift = modelResistance.size + if (modelLayer.isFixedPower) { + newModelPower.add(fixedModelPower[cntFixedPowers]) + cntFixedPowers++ + } else { + newModelPower.add(kotlin.math.exp(key[cntUnfixedPowers + shift])) + cntUnfixedPowers++ + } + } + newModelPower.add(0.0) + + val resultModel = mutableListOf() + for (i in modelData.indices) { + resultModel.add( + ModelLayer( + newModelPower[i], + newModelResistance[i], + modelData[i].isFixedPower, + modelData[i].isFixedResistance + ) + ) + } + return resultModel + } + + private fun setLimitValues( + resistances: MutableList, minResistance: Double, maxResistance: Double, + powers: MutableList, minPower: Double, maxPower: Double + ) { + for (i in resistances.indices) { + when { + resistances[i] < minResistance -> resistances[i] = minResistance + resistances[i] > maxResistance -> resistances[i] = maxResistance + } + } + for (i in powers.indices) { + when { + powers[i] != 0.0 && powers[i] < minPower -> powers[i] = minPower + powers[i] > maxPower -> powers[i] = maxPower + } + } + } + + companion object { + private const val SIDE_LENGTH_DEFAULT = 1.0 + private const val RELATIVE_THRESHOLD_DEFAULT = 1e-10 + private const val ABSOLUTE_THRESHOLD_DEFAULT = 1e-30 + } +} diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/inverse_functions/FunctionValue.java b/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/inverse_functions/FunctionValue.java deleted file mode 100644 index a784817b..00000000 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/inverse_functions/FunctionValue.java +++ /dev/null @@ -1,104 +0,0 @@ -package ru.nucodelabs.geo.ves.calc.inverse.inverse_functions; - -import org.apache.commons.math3.analysis.MultivariateFunction; -import ru.nucodelabs.geo.ves.calc.forward.ForwardSolver; -import ru.nucodelabs.geo.ves.ExperimentalData; -import ru.nucodelabs.geo.ves.ModelLayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.BiFunction; -import java.util.stream.Collectors; - -public class FunctionValue implements MultivariateFunction { - //Экспериментальные точки для FS - private final List experimentalData; - //Функция для вычисления разности между exp и theoretical точками - private final BiFunction, List, Double> inverseFunction; - //Исходная модель - private final List modelLayers; - private final ForwardSolver forwardSolver; - - private double diffMinValue = Double.MAX_VALUE; - - public FunctionValue(List experimentalData, - BiFunction, List, Double> inverseFunction, - List modelLayers, - ForwardSolver forwardSolver) { - this.experimentalData = experimentalData; - this.inverseFunction = inverseFunction; - this.modelLayers = modelLayers; - this.forwardSolver = forwardSolver; - } - - @Override - public double value(double[] variables) { - //Изменяемые сопротивления и мощности - List currentModelResistance = new ArrayList<>(); - List currentModelPower = new ArrayList<>(); - - int unfixedResistancesCnt = (int) modelLayers.stream() - .filter(modelLayer -> !modelLayer.isFixedResistance()).count(); - - //Восстановление изменяемых слоев до нормальной формы - for (int i = 0; i < unfixedResistancesCnt; i++) { - currentModelResistance.add(Math.exp(variables[i])); - } - for (int i = unfixedResistancesCnt; i < variables.length; i++) { - currentModelPower.add(Math.exp(variables[i])); - } - currentModelPower.add(0.0); - - //Объединение изменяемых и неизменяемых слоев (в нормальной форме) - List newModelResistance = new ArrayList<>(); - List newModelPower = new ArrayList<>(); - - int cntUnfixedResistances = 0; - for (ModelLayer modelLayer : modelLayers) { - if (modelLayer.isFixedResistance()) { - newModelResistance.add(modelLayer.getResistance()); - } else { - newModelResistance.add(currentModelResistance.get(cntUnfixedResistances)); - cntUnfixedResistances++; - } - } - - int cntUnfixedPowers = 0; - for (ModelLayer modelLayer : modelLayers) { - if (modelLayer.isFixedPower()) { - newModelPower.add(modelLayer.getPower()); - } else { - newModelPower.add(currentModelPower.get(cntUnfixedPowers)); - cntUnfixedPowers++; - } - } - - List newModelLayers = new ArrayList<>(); - for (int i = 0; i < modelLayers.size(); i++) { - newModelLayers.add(new ModelLayer(newModelPower.get(i), newModelResistance.get(i), false, false)); - } - - List solvedResistance = forwardSolver.invoke(experimentalData, newModelLayers); - - double diffValue = inverseFunction.apply(solvedResistance, - experimentalData.stream().map(ExperimentalData::getResistanceApparent).collect(Collectors.toList())); - - boolean flag = false; - - for (ModelLayer modelLayer : newModelLayers) { - if (modelLayer.getResistance() < 0.1 || - modelLayer.getResistance() > 1e5 || - (modelLayer.getPower() != 0.0 && modelLayer.getPower() < 0.1) || - modelLayer.getPower() > experimentalData.get(experimentalData.size() - 1).getAb2()) { - diffValue = Math.max(diffMinValue * (1.1 + 0.1 * Math.random()), diffValue); - flag = true; - break; - } - } - - if (!flag) - diffMinValue = Math.min(diffValue, diffMinValue); - - return diffValue; - } -} diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/inverse_functions/FunctionValue.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/inverse_functions/FunctionValue.kt new file mode 100644 index 00000000..f2f6cc7a --- /dev/null +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/inverse_functions/FunctionValue.kt @@ -0,0 +1,66 @@ +package ru.nucodelabs.geo.ves.calc.inverse.inverse_functions + +import org.apache.commons.math3.analysis.MultivariateFunction +import ru.nucodelabs.geo.ves.calc.forward.ForwardSolver +import ru.nucodelabs.geo.ves.ExperimentalData +import ru.nucodelabs.geo.ves.ModelLayer + +class FunctionValue( + private val experimentalData: List, + private val inverseFunction: (List, List) -> Double, + private val modelLayers: List, + private val forwardSolver: ForwardSolver +) : MultivariateFunction { + + private var diffMinValue = Double.MAX_VALUE + + override fun value(variables: DoubleArray): Double { + val unfixedResistancesCnt = modelLayers.count { !it.isFixedResistance } + + val currentModelResistance = variables + .take(unfixedResistancesCnt) + .map { kotlin.math.exp(it) } + + val currentModelPower = variables + .drop(unfixedResistancesCnt) + .map { kotlin.math.exp(it) } + .toMutableList() + .apply { add(0.0) } + + var resIdx = 0 + val newModelResistance = modelLayers.map { layer -> + if (layer.isFixedResistance) layer.resistance else currentModelResistance[resIdx++] + } + + var powIdx = 0 + val newModelPower = modelLayers.map { layer -> + if (layer.isFixedPower) layer.power else currentModelPower[powIdx++] + } + + val newModelLayers = newModelPower.zip(newModelResistance) { p, r -> + ModelLayer(p, r, false, false) + } + + val solvedResistance = forwardSolver.invoke(experimentalData, newModelLayers) + + var diffValue = inverseFunction( + solvedResistance, + experimentalData.map { it.resistanceApparent } + ) + + val invalid = newModelLayers.any { layer -> + layer.resistance < 0.1 || + layer.resistance > 1e5 || + (layer.power != 0.0 && layer.power < 0.1) || + layer.power > experimentalData.last().ab2 + } + + diffValue = if (invalid) { + kotlin.math.max(diffMinValue * (1.1 + 0.1 * Math.random()), diffValue) + } else { + diffMinValue = kotlin.math.min(diffValue, diffMinValue) + diffValue + } + return diffValue + } +} diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/inverse_functions/SquaresDiff.java b/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/inverse_functions/SquaresDiff.java deleted file mode 100644 index 593dc231..00000000 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/inverse_functions/SquaresDiff.java +++ /dev/null @@ -1,17 +0,0 @@ -package ru.nucodelabs.geo.ves.calc.inverse.inverse_functions; - -import java.util.List; -import java.util.function.BiFunction; - -import static java.lang.StrictMath.sqrt; - -public class SquaresDiff implements BiFunction, List, Double> { - @Override - public Double apply(List solvedResistance, List experimentalResistance) { - double functionValue = 0; - for (int i = 0; i < solvedResistance.size(); i++) { - functionValue += Math.pow(solvedResistance.get(i) - experimentalResistance.get(i), 2); - } - return sqrt(functionValue) / solvedResistance.size(); - } -} diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/inverse_functions/SquaresDiff.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/inverse_functions/SquaresDiff.kt new file mode 100644 index 00000000..66dab16b --- /dev/null +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/inverse/inverse_functions/SquaresDiff.kt @@ -0,0 +1,11 @@ +package ru.nucodelabs.geo.ves.calc.inverse.inverse_functions + +class SquaresDiff : (List, List) -> Double { + override fun invoke(solvedResistance: List, experimentalResistance: List): Double { + var functionValue = 0.0 + for (i in solvedResistance.indices) { + functionValue += (solvedResistance[i] - experimentalResistance[i]).let { it * it } + } + return kotlin.math.sqrt(functionValue) / solvedResistance.size + } +} diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/primarymodel/PrimaryModel.java b/src/main/java/ru/nucodelabs/geo/ves/calc/primarymodel/PrimaryModel.java deleted file mode 100644 index 3a429862..00000000 --- a/src/main/java/ru/nucodelabs/geo/ves/calc/primarymodel/PrimaryModel.java +++ /dev/null @@ -1,66 +0,0 @@ -package ru.nucodelabs.geo.ves.calc.primarymodel; - -import ru.nucodelabs.geo.ves.ExperimentalData; -import ru.nucodelabs.geo.ves.ModelLayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -public class PrimaryModel { - - private final List experimentalData; - - public PrimaryModel(List experimentalData) { - this.experimentalData = experimentalData; - } - - public List get3LayersPrimaryModel() { - if (experimentalData.size() <= 3) { - throw new IllegalStateException("Для построения стартовой модели требуется ≥ 4 измерений, было " + experimentalData.size()); - } - - List logExperimentalData = experimentalData.stream() - .map(experimentalData -> ru.nucodelabs.geo.ves.JavaApi.copy(experimentalData).ab2(Math.log(experimentalData.getAb2())).build()) - .toList(); - int pointsCnt = logExperimentalData.size(); - double ab2min = logExperimentalData.get(0).getAb2(); - double ab2max = logExperimentalData.get(pointsCnt - 1).getAb2(); - double ab2range = ab2max - ab2min; - List> logSplitData = new ArrayList<>(); - logSplitData.add(logExperimentalData.stream() - .filter(experimentalData -> experimentalData.getAb2() <= ab2min + (ab2range / 3.0)) - .collect(Collectors.toList())); - logSplitData.add(logExperimentalData.stream() - .filter(experimentalData -> experimentalData.getAb2() <= ab2min + (ab2range * 2.0 / 3.0) && experimentalData.getAb2() > ab2min + (ab2range / 3.0)) - .collect(Collectors.toList())); - logSplitData.add(logExperimentalData.stream() - .filter(experimentalData -> experimentalData.getAb2() > ab2min + (ab2range * 2.0 / 3.0)) - .collect(Collectors.toList())); - - List modelLayers = new ArrayList<>(); - for (int i = 0; i < logSplitData.size(); i++) { - - if (logSplitData.get(i).size() == 0) { - return new ArrayList<>(); - } - - double prevLast; - List list = logSplitData.get(i); - double avg = list.stream() - .map(ExperimentalData::getResistanceApparent) - .mapToDouble(Double::doubleValue) - .average() - .orElse(0); - if (i > 0) { - prevLast = Math.exp(logSplitData.get(i - 1).get(logSplitData.get(i - 1).size() - 1).getAb2()); - } else { - prevLast = 0; - } - //От последнего в этом слою отнимаем последний в прошлом - modelLayers.add(new ModelLayer(Math.exp(list.get(list.size() - 1).getAb2()) - prevLast, avg, false, false)); - } - modelLayers.set(modelLayers.size() - 1, ru.nucodelabs.geo.ves.JavaApi.copy(modelLayers.get(modelLayers.size() - 1)).power(0).build()); - return modelLayers; - } -} diff --git a/src/main/java/ru/nucodelabs/geo/ves/calc/primarymodel/PrimaryModel.kt b/src/main/java/ru/nucodelabs/geo/ves/calc/primarymodel/PrimaryModel.kt new file mode 100644 index 00000000..91901819 --- /dev/null +++ b/src/main/java/ru/nucodelabs/geo/ves/calc/primarymodel/PrimaryModel.kt @@ -0,0 +1,32 @@ +package ru.nucodelabs.geo.ves.calc.primarymodel + +import ru.nucodelabs.geo.ves.ExperimentalData +import ru.nucodelabs.geo.ves.ModelLayer + +class PrimaryModel(private val experimentalData: List) { + fun get3LayersPrimaryModel(): List { + if (experimentalData.size <= 3) { + throw IllegalStateException("Для построения стартовой модели требуется ≥ 4 измерений, было ${experimentalData.size}") + } + val logExperimentalData = experimentalData.map { ru.nucodelabs.geo.ves.copy(it).ab2(kotlin.math.ln(it.ab2)).build() } + val pointsCnt = logExperimentalData.size + val ab2min = logExperimentalData[0].ab2 + val ab2max = logExperimentalData[pointsCnt - 1].ab2 + val ab2range = ab2max - ab2min + val logSplitData = listOf( + logExperimentalData.filter { it.ab2 <= ab2min + ab2range / 3.0 }, + logExperimentalData.filter { it.ab2 <= ab2min + ab2range * 2.0 / 3.0 && it.ab2 > ab2min + ab2range / 3.0 }, + logExperimentalData.filter { it.ab2 > ab2min + ab2range * 2.0 / 3.0 } + ) + val modelLayers = mutableListOf() + for (i in logSplitData.indices) { + if (logSplitData[i].isEmpty()) return emptyList() + val list = logSplitData[i] + val avg = list.map { it.resistanceApparent }.average() + val prevLast = if (i > 0) kotlin.math.exp(logSplitData[i - 1].last().ab2) else 0.0 + modelLayers.add(ModelLayer(kotlin.math.exp(list.last().ab2) - prevLast, avg, false, false)) + } + modelLayers[modelLayers.size - 1] = ru.nucodelabs.geo.ves.copy(modelLayers.last()).power(0.0).build() + return modelLayers + } +} diff --git a/src/test/java/ru/nucodelabs/algorithms/InverseSolverTest.java b/src/test/java/ru/nucodelabs/algorithms/InverseSolverTest.java index 15b2088a..b7860fc1 100644 --- a/src/test/java/ru/nucodelabs/algorithms/InverseSolverTest.java +++ b/src/test/java/ru/nucodelabs/algorithms/InverseSolverTest.java @@ -14,10 +14,7 @@ public class InverseSolverTest { void inverseSolverTest_1() throws Exception { Picket picket = ShiraPicket.getPicket(); - final double SIDE_LENGTH = 0.1; - final double RELATIVE_THRESHOLD = 1e-10; - double ABSOLUTE_THRESHOLD = 1e-30; - InverseSolver inverseSolver = new InverseSolver(SIDE_LENGTH, RELATIVE_THRESHOLD, ABSOLUTE_THRESHOLD, ForwardSolverKt.ForwardSolver()); + InverseSolver inverseSolver = new InverseSolver(ForwardSolverKt.ForwardSolver()); List modelData = inverseSolver.getOptimizedModelData(picket); modelData.forEach(System.out::println); }