Updates to deep learning module for downloading files and to FX GUI

This commit is contained in:
Jamie Mac 2024-01-19 16:57:17 +00:00
parent 37fe953474
commit a95db3679d
28 changed files with 2142 additions and 329 deletions

View File

@ -6,6 +6,7 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="test"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="maven.pomderived" value="true"/>

View File

@ -397,6 +397,8 @@ public class HydrophoneElementDialog extends PamDialog {
dz.setText(null);
}
}
boolean getParams() {
double zCoeff = PamController.getInstance().getGlobalMediumManager().getZCoeff();

View File

@ -18,6 +18,7 @@ import javafx.scene.PerspectiveCamera;
import javafx.scene.SceneAntialiasing;
import javafx.scene.SubScene;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.PickResult;
import javafx.scene.input.ScrollEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
@ -56,8 +57,7 @@ public class Array3DPane extends PamBorderPane {
public static final Color DEFAULT_HYDRO_COL = Color.RED;
private static final Color DEFAULT_SENSOR_COL = Color.LIMEGREEN;
// private static final Color DEFAULT_SENSOR_COL = Color.LIMEGREEN;
private double scaleFactor=20;
@ -97,6 +97,11 @@ public class Array3DPane extends PamBorderPane {
* The size of the hydrophone for the 3D display.
*/
private double hydrophoneSize = 0.5;
/**
* Holds a list of hydrophone spheres
*/
private ArrayList<HydrophoneSphere> hydrophonesSpheres = new ArrayList<HydrophoneSphere>();
public Array3DPane(){
@ -131,6 +136,33 @@ public class Array3DPane extends PamBorderPane {
subScene.widthProperty().bind(this.widthProperty());
subScene.heightProperty().bind(this.heightProperty());
subScene.setDepthTest(DepthTest.ENABLE);
subScene.setOnMouseClicked((MouseEvent me) -> {
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
PickResult pr = me.getPickResult();
// System.out.println("Picked something sphere: " + pr);
//clear selected radius
for (HydrophoneSphere sphere : hydrophonesSpheres) {
sphere.setRadius(hydrophoneSize*scaleFactor);
}
if(pr!=null && pr.getIntersectedNode() != null && pr.getIntersectedNode() instanceof Sphere){
//make the selected sphere slightly larger
HydrophoneSphere s = (HydrophoneSphere) pr.getIntersectedNode();
s.setRadius(hydrophoneSize*scaleFactor*1.2);
hydrophoneSelected(s.getHydrophone());
// System.out.println("Picked a sphere: " + pr);
// distance=pr.getIntersectedDistance();
// s = (Sphere) pr.getIntersectedNode();
// isPicking=true;
// vecIni = unProjectDirection(mousePosX, mousePosY, scene.getWidth(),scene.getHeight());
}
});
//note the fill is actually quite important because if you don't have it mouse rotations etc
//onyl work if you select a 3D shape
@ -152,6 +184,14 @@ public class Array3DPane extends PamBorderPane {
}
/**
* Called whenever a hydrophone is selected.
* @param hydrophone - the selected hydrophone.
*/
public void hydrophoneSelected(Hydrophone hydrophone) {
// TODO Auto-generated method stub
}
/**
* Create a 3D axis with default colours set.
* @param- size of the axis
@ -300,7 +340,7 @@ public class Array3DPane extends PamBorderPane {
*/
public void drawArray(PamArray array) {
System.out.println("DRAW ARRAY: " + array);
// System.out.println("DRAW ARRAY: " + array);
//clear the array
arrayGroup.getChildren().removeAll(arrayGroup.getChildren());
@ -308,8 +348,9 @@ public class Array3DPane extends PamBorderPane {
ArrayList<Hydrophone> hydrophones = array.getHydrophoneArray();
//draw hydrophones
Sphere sphere;
HydrophoneSphere sphere;
Streamer streamer;
hydrophonesSpheres.clear();
for (int i=0; i<hydrophones.size(); i++){
//get the streamer for the hydrophone
@ -319,7 +360,7 @@ public class Array3DPane extends PamBorderPane {
double y = hydrophones.get(i).getY() + hydrophones.get(i).getStreamerId();
double z = hydrophones.get(i).getZ() + hydrophones.get(i).getStreamerId();
sphere=new Sphere(hydrophoneSize*scaleFactor);
sphere=new HydrophoneSphere(hydrophoneSize*scaleFactor);
sphere.setTranslateX(x*scaleFactor);
sphere.setTranslateY(z*scaleFactor);
sphere.setTranslateZ(y*scaleFactor);
@ -330,9 +371,11 @@ public class Array3DPane extends PamBorderPane {
aMaterial.setDiffuseColor(col);
aMaterial.setSpecularColor(col.brighter());
sphere.setMaterial(aMaterial);
sphere.setHydrophone(hydrophones.get(i));
// System.out.println("Add hydrophone: " + x + " " + y + " " +z);
hydrophonesSpheres.add(sphere);
arrayGroup.getChildren().add(sphere);
ArrayList<Point3D> streamerPoints=new ArrayList<Point3D>();
@ -353,7 +396,30 @@ public class Array3DPane extends PamBorderPane {
}
private class HydrophoneSphere extends Sphere {
Hydrophone hydrophone;
public Hydrophone getHydrophone() {
return hydrophone;
}
public void setHydrophone(Hydrophone hydrophone) {
this.hydrophone = hydrophone;
}
public HydrophoneSphere() {
super();
}
public HydrophoneSphere(double radius) {
super(radius);
}
}
// /**
// * Draw the entire array
// * @param pos - hydrophone and streamer positions in the same co-ordinate frame as the reference frame.

View File

@ -1,5 +1,9 @@
package Array.layoutFX;
import java.io.File;
import Array.ArrayManager;
import Array.Hydrophone;
import Array.PamArray;
import PamController.PamController;
import PamController.SettingsPane;
@ -12,9 +16,12 @@ import javafx.scene.layout.Region;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import pamViewFX.PamGuiManagerFX;
import pamViewFX.fxGlyphs.PamGlyphDude;
import pamViewFX.fxNodes.PamVBox;
import pamViewFX.fxNodes.pamDialogFX.PamDialogFX;
import pamViewFX.fxNodes.PamBorderPane;
import pamViewFX.fxNodes.PamButton;
import pamViewFX.fxNodes.PamHBox;
@ -67,10 +74,16 @@ public class ArraySettingsPane extends SettingsPane<PamArray >{
/**
* Pane with controls to change speed of sound.
*/
private SettingsPane<PamArray> environmentalPane;
private SettingsPane<PamArray> environmentalPane;
private FileChooser fileChooser;
//a copy of the current array
private PamArray currentArray;
public ArraySettingsPane() {
super(null);
mainPane=new PamBorderPane();
mainPane.setCenter(createArrayPane());
@ -150,7 +163,7 @@ public class ArraySettingsPane extends SettingsPane<PamArray >{
}
private Pane create3DPane() {
this.array3DPane = new Array3DPane();
this.array3DPane = new HydrophoneArray3DPane();
//important because the 3D pane has not default size
array3DPane.setMinWidth(MIN_3D_WIDTH);
@ -184,6 +197,11 @@ public class ArraySettingsPane extends SettingsPane<PamArray >{
arrayImportExportBox.setAlignment(Pos.CENTER_LEFT);
arrayImportExportBox.setPadding(new Insets(5,0,0,0));
fileChooser = new FileChooser();
fileChooser.setTitle("Open Resource File");
fileChooser.getExtensionFilters().addAll(
new ExtensionFilter("PAMNGuard Array Files", "*.paf"));
PamButton importButton = new PamButton("Import...");
importButton.setOnAction((action)->{
importArray();
@ -242,16 +260,23 @@ public class ArraySettingsPane extends SettingsPane<PamArray >{
* Select a file to export array settings to.
*/
private void exportArray() {
// TODO Auto-generated method stub
File file = fileChooser.showSaveDialog(getFXWindow());
if (file==null) return;
PamArray pamArray = getParams(new PamArray("saved_array: ", null));
boolean isSaved = ArrayManager.saveArrayToFile(pamArray);
if (isSaved==false) {
PamDialogFX.showError("Unable to save the array file to \n" + file.toString());
}
}
/**
* Select a file to import array settings
*/
private void importArray() {
// TODO Auto-generated method stub
File file = fileChooser.showOpenDialog(getFXWindow());
if (file==null) return;
PamArray pamArray = ArrayManager.loadArrayFromFile(file.getPath());
this.setParams(pamArray);
}
/**
@ -271,8 +296,9 @@ public class ArraySettingsPane extends SettingsPane<PamArray >{
@Override
public PamArray getParams(PamArray currParams) {
currParams = hydrophonePane.getParams(currParams);
currParams = streamerPane.getParams(currParams);
currParams = hydrophonePane.getParams(currParams);
currParams.setHydrophoneInterpolation(hydrophonePane.getHydrophoneInterp());
currParams = environmentalPane.getParams(currParams);
// System.out.println("Array settings pane: No. streamers: " + currParams.getStreamerCount());
return currParams;
@ -280,6 +306,7 @@ public class ArraySettingsPane extends SettingsPane<PamArray >{
@Override
public void setParams(PamArray input) {
this.currentArray = input.clone();
// System.out.println("Hydrophone array is: "+ input);
setReceieverLabels();
hydrophonePane.setParams(input);
@ -306,5 +333,14 @@ public class ArraySettingsPane extends SettingsPane<PamArray >{
// TODO Auto-generated method stub
}
private class HydrophoneArray3DPane extends Array3DPane {
@Override
public void hydrophoneSelected(Hydrophone hydrophone) {
hydrophonePane.selectHydrophone(hydrophone);
}
}
}

View File

@ -126,7 +126,7 @@ public class HydrophoneSettingsPane extends DynamicSettingsPane<Hydrophone> {
PamHBox interpHolder = new PamHBox();
interpHolder.setSpacing(5);
interpHolder.setAlignment(Pos.CENTER);
interpHolder.setAlignment(Pos.CENTER_LEFT);
interpHolder.getChildren().addAll(new Label("Method"), interpPane);
holderPane.getChildren().addAll(recieverIDLabel, createGeneralPane(), coOrdLabel, createPositionPane(), interpLabel, interpHolder);
@ -520,6 +520,8 @@ public class HydrophoneSettingsPane extends DynamicSettingsPane<Hydrophone> {
double zCoeff = PamController.getInstance().getGlobalMediumManager().getZCoeff();
setCoordsText();
interpPane.setSelection(currentArray.getHydrophoneInterpolation());
xPos.setText(Double.toString(hydrophone.getX()));
yPos.setText(Double.toString(hydrophone.getY()));
@ -552,8 +554,11 @@ public class HydrophoneSettingsPane extends DynamicSettingsPane<Hydrophone> {
hydrophone.setdX(Double.valueOf(xPosErr.getText()));
hydrophone.setdY(Double.valueOf(yPosErr.getText()));
hydrophone.setdZ(Double.valueOf(zPosErr.getText()));
int hi = interpPane.getSelection();
if (hi >= 0) {
this.currentArray.setHydrophoneInterpolation(interpPane.getSelectedInterpType());
}
}
catch (Exception Ex) {
System.err.println("There is a problem with one of the parameters in the hydrophone panel");

View File

@ -19,6 +19,7 @@ import javafx.scene.control.TableColumn;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.converter.IntegerStringConverter;
import pamViewFX.fxNodes.PamBorderPane;
import pamViewFX.fxNodes.PamColorsFX;
import pamViewFX.fxNodes.flipPane.PamFlipPane;
import pamViewFX.fxNodes.table.TableSettingsPane;
@ -153,7 +154,7 @@ public class HydrophonesPane extends PamBorderPane {
super(hydrophoneData);
z = new TableColumn<HydrophoneProperty,Number>("depth");
z.setCellValueFactory(cellData -> cellData.getValue().getZ());
z.setCellValueFactory(cellData -> cellData.getValue().getZ().multiply(PamController.getInstance().getGlobalMediumManager().getZCoeff()));
z.setEditable(true);
//need to set up all the rows.
@ -170,8 +171,7 @@ public class HydrophonesPane extends PamBorderPane {
Callback<TableColumn<HydrophoneProperty, Integer>, TableCell<HydrophoneProperty, Integer>> cellFactory = col -> {
TableCell<HydrophoneProperty, Integer> cell = defaultCellFactory.call(col);
cell.itemProperty().addListener((obs, oldValue, newValue) -> {
System.out.println("Hello set colour: " + newValue);
// System.out.println("Hello set colour: " + newValue);
if (newValue == null) {
cell.setStyle("cell-selection-color: -fx-selection-bar ;");
} else {
@ -180,9 +180,7 @@ public class HydrophonesPane extends PamBorderPane {
// cell.setStyle("cell-selection-color: "+ formattedColor + " ;");
cell.setStyle("-fx-background: "+ formattedColor + " ;");
cell.setStyle("-fx-background-color: "+ formattedColor + " ;");
System.out.println("Hello set style: " + formattedColor);
// System.out.println("Hello set style: " + formattedColor);
}
});
return cell;
@ -224,8 +222,11 @@ public class HydrophonesPane extends PamBorderPane {
// Create color based on int value. Just use value as hue, full saturation and brightness:
private Color createColor(int x) {
return Color.hsb(x, 1.0, 1.0);
private Color createColor(int i) {
//get channel colour and add a bit of transparancy to make less abnoxious
return PamColorsFX.getInstance().getChannelColor(i).deriveColor(1, 1, 1, 0.5);
// return Color.hsb(x, 1.0, 1.0);
}
// Format color as string for CSS (#rrggbb format, values in hex).
@ -384,4 +385,27 @@ public class HydrophonesPane extends PamBorderPane {
}
/**
* Select the current hydrophone in table.
*/
public void selectHydrophone(Hydrophone hydrophone) {
//select the current hydrophone in the table
tableArrayPane.getTableView().getSelectionModel().select(hydrophone.getID());
}
public void setCurrentArray(PamArray currentArray) {
this.currentArray=currentArray;
}
/**
* Get the hydrophone interpolation. Note that this is stored in the
* currentArray because the interpolator must be the same for all hydrophones.
*
* @return the inteprolation selection.
*/
public int getHydrophoneInterp() {
return currentArray.getHydrophoneInterpolation();
}
}

View File

@ -721,7 +721,10 @@ public class StreamerSettingsPane extends SettingsPane<Streamer> {
}
public void setRecieverLabels() {
// TODO Auto-generated method stub
String recieverDepthString = PamController.getInstance().getGlobalMediumManager().getZString();
depthLabel.setText(recieverDepthString );
depthSensorLabel.setText(recieverDepthString + " Sensor");
}

View File

@ -153,7 +153,7 @@ public class StreamersPane extends PamBorderPane {
y.setEditable(false);
z = new TableColumn<StreamerProperty,Number>("depth");
z.setCellValueFactory(cellData -> cellData.getValue().getZ());
z.setCellValueFactory(cellData -> cellData.getValue().getZ().multiply(PamController.getInstance().getGlobalMediumManager().getZCoeff()));
z.setEditable(false);
TableColumn posColumn=new TableColumn("Position (m)");
@ -229,7 +229,7 @@ public class StreamersPane extends PamBorderPane {
@Override
public void deleteData(StreamerProperty data){
super.deleteData(data);
notifyStreamerListeners(data);
notifyStreamerListeners(null);
}
private StreamerProperty createDefaultStreamerProperty() {
@ -269,6 +269,7 @@ public class StreamersPane extends PamBorderPane {
public PamArray getParams(PamArray currParams) {
//add all new streamers - bit weird because the PamArray requires that at least one streamer exists.
for (int i=0; i<tableArrayPane.getStreamers().size(); i++) {
if (i<currentArray.getStreamerCount()) {
@ -279,12 +280,11 @@ public class StreamersPane extends PamBorderPane {
}
}
while (currentArray.getStreamerCount()>tableArrayPane.getStreamers().size()) {
while (currParams.getStreamerCount()>tableArrayPane.getStreamers().size()) {
currParams.removeStreamer(currParams.getStreamerCount()-1);
}
// currentArray.updateStreamer(tableArrayPane.getStreamers().indexOf(currentStreamerData), streamer);
System.out.println("Get params streamer: " + currentArray.getNumStreamers());
return currParams;
}
@ -306,5 +306,10 @@ public class StreamersPane extends PamBorderPane {
this.streamerChangeListeners.add(e);
}
public void setCurrentArray(PamArray currentArray) {
this.currentArray=currentArray;
}
}

View File

@ -1,35 +1,296 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Created with Vectornator (http://vectornator.io/) -->
<svg height="100.0px" stroke-miterlimit="10" style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;" version="1.1" viewBox="0 0 100 100" width="100.0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs/>
<g id="layer">
<path d="M16.7142 16.0914C16.7142 13.9256 18.5294 12.1699 20.7685 12.1699C23.0076 12.1699 24.8227 13.9256 24.8227 16.0914C24.8227 18.2572 23.0076 20.0129 20.7685 20.0129C18.5294 20.0129 16.7142 18.2572 16.7142 16.0914Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M32.5588 27.8707C32.5588 25.6661 34.3586 23.8788 36.5788 23.8788C38.799 23.8788 40.5989 25.6661 40.5989 27.8707C40.5989 30.0754 38.799 31.8626 36.5788 31.8626C34.3586 31.8626 32.5588 30.0754 32.5588 27.8707Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M42.9552 44.2334C42.9552 42.2822 44.7416 40.7004 46.9452 40.7004C49.1489 40.7004 50.9353 42.2822 50.9353 44.2334C50.9353 46.1845 49.1489 47.7663 46.9452 47.7663C44.7416 47.7663 42.9552 46.1845 42.9552 44.2334Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M52.7913 60.5762C52.7913 58.5469 54.4922 56.9018 56.5903 56.9018C58.6884 56.9018 60.3893 58.5469 60.3893 60.5762C60.3893 62.6054 58.6884 64.2505 56.5903 64.2505C54.4922 64.2505 52.7913 62.6054 52.7913 60.5762Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M62.7469 75.7602C62.7469 73.8706 64.4196 72.3388 66.483 72.3388C68.5464 72.3388 70.2191 73.8706 70.2191 75.7602C70.2191 77.6498 68.5464 79.1816 66.483 79.1816C64.4196 79.1816 62.7469 77.6498 62.7469 75.7602Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M2.69599 8.67142C2.69599 6.6263 4.24746 4.96841 6.1613 4.96841C8.07514 4.96841 9.62661 6.6263 9.62661 8.67142C9.62661 10.7165 8.07514 12.3744 6.1613 12.3744C4.24746 12.3744 2.69599 10.7165 2.69599 8.67142Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M76.1272 86.2275C76.1272 84.3244 77.7324 82.7817 79.7126 82.7817C81.6928 82.7817 83.298 84.3244 83.298 86.2275C83.298 88.1306 81.6928 89.6733 79.7126 89.6733C77.7324 89.6733 76.1272 88.1306 76.1272 86.2275Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M90.4953 90.8591C90.4953 87.9777 91.9568 85.6419 93.7596 85.6419C95.5625 85.6419 97.024 87.9777 97.024 90.8591C97.024 93.7404 95.5625 96.0762 93.7596 96.0762C91.9568 96.0762 90.4953 93.7404 90.4953 90.8591Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M9.54343 71.8115C9.54343 70.6319 9.94329 69.6757 10.4365 69.6757C10.9298 69.6757 11.3297 70.6319 11.3297 71.8115C11.3297 72.991 10.9298 73.9473 10.4365 73.9473C9.94329 73.9473 9.54343 72.991 9.54343 71.8115Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M24.905 65.838C24.905 64.4855 27.1175 63.3891 29.8468 63.3891C32.576 63.3891 34.7886 64.4855 34.7886 65.838C34.7886 67.1904 32.576 68.2868 29.8468 68.2868C27.1175 68.2868 24.905 67.1904 24.905 65.838Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M45.101 10.0156C45.101 11.3508 45.5298 12.4332 46.0587 12.4332C46.5876 12.4332 47.0164 11.3508 47.0164 10.0156C47.0164 8.68035 46.5876 7.59794 46.0587 7.59794C45.5298 7.59794 45.101 8.68035 45.101 10.0156Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M44.5535 89.9229C44.5535 88.5913 46.0673 87.5118 47.9347 87.5118C49.802 87.5118 51.3158 88.5913 51.3158 89.9229C51.3158 91.2545 49.802 92.334 47.9347 92.334C46.0673 92.334 44.5535 91.2545 44.5535 89.9229Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M69.5454 51.4254C69.5454 53.0473 70.0287 54.362 70.6248 54.362C71.2209 54.362 71.7042 53.0473 71.7042 51.4254C71.7042 49.8035 71.2209 48.4887 70.6248 48.4887C70.0287 48.4887 69.5454 49.8035 69.5454 51.4254Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M71.9301 2.72895L72.1438 42.7952" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M74.8726 9.55748L74.9741 37.9559" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M68.9517 10.862L69.1636 33.377" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M77.734 14.2218L77.7338 31.0169" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M80.5345 17.6154L80.6004 27.1415" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M83.4547 19.3471L83.5056 25.1163" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M66.0744 16.0072L66.1969 27.2049" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M63.1389 19.6295L63.1389 23.9515" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M59.9308 20.8338L59.9286 22.275" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M86.3889 22.7835L86.3889 20.6748" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M57.0188 21.2022L57.0192 21.8713" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M54.3645 21.5153L54.3849 21.4545" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M89.606 21.6051L89.5477 21.663" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M92.4918 21.5637L92.5573 21.6287" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
</g>
<svg
height="100.0px"
stroke-miterlimit="10"
style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;"
version="1.1"
viewBox="0 0 100 100"
width="100.0px"
xml:space="preserve"
id="svg27"
sodipodi:docname="Click Detector Icon.svg"
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview27"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="2.36"
inkscape:cx="50.211864"
inkscape:cy="50.211864"
inkscape:window-width="1360"
inkscape:window-height="864"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="svg27" />
<defs
id="defs1">
</defs>
<path
d="m 16.7142,16.0914 c 0,-2.1658 1.8152,-3.9215 4.0543,-3.9215 2.2391,0 4.0542,1.7557 4.0542,3.9215 0,2.1658 -1.8151,3.9215 -4.0542,3.9215 -2.2391,0 -4.0543,-1.7557 -4.0543,-3.9215 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path1" /><path
d="m 32.5588,27.8707 c 0,-2.2046 1.7998,-3.9919 4.02,-3.9919 2.2202,0 4.0201,1.7873 4.0201,3.9919 0,2.2047 -1.7999,3.9919 -4.0201,3.9919 -2.2202,0 -4.02,-1.7872 -4.02,-3.9919 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path2" /><path
d="m 42.9552,44.2334 c 0,-1.9512 1.7864,-3.533 3.99,-3.533 2.2037,0 3.9901,1.5818 3.9901,3.533 0,1.9511 -1.7864,3.5329 -3.9901,3.5329 -2.2036,0 -3.99,-1.5818 -3.99,-3.5329 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path3" /><path
d="m 52.7913,60.5762 c 0,-2.0293 1.7009,-3.6744 3.799,-3.6744 2.0981,0 3.799,1.6451 3.799,3.6744 0,2.0292 -1.7009,3.6743 -3.799,3.6743 -2.0981,0 -3.799,-1.6451 -3.799,-3.6743 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path4" /><path
d="m 62.7469,75.7602 c 0,-1.8896 1.6727,-3.4214 3.7361,-3.4214 2.0634,0 3.7361,1.5318 3.7361,3.4214 0,1.8896 -1.6727,3.4214 -3.7361,3.4214 -2.0634,0 -3.7361,-1.5318 -3.7361,-3.4214 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path5" /><path
d="m 2.69599,8.67142 c 0,-2.04512 1.55147,-3.70301 3.46531,-3.70301 1.91384,0 3.46531,1.65789 3.46531,3.70301 0,2.04508 -1.55147,3.70298 -3.46531,3.70298 -1.91384,0 -3.46531,-1.6579 -3.46531,-3.70298 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path6" /><path
d="m 76.1272,86.2275 c 0,-1.9031 1.6052,-3.4458 3.5854,-3.4458 1.9802,0 3.5854,1.5427 3.5854,3.4458 0,1.9031 -1.6052,3.4458 -3.5854,3.4458 -1.9802,0 -3.5854,-1.5427 -3.5854,-3.4458 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path7" /><path
d="m 90.4953,90.8591 c 0,-2.8814 1.4615,-5.2172 3.2643,-5.2172 1.8029,0 3.2644,2.3358 3.2644,5.2172 0,2.8813 -1.4615,5.2171 -3.2644,5.2171 -1.8028,0 -3.2643,-2.3358 -3.2643,-5.2171 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path8" /><path
d="m 9.54343,71.8115 c 0,-1.1796 0.39986,-2.1358 0.89307,-2.1358 0.4933,0 0.8932,0.9562 0.8932,2.1358 0,1.1795 -0.3999,2.1358 -0.8932,2.1358 -0.49321,0 -0.89307,-0.9563 -0.89307,-2.1358 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path9" /><path
d="m 24.905,65.838 c 0,-1.3525 2.2125,-2.4489 4.9418,-2.4489 2.7292,0 4.9418,1.0964 4.9418,2.4489 0,1.3524 -2.2126,2.4488 -4.9418,2.4488 -2.7293,0 -4.9418,-1.0964 -4.9418,-2.4488 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path10" /><path
d="m 45.101,10.0156 c 0,1.3352 0.4288,2.4176 0.9577,2.4176 0.5289,0 0.9577,-1.0824 0.9577,-2.4176 0,-1.33525 -0.4288,-2.41766 -0.9577,-2.41766 -0.5289,0 -0.9577,1.08241 -0.9577,2.41766 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path11" /><path
d="m 44.5535,89.9229 c 0,-1.3316 1.5138,-2.4111 3.3812,-2.4111 1.8673,0 3.3811,1.0795 3.3811,2.4111 0,1.3316 -1.5138,2.4111 -3.3811,2.4111 -1.8674,0 -3.3812,-1.0795 -3.3812,-2.4111 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path12" /><path
d="m 69.5454,51.4254 c 0,1.6219 0.4833,2.9366 1.0794,2.9366 0.5961,0 1.0794,-1.3147 1.0794,-2.9366 0,-1.6219 -0.4833,-2.9367 -1.0794,-2.9367 -0.5961,0 -1.0794,1.3148 -1.0794,2.9367 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path13" /><path
d="M 71.9301,2.72895 72.1438,42.7952"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path14" /><path
d="M 74.8726,9.55748 74.9741,37.9559"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path15" /><path
d="m 68.9517,10.862 0.2119,22.515"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path16" /><path
d="m 77.734,14.2218 -2e-4,16.7951"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path17" /><path
d="m 80.5345,17.6154 0.0659,9.5261"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path18" /><path
d="m 83.4547,19.3471 0.0509,5.7692"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path19" /><path
d="m 66.0744,16.0072 0.1225,11.1977"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path20" /><path
d="m 63.1389,19.6295 v 4.322"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path21" /><path
d="M 59.9308,20.8338 59.9286,22.275"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path22" /><path
d="M 86.3889,22.7835 V 20.6748"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path23" /><path
d="m 57.0188,21.2022 4e-4,0.6691"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path24" /><path
d="m 54.3645,21.5153 0.0204,-0.0608"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path25" /><path
d="M 89.606,21.6051 89.5477,21.663"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path26" /><path
d="m 92.4918,21.5637 0.0655,0.065"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path27" />
</svg>

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -1,46 +1,393 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Created with Vectornator (http://vectornator.io/) -->
<svg height="100%" stroke-miterlimit="10" style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;" version="1.1" viewBox="0 0 100 100" width="100%" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:vectornator="http://vectornator.io" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs/>
<g id="layer" vectornator:layerName="layer">
<path d="M16.7142 16.0914C16.7142 13.9256 18.5294 12.1699 20.7685 12.1699C23.0076 12.1699 24.8227 13.9256 24.8227 16.0914C24.8227 18.2572 23.0076 20.0129 20.7685 20.0129C18.5294 20.0129 16.7142 18.2572 16.7142 16.0914Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M32.5588 27.8707C32.5588 25.6661 34.3586 23.8788 36.5788 23.8788C38.799 23.8788 40.5989 25.6661 40.5989 27.8707C40.5989 30.0754 38.799 31.8626 36.5788 31.8626C34.3586 31.8626 32.5588 30.0754 32.5588 27.8707Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M42.9552 44.2334C42.9552 42.2822 44.7416 40.7004 46.9452 40.7004C49.1489 40.7004 50.9353 42.2822 50.9353 44.2334C50.9353 46.1845 49.1489 47.7663 46.9452 47.7663C44.7416 47.7663 42.9552 46.1845 42.9552 44.2334Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M52.7913 60.5762C52.7913 58.5469 54.4922 56.9018 56.5903 56.9018C58.6884 56.9018 60.3893 58.5469 60.3893 60.5762C60.3893 62.6054 58.6884 64.2505 56.5903 64.2505C54.4922 64.2505 52.7913 62.6054 52.7913 60.5762Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M62.7469 75.7602C62.7469 73.8706 64.4196 72.3388 66.483 72.3388C68.5464 72.3388 70.2191 73.8706 70.2191 75.7602C70.2191 77.6498 68.5464 79.1816 66.483 79.1816C64.4196 79.1816 62.7469 77.6498 62.7469 75.7602Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M2.69599 8.67142C2.69599 6.6263 4.24746 4.96841 6.1613 4.96841C8.07514 4.96841 9.62661 6.6263 9.62661 8.67142C9.62661 10.7165 8.07514 12.3744 6.1613 12.3744C4.24746 12.3744 2.69599 10.7165 2.69599 8.67142Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M6.37104 8.51295L20.6509 16.2716" fill="none" opacity="1" stroke="#000000" stroke-linecap="butt" stroke-linejoin="round" stroke-width="3" vectornator:layerName="Line 1"/>
<path d="M76.1272 86.2275C76.1272 84.3244 77.7324 82.7817 79.7126 82.7817C81.6928 82.7817 83.298 84.3244 83.298 86.2275C83.298 88.1306 81.6928 89.6733 79.7126 89.6733C77.7324 89.6733 76.1272 88.1306 76.1272 86.2275Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M90.4953 90.8591C90.4953 87.9777 91.9568 85.6419 93.7596 85.6419C95.5625 85.6419 97.024 87.9777 97.024 90.8591C97.024 93.7404 95.5625 96.0762 93.7596 96.0762C91.9568 96.0762 90.4953 93.7404 90.4953 90.8591Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M5.26296 55.751C5.26296 53.1707 6.6501 51.079 8.36122 51.079C10.0723 51.079 11.4595 53.1707 11.4595 55.751C11.4595 58.3312 10.0723 60.4229 8.36122 60.4229C6.6501 60.4229 5.26296 58.3312 5.26296 55.751Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M26.1864 67.0811C26.1864 64.14 27.717 61.7558 29.605 61.7558C31.493 61.7558 33.0236 64.14 33.0236 67.0811C33.0236 70.0223 31.493 72.4065 29.605 72.4065C27.717 72.4065 26.1864 70.0223 26.1864 67.0811Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<path d="M45.101 10.0156C45.101 11.3508 45.5298 12.4332 46.0587 12.4332C46.5876 12.4332 47.0164 11.3508 47.0164 10.0156C47.0164 8.68035 46.5876 7.59794 46.0587 7.59794C45.5298 7.59794 45.101 8.68035 45.101 10.0156Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M69.5454 51.4254C69.5454 53.0473 70.0287 54.362 70.6248 54.362C71.2209 54.362 71.7042 53.0473 71.7042 51.4254C71.7042 49.8035 71.2209 48.4887 70.6248 48.4887C70.0287 48.4887 69.5454 49.8035 69.5454 51.4254Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M46.4667 89.0531C46.4667 86.9884 47.5735 85.3145 48.9389 85.3145C50.3043 85.3145 51.4112 86.9884 51.4112 89.0531C51.4112 91.1178 50.3043 92.7917 48.9389 92.7917C47.5735 92.7917 46.4667 91.1178 46.4667 89.0531Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.112674"/>
<g opacity="1" vectornator:layerName="Group 1">
<path d="M71.9301 2.72895L72.1438 42.7952" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="Line"/>
<path d="M74.8726 9.55748L74.9741 37.9559" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M68.9517 10.862L69.1636 33.377" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M77.734 14.2218L77.7338 31.0169" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M80.5345 17.6154L80.6004 27.1415" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M83.4547 19.3471L83.5056 25.1163" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M66.0744 16.0072L66.1969 27.2049" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M63.1389 19.6295L63.1389 23.9515" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M59.9308 20.8338L59.9286 22.275" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M86.3889 22.7835L86.3889 20.6748" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M54.3645 21.5153L54.3849 21.4545" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M57.0188 21.2022L57.0192 21.8713" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
</g>
<path d="M89.606 21.6051L89.5477 21.663" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M92.4918 21.5637L92.5573 21.6287" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065"/>
<path d="M20.9371 16.2938L37.1192 28.3844" fill="none" opacity="1" stroke="#000000" stroke-linecap="butt" stroke-linejoin="round" stroke-width="3" vectornator:layerName="Line 2"/>
<path d="M46.8938 44.3956L37.1141 28.4567" fill="none" opacity="1" stroke="#000000" stroke-linecap="butt" stroke-linejoin="round" stroke-width="3" vectornator:layerName="Line 3"/>
<path d="M56.7631 60.5458L47.9016 45.8129" fill="none" opacity="1" stroke="#000000" stroke-linecap="butt" stroke-linejoin="round" stroke-width="3" vectornator:layerName="Line 4"/>
<path d="M66.7214 75.9126L56.4789 60.1879" fill="none" opacity="1" stroke="#000000" stroke-linecap="butt" stroke-linejoin="round" stroke-width="3" vectornator:layerName="Line 5"/>
<path d="M80.4646 86.5356L66.6498 75.9581" fill="none" opacity="1" stroke="#000000" stroke-linecap="butt" stroke-linejoin="round" stroke-width="3" vectornator:layerName="Line 6"/>
<path d="M94.7094 91.2591L79.7266 85.8144" fill="none" opacity="1" stroke="#000000" stroke-linecap="butt" stroke-linejoin="round" stroke-width="3" vectornator:layerName="Line 7"/>
<path d="M49.7241 90.1821L29.3477 65.2976" fill="none" opacity="1" stroke="#000000" stroke-linecap="butt" stroke-linejoin="round" stroke-width="3" vectornator:layerName="Line 8"/>
<path d="M29.7239 67.2344L8.38409 55.9858" fill="none" opacity="1" stroke="#000000" stroke-linecap="butt" stroke-linejoin="round" stroke-width="3" vectornator:layerName="Line 9"/>
</g>
<svg
height="100%"
stroke-miterlimit="10"
style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;"
version="1.1"
viewBox="0 0 100 100"
width="100%"
xml:space="preserve"
id="svg36"
sodipodi:docname="clicktrain.svg"
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:vectornator="http://vectornator.io"><sodipodi:namedview
id="namedview36"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="2.36"
inkscape:cx="50.211864"
inkscape:cy="50.211864"
inkscape:window-width="1320"
inkscape:window-height="1120"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="svg36" />
<defs
id="defs1">
</defs>
<path
d="m 16.7142,16.0914 c 0,-2.1658 1.8152,-3.9215 4.0543,-3.9215 2.2391,0 4.0542,1.7557 4.0542,3.9215 0,2.1658 -1.8151,3.9215 -4.0542,3.9215 -2.2391,0 -4.0543,-1.7557 -4.0543,-3.9215 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path1" /><path
d="m 32.5588,27.8707 c 0,-2.2046 1.7998,-3.9919 4.02,-3.9919 2.2202,0 4.0201,1.7873 4.0201,3.9919 0,2.2047 -1.7999,3.9919 -4.0201,3.9919 -2.2202,0 -4.02,-1.7872 -4.02,-3.9919 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path2" /><path
d="m 42.9552,44.2334 c 0,-1.9512 1.7864,-3.533 3.99,-3.533 2.2037,0 3.9901,1.5818 3.9901,3.533 0,1.9511 -1.7864,3.5329 -3.9901,3.5329 -2.2036,0 -3.99,-1.5818 -3.99,-3.5329 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path3" /><path
d="m 52.7913,60.5762 c 0,-2.0293 1.7009,-3.6744 3.799,-3.6744 2.0981,0 3.799,1.6451 3.799,3.6744 0,2.0292 -1.7009,3.6743 -3.799,3.6743 -2.0981,0 -3.799,-1.6451 -3.799,-3.6743 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path4" /><path
d="m 62.7469,75.7602 c 0,-1.8896 1.6727,-3.4214 3.7361,-3.4214 2.0634,0 3.7361,1.5318 3.7361,3.4214 0,1.8896 -1.6727,3.4214 -3.7361,3.4214 -2.0634,0 -3.7361,-1.5318 -3.7361,-3.4214 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path5" /><path
d="m 2.69599,8.67142 c 0,-2.04512 1.55147,-3.70301 3.46531,-3.70301 1.91384,0 3.46531,1.65789 3.46531,3.70301 0,2.04508 -1.55147,3.70298 -3.46531,3.70298 -1.91384,0 -3.46531,-1.6579 -3.46531,-3.70298 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path6" /><path
d="M 6.37104,8.51295 20.6509,16.2716"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="butt"
stroke-linejoin="round"
stroke-width="3"
vectornator:layerName="Line 1"
id="path7" /><path
d="m 76.1272,86.2275 c 0,-1.9031 1.6052,-3.4458 3.5854,-3.4458 1.9802,0 3.5854,1.5427 3.5854,3.4458 0,1.9031 -1.6052,3.4458 -3.5854,3.4458 -1.9802,0 -3.5854,-1.5427 -3.5854,-3.4458 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path8" /><path
d="m 90.4953,90.8591 c 0,-2.8814 1.4615,-5.2172 3.2643,-5.2172 1.8029,0 3.2644,2.3358 3.2644,5.2172 0,2.8813 -1.4615,5.2171 -3.2644,5.2171 -1.8028,0 -3.2643,-2.3358 -3.2643,-5.2171 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path9" /><path
d="m 5.26296,55.751 c 0,-2.5803 1.38714,-4.672 3.09826,-4.672 1.71108,0 3.09828,2.0917 3.09828,4.672 0,2.5802 -1.3872,4.6719 -3.09828,4.6719 -1.71112,0 -3.09826,-2.0917 -3.09826,-4.6719 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path10" /><path
d="m 26.1864,67.0811 c 0,-2.9411 1.5306,-5.3253 3.4186,-5.3253 1.888,0 3.4186,2.3842 3.4186,5.3253 0,2.9412 -1.5306,5.3254 -3.4186,5.3254 -1.888,0 -3.4186,-2.3842 -3.4186,-5.3254 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path11" /><path
d="m 45.101,10.0156 c 0,1.3352 0.4288,2.4176 0.9577,2.4176 0.5289,0 0.9577,-1.0824 0.9577,-2.4176 0,-1.33525 -0.4288,-2.41766 -0.9577,-2.41766 -0.5289,0 -0.9577,1.08241 -0.9577,2.41766 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path12" /><path
d="m 69.5454,51.4254 c 0,1.6219 0.4833,2.9366 1.0794,2.9366 0.5961,0 1.0794,-1.3147 1.0794,-2.9366 0,-1.6219 -0.4833,-2.9367 -1.0794,-2.9367 -0.5961,0 -1.0794,1.3148 -1.0794,2.9367 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path13" /><path
d="m 46.4667,89.0531 c 0,-2.0647 1.1068,-3.7386 2.4722,-3.7386 1.3654,0 2.4723,1.6739 2.4723,3.7386 0,2.0647 -1.1069,3.7386 -2.4723,3.7386 -1.3654,0 -2.4722,-1.6739 -2.4722,-3.7386 z"
fill="#000000"
fill-rule="nonzero"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="0.112674"
id="path14" /><g
opacity="1"
vectornator:layerName="Group 1"
id="g26">
<path
d="M 71.9301,2.72895 72.1438,42.7952"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="Line"
id="path15" />
<path
d="M 74.8726,9.55748 74.9741,37.9559"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path16" />
<path
d="m 68.9517,10.862 0.2119,22.515"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path17" />
<path
d="m 77.734,14.2218 -2e-4,16.7951"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path18" />
<path
d="m 80.5345,17.6154 0.0659,9.5261"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path19" />
<path
d="m 83.4547,19.3471 0.0509,5.7692"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path20" />
<path
d="m 66.0744,16.0072 0.1225,11.1977"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path21" />
<path
d="m 63.1389,19.6295 v 4.322"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path22" />
<path
d="M 59.9308,20.8338 59.9286,22.275"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path23" />
<path
d="M 86.3889,22.7835 V 20.6748"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path24" />
<path
d="m 54.3645,21.5153 0.0204,-0.0608"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path25" />
<path
d="m 57.0188,21.2022 4e-4,0.6691"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path26" />
</g><path
d="M 89.606,21.6051 89.5477,21.663"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path27" /><path
d="m 92.4918,21.5637 0.0655,0.065"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
id="path28" /><path
d="M 20.9371,16.2938 37.1192,28.3844"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="butt"
stroke-linejoin="round"
stroke-width="3"
vectornator:layerName="Line 2"
id="path29" /><path
d="M 46.8938,44.3956 37.1141,28.4567"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="butt"
stroke-linejoin="round"
stroke-width="3"
vectornator:layerName="Line 3"
id="path30" /><path
d="M 56.7631,60.5458 47.9016,45.8129"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="butt"
stroke-linejoin="round"
stroke-width="3"
vectornator:layerName="Line 4"
id="path31" /><path
d="M 66.7214,75.9126 56.4789,60.1879"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="butt"
stroke-linejoin="round"
stroke-width="3"
vectornator:layerName="Line 5"
id="path32" /><path
d="M 80.4646,86.5356 66.6498,75.9581"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="butt"
stroke-linejoin="round"
stroke-width="3"
vectornator:layerName="Line 6"
id="path33" /><path
d="M 94.7094,91.2591 79.7266,85.8144"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="butt"
stroke-linejoin="round"
stroke-width="3"
vectornator:layerName="Line 7"
id="path34" /><path
d="M 49.7241,90.1821 29.3477,65.2976"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="butt"
stroke-linejoin="round"
stroke-width="3"
vectornator:layerName="Line 8"
id="path35" /><path
d="M 29.7239,67.2344 8.38409,55.9858"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="butt"
stroke-linejoin="round"
stroke-width="3"
vectornator:layerName="Line 9"
id="path36" />
</svg>

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1,40 +1,331 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Created with Vectornator (http://vectornator.io/) -->
<svg height="100.0px" stroke-miterlimit="10" style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;" version="1.1" viewBox="0 0 100 100" width="100.0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:vectornator="http://vectornator.io" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs/>
<g id="Layer-1" vectornator:layerName="Layer 1">
<path d="M22.8661 93.1624L34.1008 66.5688L50.9529 27.2473L52.8805 24.0168L55.5326 20.8446L58.163 18.3205L60.4511 16.5804L63.0203 15.1625L66.8114 13.4931L73.0881 12.2799L78.9831 12.2314L80.8814 12.2523" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3.87464" vectornator:layerName="Curve 1"/>
<g opacity="1" vectornator:layerName="Group 1">
<path d="M24.8316 30.5047L25.102 72.6218" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="Line"/>
<path d="M28.4549 37.6833L28.7829 67.5342" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M21.1978 39.0535L21.1965 62.722" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M32.0727 42.5863L32.2778 60.2402" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M35.7188 46.1531L35.8021 56.1668" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M39.4137 44.8153L39.7258 58.7443" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M17.5159 44.4622L17.484 56.2338" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M13.7081 48.2703L13.7081 52.8135" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M9.64888 49.5363L9.64609 51.0512" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M43.1263 54.4343L43.1263 47.8829" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M2.60583 50.2526L2.63165 50.1887" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M5.96432 49.9235L5.96483 50.6269" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
</g>
<g opacity="1" vectornator:layerName="Group 2">
<path d="M68.4016 31.2736L68.5538 74.1202" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="Line"/>
<path d="M71.9812 38.4086L72.3091 68.2595" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M64.724 39.7788L64.7228 63.4473" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M75.5989 43.3116L75.804 60.9655" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M79.245 46.8784L79.3284 56.8921" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M82.9888 49.5549L83.0043 52.419" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M90.1665 44.3658L90.2309 57.6081" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path 1"/>
<path d="M93.8777 49.5413L93.8995 52.4326" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path 2"/>
<path d="M97.3942 51.0314L97.3916 51.2155" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.36423" vectornator:layerName="path 3"/>
<path d="M61.0421 45.1875L61.0102 56.9591" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M57.2343 46.8472L57.2343 54.906" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M53.2003 44.8905L53.1723 58.3195" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M86.6526 55.5621L86.6526 46.4118" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M46.1063 53.487L46.1321 48.487" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
<path d="M49.3862 61.2263L49.3473 40.7476" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.38065" vectornator:layerName="path"/>
</g>
<svg
height="100.0px"
stroke-miterlimit="10"
style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;"
version="1.1"
viewBox="0 0 100 100"
width="100.0px"
xml:space="preserve"
id="svg28"
sodipodi:docname="filters.svg"
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:vectornator="http://vectornator.io"><sodipodi:namedview
id="namedview28"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="2.36"
inkscape:cx="49.788136"
inkscape:cy="50"
inkscape:window-width="1816"
inkscape:window-height="1387"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="svg28" />
<defs
id="defs1">
</defs>
<path
d="m 22.8661,93.1624 11.2347,-26.5936 16.8521,-39.3215 1.9276,-3.2305 2.6521,-3.1722 2.6304,-2.5241 2.2881,-1.7401 2.5692,-1.4179 3.7911,-1.6694 6.2767,-1.2132 5.895,-0.0485 1.8983,0.0209"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="3.87464"
vectornator:layerName="Curve 1"
id="path1" /><g
opacity="1"
vectornator:layerName="Group 1"
id="g13">
<path
d="M 24.8316,30.5047 25.102,72.6218"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="Line"
id="path2" />
<path
d="m 28.4549,37.6833 0.328,29.8509"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path3" />
<path
d="M 21.1978,39.0535 21.1965,62.722"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path4" />
<path
d="m 32.0727,42.5863 0.2051,17.6539"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path5" />
<path
d="m 35.7188,46.1531 0.0833,10.0137"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path6" />
<path
d="m 39.4137,44.8153 0.3121,13.929"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path7" />
<path
d="M 17.5159,44.4622 17.484,56.2338"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path8" />
<path
d="m 13.7081,48.2703 v 4.5432"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path9" />
<path
d="M 9.64888,49.5363 9.64609,51.0512"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path10" />
<path
d="M 43.1263,54.4343 V 47.8829"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path11" />
<path
d="M 2.60583,50.2526 2.63165,50.1887"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path12" />
<path
d="m 5.96432,49.9235 5.1e-4,0.7034"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path13" />
</g><g
opacity="1"
vectornator:layerName="Group 2"
id="g28">
<path
d="m 68.4016,31.2736 0.1522,42.8466"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="Line"
id="path14" />
<path
d="m 71.9812,38.4086 0.3279,29.8509"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path15" />
<path
d="M 64.724,39.7788 64.7228,63.4473"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path16" />
<path
d="M 75.5989,43.3116 75.804,60.9655"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path17" />
<path
d="m 79.245,46.8784 0.0834,10.0137"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path18" />
<path
d="m 82.9888,49.5549 0.0155,2.8641"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path19" />
<path
d="m 90.1665,44.3658 0.0644,13.2423"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path 1"
id="path20" />
<path
d="m 93.8777,49.5413 0.0218,2.8913"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path 2"
id="path21" />
<path
d="m 97.3942,51.0314 -0.0026,0.1841"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.36423"
vectornator:layerName="path 3"
id="path22" />
<path
d="M 61.0421,45.1875 61.0102,56.9591"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path23" />
<path
d="M 57.2343,46.8472 V 54.906"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path24" />
<path
d="m 53.2003,44.8905 -0.028,13.429"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path25" />
<path
d="M 86.6526,55.5621 V 46.4118"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path26" />
<path
d="m 46.1063,53.487 0.0258,-5"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path27" />
<path
d="M 49.3862,61.2263 49.3473,40.7476"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.38065"
vectornator:layerName="path"
id="path28" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -1,57 +1,483 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Created with Vectornator (http://vectornator.io/) -->
<svg height="100%" stroke-miterlimit="10" style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;" version="1.1" viewBox="0 0 100 100" width="100%" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:vectornator="http://vectornator.io" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs/>
<g id="Layer-1" vectornator:layerName="Layer 1">
<path d="M9.53693 42.001L9.55396 55.0401" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M6.95011 44.7703L6.95814 52.0723" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M14.9443 30.7869L15.0706 68.8049" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M12.1821 34.421L12.2162 38.1651L12.1483 63.7005" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M17.624 34.5881L17.8565 63.5895" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M20.3551 41.3096L20.3875 55.2921" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M22.9232 45.1986L23.0191 52.0107" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M25.4344 46.0393L25.4569 50.7325" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M4.31279 47.063L4.31279 50.2485" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M1.7369 47.9337L1.7369 49.6807" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M30.322 47.6424L30.3289 49.0875" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M27.8791 46.9155L27.9329 49.8896" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M32.7624 46.381L32.7946 50.4132" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M35.1242 47.3456L35.1478 49.2629" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M37.5329 45.2632L37.5617 51.1906" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M39.9932 46.4363L40.0176 48.4183L40.0413 50.3308" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M42.5239 47.2302L42.5133 49.3242" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M75.2431 70.9252L75.1456 78.8827" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M80.7037 68.2525L80.8988 94.4781" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M78.1264 54.2647L78.0158 77.0175" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M83.4584 72.2179L83.4206 75.5987" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M86.1258 73.3064L86.1258 74.3962" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M72.654 72.9281L72.6308 75.535" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M74.8766 18.2159L74.8936 31.2549" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M72.2897 20.9851L72.2978 28.2871" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M80.448 4.92126L80.4635 48.1975" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M77.5766 10.6352L77.5918 40.2454" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M83.0352 12.6295L83.2601 37.6182" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M85.7445 17.2754L85.7769 31.2579" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M88.2628 20.8157L88.3588 27.6277" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M90.8239 22.0548L90.8464 26.7481" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M69.6026 23.1284L69.6026 26.3139" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M67.0531 23.9011L67.0531 25.6481" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M93.3183 22.9311L93.3721 25.9051" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M95.7912 23.5205L95.8333 25.2734" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M98.2359 23.9422L98.2646 24.9133" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M88.585 73.3399L88.6136 74.3109" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M91.1499 73.3457L91.1786 74.3168" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M70.0363 73.4911L70.0566 74.4624" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M67.532 73.3134L67.5606 74.2844" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M52.2284 39.3307L53.6968 39.3307L53.6968 40.8655L52.2284 40.8655L52.2284 39.3307ZM49.7418 33.4204C49.7418 32.3579 50.0419 31.5032 50.642 30.8564C51.2421 30.2095 52.0661 29.8861 53.1138 29.8861C54.0829 29.8861 54.8589 30.1628 55.4418 30.7162C56.0247 31.2696 56.3162 31.9767 56.3162 32.8375C56.3162 33.3589 56.2092 33.782 55.9952 34.1066C55.7812 34.4313 55.3496 34.9085 54.7002 35.5381C54.228 35.9956 53.9218 36.3829 53.7816 36.7002C53.6414 37.0175 53.5713 37.486 53.5713 38.1059L52.2579 38.1059C52.2579 37.4024 52.3415 36.8355 52.5088 36.4051C52.676 35.9747 53.0425 35.4815 53.6082 34.9257L54.1985 34.3428C54.3756 34.1755 54.5182 34.0009 54.6265 33.8189C54.8232 33.4991 54.9216 33.1671 54.9216 32.8228C54.9216 32.3407 54.7777 31.9226 54.49 31.5684C54.2022 31.2142 53.7263 31.0371 53.0622 31.0371C52.2407 31.0371 51.6726 31.3421 51.3577 31.9521C51.1806 32.2915 51.0798 32.7809 51.0552 33.4204L49.7418 33.4204Z" fill="#000000" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" vectornator:blendMode="lighten"/>
<path d="M52.9456 65.1775L54.414 65.1775L54.414 66.7122L52.9456 66.7122L52.9456 65.1775ZM50.4591 59.2672C50.4591 58.2047 50.7591 57.35 51.3592 56.7031C51.9594 56.0563 52.7833 55.7328 53.8311 55.7328C54.8001 55.7328 55.5761 56.0095 56.159 56.5629C56.7419 57.1163 57.0334 57.8235 57.0334 58.6843C57.0334 59.2057 56.9264 59.6288 56.7124 59.9534C56.4985 60.2781 56.0668 60.7552 55.4175 61.3849C54.9453 61.8423 54.639 62.2297 54.4988 62.547C54.3587 62.8643 54.2886 63.3328 54.2886 63.9526L52.9752 63.9526C52.9752 63.2492 53.0588 62.6823 53.226 62.2519C53.3933 61.8214 53.7598 61.3283 54.3254 60.7724L54.9157 60.1895C55.0928 60.0223 55.2355 59.8477 55.3437 59.6657C55.5405 59.3459 55.6388 59.0139 55.6388 58.6695C55.6388 58.1875 55.495 57.7693 55.2072 57.4152C54.9194 57.061 54.4435 56.8839 53.7794 56.8839C52.9579 56.8839 52.3898 57.1889 52.075 57.7989C51.8979 58.1383 51.797 58.6277 51.7724 59.2672L50.4591 59.2672Z" fill="#000000" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" vectornator:blendMode="lighten" vectornator:layerName="Text 2"/>
<path d="M43.023 43.1652L49.1123 38.5916" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144" vectornator:blendMode="lighten"/>
<path d="M93.4478 73.2028L93.4764 74.1739" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M95.9335 72.7147L95.9755 74.4676" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144"/>
<path d="M42.934 52.8115L48.3186 57.7694" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144" vectornator:blendMode="lighten"/>
<path d="M58.5745 31.7814L64.9247 27.0293" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144" vectornator:blendMode="lighten"/>
<path d="M58.3677 66L63.8094 71.0964" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.0144" vectornator:blendMode="lighten"/>
</g>
<g id="Layer-2" vectornator:layerName="Layer 2"/>
<svg
height="100%"
stroke-miterlimit="10"
style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;"
version="1.1"
viewBox="0 0 100 100"
width="100%"
xml:space="preserve"
id="svg48"
sodipodi:docname="matched_click_classifier.svg"
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:vectornator="http://vectornator.io"><sodipodi:namedview
id="namedview48"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="2.36"
inkscape:cx="50.211864"
inkscape:cy="50.211864"
inkscape:window-width="1400"
inkscape:window-height="950"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="svg48" />
<defs
id="defs1">
</defs>
<path
d="M 9.53693,42.001 9.55396,55.0401"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path1" /><path
d="m 6.95011,44.7703 0.00803,7.302"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path2" /><path
d="m 14.9443,30.7869 0.1263,38.018"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path3" /><path
d="m 12.1821,34.421 0.0341,3.7441 -0.0679,25.5354"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path4" /><path
d="m 17.624,34.5881 0.2325,29.0014"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path5" /><path
d="m 20.3551,41.3096 0.0324,13.9825"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path6" /><path
d="m 22.9232,45.1986 0.0959,6.8121"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path7" /><path
d="m 25.4344,46.0393 0.0225,4.6932"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path8" /><path
d="m 4.31279,47.063 v 3.1855"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path9" /><path
d="m 1.7369,47.9337 v 1.747"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path10" /><path
d="m 30.322,47.6424 0.0069,1.4451"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path11" /><path
d="m 27.8791,46.9155 0.0538,2.9741"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path12" /><path
d="m 32.7624,46.381 0.0322,4.0322"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path13" /><path
d="m 35.1242,47.3456 0.0236,1.9173"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path14" /><path
d="m 37.5329,45.2632 0.0288,5.9274"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path15" /><path
d="m 39.9932,46.4363 0.0244,1.982 0.0237,1.9125"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path16" /><path
d="m 42.5239,47.2302 -0.0106,2.094"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path17" /><path
d="m 75.2431,70.9252 -0.0975,7.9575"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path18" /><path
d="m 80.7037,68.2525 0.1951,26.2256"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path19" /><path
d="M 78.1264,54.2647 78.0158,77.0175"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path20" /><path
d="m 83.4584,72.2179 -0.0378,3.3808"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path21" /><path
d="m 86.1258,73.3064 v 1.0898"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path22" /><path
d="M 72.654,72.9281 72.6308,75.535"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path23" /><path
d="m 74.8766,18.2159 0.017,13.039"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path24" /><path
d="m 72.2897,20.9851 0.0081,7.302"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path25" /><path
d="M 80.448,4.92126 80.4635,48.1975"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path26" /><path
d="m 77.5766,10.6352 0.0152,29.6102"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path27" /><path
d="m 83.0352,12.6295 0.2249,24.9887"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path28" /><path
d="m 85.7445,17.2754 0.0324,13.9825"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path29" /><path
d="m 88.2628,20.8157 0.096,6.812"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path30" /><path
d="m 90.8239,22.0548 0.0225,4.6933"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path31" /><path
d="m 69.6026,23.1284 v 3.1855"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path32" /><path
d="m 67.0531,23.9011 v 1.747"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path33" /><path
d="m 93.3183,22.9311 0.0538,2.974"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path34" /><path
d="m 95.7912,23.5205 0.0421,1.7529"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path35" /><path
d="m 98.2359,23.9422 0.0287,0.9711"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path36" /><path
d="m 88.585,73.3399 0.0286,0.971"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path37" /><path
d="m 91.1499,73.3457 0.0287,0.9711"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path38" /><path
d="m 70.0363,73.4911 0.0203,0.9713"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path39" /><path
d="m 67.532,73.3134 0.0286,0.971"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path40" /><path
d="m 52.2284,39.3307 h 1.4684 v 1.5348 h -1.4684 z m -2.4866,-5.9103 c 0,-1.0625 0.3001,-1.9172 0.9002,-2.564 0.6001,-0.6469 1.4241,-0.9703 2.4718,-0.9703 0.9691,0 1.7451,0.2767 2.328,0.8301 0.5829,0.5534 0.8744,1.2605 0.8744,2.1213 0,0.5214 -0.107,0.9445 -0.321,1.2691 -0.214,0.3247 -0.6456,0.8019 -1.295,1.4315 -0.4722,0.4575 -0.7784,0.8448 -0.9186,1.1621 -0.1402,0.3173 -0.2103,0.7858 -0.2103,1.4057 h -1.3134 c 0,-0.7035 0.0836,-1.2704 0.2509,-1.7008 0.1672,-0.4304 0.5337,-0.9236 1.0994,-1.4794 l 0.5903,-0.5829 c 0.1771,-0.1673 0.3197,-0.3419 0.428,-0.5239 0.1967,-0.3198 0.2951,-0.6518 0.2951,-0.9961 0,-0.4821 -0.1439,-0.9002 -0.4316,-1.2544 -0.2878,-0.3542 -0.7637,-0.5313 -1.4278,-0.5313 -0.8215,0 -1.3896,0.305 -1.7045,0.915 -0.1771,0.3394 -0.2779,0.8288 -0.3025,1.4683 z"
fill="#000000"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1"
vectornator:blendMode="lighten"
id="path41" /><path
d="m 52.9456,65.1775 h 1.4684 v 1.5347 h -1.4684 z m -2.4865,-5.9103 c 0,-1.0625 0.3,-1.9172 0.9001,-2.5641 0.6002,-0.6468 1.4241,-0.9703 2.4719,-0.9703 0.969,0 1.745,0.2767 2.3279,0.8301 0.5829,0.5534 0.8744,1.2606 0.8744,2.1214 0,0.5214 -0.107,0.9445 -0.321,1.2691 -0.2139,0.3247 -0.6456,0.8018 -1.2949,1.4315 -0.4722,0.4574 -0.7785,0.8448 -0.9187,1.1621 -0.1401,0.3173 -0.2102,0.7858 -0.2102,1.4056 h -1.3134 c 0,-0.7034 0.0836,-1.2703 0.2508,-1.7007 0.1673,-0.4305 0.5338,-0.9236 1.0994,-1.4795 l 0.5903,-0.5829 c 0.1771,-0.1672 0.3198,-0.3418 0.428,-0.5238 0.1968,-0.3198 0.2951,-0.6518 0.2951,-0.9962 0,-0.482 -0.1438,-0.9002 -0.4316,-1.2543 -0.2878,-0.3542 -0.7637,-0.5313 -1.4278,-0.5313 -0.8215,0 -1.3896,0.305 -1.7044,0.915 -0.1771,0.3394 -0.278,0.8288 -0.3026,1.4683 z"
fill="#000000"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1"
vectornator:blendMode="lighten"
vectornator:layerName="Text 2"
id="path42" /><path
d="m 43.023,43.1652 6.0893,-4.5736"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
vectornator:blendMode="lighten"
id="path43" /><path
d="m 93.4478,73.2028 0.0286,0.9711"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path44" /><path
d="m 95.9335,72.7147 0.042,1.7529"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
id="path45" /><path
d="m 42.934,52.8115 5.3846,4.9579"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
vectornator:blendMode="lighten"
id="path46" /><path
d="m 58.5745,31.7814 6.3502,-4.7521"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
vectornator:blendMode="lighten"
id="path47" /><path
d="m 58.3677,66 5.4417,5.0964"
fill="none"
opacity="1"
stroke="#000000"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2.0144"
vectornator:blendMode="lighten"
id="path48" />
<g
id="Layer-2"
vectornator:layerName="Layer 2" />
</svg>

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -529,7 +529,7 @@ public class DataModelPaneFX extends PamBorderPane {
continue;
}
System.out.println("Checking: child: " + childNode + " parent: " + potentialParent);
// System.out.println("Checking: child: " + childNode + " parent: " + potentialParent);
if (ConnectionPane.isNodeConnected(childNode, potentialParent, true, true)) {
// everything is fine. Connected;
// System.out.println("The module "+
@ -545,10 +545,10 @@ public class DataModelPaneFX extends PamBorderPane {
// " should be connected to " +
// potentialParent.getPamControlledUnit().getUnitName());
if (useNodeConnection) {
System.out.println("DataModelPaneFX: CONNECTING TWO NODES: childNode: "
+childNode.getPamControlledUnit().getUnitName() +" to parentNode "
+potentialParent.getPamControlledUnit().getUnitName()+ " "
+potentialParent.isEnableConnectListeners());
// System.out.println("DataModelPaneFX: CONNECTING TWO NODES: childNode: "
// +childNode.getPamControlledUnit().getUnitName() +" to parentNode "
// +potentialParent.getPamControlledUnit().getUnitName()+ " "
// +potentialParent.isEnableConnectListeners());
childNode.connectNode(potentialParent);
} else {
// System.out.println("DataModelPaneFX: DISCONNECTING TWO NODES: childNode: "

View File

@ -43,69 +43,94 @@ public class ModuleIconFactory {
* @return the icon for the controlled unit
*/
public Node getModuleNode(ModuleIcon icon){
long time1 = System.currentTimeMillis();
Node iconNode =null;
switch (icon){
case ARRAY:
// return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/array_manager.png")));
return getSVGIcon("/Resources/modules/Array Icon2.svg",Color.BLACK, 3);
iconNode = getSVGIcon("/Resources/modules/Array Icon2.svg",Color.BLACK, 3);
break;
case BINARY:
// return PamGlyphDude.createModuleGlyph(OctIcon.FILE_BINARY);
return PamGlyphDude.createModuleIcon("mdi2f-file-star-outline");
iconNode = PamGlyphDude.createModuleIcon("mdi2f-file-star-outline");
break;
case CLICK:
// return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/click.png")));
return getSVGIcon("/Resources/modules/Click Detector Icon.svg", Color.BLACK, 2);
iconNode = getSVGIcon("/Resources/modules/Click Detector Icon.svg", Color.BLACK, 2);
break;
case CLICK_TRAIN:
// return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/clicktrain.png")));
return getSVGIcon("/Resources/modules/clicktrain.svg",Color.BLACK, 2);
iconNode = getSVGIcon("/Resources/modules/clicktrain.svg",Color.BLACK, 2);
break;
case DATABASE:
// return PamGlyphDude.createModuleGlyph(FontAwesomeIcon.DATABASE);
return PamGlyphDude.createModuleIcon("mdi2d-database");
iconNode = PamGlyphDude.createModuleIcon("mdi2d-database");
break;
case DATAMAP:
return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/dataMap.png")));
iconNode = new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/dataMap.png")));
break;
case FFT:
// return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/fft.png")));
return getSVGIcon("/Resources/modules/fft.svg",Color.BLACK, 2);
iconNode = getSVGIcon("/Resources/modules/fft.svg",Color.BLACK, 2);
break;
case FILTER:
// return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/filters.png")));
return getSVGIcon("/Resources/modules/filters.svg",Color.BLACK, 2);
iconNode = getSVGIcon("/Resources/modules/filters.svg",Color.BLACK, 2);
break;
case GPS:
// return PamGlyphDude.createModuleGlyph(MaterialIcon.GPS_FIXED);
return PamGlyphDude.createModuleIcon("mdi2c-crosshairs-gps");
iconNode = PamGlyphDude.createModuleIcon("mdi2c-crosshairs-gps");
break;
case MAP:
// return PamGlyphDude.createModuleGlyph(MaterialIcon.MAP);
return PamGlyphDude.createModuleIcon("mdi2m-map");
iconNode = PamGlyphDude.createModuleIcon("mdi2m-map");
break;
case NMEA:
return createNMEASymbol();
iconNode = createNMEASymbol();
case NOISE_BAND:
return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/filterdNoiseMeasurementBank.png")));
iconNode = new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/filterdNoiseMeasurementBank.png")));
break;
case NOISE_FILT:
return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/filterdNoiseMeasurement.png")));
iconNode = new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/filterdNoiseMeasurement.png")));
break;
case RECORDER:
return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/recorder.png")));
iconNode = new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/recorder.png")));
break;
case SOUND_AQ:
return getSVGIcon("/Resources/modules/noun_Soundwave_1786340.svg");
iconNode = getSVGIcon("/Resources/modules/noun_Soundwave_1786340.svg");
break;
case MATCHED_CLICK_CLASSIFIER:
return getSVGIcon("/Resources/modules/matched_click_classifier.svg",Color.BLACK, 2);
iconNode = getSVGIcon("/Resources/modules/matched_click_classifier.svg",Color.BLACK, 2);
break;
//return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/aquisition.png")));
case SOUND_OUTPUT:
// return PamGlyphDude.createModuleGlyph(MaterialDesignIcon.HEADPHONES);
return PamGlyphDude.createModuleIcon("mdi2h-headphones");
//return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/playback.png")));
iconNode = PamGlyphDude.createModuleIcon("mdi2h-headphones");
break;
//return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/playback.png")));
case WHISTLE_MOAN:
return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/whistles.png")));
iconNode = new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/whistles.png")));
break;
case TIME_DISPLAY:
return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/timeDisplay.png")));
iconNode = new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/timeDisplay.png")));
break;
case DETECTION_DISPLAY:
return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/detectionDisplay.png")));
iconNode = new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/detectionDisplay.png")));
break;
case DEEP_LEARNING:
//System.out.println("------GET THE SVG ICON FOR DEEP LEARNING--------");
return getSVGIcon("/Resources/modules/noun_Deep Learning_2486374.svg");
iconNode = getSVGIcon("/Resources/modules/noun_Deep Learning_2486374.svg");
break;
default:
break;
}
return null;
long time2 = System.currentTimeMillis();
System.out.println("GET MODULE ICON: " + icon + " load time: " + (time2-time1));
return iconNode;
};
/**
@ -182,7 +207,6 @@ public class ModuleIconFactory {
* @return the module icon enum
*/
public ModuleIcon getModuleIcon(String className) {
System.out.println("CLASS NAME: " + className);
ModuleIcon icon = null;
switch (className) {
case "Acquisition.AcquisitionControl":

View File

@ -75,106 +75,7 @@ public class PamColorsFX implements PamSettings {
//PamSettingManager.getInstance().registerSettings(this, PamSettingManager.LIST_SYSTEMGLOBAL);
}
// public JMenuItem getMenu(JFrame parentFrame) {
//
// JMenu colorMenu = new JMenu("Color Scheme");
//
// JMenuItem menuItem;
//
// int n = colorSettings.getNumSchemes();
// for (int i = 0; i < n; i++) {
// String name = colorSettings.getScheme(i).getName();
// menuItem = new JMenuItem(name);
// menuItem.addActionListener(new SelectScheme(name));
// colorMenu.add(menuItem);
// }
//
//
// menuItem = new JMenu("Edit");
// colorMenu.addSeparator();
// colorMenu.add(menuItem);
//
// JMenuItem editItem = new JMenuItem("Whale Colours");
// editItem.addActionListener(new EditWhaleColours(parentFrame));
// menuItem.add(editItem);
// editItem = new JMenuItem("Channel Colours");
// editItem.addActionListener(new EditChannelColours(parentFrame));
// menuItem.add(editItem);
//
//
//// dayMenuItem = new JCheckBoxMenuItem("Day");
//// dayMenuItem.addActionListener(new menuColorDay());
//// colorMenu.add(dayMenuItem);
//// dayMenuEnabler.addMenuItem(dayMenuItem);
////
//// nightMenuItem = new JCheckBoxMenuItem("Night");
//// nightMenuItem.addActionListener(new menuColorNight());
//// colorMenu.add(nightMenuItem);
//// nightMenuEnabler.addMenuItem(nightMenuItem);
////
//// printMenuItem = new JCheckBoxMenuItem("Print");
//// printMenuItem.addActionListener(new menuColorPrint());
//// if ( SMRUEnable.isEnable() )
//// colorMenu.add(printMenuItem);
////
//// printMenuEnabler.addMenuItem(printMenuItem);
//
// return colorMenu;
// }
// private class SelectScheme implements ActionListener {
//
// private String schemeName;
//
// public SelectScheme(String schemeName) {
// super();
// this.schemeName = schemeName;
// }
//
// @Override
// public void actionPerformed(ActionEvent e) {
// colourScheme = colorSettings.selectScheme(schemeName);
// setColors();
// }
//
// }
// private class EditWhaleColours implements ActionListener {
//
// private JFrame parentFrame;
//
// public EditWhaleColours(JFrame parentFrame) {
// this.parentFrame = parentFrame;
// }
//
// @Override
// public void actionPerformed(ActionEvent e) {
// Color[] wCols = colourScheme.getWhaleColors();
//// Color[] newCols = ColourListDialog.show(parentFrame, "Whale Colours", wCols);
//// if (newCols) {
//// colourScheme.setWhaleColors(newCols);
//// setColors();
//// }
// }
// }
// private class EditChannelColours implements ActionListener {
//
// private JFrame parentFrame;
//
// public EditChannelColours(JFrame parentFrame) {
// this.parentFrame = parentFrame;
// }
//
// @Override
// public void actionPerformed(ActionEvent e) {
// Color[] wCols = colourScheme.getChannelColors();
//// Color[] newCols = ColourListDialog.show(parentFrame, "Whale Colours", wCols);
//// if (newCols) {
//// colourScheme.setChannelColors(newCols);
//// setColors();
//// }
// }
// }
static public PamColorsFX getInstance() {
if (singleInstance == null) {

View File

@ -35,6 +35,7 @@ import rawDeepLearningClassifier.dlClassification.DLClassifyProcess;
import rawDeepLearningClassifier.dlClassification.animalSpot.SoundSpotClassifier;
import rawDeepLearningClassifier.dlClassification.genericModel.GenericDLClassifier;
import rawDeepLearningClassifier.dlClassification.ketos.KetosClassifier;
import rawDeepLearningClassifier.layoutFX.DLModelSelectPane;
import rawDeepLearningClassifier.layoutFX.DLSidePanelSwing;
import rawDeepLearningClassifier.layoutFX.DLSymbolManager;
import rawDeepLearningClassifier.layoutFX.PredictionSymbolManager;
@ -187,6 +188,8 @@ public class DLControl extends PamControlledUnit implements PamSettings {
*/
private DLClassifierChooser dlClassifierChooser;
private DLDownloadManager modelDownloadManager;
/**
@ -215,7 +218,11 @@ public class DLControl extends PamControlledUnit implements PamSettings {
// classify the raw data segments.
addPamProcess(dlClassifyProcess = new DLClassifyProcess(this, segmenterProcess.getSegmenterDataBlock()));
//manages the names assigned to different output classes.
dlClassNameManager = new DLClassNameManager(this);
//manages downloading models
modelDownloadManager = new DLDownloadManager();
// add storage options etc.
dlBinaryDataSource = new DLResultBinarySource(dlClassifyProcess);
@ -267,7 +274,7 @@ public class DLControl extends PamControlledUnit implements PamSettings {
//create the classiifer chooser.
dlClassifierChooser = new DLClassifierChooser(this);
// ensure everything is updated.
updateParams(rawDLParmas);
}
@ -576,6 +583,14 @@ public class DLControl extends PamControlledUnit implements PamSettings {
return dlClassifierChooser;
}
/**
* Get the download manager for downloading models offline.
* @return the download manager.
*/
public DLDownloadManager getDownloadManager() {
return modelDownloadManager;
}
}

View File

@ -0,0 +1,232 @@
package rawDeepLearningClassifier;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FilenameUtils;
import rawDeepLearningClassifier.defaultModels.RightWhaleModel1;
/**
* Manages the downloading and unzipping of models.
*/
public class DLDownloadManager {
public DLDownloadManager() {
}
/**
* Check whether has been downloaded already to a default local folder?
* @param modelURI - the URL of the model
* @return
* @return true if the model has been downloaded.
*/
public boolean isModelDownloaded(URL modelURL) {
return isModelDownloaded(modelURL, getModelName(modelURL));
}
/**
* Check whether has been downloaded already?
* @param modelURI - the URL of the model
* @param modelName - the model name that has been used to name the temporary folder.
* @return true if the model has been downloaded.
*/
public boolean isModelDownloaded(URL modelURL, String modelName) {
return getModelDownloadedFile( modelURL, modelName).exists();
}
/**
* Get the path to the model if it has been downloaded.
* @param modelURL - the URL to the model
* @param modelName - the model name. Use getModelName(modelURL) to use the default model name.
* @return a file object - may not exist.
*/
public File getModelDownloadedFile(URL modelURL, String modelName) {
//get the name of the file
String fileName = FilenameUtils.getName(modelURL.toString());
return new File(getModelFolder(modelName) + File.separator + fileName);
}
/**
* Get the path to a model. If the URI is a URL then the model is download to a local folder and the path to
* the local folder is returned.
* @param model - the model to load.
* @param modelName - the name of the model - this is used to create the local folder name if the model is downloaded.
* @return the path to the model The model might be a zip file, py file, koogu file.
*/
public URI downloadModel(URI modelURI) {
String modelName = getModelName(modelURI);
return downloadModel( modelURI, modelName);
}
/**
* Get a model name based on it's filename
* @param modelURI - URI to the model
* @return the model name.
*/
private String getModelName(URI modelURI) {
return FilenameUtils.getBaseName(modelURI.getPath());
}
/**
* Get a model name based on it's filename
* @param modelURL - URL to the model
* @return the model name.
*/
private String getModelName(URL modelURI) {
return FilenameUtils.getBaseName(modelURI.getPath());
}
/**
* Get the path to a model. If the URI is a URL then the model is download to a local folder and the path to
* the local folder is returned.
* @param model - the model to load.
* @param modelName - the name of the model - this is used to create the local folder name if the model is downloaded.
* @return the path to the model The model might be a zip file, py file, .kgu file.
*/
public URI downloadModel(URI modelURI, String modelName) {
if ("file".equalsIgnoreCase(modelURI.getScheme())) {
// It's a file path
return modelURI; //the model is already a path.
} else {
// It's a URL
try {
System.out.println("Download: " + modelURI.toURL().getPath());
String folder = getModelFolder(modelName);
if (folder==null) {
System.err.println("DLDefaultModelManager.loadModel: Unable to make model folder: ");
}
File file = downLoadModel(modelURI.toURL(), getModelFolder(modelName) );
return file.toURI();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
}
private static boolean isRedirected( Map<String, List<String>> header ) {
for( String hv : header.get( null )) {
if( hv.contains( " 301 " )
|| hv.contains( " 302 " )) return true;
}
return false;
}
/**
* Get the model folder - create it if it doesn't exist.
* @return file object for new folder
*/
static public String getModelFolder() {
String settingsFolder = System.getProperty("user.home");
settingsFolder += File.separator + "Pamguard_deep_learning";
// now check that folder exists
File folder = makeFolder( settingsFolder);
if (folder==null) return null;
return folder.getPath();
}
/**
* Get the model folder - create it if it doesn't exist.
* @param modelname - the name of the model - this is used to create the local folder name.
* @return file object for new folder
*/
static public String getModelFolder(String modelname) {
String folder = getModelFolder();
if (folder == null) return null;
// now check that folder exists
File dlFolder = makeFolder( folder + File.separator + modelname);
if (dlFolder==null) return null;
return dlFolder.getPath();
}
/**
* Make a settings folder.
* @param settingsFolder
* @return
*/
private static File makeFolder(String settingsFolder) {
File folder = new File(settingsFolder);
if (folder.exists() == false) {
folder.mkdirs();
if (folder.exists() == false) {
return null;
}
}
return folder;
}
/**
* Download a model to the default file location.
* @param link - the link to download from
* @param outFolder - the folder in which to save the file.
* @return the model file output.
* @throws IOException - exception if something goes wrong.
*/
private static File downLoadModel(URL url, String outFolder) throws IOException {
String link = url.toString();
//get the name of the file
String fileName = FilenameUtils.getName(link);
File outFile = new File( outFolder + File.separator + fileName);
HttpURLConnection http = (HttpURLConnection)url.openConnection();
Map< String, List< String >> header = http.getHeaderFields();
//handle any redorects - e.g. from GitHub
while( isRedirected( header )) {
link = header.get( "Location" ).get( 0 );
url = new URL( link );
http = (HttpURLConnection)url.openConnection();
header = http.getHeaderFields();
}
InputStream input = http.getInputStream();
byte[] buffer = new byte[4096]; //download in 4kB chunks
int n = -1;
OutputStream output = new FileOutputStream(outFile);
while ((n = input.read(buffer)) != -1) {
System.out.println("Chunk: " + n);
output.write( buffer, 0, n );
}
output.close();
return outFile;
}
public static void main(String[] args) {
DLDownloadManager dlDefaultModelManager = new DLDownloadManager();
System.out.println("Test downloading a model: ");
URI path = dlDefaultModelManager.downloadModel(new RightWhaleModel1().getModelURI(), new RightWhaleModel1().getModelName());
}
}

View File

@ -0,0 +1,63 @@
package rawDeepLearningClassifier.defaultModels;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import PamUtils.FileFunctions;
import java.io.OutputStream;
import java.io.InputStream;
import rawDeepLearningClassifier.DLControl;
/**
* Manages default models.
*/
public class DLDefaultModelManager {
/**
* A list of the default models
*/
private ArrayList<DLModel> defaultModels = new ArrayList<DLModel>();
/**
* Reference ot the DL control.
*/
private DLControl dlControl;
/**
* Constructor for the Defulat Model Manager.
* @param dlControl - reference to the controller for this model manager.
*/
public DLDefaultModelManager(DLControl dlControl) {
this.dlControl = dlControl;
}
/**
* Get a default model at index i
* @param i - the index of the default model
*/
public DLModel getDefaultModel(int i) {
return defaultModels.get(i);
}
/**
* Get the number of default models
* @return the number of default models.
*/
public int getNumDefaultModels() {
return defaultModels.size();
}
}

View File

@ -0,0 +1,50 @@
package rawDeepLearningClassifier.defaultModels;
import java.net.URI;
import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams;
/**
* A default model that can be loaded from a file or a URL.
*/
public interface DLModel {
/**
* Get a brief description of the model.
* @return a brief description of the model.
*/
public String getDescription();
/**
* Get a name for the model
* @return
*/
public String getName();
/**
* Get the citation for the model
* @return - the citation.
*/
public String getCitation();
/**
* Get the URI to the model file
* @return the model URI.
*/
public URI getModelURI();
/**
* Get the model settings - these are used to ensure the model is set up correctly once loaded.
*/
public StandardModelParams getModelSettings();
/**
* The model name. This is used if, for example, a model is downloaded as a zip file and the model
* file is located somewhere within the saved folder. For Tensorflow models this will often be saved_model.pb
* @return the model name;
*/
public String getModelName();
}

View File

@ -0,0 +1,59 @@
package rawDeepLearningClassifier.defaultModels;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams;
/**
* Right whale model from Shiu et al. 2019
* <p>
* * <p>
* Shiu, Y., Palmer, K.J., Roch, M.A., Fleishman, E., Liu, X., Nosal, E.-M., Helble, T., Cholewiak, D., Gillespie, D., Klinck, H., 2020.
* Deep neural networks for automated detection of marine mammal species. Scientific Reports 10, 607. https://doi.org/10.1038/s41598-020-57549-y
*/
public class RightWhaleModel1 implements DLModel {
@Override
public String getDescription() {
return "Detects right whales";
}
@Override
public String getName() {
return "Right Whale";
}
@Override
public String getCitation() {
return " Shiu, Y., Palmer, K.J., Roch, M.A., Fleishman, E., Liu, X., Nosal, E.-M., Helble, T., Cholewiak, D., Gillespie, D., Klinck, H., 2020."
+ " Deep neural networks for automated detection of marine mammal species. Scientific Reports 10, 607. https://doi.org/10.1038/s41598-020-57549-y";
}
@Override
public URI getModelURI() {
try {
return new URL("https://github.com/PAMGuard/deeplearningmodels/raw/master/right_whale_1/model_lenet_dropout_input_conv_all.zip").toURI();
} catch (MalformedURLException | URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
public StandardModelParams getModelSettings() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getModelName() {
return "saved_model.pb";
}
}

View File

@ -102,8 +102,6 @@ public interface DLClassiferModel {
*/
public boolean checkModelOK();
/**
* Get warnings for the classifier model. This is called when the user confirms settings and
* used to return a warning dialog.

View File

@ -247,8 +247,10 @@ public class DLModelSelectPane extends PamBorderPane {
// runnable for that thread
public void run() {
try {
newModelSelected(uri);
currentSelectedFile = uri;
URI modelPath = dlControl.getDownloadManager().downloadModel(uri);
newModelSelected(modelPath);
currentSelectedFile = modelPath;
Thread.sleep(1000); //just show the user something happened if model loading is rapid.
} catch (InterruptedException e) {
// TODO Auto-generated catch block
@ -282,6 +284,8 @@ public class DLModelSelectPane extends PamBorderPane {
return;
}
this.currentClassifierModel = this.dlControl.getDlClassifierChooser().selectClassiferModel(file);
System.out.println("New classifier model selected!: " + currentClassifierModel);