Skip to content
Snippets Groups Projects
Commit 68920891 authored by Jari-Matti Mäkelä's avatar Jari-Matti Mäkelä
Browse files

Initial commit

parents
No related branches found
No related tags found
No related merge requests found
Pipeline #21383 passed
Showing
with 1124 additions and 0 deletions
contracts/
.classpath
.project
.history/
.idea
.jqwik-database
.lib/
.worksheet
.settings/
*.iml
*.ipr
*.iws
*.log
project/boot/
project/plugins/project/
project/project/
project/*-shim.sbt
project/target/
target/
openjfx/
image: maven:latest
stages:
- build
- test
build:
script:
- mvn compile
test:
script:
- mvn test
\ No newline at end of file
# Project description
Project template for Visual Notes (DTEK 1049 exercise D / 2020).
Requires Java 11 or later. Compatible with
Eclipse and IntelliJ IDEA. Minor issues with Netbeans. Automatically
integrates with Gitlab CI.
## Installation
Maven:
```bash
$ git clone https://gitlab.utu.fi/tech/education/gui/visualnotes
$ cd visualnotes
$ mvn compile exec:java
```
SBT:
```bash
$ git clone https://gitlab.utu.fi/tech/education/gui/visualnotes
$ cd visualnotes
$ sbt compile run
```
## Further instructions
* Java platform: https://gitlab.utu.fi/soft/ftdev/wikis/tutorials/jvm-platform
* Maven: https://gitlab.utu.fi/soft/ftdev/wikis/tutorials/maven-misc
* SBT: https://gitlab.utu.fi/soft/ftdev/wikis/tutorials/sbt-misc
External sources:
* JavaFX: https://openjfx.io/javadoc/11/
* Scene Builder: https://docs.gluonhq.com/scenebuilder/
build.sbt 0 → 100644
// Project template
// Supported operating systems: Windows, Mac, Linux
// Supported JDKs: 8, 10+
// Project name
name := "visualnotes"
// organization name
organization := "fi.utu.tech"
version := "1.0"
// project description
description := "Visual Notes"
// main class
Compile/mainClass := Some("fi.utu.tech.visualnotes.Main")
// force the java version by typing it here (remove the comment)
val force_javaVersion = None // Some(13)
// force the javafx version by typing it here (remove the comment)
val force_javaFxVersion = None // Some(13)
val useJavaFX = true
val useScalaOrScalaFX = true
// END_OF_SIMPLE_CONFIGURATION
// you can copy the rest for each new project
// --- --- ---
def fail(msg: String) = {
println("Error :-/")
println
println(msg)
System.exit(1)
null
}
val detectedJDK = System.getProperty("java.version").replace("-ea","").split('.').dropWhile(_.toInt<8).head.toInt
val javaVersionNum = force_javaVersion.getOrElse(detectedJDK)
val javaVersionString = javaVersionNum match {
case 7 => "1.7"
case 8 => "1.8"
case x if x > 8 => x.toString
}
val lts = 11
val dev = 13
val supported = javaVersionNum match {
case x if x < 8 => fail("Your Java installation is obsolete. Please upgrade to Java " + lts + "LTS")
case 9 => fail("Your Java installation is unsupported and has known issues. Please upgrade to Java " + lts + "LTS")
case x if x < lts => println("Consider upgrading to Java " + lts + " LTS"); true
case x if x > lts && x < dev => println("Consider upgrading to Java " + dev); true
case x if x > dev => println("Unsupported early access version. Consider switching back to Java " + dev); true
case _ => true
}
javacOptions ++= Seq("-source", javaVersionString, "-target", javaVersionString, "-encoding", "utf8", "-Xlint:unchecked", "-Xlint:deprecation")
javacOptions in doc := Seq("-source", javaVersionString)
enablePlugins(JShellPlugin)
compileOrder := CompileOrder.JavaThenScala
// Enables publishing to maven repo
publishMavenStyle := true
// Do not append Scala versions to the generated artifacts
crossPaths := false
// This forbids including Scala related libraries into the dependency
autoScalaLibrary := false
assemblyMergeStrategy in assembly := {
case PathList("META-INF", xs @ _*) => MergeStrategy.discard
case _ => MergeStrategy.first
}
// contains libraries provided by utu/ft dep
resolvers += "ftdev" at "https://ftdev.utu.fi/maven2"
fork in Global := true
val javaVersion = taskKey[Unit]("Prints the Java version.")
javaVersion := { println("SBT uses Java SDK located at "+System.getProperty("java.home")) }
publishTo := Some(Resolver.file("file", new File("/tmp/repository")))
val oomkit = "fi.utu.tech" % "oomkit" % "1.15"
libraryDependencies ++= Seq()
////
//// JQWIK / JUNIT configuration
////
resolvers in ThisBuild += Resolver.jcenterRepo
val junit_version = "5.5.2"
// library dependencies. (orginization name) % (project name) % (version)
libraryDependencies ++= Seq(
"net.aichler" % "jupiter-interface" % JupiterKeys.jupiterVersion.value % Test,
"org.junit.platform" % "junit-platform-commons" % ("1"+junit_version.tail) % Test,
"org.junit.platform" % "junit-platform-runner" % ("1"+junit_version.tail) % Test,
"org.junit.jupiter" % "junit-jupiter-engine" % junit_version % Test,
"org.junit.jupiter" % "junit-jupiter-api" % junit_version % Test,
"org.junit.jupiter" % "junit-jupiter-migrationsupport" % junit_version % Test,
"org.junit.jupiter" % "junit-jupiter-params" % junit_version % Test,
"net.jqwik" % "jqwik" % "1.2.0" % Test,
"org.scalatest" %% "scalatest" % "3.0.8" % Test,
)
testOptions += Tests.Argument(TestFrameworks.JUnit, "-q", "-c")
////
//// JAVAFX configuration
////
val javafx_versions = if (!useJavaFX) (0,"-","-") else (force_javaFxVersion getOrElse javaVersionNum) match {
case 7 => (7, "7", "8.0.181-R13")
case 8 => (8, "8", "8.0.181-R13")
case 10 => (11, "11.0.2", "11-R16")
case x if x>10 => (13, "13.0.2", "12.0.2-R18")
case _ => fail("Unsupported Java version for JavaFX")
}
// JAVA_HOME location
val javaHomeDir = {
val path = try {
if (scala.sys.env("JAVA_HOME").trim.isEmpty) throw new Exception("Empty JAVA_HOME") else scala.sys.env("JAVA_HOME")
} catch {
case _: Throwable => System.getProperty("java.home") // not set -> ask from current JVM
}
val f = file(path)
if (!f.exists()) fail("The environment variable JAVA_HOME points to a non-existent directory!\nSolution: Edit your system settings (Windows control panel / *nix .bashrc) and fix the JAVA_HOME location.")
f
}
val osName: SettingKey[String] = SettingKey[String]("osName")
osName := (System.getProperty("os.name") match {
case n if n.startsWith("Linux") => "linux"
case n if n.startsWith("Mac") => "mac"
case n if n.startsWith("Windows") => "win"
case _ => throw new Exception("Unknown platform!")
})
def legacyJavaFX() = {
val searchDirs = Seq(
"/jre/lib/jfxrt.jar", // OpenJDK 7
"/jre/lib/ext/jfxrt.jar", // OpenJDK 8
"/lib/ext/jfxrt.jar" // Windows & Oracle Java 8
)
if (detectedJDK > 8) fail(s"Trying to use legacy non-modular JavaFX with a modern JDK [$detectedJDK].\nSolution: Check the line 'val force_javaFxVersion =' in build.sbt.")
val javaFxJAR = searchDirs.map{ searchDir => file(javaHomeDir + searchDir) }.find{ _.exists() }
javaFxJAR.getOrElse {
fail(s"Java FX runtime not installed in [${javaHomeDir.toString}]!\nSolution: Install JavaFX or consider upgrading your JDK so that JavaFX can be installed automatically.")
}
}
val jfx_sdk_version = javafx_versions._2
val jfx_scalafx_version = javafx_versions._3
val javaFxPath = Def.taskKey[File]("OpenJFX fetcher")
javaFxPath := {
val javaFxHome =
try {
val envHome = file(scala.sys.env("JAVAFX_HOME"))
if (envHome.toString.trim.isEmpty) throw new Exception("Empty JAVAFX_HOME")
println("Using OpenJFX from " + envHome)
envHome
}
catch { case _: Throwable =>
println("Using local OpenJFX")
baseDirectory.value / "openjfx"
}
if (!javaFxHome.exists()) java.nio.file.Files.createDirectory(javaFxHome.toPath)
val jfx_os = osName.value match {
case "linux" => "linux"
case "mac" => "osx"
case "win" => "windows"
}
val sdkURL = "http://download2.gluonhq.com/openjfx/" + jfx_sdk_version + "/openjfx-" + jfx_sdk_version + "_" + jfx_os + "-x64_bin-sdk.zip"
try {
val testDir = javaFxHome / "all.ok"
if (!testDir.exists()) {
println("Fetching OpenJFX from "+sdkURL+"..")
IO.unzipURL(new URL(sdkURL), javaFxHome)
java.nio.file.Files.createDirectory(testDir.toPath)
println("Fetching OpenJFX done.")
} else {
println("Using OpenJFX from "+javaFxHome)
}
javaFxHome
}
catch {
case t: Throwable => fail("Could not load OpenJFX! Reason:" + t.getMessage)
}
}
val jfxModules = Seq("base","controls","fxml","graphics","media","swing","web")
if (!useJavaFX) Seq() else javafx_versions._1 match {
case 7 =>
// TODO libraryDependencies
Seq(unmanagedJars in Compile += Attributed.blank(legacyJavaFX()))
case 8 =>
(if (useScalaOrScalaFX) Seq(libraryDependencies += "org.scalafx" %% "scalafx" % jfx_scalafx_version) else Seq()) ++
Seq(unmanagedJars in Compile += Attributed.blank(legacyJavaFX()))
case _ =>
Seq(
javaOptions in run ++= Seq(
"--module-path", (javaFxPath.value / ("javafx-sdk-" + jfx_sdk_version) / "lib").toString,
"--add-modules=" + jfxModules.map("javafx."+_).mkString(","))
) ++
(if (useScalaOrScalaFX) Seq(libraryDependencies += "org.scalafx" % "scalafx_2.13" % jfx_scalafx_version) else Seq()) ++
jfxModules.map(module => libraryDependencies += "org.openjfx" % ("javafx-"+module) % jfx_sdk_version classifier osName.value)
}
pom.xml 0 → 100644
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--
Welcome!
This pom.xml is *THE* file that defines your Maven style Java project.
Eclipse, IDEA and other development environments with Maven support
or plugins can *import* this project by reading this file.
It usually contains tons of barely readable configuration. Luckily
this basic pom.xml is somewhat readable. All necessary configuration
for customizing your project if located here on top before the
'END OF SIMPLE CONFIGURATION' line below.
Some basics:
- Maven is a build system for Java/JVM
- the Maven projects define an artifact that has a three part id:
groupId - artifactId - version
- For example, this project is called:
fi.utu.tech - visualnotes - 1.0
- The group id is usually a web domain in reverse order.
- You can use these id parts to search for projects at
https://search.maven.org/
- If your version is not final and you have plans to modify the
source code at some point, please use a version id that ends with
-SNAPSHOT, e.g 1.0-SNAPSHOT. Maven may cache the project jar
and refuse to overwrite old cached versions with new ones unless
you remember this convention.
- This file supports
compiling the project with 'mvn compile' (see target/)
cleaning the class files with 'mvn clean'
executing the main routine with 'mvn exec:java'
executing the unit tests with 'mvn test'
packaging the application with 'mvn package' (see target/)
- the Maven project structure is as follows:
https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html
-->
<!-- ==== START OF SIMPLE CONFIGURATION ==== -->
<!-- the three parts of the artifact name -->
<groupId>fi.utu.tech</groupId>
<artifactId>visualnotes</artifactId>
<version>1.0</version>
<!-- additional information about the project -->
<name>Visual Notes</name>
<url>https://gitlab.utu.fi/tech/education/gui/visualnotes</url>
<packaging>jar</packaging>
<!-- HINT: More configuration here! -->
<properties>
<!-- Configures this project to use 'fi.utu.tech.AppMain' as its main class -->
<project.mainclass>fi.utu.tech.visualnotes.Main</project.mainclass>
<!-- Don't touch these unless you know what you're doing!
For example, the source encoding should always be utf-8.
You're probably doing something stupid if you think it
should be a 8-bit code page in 2019. -->
<jdk.version>11</jdk.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jqwik.version>1.2.0</jqwik.version>
<junit.version>5.5.2</junit.version>
<junitplatform.version>1.5.2</junitplatform.version>
<javafx.version>13.0.2</javafx.version>
<spatial.version>1.0</spatial.version>
</properties>
<!-- ==== END OF SIMPLE CONFIGURATION ==== -->
<repositories>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
<repository>
<id>jcenter</id>
<name>jcenter</name>
<url>https://jcenter.bintray.com/</url>
</repository>
<!-- UTU repository -->
<repository>
<id>ftdev</id>
<name>ftdev</name>
<url>https://ftdev.utu.fi/maven2</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-commons</artifactId>
<version>${junitplatform.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.jqwik</groupId>
<artifactId>jqwik</artifactId>
<version>${jqwik.version}</version>
<scope>test</scope>
</dependency><!--
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-migrationsupport</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>${junitplatform.version}</version>
<scope>test</scope>
</dependency> -->
<!-- JavaFX (remove if not needed to speed up dep downloads)-->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-base</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-swing</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId>
<version>${javafx.version}</version>
</dependency>
<!-- UTU libraries -->
<dependency>
<groupId>fi.utu.tech</groupId>
<artifactId>spatial-data</artifactId>
<version>${spatial.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Make a 'fat' jar, that is, jar that contains all its dependencies and runs as is.
See: https://stackoverflow.com/a/57691362 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>module-info.class</exclude>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>${project.mainclass}</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<!-- Run this app with exec:java -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>${project.mainclass}</mainClass>
<arguments>
<argument>arg1</argument>
<argument>arg2</argument>
</arguments>
</configuration>
</plugin>
<!-- Make the packaged jar executable -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<!-- DO NOT include log4j.properties file in your Jar -->
<excludes>
<exclude>**/log4j.properties</exclude>
</excludes>
<archive>
<manifest>
<!-- Jar file entry point -->
<mainClass>${project.mainclass}</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<!-- download source code in Eclipse, best practice -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.10</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>false</downloadJavadocs>
</configuration>
</plugin>
<!-- JDK source/target versions -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
<configuration>
<tags>
<tag>
<name>toDo</name>
<placement>a</placement>
<head>To&nbsp;do:</head>
</tag>
<tag>
<name>classInvariant</name>
<placement>t</placement>
<head>Class&nbsp;invariant:</head>
</tag>
<tag>
<name>classInvariantProtected</name>
<placement>t</placement>
<head>Protected&nbsp;class&nbsp;invariant:</head>
</tag>
<tag>
<name>classInvariantPrivate</name>
<placement>t</placement>
<head>Private&nbsp;class&nbsp;invariant:</head>
</tag>
<tag>
<name>abstractionFunction</name>
<placement>t</placement>
<head>Abstraction&nbsp;function:</head>
</tag>
<tag>
<name>pre</name>
<placement>cm</placement>
<head>Precondition:</head>
</tag>
<tag>
<name>post</name>
<placement>cm</placement>
<head>Postcondition:</head>
</tag>
<tag>
<name>postProtected</name>
<placement>cm</placement>
<head>Protected&nbsp;postcondition:</head>
</tag>
<tag>
<name>postPrivate</name>
<placement>cm</placement>
<head>Private&nbsp;postcondition:</head>
</tag>
<tag>
<name>time</name>
<placement>cmf</placement>
<head>Time&nbsp;complexity:</head>
</tag>
<tag>
<name>space</name>
<placement>cmf</placement>
<head>Space&nbsp;complexity:</head>
</tag>
<tag>
<name>correspondence</name>
<placement>a</placement>
<head>Correspondence:</head>
</tag>
<tag>
<name>download</name>
<placement>a</placement>
<head>Download:</head>
</tag>
</tags>
<show>protected</show>
<failOnError>false</failOnError>
<sourceFileExcludes>
<sourceFileExclude>**/module-info.java</sourceFileExclude>
</sourceFileExcludes>
</configuration>
</plugin>
<!-- JUnit & JQwik test integration -->
<!-- junit-platform-maven-plugin: supports modular tests
maven-surefire-plugin: non-modular tests
Modular testing works via command line mvn, but is
still broken in Eclipse due to this
https://bugs.eclipse.org/bugs/show_bug.cgi?id=520667
-->
<plugin>
<groupId>de.sormuras.junit</groupId>
<artifactId>junit-platform-maven-plugin</artifactId>
<version>1.0.0-M5</version>
<extensions>true</extensions>
<configuration>
<executor>JAVA</executor>
</configuration>
</plugin>
<!--
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M3</version>
</plugin> -->
<!-- javafx:jlink:
https://github.com/openjfx/javafx-maven-plugin
Use 'mvn package' instead if you don't need jlink.
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.3</version>
<configuration>
<mainClass>${project.mainclass}</mainClass>
</configuration>
</plugin> -->
</plugins>
<extensions>
<!-- Enables the use of SSH for deployments -->
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh-external</artifactId>
<version>3.3.3</version>
</extension>
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
<version>3.3.3</version>
</extension>
</extensions>
</build>
<distributionManagement>
<repository>
<id>ftdev</id>
<name>UTU tech ftdev repository</name>
<url>scp://localhost:2222/var/www/maven2</url>
</repository>
</distributionManagement>
</project>
sbt.version=1.3.8
resolvers += Resolver.jcenterRepo
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.9")
addSbtPlugin("net.aichler" % "sbt-jupiter-interface" % "0.8.3")
addSbtPlugin("com.github.xuwei-k" % "sbt-jshell" % "0.1.2")
//addSbtPlugin("org.xerial.sbt" % "sbt-sql-sqlite" % "0.8")
addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.4.0")
package fi.utu.tech.visualnotes.graphics;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
public enum Color implements Serializable {
Red, Blue, Green, Yellow, Orange, Black, White;
public javafx.scene.paint.Color toFx() {
switch (this) {
case Red:
return javafx.scene.paint.Color.RED;
case Blue:
return javafx.scene.paint.Color.BLUE;
case Green:
return javafx.scene.paint.Color.GREEN;
case Yellow:
return javafx.scene.paint.Color.YELLOW;
case Orange:
return javafx.scene.paint.Color.ORANGE;
case Black:
return javafx.scene.paint.Color.BLACK;
case White:
return javafx.scene.paint.Color.WHITE;
}
return null;
}
public static List<String> names() {
return Arrays.stream(Color.values()).map(Enum::name).collect(Collectors.toList());
}
public static Color random() {
return Color.values()[new Random().nextInt(Color.values().length)];
}
}
\ No newline at end of file
package fi.utu.tech.visualnotes.graphics;
import fi.utu.tech.graphics.Point2D;
import fi.utu.tech.visualnotes.graphics.shapes.Shape;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Collection;
public class Demo {
static void test() throws IOException {
// container for shapes
ShapeGraphRoot root = new ShapeGraphRoot();
// an active view of the shape graph
ShapeGraphView view = new ShapeGraphView(root);
// 500x500 pixel view (10,10) - (510,510)
view.setView(10, 10, 500, 500);
// create a new blue rectangle @ (20,30) - (50,50)
// keep in mind that the shape is created relative
// to the view's top left corner, so it is actually
// located at (30,40) - (60,60)
Shape rect = view.createShape(
Shape.ShapeType.Rectangle,
Color.Blue,
new Point2D(20, 30),
new Point2D(50, 50));
// add the rectangle to the shape graph
root.add(rect);
// list all visible shapes inside the view
// that is, (10,10) - (510,510)
Collection<Shape> shapes = view.visibleShapes();
// the view should contain our rectangle
assert(shapes.size() == 1);
// if we had a graphics context, we could draw the rectangle
// GraphicsContext context = null;
// rect.render(context, view.offset());
// store the graph to a file "test.vin"
root.save(Paths.get("test.vin"));
// restore the graph from the file "test.vin"
root.load(Paths.get("test.vin"));
}
}
package fi.utu.tech.visualnotes.graphics;
import java.io.*;
import java.util.Optional;
/**
* Helpers for serializing to/from byte arrays / base64 strings.
*/
public class ObjectHelper {
public static Optional<byte[]> toBytes(Serializable object) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(object);
return Optional.of(baos.toByteArray());
} catch (IOException e) {
e.printStackTrace();
return Optional.empty();
}
}
@SuppressWarnings("unchecked")
public static <T extends Serializable> Optional<T> fromBytes(byte[] data) {
try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data))) {
return Optional.of((T) ois.readObject());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return Optional.empty();
}
}
}
\ No newline at end of file
package fi.utu.tech.visualnotes.graphics;
import fi.utu.tech.graphics.spatial.rtree.Node;
import fi.utu.tech.graphics.spatial.rtree.Root;
import fi.utu.tech.visualnotes.graphics.shapes.Shape;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
public class ShapeGraphRoot extends Root<Shape> {
public void save(Path path) throws IOException {
Optional<byte[]> data = ObjectHelper.toBytes(tree);
if (data.isEmpty()) return;
Files.write(path, data.get());
System.out.println("Saved to file.");
}
public void load(Path path) throws IOException {
Optional<byte[]> data = ObjectHelper.toBytes(tree);
if (data.isEmpty()) return;
tree = ObjectHelper.<Node<Shape>>fromBytes(Files.readAllBytes(path)).get();
System.out.println("Loaded from file.");
}
}
\ No newline at end of file
package fi.utu.tech.visualnotes.graphics;
import fi.utu.tech.graphics.Point2D;
import fi.utu.tech.graphics.Rect;
import fi.utu.tech.graphics.Region;
import fi.utu.tech.visualnotes.graphics.shapes.Shape;
import java.util.Collection;
import java.util.Optional;
import java.util.function.Consumer;
public class ShapeGraphView {
private final ShapeGraphRoot root;
private final Region view = new Rect(new Point2D(0, 0), new Point2D(0, 0));
public ShapeGraphView(ShapeGraphRoot root) {
this.root = root;
}
public Collection<Shape> visibleShapes() {
return root.findIntersections(view);
}
public Point2D offset() {
return view.topLeft();
}
public void setView(double x, double y, double w, double h) {
// calculate a new view top left
view.topLeft().set(x, y);
setView(w, h);
}
public void setView(double w, double h) {
// calculate a new view bottom right
view.bottomRight().set(view.topLeft()).add(w, h);
}
private final Rect tmp = new Rect(new Point2D(0, 0), new Point2D(0, 0));
private Shape ret = null;
private final Consumer<Shape> selector = s -> ret = s;
public Optional<Shape> extractShape(Point2D p) {
int dist = 3;
tmp.topLeft.set(view.topLeft()).add(p).sub(dist,dist);
tmp.bottomRight.set(view.topLeft()).add(p).add(dist,dist);
ret = null;
root.handleIntersections(tmp, selector);
if (ret == null) return Optional.empty();
root.remove(ret);
return Optional.of(ret);
}
public Shape createShape(Shape.ShapeType type, Color color, Point2D topLeft, Point2D bottomRight) {
return Shape.createShape(type, color, view.topLeft().copy().add(topLeft), view.topLeft().copy().add(bottomRight));
}
}
\ No newline at end of file
package fi.utu.tech.visualnotes.graphics.shapes;
import fi.utu.tech.graphics.Point2D;
import fi.utu.tech.visualnotes.graphics.Color;
import javafx.scene.canvas.GraphicsContext;
public class Line extends Shape {
protected final Point2D p1, p2;
public Line(Color color, Point2D p1, Point2D p2) {
super(color, p1, p2);
this.p1 = p1;
this.p2 = p2;
}
@Override
public Shape move(Point2D offset) {
return new Line(color, p1.copy().add(offset), p2.copy().add(offset));
}
@Override
public void render(GraphicsContext context, Point2D offset) {
super.render(context, offset);
context.strokeLine(p1.x - offset.x, p1.y - offset.y, p2.x - offset.x, p2.y - offset.y);
}
}
\ No newline at end of file
package fi.utu.tech.visualnotes.graphics.shapes;
import fi.utu.tech.graphics.Point2D;
import fi.utu.tech.visualnotes.graphics.Color;
import javafx.scene.canvas.GraphicsContext;
public class Oval extends Shape {
public Oval(Color color, Point2D p1, Point2D p2) {
super(color, p1, p2);
}
@Override
public Shape move(Point2D offset) {
return new Oval(color, topLeft().copy().add(offset), bottomRight().copy().add(offset));
}
@Override
public void render(GraphicsContext context, Point2D offset) {
super.render(context, offset);
if (filled) context.fillOval(topLeft().x - offset.x, topLeft().y - offset.y, bottomRight().x - topLeft().x, bottomRight().y - topLeft().y);
context.strokeOval(topLeft().x - offset.x, topLeft().y - offset.y, bottomRight().x - topLeft().x, bottomRight().y - topLeft().y);
}
}
package fi.utu.tech.visualnotes.graphics.shapes;
import fi.utu.tech.graphics.Point2D;
import fi.utu.tech.visualnotes.graphics.Color;
import javafx.scene.canvas.GraphicsContext;
public class Rectangle extends Shape {
public Rectangle(Color color, Point2D p1, Point2D p2) {
super(color, p1, p2);
}
@Override
public Shape move(Point2D offset) {
return new Rectangle(color, topLeft().copy().add(offset), bottomRight().copy().add(offset));
}
@Override
public void render(GraphicsContext context, Point2D offset) {
super.render(context, offset);
if (filled) context.fillRect(topLeft().x - offset.x, topLeft().y - offset.y, bottomRight().x - topLeft().x, bottomRight().y - topLeft().y);
context.strokeRect(topLeft().x - offset.x, topLeft().y - offset.y, bottomRight().x - topLeft().x, bottomRight().y - topLeft().y);
}
}
package fi.utu.tech.visualnotes.graphics.shapes;
import fi.utu.tech.graphics.Point2D;
import fi.utu.tech.graphics.Region;
import fi.utu.tech.visualnotes.graphics.Color;
import javafx.scene.canvas.GraphicsContext;
public abstract class Shape implements Region, Comparable<Shape> {
public final Color color;
public boolean focused = false;
public boolean filled = false;
private final Point2D topLeft, bottomRight;
private static int zz;
public final int z = zz++;
public Shape(Color color, Point2D p1, Point2D p2) {
this.color = color == null ? Color.Black : color;
if (color != null) filled = true;
this.topLeft = new Point2D(Math.min(p1.x, p2.x), Math.min(p1.y, p2.y));
this.bottomRight = new Point2D(Math.max(p1.x, p2.x), Math.max(p1.y, p2.y));
}
abstract public Shape move(Point2D offset);
@Override
public Point2D topLeft() {
return topLeft;
}
@Override
public Point2D bottomRight() {
return bottomRight;
}
@Override
public int compareTo(Shape o) {
return z - o.z;
}
public void render(GraphicsContext context, Point2D offset) {
javafx.scene.paint.Color c = focused ? color.toFx().invert() : color.toFx();
context.setFill(c);
context.setStroke(c);
}
public enum ShapeType {Line, Oval, Rectangle}
public static Shape createShape(ShapeType type, Color color, Point2D p1, Point2D p2) {
switch (type) {
case Line:
return new Line(color, p1, p2);
case Rectangle:
return new Rectangle(color, p1, p2);
case Oval:
return new Oval(color, p1, p2);
}
return null;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment