This project contains source code in Scala that implements the WCON data format for tracking data. When the text specification and the behavior of the Scala implementation differ, and it is not obvious which one is correct, the behavior of the Scala implementation should be presumed to be authoritative.
This project requires Java 8 and Scala 2.12. You do not need to install Scala explicitly, as the build process is managed by SBT. SBT must be installed to build the project, and it will take care of downloading Scala and any needed libraries.
Type sbt package
in this directory. SBT will tell you where it has
created the jar file. You can include this jar in your classpath.
Here is an example of reading WCON data with the Scala implementation.
This example is meant to run in the SBT console (sbt console
from the
command prompt, when within the src/scala
directory). The scala
REPL works just as well if you put the TrackerCommons jar file on the
classpath.
import org.openworm.trackercommons._
val worms = ReadWrite.read("../../tests/intermediate.wcon") match {
case Right(ws) => ws
case Left(err) => println(err); throw new Exception
}
The ReadWrite
object will attempt to read a data file, delivering an
error message if it cannot. The code above extracts the correct data if
there (the Right
case), and prints the error and throws an exception if
not. (If you don't care about error-handling, replace the match
and following
statements with .right.get
.)
The Scala implementation also contains routines to create data suitable for writing in WCON format. In particular, it helps populate the standard data structures and ensure that minimal requirements are met.
To create a simple WCON data file in memory, one can do something like the following:
import org.openworm.trackercommons._
val one = Create.worm(1).add(
0, Array(-0.6, -0.3, 0, 0.3, 0.6), Array(0, -0.2, 0, 0.2, 0),
ox = 0.6, oy = 0
).add(
1, Array(-0.6, -0.3, 0, 0.3, 0.6), Array(-0.16, 0.04, 0.24, 0.04, -0.16),
ox = 0.9, oy = -0.04
)
val two = Create.worm(2).add(
1, Array(0, 0.2, 0, -0.2, 0), Array(-0.5, -0.25, 0, 0.25, 0.5),
ox = 0, oy = 1.5
)
val wcon = Create.wcon().
addData(one.result, two.result).
setUnits()
val inMemory = wcon.result
val onDisk = wcon.setFile("scala-create-example.wcon").write
Note that the creation methods are meant to be used fluently (i.e. that(arg).other(arg2).more(stuff)
). The reason is that it uses phantom types to make sure you've actually gone through the necessary steps to create a valid WCON file (i.e. you must add some data, and you must set the units; and if you want to write the file, you must set the file).
Worm creation starts with specification of the worm ID, followed by calls to one or more of the large number of add
methods that allow you to specify different subsets of optional data.
Note that all coordinates are global coordinates. If you specify offsets they will be used in the WCON file but not in memory.
Type sbt test
in this directory. The test suite will run, which mostly
involves reading basic and advanced sample files, writing them, and checking
that the output is as expected.
The Tracker Commons code repository will contain code for a variety of languages that may be used to read and write WCON files. The behavior of all of these should be identical. Common sense should be used when output disagrees as to which implementation is correct, but if it is not obvious the Scala version is considered to have the "correct behavior".
Submit a bug report, or make a pull request with a fix! Unless the implmentation is documented to be incomplete, any differences from specification are bugs.
-
Scala's strong typing and functional approach makes it easier to ensure that code is correct.
-
There are parsing libraries available that compactly represent the logic of what you are trying to parse. This makes the gap between text and code especially small, which is an advantage when trying to keep the two synchronized.
-
Rex wrote this code, and he knows Scala well and likes it.