tunnelx-20190701/ 0000775 0001750 0001750 00000000000 13772477744 013120 5 ustar wookey wookey tunnelx-20190701/trunk/ 0000775 0001750 0001750 00000000000 13531571147 014244 5 ustar wookey wookey tunnelx-20190701/trunk/t.bat 0000664 0001750 0001750 00000000362 13531571147 015200 0 ustar wookey wookey REM get the name of the file right for the release
tar --create --gzip --file=tunnel2012-12.tar.gz --transform='s:^:tunnel2012-12/:' src symbols tutorials b.bat j.bat
REM then add this to https://bitbucket.org/goatchurch/tunnelx/downloads
tunnelx-20190701/trunk/AATunnelTopParser.java 0000664 0001750 0001750 00000013426 13531571147 020424 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2011 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// FoUndation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
// See TopParser/readtop.py for the source code
import java.awt.geom.Line2D;
import java.awt.geom.GeneralPath;
import java.util.List;
import java.util.ArrayList;
import java.awt.Font;
import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.Reader;
import java.io.File;
import java.io.FileInputStream;
import java.io.StringReader;
import java.io.FileReader;
import java.io.StreamTokenizer;
import java.io.InputStreamReader;
/////////////////////////////////////////////
class TN
{
static void emitWarning(String s)
{
System.out.println(s);
}
}
/////////////////////////////////////////////
// placeholder class (add more parameters as necessary) which we can use to hold the data
// before it gets imported into other systems (eg tunnel)
class OnePath
{
String stationfrom = "";
String stationto = "";
GeneralPath gp = null;
OnePath() { }
};
/////////////////////////////////////////////
class AATunnelTopParser
{
List paths = new ArrayList();
int version;
/////////////////////////////////////////////
int ReadInt(InputStream inp) throws IOException
{
int b0 = inp.read();
int b1 = inp.read();
int b2 = inp.read();
int b3 = inp.read();
int res = b0 + (b1 << 8) + (b2 << 16) + (b3 << 24);
System.out.println("eee "+b0+" "+b1+" "+b2+" "+b3+" "+res);
return res;
}
/////////////////////////////////////////////
int ReadDate(InputStream inp) throws IOException
{
byte[] sdate = new byte[8];
inp.read(sdate, 0, 8);
System.out.println(ReadInt(inp)+" "+ReadInt(inp));
return 0;
// ticks = struct.unpack('= 128)
{
int commentlength2 = inp.read();
commentlength = commentlength - 128 + 128*commentlength2;
assert commentlength2 < 128;
}
System.out.println("Commentlength "+commentlength);
byte[] cstr = new byte[commentlength];
return new String(cstr);
}
/////////////////////////////////////////////
boolean ParseFile(File tfile)
{ try {
InputStream inp = new FileInputStream(tfile);
byte[] htop = new byte[3];
inp.read(htop, 0, 3);
System.out.println(new String(htop));
assert "Top".equals(new String(htop));
version = inp.read();
TN.emitWarning("We have a top file version " + version);
int ntrips = ReadInt(inp);
for (int i = 0; i < ntrips; i++)
{
ReadDate(inp);
String comments = ReadComments(inp);
System.out.println("::"+comments+"::");
int declination = (inp.read()<<8) + inp.read();
System.out.println("declination "+declination);
}
for (int i = 0; i < 10; i++)
System.out.println(i+" "+inp.read());
inp.close();
}
catch (IOException e)
{
TN.emitWarning(e.toString());
}
return false;
}
/////////////////////////////////////////////
// startup the program
public static void main(String args[])
{
if (args.length != 0)
{
AATunnelTopParser aatunneltopparser = new AATunnelTopParser();
aatunneltopparser.ParseFile(new File(args[0]));
System.out.println("We have read "+aatunneltopparser.paths.size()+" paths");
}
else
TN.emitWarning("need to put in a file name");
}
}
/*
def station(F):
#id's split into major.decimal(minor)
idd = struct.unpack(''
if (flags[0] & 0b00000010) == 0b000000010:
thline['comment'] = comments(F)
return thline
*/
tunnelx-20190701/trunk/bh.bat 0000664 0001750 0001750 00000000060 13531571147 015321 0 ustar wookey wookey "d:\java\jdk1.5.0_03\bin\javac" -d . src\*.java
tunnelx-20190701/trunk/j.bat 0000664 0001750 0001750 00000000557 13531571147 015174 0 ustar wookey wookey dir/b symbols > symbols\listdir.txt
dir/b tutorials > tutorials\listdir.txt
"C:\Program Files\Java\jdk1.6.0_26\bin\jar" cmf tunnelmanifest.txt tunnel.jar Tunnel symbols/*.xml symbols/*.html symbols/listdir.txt tutorials/*.* tutorials/listdir.txt
REM "C:\Program Files\Java\jdk1.6.0_26\bin\jar" i tunnel.jar
REM "C:\Program Files\Java\jdk1.6.0\bin\jar" tf tunnel.jar
tunnelx-20190701/trunk/rerw.bat 0000664 0001750 0001750 00000000155 13531571147 015714 0 ustar wookey wookey java -showversion -ea -Xmx400M -cp . Tunnel.MainBox C:\tunnel\houping\Survey_data\sketches\48h-h12-2-erwang
tunnelx-20190701/trunk/runtunnel.bat 0000775 0001750 0001750 00000000044 13531571147 016767 0 ustar wookey wookey java -Xmx2000M -jar tunnel2019a.jar
tunnelx-20190701/trunk/README.txt 0000664 0001750 0001750 00000004412 13531571147 015743 0 ustar wookey wookey Files locations
---------------
(Julian Todd, 2009-06-21)
The scripts b(.bat) and j(.bat) compile and package a jar file for you,
r runs it with appropriate command line settings.
Vary these according to which compiler version you have.
The default symbols directory is either ~/.tunnelx/symbols/
or /usr/share/tunnelx/symbols/
or tunnelx[current directory]/symbols/ [particularly in Windows].
The tmp file used for calling cavern is ~/.tunnelx/tmp/tunnel_tmp_all.svx
or /tmp/tunnel_tmp_all.svx
or tunnelx[current directory]/tmp/tunnel_tmp_all.svx
The .jar file version additionally contains its own symbols directory
so it can run self-contained like an executable.
Settings can be found in TN.java and FileAbstraction.java,
which include setting the username, project name and password
(in the case of uploading to troggle capability).
Compiling and running Tunnel
----------------------------
(David Loeffler, Sunday 2006-01-22)
To compile Tunnel on a Windows system, grab a DOS window, change to the Tunnel directory and run the following command:
"C:\Program Files\Java\jdk1.5.0_06\bin\javac" -d . -source 1.5 src\*.java
You'll need to have the Java Development Kit installed to do this; it can be downloaded from java.sun.com. You may need to edit the path to the Java compiler, depending on where the installer puts it. The batch file "b.bat" is provided in case you need to do this frequently; but this will only apply to people doing Tunnel development, who can probably work this out for themselves.
For other operating systems, something similar should work; just run the Java compiler in whatever way you normally would on your system. (If anyone feels like trying this out on a Mac and checking that it works, please do so and get in touch.)
Having compiled Tunnel, you can now run it by issuing the command
"C:\Program Files\Java\jdk1.5.0_06\bin\java" -ea -Xmx300m Tunnel.MainBox
(or an appropriate variant if your Java path is different). If you have a Tunnel XML directory set up already, you can load it automatically by giving the path to it at the end of the command line. The -Xmx300m option gives Tunnel 300 megabytes of memory to play with; it can be quite memory-hungry, particularly when dealing with very large surveys, so crank up this number if it's being slow.
tunnelx-20190701/trunk/cavesax.py 0000664 0001750 0001750 00000015221 13531571147 016251 0 ustar wookey wookey import vtk
import sys
from math import sqrt
from xml.sax.handler import ContentHandler
from xml.sax.xmlreader import InputSource
from xml.sax import make_parser
def MakeDelaunConstr(mspts):
onepolylines = vtk.vtkCellArray()
onepolylines.InsertNextCell(mspts.GetNumberOfPoints())
# for i in range(mspts.GetNumberOfPoints()):
# onepolylines.InsertCellPoint(i)
# onepolylines.InsertCellPoint(0)
for i in range(mspts.GetNumberOfPoints()):
onepolylines.InsertCellPoint(mspts.GetNumberOfPoints() - 1 - i)
# onepolylines.InsertCellPoint(mspts.GetNumberOfPoints() - 1)
onepoly = vtk.vtkPolyData()
onepoly.SetPoints(mspts)
onepoly.SetPolys(onepolylines)
delaun = vtk.vtkDelaunay2D()
delaun.SetInput(onepoly)
delaun.SetSource(onepoly)
print mspts.GetNumberOfPoints()
return delaun.GetOutput()
class CHandler(ContentHandler):
def __init__(self):
pass
def FindZ(self, x0, y0, z0, x1, y1, z1, x2, y2):
diffx10 = x1 - x0
diffx20 = x2 - x0
diffy10 = y1 - y0
diffy20 = y2 - y0
n = diffx10 * diffx20 + diffy10 * diffy20
d = diffx10 * diffx10 + diffy10 * diffy10
d = sqrt(d)
r = n / (d * d)
return (1.0 - r) * z0 + r * z1
def startElement(self, name, attrs):
output_function = getattr(self, "start_%s" % name, self.start_unkown_tag)
output_function(name, attrs)
def start_tunnelxpyvtk(self, name, attrs):
self.pyvtkareaIndex = -1
self.appendF = vtk.vtkAppendPolyData()
def start_pyvtkarea(self, name, attrs):
self.pyvtkareaIndex += 1
if self.pyvtkareaIndex % 100 == 0:
print "pyvtkareaIndex:%d" % self.pyvtkareaIndex
self.ms = vtk.vtkFloatArray()
self.mspts = vtk.vtkPoints()
self.ms.SetNumberOfComponents(3)
self.polygon = vtk.vtkPolygon()
def start_path(self, name, attrs):
self.Points = []
for attrName in attrs.keys():
if attrName == "zstart":
self.z0 = float(attrs.get(attrName))
elif attrName == "zend":
self.z1 = float(attrs.get(attrName))
elif attrName == "reversed":
self.reversed = int(attrs.get(attrName))
def start_pt(self, name, attrs):
for attrName in attrs.keys():
if attrName == "x":
self.x = float(attrs.get(attrName))
elif attrName == "y":
self.y = float(attrs.get(attrName))
self.Points.append([self.x,self.y])
def start_unkown_tag(self, name, attrs):
if name == None:
print "Warning:no name given for tag"
else:
print "start of unknown tag:%s" % name
for attrName in attrs.keys():
print "Attribute -- Name: %s Value: %s" % (attrName, attrs.get(attrName))
def endElement(self, name):
output_function = getattr(self, "end_%s" % name, self.end_unkown_tag)
output_function(name)
def end_pyvtkarea(self, name):
self.appendF.AddInput(MakeDelaunConstr(self.mspts))
return
polygon = self.polygon
polygon.GetPoints().SetData(self.ms)
n = polygon.GetPoints().GetNumberOfPoints()
ids = polygon.GetPointIds()
ids.SetNumberOfIds(n)
for i in range(n):
ids.SetId(i,i)
ids = vtk.vtkIdList()
polygon.Triangulate(ids)
numberOfIds = ids.GetNumberOfIds()
numberOfTriangles = numberOfIds / 3
if ids.GetNumberOfIds() != numberOfTriangles * 3:
print "id list should contain a multipul of 3 points"
cellArray = vtk.vtkCellArray()
for triIndex in range(numberOfTriangles):
a = ids.GetId(3 * triIndex)
b = ids.GetId(3 * triIndex + 1)
c = ids.GetId(3 * triIndex + 2)
cellArray.InsertNextCell(3)
cellArray.InsertCellPoint(a)
cellArray.InsertCellPoint(b)
cellArray.InsertCellPoint(c)
pD = vtk.vtkPolyData()
points = vtk.vtkPoints()
points.SetData(self.ms)
pD.SetPoints(points)
#pD.SetPoints(self.polygon.GetPoints())
pD.SetPolys(cellArray)
self.appendF.AddInput(pD)
def end_tunnelxpyvtk(self, name):
print "pyvtkareaIndex:%d" % self.pyvtkareaIndex
def end_path(self, name):
z0 = self.z0
z1 = self.z1
reversed = self.reversed
points = self.Points
if reversed == 1:
points.reverse()
tmp = z0
z0 = z1
z1 = z0
ptstart = points[0]
ptend = points[-1]
x0 = ptstart[0]
y0 = ptstart[1]
x1 = ptend[0]
y1 = ptend[1]
if x0 == x1 and y0 == y1 and z0 != z1:
print "the data is a bit nasty, but I shouldnt crash!"
for point in points[:-1]:
x2 = point[0]
y2 = point[1]
if z0 == z1:
z2 = z0
else:
z2 = self.FindZ(x0, y0, z0, x1, y1, z1, x2, y2)
self.ms.InsertNextTuple3(x2, y2, z2)
self.mspts.InsertNextPoint(x2, y2, z2)
#self.polygon.GetPoints().InsertNextPoint(x2, y2, z2)
def end_pt(self, name):
pass
def end_unkown_tag(self, name):
if name == None:
print "Warning:end of tag:no name given for tag"
else:
print "end of unknown tag:%s" % name
# the main part
xmlfilename = len(sys.argv) >= 2 and sys.argv[1] or 'forsimon.xml'
handler = CHandler()
xmlParser = make_parser()
xmlParser.setContentHandler(handler)
xmlParser.setErrorHandler(handler);
xmlParser.parse(InputSource(xmlfilename))
mapper = vtk.vtkPolyDataMapper()
mapper.SetInput(handler.appendF.GetOutput())
#######
if False:
ppp = [ (0, 0, 0), (0, 3, 0), (2, 3, 1), (3, 6, 1), (0, 6, 0), (0, 10, 0), (10, 10, 0), (10, 0, 0) ]
ppp.reverse()
#del ppp[1]
polylines = vtk.vtkCellArray()
pts = vtk.vtkPoints()
polylines.InsertNextCell(len(ppp) + 1)
i0 = -1
for p in ppp:
i = pts.InsertNextPoint(p[0], p[1], p[2])
if i0 == -1:
i0 = i
polylines.InsertCellPoint(i)
print i
polylines.InsertCellPoint(i0)
polyData = MakeDelaunConstr(pts)
mapMesh = vtk.vtkPolyDataMapper()
mapMesh.SetInput(MakeDelaunConstr(pts))
########
actor = vtk.vtkActor()
actor.SetMapper(mapper)
ren = vtk.vtkRenderer()
renWin = vtk.vtkRenderWindow()
renWin.AddRenderer(ren)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)
ren.AddActor(actor)
ren.SetBackground(0.1, 0.2, 0.4)
renWin.SetSize(500, 500)
cam1 = ren.GetActiveCamera()
cam1.Elevation(-30)
cam1.Roll(-20)
ren.ResetCameraClippingRange()
iren.Initialize()
renWin.Render()
iren.Start()
tunnelx-20190701/trunk/r.bat 0000775 0001750 0001750 00000003702 13531571147 015202 0 ustar wookey wookey REM "C:\Program Files\Java\jdk1.7.0_17\bin\java" -showversion -ea -Xmx2000M -cp . Tunnel.MainBox C:\\otherdevelopment\\cavedata\\englishsurvex\\leckfell.svx
REM "C:\Program Files\Java\jdk1.6.0_17\bin\java" -showversion -ea -Xmx2000M -cp . Tunnel.MainBox C:\\otherdevelopment\\cavedata\\englishsurvex\\Ireby\\Ireby.svx
REM java -showversion -ea -Xmx2000M -cp . Tunnel.MainBox C:\\Users\\goatchurch\\caving\\YorkshireSVN\\mmmmc\\rawscans\\GetDownShep\\getdownshep.top
REM java -showversion -ea -Xmx1000M -cp . Tunnel.MainBox C:\\Users\\goatchurch\\tunneldata
REM java -showversion -ea -Xmx1000M -cp . Tunnel.MainBox http://seagrass.goatchurch.org.uk/~expo/tunneldata/
REM java -showversion -ea -Xmx1000M -cp . Tunnel.MainBox C:\\Users\\goatchurch\\tunneldata\\204-piece-frame-side.xml
java -showversion -ea -Xmx2000M -cp . Tunnel.MainBox C:\\Users\\goatchurch\\caving\\tunneldata
REM java -showversion -ea -Xmx2000M -cp . Tunnel.MainBox C:\\Users\\goatchurch\\caving\\loser\\all.svx
REM java -showversion -ea -Xmx2000M -cp . Tunnel.MainBox C:\\Users\\goatchurch\\caving\\loser\\caves\\107\\107.svx
REM java -showversion -ea -Xmx2000M -cp . Tunnel.MainBox "C:\\Users\\goatchurch\\caving\\expoimages\\surveyscans\\2010\\2010#20"
REM java -showversion -ea -Xmx2000M -cp . Tunnel.MainBox C:\\Users\\goatchurch\\caving\\expoimages\\surveyscans\\2010\\2010#20\\StraightChoiceExposed.top
REM java -showversion -ea -Xmx2000M -cp . Tunnel.MainBox C:\\Users\\goatchurch\\caving\\tunneldata\\161\\dddphumour2.xml
REM java -showversion -ea -Xmx2000M -cp . Tunnel.MainBox C:\\Users\\goatchurch\\caving\\YorkshireSVN\\mmmmc\\tunneldata
REM -- should work when no survex installed by uploading to executable on server
REM -- allow net upload to take path, save on server and commit to mercurial (with username)
REM -- release of jar file which downloads the current conditions from the net and configures itself
REM -- automatic tail uploading of any edits as they happen
tunnelx-20190701/trunk/darkside_build_tunnel.bat 0000664 0001750 0001750 00000000076 13531571147 021271 0 ustar wookey wookey "c:\program files\java\jdk1.5.0_02\bin\javac" -d . src\*.java
tunnelx-20190701/trunk/ri.bat 0000664 0001750 0001750 00000000171 13531571147 015345 0 ustar wookey wookey java -showversion -ea -Xmx1000M -cp . Tunnel.MainBox --makeimages --twotone C:\\Users\\goatchurch\\caving\\tunneldata\\
tunnelx-20190701/trunk/bw.bat 0000664 0001750 0001750 00000000412 13531571147 015341 0 ustar wookey wookey "C:\Program Files\Java\jdk1.6.0\bin\javac" -d . src\*.java
dir/b symbols > symbols\listdir.txt
"C:\Program Files\Java\jdk1.6.0\bin\jar" cmf tunnelmanifest.txt tunnel.jar Tunnel symbols/*.xml symbols/listdir.txt
"C:\Program Files\Java\jdk1.6.0\bin\jar" i tunnel.jar
tunnelx-20190701/trunk/c.bat 0000775 0001750 0001750 00000000101 13531571147 015151 0 ustar wookey wookey "%JAVA_HOME%\bin\javac" -source 1.4 -target 1.4 -d . src\*.java
tunnelx-20190701/trunk/b.bat 0000775 0001750 0001750 00000000326 13531571147 015161 0 ustar wookey wookey "C:\Program Files\Java\jdk1.6.0_26\bin\javac" -source 1.5 -target 1.5 -Xlint:deprecation -d . src\*.java
REM "C:\Program Files\Java\jdk1.7.0_17\bin\javac" -source 1.5 -target 1.5 -Xlint:deprecation -d . src\*.java
tunnelx-20190701/trunk/build 0000775 0001750 0001750 00000001222 13531571147 015266 0 ustar wookey wookey #! /bin/bash
echo "Compiling"
rm Tunnel/*.class
export CLASSPATH=.:j3dcore.jar:j3dutils.jar:vecmath.jar
#export LD_LIBRARY_PATH=/home/goatchurch/expo/tunnelx/j3dlib/i386
javac -target 1.5 -version -d . src/*.java
echo "Buiding jar file"
ls -w1 symbols > symbols\listdir.txt
jar cmf tunnelmanifest.txt tunnel.jar Tunnel symbols/*.xml symbols/listdir.txt symbols/helpfile.html
#jar tf tunnel.jar
echo "Backing up src"
zip -q tunnelsrc src/*java
echo "Copying to mmmmc"
cp tunnel.jar ../mmmmc/tunnelprogram/
cp symbols/*.xml ../mmmmc/tunnelprogram/symbols/
#cp symbols/helpfile.html ../mmmmc/tunnelprogram/symbols/
mv tunnelsrc.zip ../mmmmc/tunnelprogram/
tunnelx-20190701/readme.md 0000664 0001750 0001750 00000002327 13531571147 014664 0 ustar wookey wookey 
# Introduction #
Tunnel is a [free](http://www.gnu.org/) [Java](http://sun.java.net/) 2.5D cave drawing program surveys based on [Survex](http://www.survex.com/)-compatible data which can also read and [PocketTopo](http://paperless.bheeb.ch/) files.
It is used primarily to draw up [CUCC Austria caves](http://expo.survex.com/) and the [Three Counties System](http://cave-registry.org.uk/nengland).
The defining feature (ie why you cannot use a standard drawing software for this application) is the ability to distort the maps to fit to changes to the underlying survey network.
The main alternative to Tunnel is [Therion](http://therion.sk), which also solves this problem, but in a completely different manner and with a slightly steeper learning curve.
# Quickstart #
Download `tunnel2014-08-31.jar` and `runtunnel2014-08-31.bat` (if you are in Windows) from the [downloads page](https://bitbucket.org/goatchurch/tunnelx/downloads), and double-click on the latter file
Read the [inline help file](https://bitbucket.org/goatchurch/tunnelx/wiki/Inline%20help%20file%20) online or from within the program.
tunnelx-20190701/symbols/ 0000775 0001750 0001750 00000000000 13531571147 014571 5 ustar wookey wookey tunnelx-20190701/symbols/mud.xml 0000664 0001750 0001750 00000001713 13531571147 016102 0 ustar wookey wookey
tunnelx-20190701/symbols/bedrock.xml 0000664 0001750 0001750 00000002237 13531571147 016730 0 ustar wookey wookey
tunnelx-20190701/symbols/triangleboulder.xml 0000775 0001750 0001750 00000002032 13531571147 020475 0 ustar wookey wookey
tunnelx-20190701/symbols/stream.xml 0000775 0001750 0001750 00000003267 13531571147 016621 0 ustar wookey wookey
tunnelx-20190701/symbols/stalagmite.xml 0000775 0001750 0001750 00000005147 13531571147 017457 0 ustar wookey wookey
tunnelx-20190701/symbols/helictite.xml 0000664 0001750 0001750 00000003036 13531571147 017267 0 ustar wookey wookey
tunnelx-20190701/symbols/straws.xml 0000664 0001750 0001750 00000003666 13531571147 016651 0 ustar wookey wookey
tunnelx-20190701/symbols/pebble2.xml 0000664 0001750 0001750 00000003473 13531571147 016635 0 ustar wookey wookey
tunnelx-20190701/symbols/bats.xml 0000664 0001750 0001750 00000007434 13531571147 016254 0 ustar wookey wookey
tunnelx-20190701/symbols/pants.xml 0000664 0001750 0001750 00000013136 13531571147 016444 0 ustar wookey wookey
tunnelx-20190701/symbols/northarrowsmall.xml 0000775 0001750 0001750 00000002642 13531571147 020560 0 ustar wookey wookey
tunnelx-20190701/symbols/helpfile.html 0000664 0001750 0001750 00000054171 13531571147 017257 0 ustar wookey wookey Drawing
Click the Left Mouse Button in the graphics pane whilst (optionally) holding down the Shift or Control keys.
- Shift + Left Mouse ends a path
- Control + Left Mouse starts or ends on a node
- Shift+Control + Left Mouse inserts a node on a selected path
The drop-down box in the top left of the window (or single letter buttons 'W' 'E' 'P' 'C' 'D' 'I' 'N' 'F')
sets the type of the selected path, with 'S' controlling the spline. Buttons:
- Delete acts on any number of selected paths
- Back undo last click or button
- Reflect reverses direction of the selected path
- Fuse joins two selected paths
The img tab has a Snap to grid feature where you can change the grid spacing.
Centreline paths cannot be deleted without setting the menu Action -> Allow Delete Centreline.
The Pitch Bound and Ceiling Bound paths have a dash on one side to show the direction of the
'whiskers' (always to the right according to the direction it was drawn). Click Reflect to reverse it.
Connecting to the correct node among an overlapping set (some will be drawn as diamonds and pentagons)
is possible by dragging away from the Control+Left Mouse selected node without releasing it in
order to select the next one.
Viewing
Click and drag with the Middle Mouse Button to move the viewing position.
Zoom with the Scroll-wheel or by holding the Control-key
down before you click and drag the middle mouse.
The View menu contains the Max feature, and Display can turn on station names.
Change the thickness of the lines using the Stroke buttons.
Draw the final result with Detail render.
The view tab shows a second pane where you can store the current view using the Copy button.
Selecting
Click the Right Mouse Button on the desired path
whilst (optionally) holding down the Shift or Control keys.
Multiple clicks cycle through the overlapping paths.
- Control + Right Mouse selects (or deselects) multiple paths
- Shift + Right Mouse selects all paths for an area
The Component button selects all paths that connect to the selected path(s).
Click Component again to select all paths to one side of the selected path(s).
Fuse and fuse translate
Centreline
TunnelX is Survex based. (see http://www.survex.com)
Either use Import -> Import survex file to load the centreline data, or
do File -> Open survex... from the Main window.
The centreline data can be previewed by selecting the dotted green (connective) 'S' to see the label text,
or do Import -> Wireframe view to see the centreline in Survex-Aven.
If Survex is not found, Import -> Use Survex should be disabled,
and TunnelX's computation (without loop closures) will be used.
Do Import -> Import centreline to load the geometry defined by the Survex data.
You can import a centreline as an elevation by including the line:
;IMPORT_AS_ELEVATION 60
somewhere in the survex file (where 60 is the angle of projection).
All this does is loads it through a transformation which swaps the y axis for the z axis.
Backgrounds
Select the img tab for loading and moving the background image.
Add image adds a new image to the background.
Select image requires the rectangle outline of an image to be selected.
Alternatively, use the drop-down box of visible background images.
Move the selected image into position by drawing a single line path and clicking
on the Shift ground button.
Rotate and resize the image by drawing a three point (two line) path before clicking
Shift ground --
the first point is the centre of rotation while the second point is moved to the third point.
Always connect the corner of the rectangle outline of the image to part of the passage
it depicts so that it stays in place when the passage moves.
Not done yet: It will be possible to draw smaller areas to trim out from the
big rectangular paper to show only what is required and to make it possible to render multiple background
images without too much undesirtable overlapping.
This may also be used to bring together scattered cross-sectional outlines.
Files
The Main window show the list of sketch files.
Double-click (or select it and do Tunnel -> View sketch) to work on the drawing.
Open a new file using File -> Open sketch....
The file name is green when it is loaded and up to date,
and red if it needs to be saved.
From the drawing window, use File -> Save as... to give it a different name.
To copy another sketch into the current sketch (while distorting to fit the centreline),
select it in the Main window and do Import -> Import down sketch.
Always preview the import using Preview down sketch.
Sketches can be downloaded from the internet by pasting their 'http://...' url into the file open dialog.
Areas
The Update areas button creates the areas of the sketch by finding the
closed outlines of series of paths that are properly joined up at their nodes.
Paths of type Centreline and Connective are ignored,
but Invisible paths count.
Preview the areas with Display -> Stripe areas.
If areas do not appear, check for failed joins or unintended crossings near nodes,
and that the area itself does not self-intersect.
Disconnected features or rock pillars within an area must be joined with an
Invisible path.
The filling in of a rock pillar is disabled by drawing a Connective path
into it from one of the nodes, clicking Area signal
and selecting rock from the drop-down box.
Then do Update areas to refresh.
Z-depth
The altitude of the paths and nodes are defined by the average of the nearest three centreline stations
(by connectivity). Compute this by clicking the Update Node Z button.
The areas will be sorted by their average altitude and rendered in order.
Paths (and their areas) can be forced to a relative altitude by connecting them
by a Connective line to a centreline node, clicking Area signal,
selecting zsetrelative and changing the 0.0 to
a different displacement.
Select a Pitch Boundary type path and do Action -> Pitch Undercut to
create an Invisible path beneath it connected by two Connective paths,
which can be used for connecting a passage that breaks through the wall below the pitch.
This is necessary because you cannot connect three areas to one path.
Select an area and do Display -> Thin Z Selection to restrict the
drawing to a Z-range close to that which was selected.
Expand this visible area using Display -> Widen Z Selection.
A vertical bar on the left of the graphics area depicts the Z-region in view and selected.
The altitudes of centreline stations can be shown using Display -> Station Altitudes.
Do Colour -> Height to fill in a colour spectrum of heights those visible in the
graphics window at the time (zoom in to a small section of the cave to exaggerate the colour spread for that part).
Symbols
Symbols are placed on Connective paths.
They are always part of the area they point into from the node they join
(though the rest of the path can go outside the area).
Click on Add Symbols and select the chosen symbol.
Some are single symbols (eg stalactite, straws),
directional (eg slope, stream),
and the rest are area filling (eg puddle, boulders).
To render, first Update Areas to bind the symbols into the correct area,
and then Update Symbols to lay them out.
The subs tab allows for setting the subset style for rendering the symbols to different scales.
Symbol files
The symbols directory contains all the basic symbols in the form of little sketches
(eg a single boulder, one stream arrow, etc). You can see and edit them them by doing
Tunnel -> Symbols list from the MainBox.
The fontcolours.xml files contain the real work of defining what happens
for each Subset Style. For example, the baseSymbols250 style defines:
<symbolaut dname="stream" description="stream symbol" multiplicity="1" buttonaction="overwrite" area-interaction="allowed-outside" position="endpath" scale="fixed" orientation="fixed">
<asymbol name="stream" picscale="0.5" orientation="nearaxis"/>
</symbolaut>
A symbol (usually a puddle) can be set to a solid fill colour using the parameter symbolareafillcolour="#ff0000ff".
The symbols directory will be loaded from [current-directory]/symbols if it exists, or
[home-directory]/.tunnelx/symbols (if in unix) or [home-directory]/symbols (if in windows),
or finally /usr/share/tunnelx/symbols/. If none of these exist, it will use the symbols directory
that comes with the .jar file.
Labels
Labels are placed on Connective paths.
Click on Write Text and write the label in the text area,
selecting the type of label from the drop down box.
The origin position is located at the first node of the path.
The 3x3 choice matrix sets which corner or side of the box containing the
text is placed on the origin.
Fine positioning can be done by drawing a short path from the first node
and clicking Fuse.
Always connect one end to the associated passage so it stays with in place
when the passage is moved.
Use the Arrow selection to point at one end, and
the Box to further highlight a label.
Scale bars
Paste one of the following blocks of text into a label to produce a scale bar. Simple version:
- %10/1.0000%%whiterect%
- ;%10/%%blackrect%
- ;%10/%%whiterect%
- ;%10/%%blackrect%
- ;%10/%%whiterect%
- %v1.0/1%
- %10/%0m
- ;%10/%10m
- ;%10/%20m
- ;%10/%30m
- ;%10/%40m
- ;%10/%50m
Complex scale bar:
- %0/1.0000%%v0/%
- ;%50/%%v1/%%whiterect%
- %1/%%v0.5/%
- ;%1/%%v0.5/%%blackrect%
- ;%1/%
- ;%1/%%v0.5/%%blackrect%
- ;%1/%
- ;%5/%%v0.5/%%blackrect%
- ;%5/%%v1/%
- ;%5/%%v0.5/%%blackrect%
- ;%5/%%v1/%
- ;%5/%%v0.5/%%blackrect%
- ;%5/%%v1/%
- ;%5/%%v0.5/%%blackrect%
- ;%5/%%v1/%
- ;%5/%%v0.5/%%blackrect%
- %1/%%v0.5/%%blackrect%
- ;%1/%
- ;%1/%%v0.5/%%blackrect%
- ;%1/%
- ;%1/%%v0.5/%%blackrect%
- ;%5/%
- ;%5/%%v0.5/%%blackrect%
- ;%5/%
- ;%5/%%v0.5/%%blackrect%
- ;%5/%
- ;%5/%%v0.5/%%blackrect%
- ;%5/%
- ;%5/%%v0.5/%%blackrect%
- %v0.8/%
- %4.5/%0m
- ;%5/%5m
- ;%10/%10m
- ;%10/%20m
- ;%10/%30m
- ;%10/%40m
- ;%10/%50m
North arrow:
- N
- %t1/0.1%%v0/%%h0/%
- ;%v3/%%t0/%%h2/%%whiterect%
- %t1/%%v0/%%h0/%
- ;%v3/%%t0/%%h1/%%blackrect%
Left arrow:
- %t2/0.1%%v0/%%h0/%
- ;%v0.5/%%t0/%%h2/%%whiterect%
- %v0.5/0.1%
- %v0.5/%%t0/%%h2/%
- ;%v0.5/%%t2/%%h0/%%blackrect%
Depth scale bar:
- %10/3%%v50/%%blackrect%
- ;1800m
- %10/%%v50.0/%%whiterect%
- ;1600m
- %10/%%v50/%%blackrect%
- ;1500m
- %10/%%v50.0/%%whiterect%
- ;1400m
- %10/%%v50/%%blackrect%
- ;1300m
- %10/%%v50.0/%%whiterect%
- ;1200m
- %10/%%v50/%%blackrect%
- ;1100m
- %10/%%v0/%
- ;1700m
The ';' at the start of the line means the block stays on the same row.
(each new line is displaced down by the vertical height of the first block).
The code '%X/Y%' at the beginning of a block makes it have a width of X/Y metres,
while '%vX/Y' sets its height.
(If 'Y' is left out, then it takes the previous value, so in the first example
the 50m scale bar can be converted to a 500m scale bar by changing 1.0000 to 0.1 in the first line.)
The symbols '%whiterect%' and '%blackrect%' fill the block with an outline or a filled in rectangle.
Alternatively, place text here and use the blocks to define the cells of a table.
The top and bottom widths of a block can be set independently with '%tX/Y' for the top and '%hX/Y' for the bottom (the 'h' is optional)
to produce triangles or parallelograms.
Info
Use the info panel to find information about
paths.
Searching - Fill in the text box and click search to
produce a list of labels the text appears in. Click on the label
to select the path.
Making new paths - Comma or space separated list in
the same search box, then click on New nodes to
add these nodes to the drawn path.
Subsets
The current subset can be selected from the tree view in subs tab.
Select a colour beneath the 'visiblesets' and all the paths will turn grey.
Select a path (Mouse Right) or an area (Shift+Mouse Right) and
click Add to Subset to make it appear in the subset.
Labels should be added to the subset, but their colours will only show after
clicking Detail Render.
Do Clear subset selection to undo the subset selection.
The subsets of a selected path appears in the drop-down box at the bottom,
which can be used for quick selection of an individual subset.
Named subsets can be made by making a Connective path,
clicking Area signal, and choosing frame from the
drop-down box. Above the line '</sketchframe>' (the last line),
insert:
-
<subsetattr uppersubset="blue" name="Secret Grotto"/>
... then click Copy. The tree view in the lower window will now have
'(Secret Grotto)' beneath 'visiblesets' -> 'blue'.
Select it to add paths and areas to the 'Secret Grotto' subset.
The colour can be altered later by changing the value of 'uppersubset'.
The colour set when 'name="default"' applies to all remaining areas.
An uppersubset="obscuredsets" will render the section invisible.
Frame
Start a new empty sketch, and make a Connective path,
click Area signal
and selecting frame from the drop-down box.
Now click Import -> Import paper -> Make A1
to create an A1 size sheet of paper.
Draw a rectangle in it, make a path into it, and make it frame type too.
Now we can add another sketch to it, apply Max, move it around into position,
set its colours, and render it.
It's possible to render the same survey at two different scales in the same
area with different subset styles overlaid on a aerial photo or bitmap of a map.
Also put in all the title box and other clobber in this, so as not to clutter
the main survey with it. Use subset style baseA3page or similar to
find a new set of fonts.
Images can be placed inside areas (as well as other sketches) where they will be trimmed.
This allows for background overlays of aerial imagery.
Multiple sketchs can appear in the same window, where the order is controlled by setting
the nodeconnzsetrelative values.
DistoX TOP files
DistoX laser and compass devices that transmit their measurements to a Windows PDA via bluetooth
saves its data into a binary .top file which contains the survey legs, plan drawing and
elevation drawing in three separate sections.
You can open a .top file by doing
File -> Open survex... from the Main window and selecting it.
This will open both plan and elevation drawings into the same sketch and put the
survey data into the label of the big green 'S'.
Unfortunately, this TOP file cannot be used natively in TunnelX because the lines tend to be
disconnected and sketchy, so you will need to copy and paste the Survex data into its own text file and
link it into the rest of the data by hand, and then render the drawings into two .png files by
selecting the subs tab, then picking plan_TOP in the _Unattributed_ folder
before going to the print tab and rendering the image to a PNG file.
(Don't forget to reset the dots/inch to a higher value for a better quality image.)
Do the same for the elev_TOP subset.
It is important for the subset style to be "pockettopo" for the colours to come out.
Now you can reload the whole survex file and
add the rendering as the background image ready to be traced over.
To render the elevation centreline from a TOP survex file, open the .svx file from the Main window
and click Back to get rid of the plan view. Now you can do
Import -> Import Centreline Elev to generate the extended elevation of this centreline.
The legs that contain flip_TOP are oriented left to right, as well as
any legs that have their tail visited first during the traversal from the starting point
(which is either the first point in the survey, or the nearest fixed point).
Elevations
Provisional owing to user interface difficulties
Drawings for cross sections and extended elevations are tied to a
Connective path by all being in a subset of name "XC stationname" or "ELEV stationname1 stationname2".
To make a cross section, draw a Connective line from a node in one wall across the passage
into a node in the other wall. Then (with the path selected) do Elevation -> XC Subset to
create the new subset (with a name of the form "XC something") and the axis of the cross section
(as a disconnected centreline piece). Move and fit this axis to the cross section (using Fuse and Component)
and then draw around the cross section (connecting it to the axis).
Note that an arrow pointer moves along the corresponding path cutting the passage for the purpose of lining up features
between the plan and the cross section.
To make an extended elevation, draw a Connective line from a centreline node (or a node immediately connected to a centreline)
to another such node, then do Elevation -> Elevation Subset to generate a long centreline path
for use as the axis in the elevation drawing.
After the elevation has been drawn (with all the paths in the "ELEV" subset), the endpoint of the centreline axis
can be moved (using Fuse) to stretch and fit the pieces together.
Use the img tab to see what is happening when the elevation/cross section drawing and corresponding
place in the plan are too far apart to show in the same graphics area at a resonable scale.
Printing
The print tab enables output to PNG or JPG type images, which can then be printed
using standard image handling software. The printing area is either the bounding box for
the currently selected subset (set through the subs tab), or the viewable graphics area.
Select the subset for the A1 frame to produce a consistent result.
The dimensions stated in Real dimensions: correspond to a
baseline scale of 1:1000, so a 500m wide cave will be 50cm on the paper.
Vary the pixel dimensions by changing the resolution in dots per inch (on this 1:1000 paper).
The directory for output and name of file are listed below.
Because the same sketch may appear as in different subset styles,
a proper rendering may require the symbols to be layed out multiple times.
Select Full draw to enable this, or preview using one of the
lesser modes.
Other options include output to Gray scale and Transparent colour to make the white
areas alpha=0 for use in other graphics packages.
Requires re-implementation: If the centreline is in the right coordinate space, click on
Overlay to render it and upload it to the cave map overlay automatically, for maximum
speed of publication.
Command line
To compile do:
"C:\Program Files\Java\jdk1.6.0_26\bin\javac" -target 1.5 -Xlint:deprecation -d . src\*.java
To run do:
java -showversion -ea -Xmx1000M -cp . Tunnel.MainBox C:\\Users\\goatchurch\\tunneldata\\
Other options:
- --verbose
- --quiet
- --todenode
- --netconnection
- --makeimages Automatically generates images from all the areas that have an areasignal of frame and subset "framestyle"
- --printdir=
- --twotone Forces a grey scale which is mapped to black and white pixels at a threshold of 65000
Main - Start here
Welcome to TunnelX, a free Cave drawing system that depends on Survex and which does the
same thing as Therion, except completely different.
See https://bitbucket.org/goatchurch/tunnelx for updates and development.
If this is your first time using TunnelX, try opening the tutorials and double-clicking
on the first one.
Updated 2012-06-01
tunnelx-20190701/symbols/pebble.xml 0000664 0001750 0001750 00000003370 13531571147 016547 0 ustar wookey wookey
tunnelx-20190701/symbols/snow.xml 0000775 0001750 0001750 00000003354 13531571147 016311 0 ustar wookey wookey
tunnelx-20190701/symbols/boulder.xml 0000775 0001750 0001750 00000001417 13531571147 016755 0 ustar wookey wookey
tunnelx-20190701/symbols/bigboulder2.xml 0000775 0001750 0001750 00000002537 13531571147 017525 0 ustar wookey wookey
tunnelx-20190701/symbols/northarrowbig.xml 0000775 0001750 0001750 00000003572 13531571147 020214 0 ustar wookey wookey
tunnelx-20190701/symbols/bigboulder1.xml 0000775 0001750 0001750 00000002462 13531571147 017521 0 ustar wookey wookey
tunnelx-20190701/symbols/npit.xml 0000664 0001750 0001750 00000004056 13531571147 016272 0 ustar wookey wookey
tunnelx-20190701/symbols/puddle.xml 0000775 0001750 0001750 00000002100 13531571147 016564 0 ustar wookey wookey
tunnelx-20190701/symbols/helpfile.md 0000664 0001750 0001750 00000047221 13531571147 016711 0 ustar wookey wookey # Drawing #
Click the **Left Mouse Button** in the graphics pane whilst (optionally) holding down the *Shift* or *Control* keys.
* **Shift** + **Left Mouse** ends a path
* **Control** + **Left Mouse** starts or ends on a node
* **Shift+Control** + **Left Mouse** inserts a node on a selected path
The drop-down box in the top left of the window (or single letter buttons `'W' 'E' 'P' 'C' 'D' 'I' 'N' 'F'`)
sets the type of the selected path, with `**'S'**` controlling the spline. Buttons:
* **Delete** acts on any number of selected paths
* **Back** undo last click or button
* **Reflect** reverses direction of the selected path
* **Fuse** joins two selected paths
The **img** tab has a **Snap to grid** feature where you can change the grid spacing.
Centreline paths cannot be deleted without setting the menu **Action** -> **Allow Delete Centreline**.
The *Pitch Bound* and *Ceiling Bound* paths have a dash on one side to show the direction of the
'whiskers' (always to the right according to the direction it was drawn). Click **Reflect** to reverse it.
Connecting to the correct node among an overlapping set (some will be drawn as diamonds and pentagons)
is possible by dragging away from the *Control+Left Mouse* selected node without releasing it in
order to select the next one.
# Viewing #
Click and drag with the **Middle Mouse Button** to move the viewing position.
Zoom with the **Scroll-wheel** or by holding the **Control-key**
down before you click and drag the middle mouse.
The **View** menu contains the **Max** feature, and **Display** can turn on station names.
Change the thickness of the lines using the **Stroke** buttons.
Draw the final result with **Detail render**.
The **view** tab shows a second pane where you can store the current view using the **Copy** button.
# Selecting #
Click the **Right Mouse Button** on the desired path
whilst (optionally) holding down the *Shift* or *Control* keys.
Multiple clicks cycle through the overlapping paths.
* **Control** + **Right Mouse** selects (or deselects) multiple paths
* **Shift** + **Right Mouse** selects all paths for an area
The **Component** button selects all paths that connect to the selected path(s).
Click **Component** again to select all paths to one side of the selected path(s).
Fuse and fuse translate
# Centreline #
TunnelX is *Survex* based. (see http://www.survex.com)
Either use **Import** -> **Import survex file** to load the centreline data, or
do **File** -> **Open survex...** from the Main window.
The centreline data can be previewed by selecting the dotted green (connective) 'S' to see the label text,
or do **Import** -> **Wireframe view** to see the centreline in *Survex-Aven*.
If *Survex* is not found, **Import** -> **Use Survex** should be disabled,
and TunnelX's computation (without loop closures) will be used.
Do **Import** -> **Import centreline** to load the geometry defined by the *Survex* data.
You can import a centreline as an elevation by including the line:
;IMPORT_AS_ELEVATION 60
somewhere in the survex file (where 60 is the angle of projection).
All this does is loads it through a transformation which swaps the y axis for the z axis.
# Backgrounds #
Select the **img** tab for loading and moving the background image.
**Add image** adds a new image to the background.
**Select image** requires the rectangle outline of an image to be selected.
Alternatively, use the drop-down box of visible background images.
Move the selected image into position by drawing a single line path and clicking
on the **Shift ground** button.
Rotate and resize the image by drawing a three point (two line) path before clicking
**Shift ground** --
the first point is the centre of rotation while the second point is moved to the third point.
Always connect the corner of the rectangle outline of the image to part of the passage
it depicts so that it stays in place when the passage moves.
*Not done yet:* It will be possible to draw smaller areas to trim out from the
big rectangular paper to show only what is required and to make it possible to render multiple background
images without too much undesirtable overlapping.
This may also be used to bring together scattered cross-sectional outlines.
# Files #
The Main window show the list of sketch files.
Double-click (or select it and do **Tunnel** -> **View sketch**) to work on the drawing.
Open a new file using **File** -> **Open sketch...**.
The file name is *green* when it is loaded and up to date,
and *red* if it needs to be saved.
From the drawing window, use **File** -> **Save as...** to give it a different name.
To copy another sketch into the current sketch (while distorting to fit the centreline),
select it in the Main window and do **Import** -> **Import down sketch**.
Always preview the import using **Preview down sketch**.
Sketches can be downloaded from the internet by pasting their 'http://...' url into the file open dialog.
# Areas #
The **Update areas** button creates the areas of the sketch by finding the
closed outlines of series of paths that are properly joined up at their nodes.
Paths of type *Centreline* and *Connective* are ignored,
but *Invisible* paths count.
Preview the areas with **Display** -> **Stripe areas**.
If areas do not appear, check for failed joins or unintended crossings near nodes,
and that the area itself does not self-intersect.
Disconnected features or rock pillars within an area must be joined with an
*Invisible* path.
The filling in of a rock pillar is disabled by drawing a *Connective* path
into it from one of the nodes, clicking **Area signal**
and selecting *rock* from the drop-down box.
Then do **Update areas** to refresh.
# Z-depth #
The altitude of the paths and nodes are defined by the average of the nearest three centreline stations
(by connectivity). Compute this by clicking the **Update Node Z** button.
The areas will be sorted by their average altitude and rendered in order.
Paths (and their areas) can be forced to a relative altitude by connecting them
by a *Connective* line to a centreline node, clicking **Area signal**,
selecting *zsetrelative* and changing the `0.0` to
a different displacement.
Select a *Pitch Boundary* type path and do **Action** -> **Pitch Undercut** to
create an *Invisible* path beneath it connected by two *Connective* paths,
which can be used for connecting a passage that breaks through the wall below the pitch.
This is necessary because you cannot connect three areas to one path.
Select an area and do **Display** -> **Thin Z Selection** to restrict the
drawing to a Z-range close to that which was selected.
Expand this visible area using **Display** -> **Widen Z Selection**.
A vertical bar on the left of the graphics area depicts the Z-region in view and selected.
The altitudes of centreline stations can be shown using **Display** -> **Station Altitudes**.
Do **Colour** -> **Height** to fill in a colour spectrum of heights those visible in the
graphics window at the time (zoom in to a small section of the cave to exaggerate the colour spread for that part).
# Symbols #
Symbols are placed on *Connective* paths.
They are always part of the area they point into from the node they join
(though the rest of the path can go outside the area).
Click on **Add Symbols** and select the chosen symbol.
Some are single symbols (eg stalactite, straws),
directional (eg slope, stream),
and the rest are area filling (eg puddle, boulders).
To render, first **Update Areas** to bind the symbols into the correct area,
and then **Update Symbols** to lay them out.
The **subs** tab allows for setting the subset style for rendering the symbols to different scales.
# Symbol files #
The symbols directory contains all the basic symbols in the form of little sketches
(eg a single boulder, one stream arrow, etc). You can see and edit them them by doing
**Tunnel** -> **Symbols list** from the MainBox.
The *fontcolours.xml* files contain the real work of defining what happens
for each Subset Style. For example, the baseSymbols250 style defines:
```
```
A symbol (usually a puddle) can be set to a solid fill colour using the parameter `symbolareafillcolour="#ff0000ff"`.
The *symbols* directory will be loaded from `[current-directory]/symbols` if it exists, or
`[home-directory]/.tunnelx/symbols` (if in unix) or `[home-directory]/symbols` (if in windows),
or finally `/usr/share/tunnelx/symbols/`. If none of these exist, it will use the symbols directory
that comes with the *.jar* file.
# Labels #
Labels are placed on *Connective* paths.
Click on **Write Text** and write the label in the text area,
selecting the type of label from the drop down box.
The origin position is located at the first node of the path.
The 3x3 choice matrix sets which corner or side of the box containing the
text is placed on the origin.
Fine positioning can be done by drawing a short path from the first node
and clicking **Fuse**.
Always connect one end to the associated passage so it stays with in place
when the passage is moved.
Use the **Arrow** selection to point at one end, and
the **Box** to further highlight a label.
# Scale bars #
Paste one of the following blocks of text into a label to produce a scale bar. Simple version:
```
%10/1.0000%%whiterect%
;%10/%%blackrect%
;%10/%%whiterect%
;%10/%%blackrect%
;%10/%%whiterect%
%v1.0/1%
%10/%0m
;%10/%10m
;%10/%20m
;%10/%30m
;%10/%40m
;%10/%50m
```
Complex scale bar:
```
%0/1.0000%%v0/%
;%50/%%v1/%%whiterect%
%1/%%v0.5/%
;%1/%%v0.5/%%blackrect%
;%1/%
;%1/%%v0.5/%%blackrect%
;%1/%
;%5/%%v0.5/%%blackrect%
;%5/%%v1/%
;%5/%%v0.5/%%blackrect%
;%5/%%v1/%
;%5/%%v0.5/%%blackrect%
;%5/%%v1/%
;%5/%%v0.5/%%blackrect%
;%5/%%v1/%
;%5/%%v0.5/%%blackrect%
%1/%%v0.5/%%blackrect%
;%1/%
;%1/%%v0.5/%%blackrect%
;%1/%
;%1/%%v0.5/%%blackrect%
;%5/%
;%5/%%v0.5/%%blackrect%
;%5/%
;%5/%%v0.5/%%blackrect%
;%5/%
;%5/%%v0.5/%%blackrect%
;%5/%
;%5/%%v0.5/%%blackrect%
%v0.8/%
%4.5/%0m
;%5/%5m
;%10/%10m
;%10/%20m
;%10/%30m
;%10/%40m
;%10/%50m
```
North arrow:
```
N
%t1/0.1%%v0/%%h0/%
;%v3/%%t0/%%h2/%%whiterect%
%t1/%%v0/%%h0/%
;%v3/%%t0/%%h1/%%blackrect%
```
Left arrow:
```
%t2/0.1%%v0/%%h0/%
;%v0.5/%%t0/%%h2/%%whiterect%
%v0.5/0.1%
%v0.5/%%t0/%%h2/%
;%v0.5/%%t2/%%h0/%%blackrect%
```
Depth scale bar:
```
%10/3%%v50/%%blackrect%
;1800m
%10/%%v50.0/%%whiterect%
;1600m
%10/%%v50/%%blackrect%
;1500m
%10/%%v50.0/%%whiterect%
;1400m
%10/%%v50/%%blackrect%
;1300m
%10/%%v50.0/%%whiterect%
;1200m
%10/%%v50/%%blackrect%
;1100m
%10/%%v0/%
;1700m
```
The **';'** at the start of the line means the block stays on the same row.
(each new line is displaced down by the vertical height of the first block).
The code **'%X/Y%'** at the beginning of a block makes it have a width of *X/Y* metres,
while **'%vX/Y'** sets its height.
(If **'Y'** is left out, then it takes the previous value, so in the first example
the 50m scale bar can be converted to a 500m scale bar by changing `1.0000` to `0.1` in the first line.)
The symbols **'%whiterect%'** and **'%blackrect%'** fill the block with an outline or a filled in rectangle.
Alternatively, place text here and use the blocks to define the cells of a table.
The top and bottom widths of a block can be set independently with **'%tX/Y'** for the top and **'%hX/Y'** for the bottom (the 'h' is optional)
to produce triangles or parallelograms.
# Info #
Use the **info** panel to find information about
paths.
**Searching** - Fill in the text box and click *search* to
produce a list of labels the text appears in. Click on the label
to select the path.
**Making new paths** - Comma or space separated list in
the same search box, then click on *New nodes* to
add these nodes to the drawn path.
# Subsets #
The current subset can be selected from the tree view in **subs** tab.
Select a colour beneath the '`visiblesets`' and all the paths will turn grey.
Select a path (*Mouse Right*) or an area (*Shift+Mouse Right*) and
click **Add to Subset** to make it appear in the subset.
Labels should be added to the subset, but their colours will only show after
clicking **Detail Render**.
Do **Clear subset selection** to undo the subset selection.
The subsets of a selected path appears in the drop-down box at the bottom,
which can be used for quick selection of an individual subset.
Named subsets can be made by making a *Connective* path,
clicking **Area signal**, and choosing *frame* from the
drop-down box. Above the line `''` (the last line),
insert:
*
``
... then click **Copy**. The tree view in the lower window will now have
'`(Secret Grotto)`' beneath '`visiblesets`' -> '`blue`'.
Select it to add paths and areas to the 'Secret Grotto' subset.
The colour can be altered later by changing the value of '`uppersubset`'.
The colour set when '`name="default"`' applies to all remaining areas.
# Import relaying sketches
When the centreline gets extended and interlinked to other caves
so that it changes form, it is necessary to recreate it and then
import the drawn sketches distorting them to the new centeline
[keeping them separate]
# Frame #
Start a new empty sketch, and make a *Connective* path,
click **Area signal**
and selecting *frame* from the drop-down box.
Now click **Import** -> **Import paper** -> **Make A1**
to create an *A1* size sheet of paper.
Draw a rectangle in it, make a path into it, and make it *frame* type too.
Now we can add another sketch to it, apply Max, move it around into position,
set its colours, and render it.
It's possible to render the same survey at two different scales in the same
area with different subset styles overlaid on a aerial photo or bitmap of a map.
Also put in all the title box and other clobber in this, so as not to clutter
the main survey with it. Use *subset style* `baseA3page` or similar to
find a new set of fonts.
Images can be placed inside areas (as well as other sketches) where they will be trimmed.
This allows for background overlays of aerial imagery.
Multiple sketchs can appear in the same window, where the order is controlled by setting
the *nodeconnzsetrelative* values.
# DistoX TOP files #
DistoX laser and compass devices that transmit their measurements to a Windows PDA via bluetooth
saves its data into a binary **.top** file which contains the survey legs, plan drawing and
elevation drawing in three separate sections.
You can open a .top file by doing
**File** -> **Open survex...** from the Main window and selecting it.
This will open both plan and elevation drawings into the same sketch and put the
survey data into the label of the big green 'S'.
Unfortunately, this TOP file cannot be used natively in TunnelX because the lines tend to be
disconnected and sketchy, so you will need to copy and paste the Survex data into its own text file and
link it into the rest of the data by hand, and then render the drawings into two .png files by
selecting the **subs** tab, then picking *plan_TOP* in the *_Unattributed_* folder
before going to the **print** tab and rendering the image to a PNG file.
(Don't forget to reset the dots/inch to a higher value for a better quality image.)
Do the same for the *elev_TOP* subset.
It is important for the subset style to be "pockettopo" for the colours to come out.
Now you can reload the whole survex file and
add the rendering as the background image ready to be traced over.
To render the elevation centreline from a TOP survex file, open the .svx file from the Main window
and click **Back** to get rid of the plan view. Now you can do
**Import** -> **Import Centreline Elev** to generate the extended elevation of this centreline.
The legs that contain *flip_TOP* are oriented left to right, as well as
any legs that have their tail visited first during the traversal from the starting point
(which is either the first point in the survey, or the nearest fixed point).
# Elevations #
*Provisional owing to user interface difficulties*
Drawings for cross sections and extended elevations are tied to a
*Connective* path by all being in a subset of name "XC stationname" or "ELEV stationname1 stationname2".
To make a cross section, draw a *Connective* line from a node in one wall across the passage
into a node in the other wall. Then (with the path selected) do **Elevation** -> **XC Subset** to
create the new subset (with a name of the form "XC something") and the axis of the cross section
(as a disconnected centreline piece). Move and fit this axis to the cross section (using **Fuse** and **Component**)
and then draw around the cross section (connecting it to the axis).
Note that an arrow pointer moves along the corresponding path cutting the passage for the purpose of lining up features
between the plan and the cross section.
To make an extended elevation, draw a *Connective* line from a centreline node (or a node immediately connected to a centreline)
to another such node, then do **Elevation** -> **Elevation Subset** to generate a long centreline path
for use as the axis in the elevation drawing.
After the elevation has been drawn (with all the paths in the "ELEV" subset), the endpoint of the centreline axis
can be moved (using **Fuse**) to stretch and fit the pieces together.
Use the **img** tab to see what is happening when the elevation/cross section drawing and corresponding
place in the plan are too far apart to show in the same graphics area at a resonable scale.
# Printing #
The **print** tab enables output to PNG or JPG type images, which can then be printed
using standard image handling software. The printing area is either the bounding box for
the currently selected subset (set through the **subs** tab), or the viewable graphics area.
Select the subset for the *A1 frame* to produce a consistent result.
The dimensions stated in *Real dimensions:* correspond to a
baseline scale of `1:1000`, so a 500m wide cave will be 50cm on the paper.
Vary the pixel dimensions by changing the resolution in dots per inch (on this 1:1000 paper).
The directory for output and name of file are listed below.
Because the same sketch may appear as in different *subset styles*,
a proper rendering may require the symbols to be layed out multiple times.
Select *Full draw* to enable this, or preview using one of the
lesser modes.
Other options include output to *Gray scale* and *Transparent* colour to make the white
areas alpha=0 for use in other graphics packages.
*Requires re-implementation:* If the centreline is in the right coordinate space, click on
**Overlay** to render it and upload it to the cave map overlay automatically, for maximum
speed of publication.
# Command line #
To compile do:
`"C:\Program Files\Java\jdk1.6.0_26\bin\javac" -target 1.5 -Xlint:deprecation -d . src\*.java`
To run do:
`java -showversion -ea -Xmx1000M -cp . Tunnel.MainBox C:\\Users\\goatchurch\\tunneldata\\`
Other options:
* `--verbose`
* `--quiet`
* `--todenode`
* `--netconnection`
* `--makeimages` Automatically generates images from all the areas that have an areasignal of frame and subset "framestyle"
* `--printdir=`
* `--twotone` Forces a grey scale which is mapped to black and white pixels at a threshold of 65000
# Main - Start here #
Welcome to TunnelX, a free Cave drawing system that depends on Survex and which does the
same thing as Therion, except completely different.
See **https://bitbucket.org/goatchurch/tunnelx** for updates and development.
If this is your first time using TunnelX, try opening the tutorials and double-clicking
on the first one.
Updated 2012-06-01
tunnelx-20190701/symbols/curtain.xml 0000664 0001750 0001750 00000002262 13531571147 016762 0 ustar wookey wookey
tunnelx-20190701/symbols/fontcolours_b.xml 0000664 0001750 0001750 00000066073 13531571147 020205 0 ustar wookey wookey
tunnelx-20190701/symbols/flowstone.xml 0000664 0001750 0001750 00000002152 13531571147 017333 0 ustar wookey wookey
tunnelx-20190701/symbols/hexagons.xml 0000664 0001750 0001750 00000005106 13531571147 017131 0 ustar wookey wookey
tunnelx-20190701/symbols/sand.xml 0000664 0001750 0001750 00000001747 13531571147 016251 0 ustar wookey wookey
tunnelx-20190701/symbols/fontcolours.xml 0000664 0001750 0001750 00000011263 13531571147 017673 0 ustar wookey wookey
tunnelx-20190701/symbols/popcorn.xml 0000664 0001750 0001750 00000004072 13531571147 016776 0 ustar wookey wookey
tunnelx-20190701/symbols/column.xml 0000664 0001750 0001750 00000002330 13531571147 016606 0 ustar wookey wookey
tunnelx-20190701/symbols/slope.xml 0000775 0001750 0001750 00000001256 13531571147 016444 0 ustar wookey wookey
tunnelx-20190701/symbols/rats.xml 0000664 0001750 0001750 00000013214 13531571147 016265 0 ustar wookey wookey
tunnelx-20190701/symbols/sump.xml 0000775 0001750 0001750 00000003230 13531571147 016300 0 ustar wookey wookey
tunnelx-20190701/symbols/stalboss.xml 0000664 0001750 0001750 00000007161 13531571147 017152 0 ustar wookey wookey
tunnelx-20190701/symbols/breeze.xml 0000775 0001750 0001750 00000003707 13531571147 016601 0 ustar wookey wookey
tunnelx-20190701/symbols/stalagtite.xml 0000664 0001750 0001750 00000003066 13531571147 017461 0 ustar wookey wookey
tunnelx-20190701/symbols/stalactite.xml 0000664 0001750 0001750 00000003066 13531571147 017455 0 ustar wookey wookey
tunnelx-20190701/symbols/fontcolours_a.xml 0000664 0001750 0001750 00000052571 13531571147 020202 0 ustar wookey wookey
tunnelx-20190701/run 0000775 0001750 0001750 00000000326 13531571147 013634 0 ustar wookey wookey java -showversion -ea -Xmx3000M -cp . Tunnel.MainBox /home/julian/data/expodata/drawings
#java -showversion -ea -Xmx2000M -cp . Tunnel.MainBox /home/goatchurch/caving/NorthernEngland/ThreeCountiesArea/tunneldata
tunnelx-20190701/jmake 0000775 0001750 0001750 00000000350 13531571147 014114 0 ustar wookey wookey ls -1 symbols > symbols/listdir.txt
ls -1 tutorials > tutorials/listdir.txt
jar cmf tunnelmanifest.txt tunnel2019a.jar Tunnel symbols/*.xml symbols/*.html symbols/helpfile.md symbols/listdir.txt tutorials/*.* tutorials/listdir.txt
tunnelx-20190701/tunnelmanifest.txt 0000664 0001750 0001750 00000000035 13531571147 016674 0 ustar wookey wookey Main-Class: Tunnel.MainBox
tunnelx-20190701/.hgignore 0000664 0001750 0001750 00000000037 13531571147 014704 0 ustar wookey wookey syntax: glob
*.class
*~
*.diff
tunnelx-20190701/tutorials/ 0000775 0001750 0001750 00000000000 13531571147 015127 5 ustar wookey wookey tunnelx-20190701/tutorials/060_symbols_areas.xml 0000664 0001750 0001750 00000026117 13531571147 021110 0 ustar wookey wookey
(Go&space;to&space;next&space;lesson)
Symbols&space;in&space;areas
Click&space;on&space;the&space;[Update&space;Areas]&space;button.&newline;Then&space;click&space;on&space;the&space;[Update&space;Symbols&space;Lay]&space;button
Symbols&space;in&space;areas&newline;&newline;Islands&space;in&space;areas&space;invisible&space;lines.&newline;&newline;Pitch&space;holes.
tunnelx-20190701/tutorials/010_lesson_one.xml 0000664 0001750 0001750 00000007612 13531571147 020403 0 ustar wookey wookey
Drawing&space;and&space;selecting
TunnelX&space;is&space;best&space;controlled&space;using&space;a&space;3&space;button&space;mouse&space;&newline;with&space;a&space;scrollwheel.
Click&space;with&space;the&space;Left-mouse&space;button&space;anywhere&space;on&space;this&space;&newline;pane&space;and&space;keep&space;clicking&space;to&space;draw&space;a&space;scribble,&space;like&space;this:
Try&space;drawing&space;some&space;more&space;paths.&newline;&newline;A&space;path&space;is&space;coloured&space;pink&space;when&space;it&space;is&space;selected.&newline;&newline;Click&space;the&space;Right-mouse&space;button&space;on&space;any&space;path&space;to&space;select&space;it.&newline;&newline;When&space;a&space;path&space;is&space;selected&space;you&space;can&space;delete&space;it&space;by&space;clicking&space;on&space;&newline;the&space;[Delete]&space;button&space;in&space;the&space;row&space;of&space;five&space;buttons:&space;&newline;.&space;[Reflect]&space;.&space;[Fuse]&space;.&space;[Component]&space;.&space;[Back]&space;.&space;[Delete]&space;.
Now&space;hold&space;the&space;Shift-key&space;on&space;the&space;keyboard&space;down&space;as&space;you&space;&newline;click&space;the&space;left&space;mouse&space;button&space;again&space;to&space;finish&space;the&space;path.
Now&space;close&space;this&space;window&space;and&space;go&space;&newline;to&space;the&space;next&space;lesson
tunnelx-20190701/tutorials/020_lesson_two.xml 0000664 0001750 0001750 00000003707 13531571147 020435 0 ustar wookey wookey
Hold&space;the&space;Control-key&space;down;&space;&newline;click&space;your&space;Middle-mouse&space;button&space;&newline;on&space;the&space;tiny&space;writing&space;below;&newline;and&space;drag&space;to&space;the&space;right&space;&newline;to&space;zoom
The&space;scroll-wheel&space;can&space;also&space;zoom&space;&newline;into&space;and&space;out&space;from&space;the&space;place&space;where&space;&newline;the&space;Mouse-cursor&space;is&space;pointing.&newline;&newline;The&space;Middle-mouse&space;button&space;on&space;its&space;&newline;own&space;(without&space;the&space;Conrol-key)&space;&newline;will&space;drag&space;the&space;view&space;position.
Once&space;you&space;have&space;mastered&space;these&space;controls,&space;&newline;close&space;this&space;window&space;and&space;go&space;to&space;the&space;next&space;lesson
tunnelx-20190701/tutorials/050_building_areas.xml 0000664 0001750 0001750 00000025377 13531571147 021223 0 ustar wookey wookey
This&space;path&space;isn&apostrophe;t&space;attached.
This&space;path&space;is&space;&newline;attached&space;&newline;with&space;a&space;hook&newline;(zoom&space;in&space;and&space;&newline;[stroke&space;<<]&space;&newline;to&space;look)
Click&space;on&space;the&space;[Update&space;Areas]&space;button.&newline;&newline;This&space;generates&space;the&space;areas&space;from&space;the&space;way&space;the&space;paths&space;&newline;are&space;joined.&space;&space;&newline;&newline;Hold&space;the&space;Shift-key&space;down&space;and&space;Right-mouse&space;click&space;in&newline;an&space;area&space;to&space;select&space;all&space;the&space;paths&space;that&space;are&space;its&space;boundary
There&space;are&space;two&space;mistakes&space;with&space;this&space;diagram
You&space;will&space;have&space;to&space;delete&space;and&space;redraw&space;each&space;&newline;bad&space;path&space;--&space;attaching&space;to&space;the&space;nodes&space;properly&space;--&space;&newline;and&space;then&space;click&space;on&space;[Update&space;Areas]&space;again&space;to&space;&newline;fix&space;the&space;mistake.
Areas&space;are&space;made&space;from&space;paths&space;&newline;which&space;join&space;correctly
(Go&space;to&space;next&space;lesson)
tunnelx-20190701/tutorials/030_lesson_three.xml 0000664 0001750 0001750 00000010411 13531571147 020722 0 ustar wookey wookey
The&space;seven&space;line&space;types&space;are&space;drawn&space;below:&space;&newline;.&space;Wall&space;.&space;Estimated&space;Wall&space;.&space;&newline;.&space;Pitch&space;Boundary&space;.&space;Ceiling&space;Boundary&space;.&space;&newline;.&space;Detail&space;.&space;Invisible&space;.&space;Connective&space;.&space;&space;Filled&space;.
Click&space;on&space;[Detail&space;Render]&space;to&space;see&space;how&space;they&space;&newline;appear&space;in&space;the&space;final&space;drawing.
Select&space;the&space;Wall&space;(W)&space;path&space;&newline;(click&space;on&space;it&space;with&space;the&space;Right-mouse&space;button)&space;&newline;and&space;change&space;its&space;type&space;by&space;using&space;the&space;&newline;drop-down&space;box&space;in&space;the&space;top&space;of&space;the&space;side&space;panel.
Close&space;this&space;window&space;and&space;&newline;go&space;to&space;the&space;next&space;lesson
tunnelx-20190701/tutorials/810_scalebars.xml 0000664 0001750 0001750 00000007424 13531571147 020207 0 ustar wookey wookey
%10/1.0000%%whiterect%&newline;;%10/%%blackrect%&newline;;%10/%%whiterect%&newline;;%10/%%blackrect%&newline;;%10/%%whiterect%&newline;%v1.0/1%&newline;%10/%0m&newline;;%10/%10m&newline;;%10/%20m&newline;;%10/%30m&newline;;%10/%40m&newline;;%10/%50m
%0/1.0000%%v0/%&newline;;%50/%%v1/%%whiterect%&newline;%1/%%v0.5/%&newline;;%1/%%v0.5/%%blackrect%&newline;;%1/%&newline;;%1/%%v0.5/%%blackrect%&newline;;%1/%&newline;;%5/%%v0.5/%%blackrect%&newline;;%5/%%v1/%&newline;;%5/%%v0.5/%%blackrect%&newline;;%5/%%v1/%&newline;;%5/%%v0.5/%%blackrect%&newline;;%5/%%v1/%&newline;;%5/%%v0.5/%%blackrect%&newline;;%5/%%v1/%&newline;;%5/%%v0.5/%%blackrect%&newline;%1/%%v0.5/%%blackrect%&newline;;%1/%&newline;;%1/%%v0.5/%%blackrect%&newline;;%1/%&newline;;%1/%%v0.5/%%blackrect%&newline;;%5/%&newline;;%5/%%v0.5/%%blackrect%&newline;;%5/%&newline;;%5/%%v0.5/%%blackrect%&newline;;%5/%&newline;;%5/%%v0.5/%%blackrect%&newline;;%5/%&newline;;%5/%%v0.5/%%blackrect%&newline;%v0.8/%&newline;%4.5/%0m&newline;;%5/%5m&newline;;%10/%10m&newline;;%10/%20m&newline;;%10/%30m&newline;;%10/%40m&newline;;%10/%50m
N&newline;%t1/0.1%%v0/%%h0/%&newline;;%v3/%%t0/%%h2/%%whiterect%&newline;%t1/%%v0/%%h0/%&newline;;%v3/%%t0/%%h1/%%blackrect%
%10/3%%v50/%%blackrect%&newline;;1800m&newline;%10/%%v50.0/%%whiterect%&newline;;1600m&newline;%10/%%v50/%%blackrect%&newline;;1500m&newline;%10/%%v50.0/%%whiterect%&newline;;1400m&newline;%10/%%v50/%%blackrect%&newline;;1300m&newline;%10/%%v50.0/%%whiterect%&newline;;1200m&newline;%10/%%v50/%%blackrect%&newline;;1100m&newline;%10/%%v0/%&newline;;1700m
%1/1%%v50.0/%&space;&newline;;%15/%%v52.0/%1550m&newline;;%10/%%v50.0/%&space;&newline;%1/%%v50.0/%&newline;;%15/%%v52.0/%1500m&newline;;%10/%%v50.0/%%blackrect%&space;&space;&space;&space;&newline;%1/%%v50.0/%&newline;;%15/%%v52.0/%1450m&space;&newline;;%10/%%v50.0/%%whiterect%&space;&space;&newline;%1/%%v50.0/%&newline;;%15/%%v52.0/%1400m&newline;;%10/%%v50.0/%%blackrect%&space;&space;&space;&space;&newline;%1/%%v50.0/%&newline;;%15/%%v52.0/%1350m&space;&newline;;%10/%%v50.0/%%whiterect%&space;&space;&newline;%1/%%v50.0/%&newline;;%15/%%v52.0/%1300m&newline;;%10/%%v50.0/%%blackrect%&space;&space;&space;&space;&newline;%1/%%v50.0/%&newline;;%15/%%v52.0/%1250m&newline;;%10/%%v50.0/%%whiterect%&space;&space;&newline;%1/%%v50.0/%&newline;;%15/%%v52.0/%1200m&newline;;%10/%%v50.0/%%blackrect%
tunnelx-20190701/tutorials/040_joining_nodes.xml 0000664 0001750 0001750 00000017234 13531571147 021070 0 ustar wookey wookey
None&space;of&space;these&space;paths&newline;are&space;joined
These&space;6&space;paths&space;are&space;&newline;joined&space;at&space;5&space;nodes
You&space;can&space;inspect&space;the&space;junctions&space;by&space;zooming&space;into&space;&newline;them&space;and&space;clicking&space;on&space;the&space;[Stroke&space;<<]&space;button&space;&newline;to&space;change&space;the&space;size&space;of&space;the&space;lines.
Connect&space;these&space;two&space;walls
It&space;is&space;very&space;important&space;that&space;paths&space;&newline;join&space;correctly&space;at&space;their&space;end&space;nodes.
Hold&space;the&space;Control-key&space;&newline;down&space;and&space;Left-mouse&space;&newline;click&space;on&space;this&space;node&space;to&space;&newline;attach&space;the&space;start&space;of&space;&newline;your&space;path&space;here.
Now&space;close&space;this&space;window&space;and&space;go&space;on&space;to&space;the&space;next&space;lesson
Hold&space;the&space;Control-key&newline;down&space;again&space;(while&space;you&space;&newline;are&space;drawing)&space;and&space;Left-&newline;mouse&space;click&space;on&space;this&space;&newline;node&space;to&space;attach&space;the&space;end&space;&newline;of&space;your&space;path&space;here.
tunnelx-20190701/src/ 0000775 0001750 0001750 00000000000 13531571147 013670 5 ustar wookey wookey tunnelx-20190701/src/DepthCol.java 0000664 0001750 0001750 00000004155 13531571147 016242 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.awt.Color;
import java.util.List;
import java.util.ArrayList;
// separates the different colours for depth drawing.
class DepthCol
{
boolean bByAbssolute;
// Range in depth.
float zlo;
float zhi;
// number of slices
int znslices;
Color[] col;
// date list
List svxdates = new ArrayList();
String datelimit = "";
/////////////////////////////////////////////
void SetDateLimit(double slv)
{
int idl = Math.min(svxdates.size() - 1, (int)(slv * svxdates.size()));
datelimit = (idl != -1 ? svxdates.get(idl) : "");
System.out.println("datelimit " + datelimit);
}
/////////////////////////////////////////////
DepthCol()
{
znslices = 10;
col = new Color[znslices];
for (int i = 0; i < znslices; i++)
{
float scz = (float)i / znslices;
col[i] = new Color(Color.HSBtoRGB(scz, 1.0F, 1.0F));
}
}
/////////////////////////////////////////////
// find the range of stations
void AbsorbRange(OneStation os, boolean bFirst)
{
float zval = os.Loc.z;
if (bFirst)
{
zlo = zval;
zhi = zlo;
}
else if (zlo > zval)
zlo = zval;
else if (zhi < zval)
zhi = zval;
}
}
tunnelx-20190701/src/SqliteInterface.java 0000664 0001750 0001750 00000014415 13531571147 017622 0 ustar wookey wookey package Tunnel;
import java.util.List;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
public class SqliteInterface
{
Connection conn;
SqliteInterface(String path)
{ try {
Class.forName("org.sqlite.JDBC");
conn = DriverManager.getConnection("jdbc:sqlite:"+path);
} catch (java.sql.SQLException e) {System.out.println(e);} catch (java.lang.ClassNotFoundException e) {System.out.println(e);} }
void CreateTables()
{ try {
Statement stat = conn.createStatement();
stat.executeUpdate("drop table if exists paths;");
String pathfields = "pathid integer unique, linestyle text, d text, bsplined boolean, "+
"pathidtailleft integer, btailleftfore boolean, "+
"pathidheadright integer, bheadrightfore boolean, "+
"zalttail real, zalthead real";
stat.executeUpdate("create table paths ("+pathfields+");");
// centreline node names and zalt values in separate table?
// also need to insert locx and locy into this scheme
// then some calculated tables of symbol layouts and connected components
stat.executeUpdate("drop table if exists pathsymbols;");
stat.executeUpdate("create table pathsymbols (pathid integer, labsymb text);");
stat.executeUpdate("drop table if exists pathlabels;");
String pathlabelfields = "pathid integer, sfontcode text, drawlab text, fnodeposxrel real, fnodeposyrel real, barrowpresent boolean, bboxpresent boolean";
stat.executeUpdate("create table pathlabels ("+pathlabelfields+");");
stat.executeUpdate("drop table if exists pathareasignals;");
stat.executeUpdate("create table pathareasignals (pathid integer, areasignal text, zsetrelative real);");
stat.executeUpdate("drop table if exists sketchframes;");
String sketchframefields = "pathid integer, sfsketch text, scaledown real, rotatedeg real, xtrans real, ytrans real, submapping text, style text, imagepixelswidth integer, imagepixelsheight integer";
stat.executeUpdate("create table sketchframes ("+sketchframefields+");");
} catch (java.sql.SQLException e) {System.out.println(e);} }
void WritePaths(List vpaths)
{ try {
for (int i = 0; i < vpaths.size(); i++)
vpaths.get(i).svgid = i;
PreparedStatement preppath = conn.prepareStatement("insert into paths values (?,?,?,?,?, ?,?,?,?,?);");
PreparedStatement preppathsymbol = conn.prepareStatement("insert into pathsymbols values (?,?);");
PreparedStatement preppathlabel = conn.prepareStatement("insert into pathlabels values (?,?,?,?,?, ?,?);");
PreparedStatement preppathareasignal = conn.prepareStatement("insert into pathareasignals values (?,?,?);");
PreparedStatement prepsketchframe = conn.prepareStatement("insert into sketchframes values (?,?,?,?,?, ?,?,?,?,?);");
for (OnePath op : vpaths)
{
preppath.setInt(1, op.svgid);
preppath.setString(2, SketchLineStyle.shortlinestylenames[op.linestyle]);
preppath.setString(3, "NOOOOO"); //op.svgdvalue(0.0F, 0.0F));
preppath.setBoolean(4, op.bSplined);
preppath.setInt(5, (op.aptailleft == null ? op.aptailleft.svgid : -1));
preppath.setBoolean(6, op.baptlfore);
preppath.setInt(7, (op.apforeright == null ? op.apforeright.svgid : -1));
preppath.setBoolean(8, op.bapfrfore);
preppath.setFloat(9, op.pnstart.zalt);
preppath.setFloat(10, op.pnend.zalt);
preppath.addBatch();
if (op.plabedl == null)
continue;
for (String labsymb : op.plabedl.vlabsymb)
{
preppathsymbol.setInt(1, op.svgid);
preppathsymbol.setString(2, labsymb);
preppathsymbol.addBatch();
}
if (!op.plabedl.sfontcode.equals(""))
{
preppathlabel.setInt(1, op.svgid);
preppathlabel.setString(2, op.plabedl.sfontcode);
preppathlabel.setString(3, op.plabedl.drawlab);
preppathlabel.setFloat(4, op.plabedl.fnodeposxrel);
preppathlabel.setFloat(5, op.plabedl.fnodeposyrel);
preppathlabel.setBoolean(6, op.plabedl.barrowpresent);
preppathlabel.setBoolean(7, op.plabedl.bboxpresent);
preppathlabel.addBatch();
}
if (op.plabedl.iarea_pres_signal != 0)
{
preppathareasignal.setInt(1, op.svgid);
preppathareasignal.setString(2, SketchLineStyle.areasignames[op.plabedl.iarea_pres_signal]);
preppathareasignal.setFloat(3, op.plabedl.nodeconnzsetrelative);
preppathareasignal.addBatch();
}
if (op.plabedl.barea_pres_signal == SketchLineStyle.ASE_SKETCHFRAME)
{
prepsketchframe.setInt(1, op.svgid);
prepsketchframe.setString(2, op.plabedl.sketchframedef.sfsketch);
prepsketchframe.setFloat(3, op.plabedl.sketchframedef.sfscaledown);
prepsketchframe.setFloat(4, op.plabedl.sketchframedef.sfrotatedeg);
prepsketchframe.setDouble(5, op.plabedl.sketchframedef.sfxtrans);
prepsketchframe.setDouble(6, op.plabedl.sketchframedef.sfytrans);
// Map submapping = new TreeMap();
prepsketchframe.setString(7, "notset");
prepsketchframe.setString(8, op.plabedl.sketchframedef.sfstyle);
prepsketchframe.setInt(9, op.plabedl.sketchframedef.imagepixelswidth);
prepsketchframe.setInt(10, op.plabedl.sketchframedef.imagepixelsheight);
prepsketchframe.addBatch();
}
}
conn.setAutoCommit(false);
preppath.executeBatch();
preppathsymbol.executeBatch();
preppathlabel.executeBatch();
preppathareasignal.executeBatch();
prepsketchframe.executeBatch();
conn.setAutoCommit(true);
} catch (java.sql.SQLException e) {System.out.println(e);} }
} tunnelx-20190701/src/PocketTopoLoader.java 0000664 0001750 0001750 00000031536 13531571147 017761 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2009 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.Stack;
import java.util.Collections;
import java.util.Collection;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
/////////////////////////////////////////////
// This is of the .txt files. For loading the binary .top files
// look at TunnelTopParser.java
/////////////////////////////////////////////
class PocketTopoLoader
{
/////////////////////////////////////////////
int[] splaycounters = new int[512];
StringBuilder sbsvx = new StringBuilder();
StringBuilder sbsvxsplay = new StringBuilder();
List vpathsplan = new ArrayList();
/////////////////////////////////////////////
//FIX
//1.0 0.000 0.000 0.000
void LoadFix(LineInputStream lis) throws IOException
{
assert (lis.GetLine().equals("FIX"));
lis.FetchNextLine();
//1.0 0.000 0.000 0.000
assert lis.w[0].startsWith("1.");
sbsvx.append("*fix\t" + lis.w[0].substring(2) + "\t" + lis.w[1] + "\t" + lis.w[2] + "\t" + lis.w[3] + TN.nl);
lis.FetchNextLine();
}
/////////////////////////////////////////////
//TRIP
//DATE 2009-04-20
//DECLINATION 0.00
//DATA
void LoadTrip(LineInputStream lis) throws IOException
{
assert (lis.GetLine().equals("TRIP"));
lis.FetchNextLine();
assert lis.w[0].equals("DATE");
sbsvx.append("*date\t" + lis.w[1].replace("-", ".") + TN.nl);
lis.FetchNextLine();
assert lis.w[0].equals("DECLINATION");
sbsvx.append("*calibrate\tdeclination\t" + lis.w[1] + TN.nl);
lis.FetchNextLine();
assert lis.GetLine().equals("DATA");
lis.FetchNextLine();
}
/////////////////////////////////////////////
static OnePathNode NewCentrelineNode(String stationlabel, String sx, String sy, float xdisp)
{
String sxy = sx+","+sy;
float x = Float.valueOf(sx) * TN.CENTRELINE_MAGNIFICATION + xdisp;
float y = -Float.valueOf(sy) * TN.CENTRELINE_MAGNIFICATION;
OnePathNode opn = new OnePathNode(x, y, 0.0F);
opn.pnstationlabel = stationlabel + " ".substring(stationlabel.length()) +
sx+","+sy;
return opn;
}
/////////////////////////////////////////////
static OnePathNode FindStationNode(String sx, String sy, List stationnodes, int iss, float xdisp)
{
String sxy = sx+","+sy;
assert ((iss == 0) || (iss == 10));
for (OnePathNode opn : stationnodes)
{
if (sxy.equals(opn.pnstationlabel.substring(iss)))
return opn;
}
// no new nodes in case of the station
if (iss == 10)
return null;
// make new node in case of the sketch
float x = Float.valueOf(sx) * TN.CENTRELINE_MAGNIFICATION + xdisp;
float y = -Float.valueOf(sy) * TN.CENTRELINE_MAGNIFICATION;
OnePathNode opn = new OnePathNode(x, y, 0.0F);
opn.pnstationlabel = sxy;
return opn;
}
/////////////////////////////////////////////
void LoadTopoSketch(LineInputStream lis, List vpaths, float xdisp) throws IOException
{
System.out.println("Loadingplan");
lis.FetchNextLine();
assert (lis.GetLine().equals("STATIONS"));
List stationnodes = new ArrayList();
while (lis.FetchNextLine())
{
if (lis.GetLine().equals("SHOTS"))
break;
assert (lis.iwc == 3);
assert lis.w[2].startsWith("1.");
stationnodes.add(NewCentrelineNode(lis.w[2].substring(2), lis.w[0], lis.w[1], xdisp));
}
List splaynodes = new ArrayList();
assert (lis.GetLine().equals("SHOTS"));
int splaycount = 1;
while (lis.FetchNextLine())
{
if (lis.GetLine().startsWith("POLYLINE"))
break;
if (lis.GetLine().startsWith("ELEVATION"))
break;
if (lis.iwc == 0)
continue;
if (lis.iwc != 4)
lis.emitError("SHOTS line does not have 4 terms");
OnePathNode lpnstart = FindStationNode(lis.w[0], lis.w[1], stationnodes, 10, xdisp);
OnePathNode lpnend = FindStationNode(lis.w[2], lis.w[3], stationnodes, 10, xdisp);
// centreline type
if ((lpnstart != null) && (lpnend != null)) // not splay type
vpaths.add(new OnePath(lpnstart, lpnstart.pnstationlabel.substring(0, 10).trim(), lpnend, lpnend.pnstationlabel.substring(0, 10).trim()));
// build the splay type (sigh)
else if ((lpnstart != null) || (lpnend != null))
{
if (lpnstart == null)
{
lpnstart = NewCentrelineNode(String.valueOf(splaycount++), lis.w[0], lis.w[1], xdisp);
splaynodes.add(lpnstart);
}
if (lpnend == null)
{
lpnend = NewCentrelineNode(String.valueOf(splaycount++), lis.w[2], lis.w[3], xdisp);
splaynodes.add(lpnend);
}
vpaths.add(new OnePath(lpnstart, lpnstart.pnstationlabel.substring(0, 10).trim(), lpnend, lpnend.pnstationlabel.substring(0, 10).trim()));
}
else
lis.emitWarning("Unable to find stations for shot endpoints");
}
for (OnePathNode opn : stationnodes)
opn.pnstationlabel = null;
for (OnePathNode opn : splaynodes)
opn.pnstationlabel = null;
// the sketch
List vnodes = new ArrayList();
if (lis.GetLine().startsWith("ELEVATION"))
return; // missing shots section
assert (lis.GetLine().startsWith("POLYLINE"));
while (true)
{
if (lis.iwc == 0)
break;
assert (lis.iwc == 2);
assert (lis.w[0].equals("POLYLINE"));
String col = lis.w[1];
OnePathNode opnstart = null;
OnePath op = null;
String sx = null;
String sy = null;
while (lis.FetchNextLine())
{
if ((lis.iwc != 2) || lis.w[0].equals("POLYLINE"))
break;
sx = lis.w[0];
sy = lis.w[1];
if (opnstart == null)
{
opnstart = FindStationNode(lis.w[0], lis.w[1], vnodes, 0, xdisp);
op = new OnePath(opnstart);
}
else
{
float x = Float.valueOf(sx) * TN.CENTRELINE_MAGNIFICATION + xdisp;
float y = -Float.valueOf(sy) * TN.CENTRELINE_MAGNIFICATION;
op.LineTo(x, y);
}
}
// case of single point
if (op.nlines == 0)
{
sy = String.valueOf(Float.valueOf(sy) + 0.06F);
float x = Float.valueOf(sx) * TN.CENTRELINE_MAGNIFICATION + xdisp;
float y = -Float.valueOf(sy) * TN.CENTRELINE_MAGNIFICATION;
op.LineTo(x, y);
}
OnePathNode opnend = FindStationNode(sx, sy, vnodes, 0, xdisp);
op.EndPath(opnend);
if (col.equals("CONNECT"))
op.linestyle = SketchLineStyle.SLS_CONNECTIVE;
else if (col.equals("BROWN"))
{
op.linestyle = SketchLineStyle.SLS_DETAIL;
op.vssubsets.add("orange");
}
else if (col.equals("BLACK"))
op.linestyle = SketchLineStyle.SLS_WALL;
else if (col.equals("RED"))
{
op.linestyle = SketchLineStyle.SLS_DETAIL;
op.vssubsets.add("red");
}
else if (col.equals("GRAY"))
{
op.linestyle = SketchLineStyle.SLS_DETAIL;
op.vssubsets.add("strongrey");
}
else if (col.equals("BLUE"))
{
op.linestyle = SketchLineStyle.SLS_DETAIL;
op.vssubsets.add("blue");
}
else if (col.equals("GREEN"))
{
op.linestyle = SketchLineStyle.SLS_DETAIL;
op.vssubsets.add("green");
}
else
{
op.linestyle = SketchLineStyle.SLS_CEILINGBOUND;
System.out.println("Unknown topocolo: " + col);
}
vpaths.add(op);
}
}
/////////////////////////////////////////////
void LoadSVXData(LineInputStream lis) throws IOException
{
lis.FetchNextLine();
if (lis.GetLine().equals("FIX"))
LoadFix(lis);
assert lis.GetLine().equals("TRIP"); // the trip group is at the start, but sometimes there's one halfway through (eg to set the date)
lis.UnFetch();
while (lis.FetchNextLine())
{
if (lis.GetLine().equals("TRIP"))
LoadTrip(lis);
// quit when we have a blank line
if (lis.iwc == 0)
break;
assert !lis.w[0].equals("PLAN");
// 1.19 1.18 351.68 -26.98 6.404 >
assert lis.w[0].startsWith("1.");
if (lis.iwc == 6)
{
assert lis.w[1].startsWith("1.");
// < > indicate the direction on the extended elevation
assert lis.w[5].equals(">") || lis.w[5].equals("<");
sbsvx.append(lis.w[0].substring(2) + "\t" + lis.w[1].substring(2) + "\t" +
lis.w[4] + "\t" + lis.w[2] + "\t" + lis.w[3] + TN.nl);
}
else if (lis.iwc == 5)
{
assert lis.w[4].equals(">") || lis.w[4].equals("<");
String splaystation = lis.w[0].substring(2);
int isplaystation = Integer.valueOf(splaystation);
splaycounters[isplaystation]++;
sbsvxsplay.append(splaystation);
sbsvxsplay.append("\t");
sbsvxsplay.append(splaystation);
sbsvxsplay.append("_");
sbsvxsplay.append(splaycounters[isplaystation]);
sbsvxsplay.append("\t");
sbsvxsplay.append(lis.w[3] + "\t" + lis.w[1] + "\t" + lis.w[2] + TN.nl);
}
else
assert false; // unknown string format
}
}
/////////////////////////////////////////////
void LoadPockettopo(FileAbstraction loadfile)
{
try
{
LineInputStream lis = new LineInputStream(loadfile.GetInputStream(), loadfile, null, null);
LoadSVXData(lis);
lis.FetchNextLine();
if (lis.GetLine().equals("PLAN"))
LoadTopoSketch(lis, vpathsplan, 0.0F);
lis.FetchNextLine();
if (lis.GetLine().equals("ELEVATION"))
LoadTopoSketch(lis, vpathsplan, 1000.F);
if (!lis.FetchNextLine())
{
TN.emitWarning("Unaccounted lines");
lis.UnFetch();
while (lis.FetchNextLine())
System.out.println("Unnacounted line: " + lis.GetLine());
}
lis.inputstream.close();
}
catch (IOException e)
{ TN.emitError(e.toString()); };
}
/////////////////////////////////////////////
String GetSVX()
{
return sbsvx.toString() + TN.nl + "*flags splay" + TN.nl + sbsvxsplay.toString() + TN.nl;
}
/////////////////////////////////////////////
static boolean IsPocketTopo(String sfilehead)
{
if (sfilehead.indexOf("FIX") == 0)
return true;
if (sfilehead.indexOf("TRIP") == 0)
return true;
return false;
}
}
tunnelx-20190701/src/LineStyleAttr.java 0000664 0001750 0001750 00000012272 13531571147 017302 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2007 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.awt.BasicStroke;
import java.awt.Font;
import java.awt.Color;
/////////////////////////////////////////////
class LineStyleAttr
{
static int Nlinestyles = 9; // takes in SLS_FILLED
int linestyle;
private String sstrokewidth;
private String sspikegap;
private String sgapleng;
private String sspikeheight;
private String sstrokecolour;
Color strokecolour;
float strokewidth;
float spikegap;
float gapleng;
float spikeheight;
BasicStroke linestroke = null;
String Dsubsetname = "";
String Duppersubsetname = "";
/////////////////////////////////////////////
LineStyleAttr(LineStyleAttr lls)
{
linestyle = lls.linestyle;
sstrokewidth = lls.sstrokewidth;
sspikegap = lls.sspikegap;
sgapleng = lls.sgapleng;
sspikeheight = lls.sspikeheight;
sstrokecolour = lls.sstrokecolour;
Dsubsetname = lls.Dsubsetname;
Duppersubsetname = lls.Duppersubsetname;
//System.out.println("sg3 " + sspikegap + " ls " + linestyle);
}
/////////////////////////////////////////////
LineStyleAttr(int llinestyle, String lsstrokewidth, String lsspikegap, String lsgapleng, String lsspikeheight, String lsstrokecolour, String lDsubsetname)
{
linestyle = llinestyle;
sstrokewidth = lsstrokewidth;
sspikegap = lsspikegap;
sgapleng = lsgapleng;
sspikeheight = lsspikeheight;
sstrokecolour = lsstrokecolour;
//System.out.println("sg2 " + sspikegap + " ls " + linestyle);
Dsubsetname = lDsubsetname;
}
/////////////////////////////////////////////
LineStyleAttr(int llinestyle, float lstrokewidth, float lspikegap, float lgapleng, float lspikeheight, Color lstrokecolour)
{
//assert lstrokecolour != null;
linestyle = llinestyle;
strokewidth = lstrokewidth;
spikegap = lspikegap;
gapleng = lgapleng;
spikeheight = lspikeheight;
strokecolour = lstrokecolour;
Dsubsetname = "SetStrokeWidthskind";
SetUpBasicStroke();
}
/////////////////////////////////////////////
void Construct(SubsetAttr lsubsetattr, Color defaultcolor)
{
strokewidth = SubsetAttr.ConvertFloat(lsubsetattr.EvalVars(sstrokewidth), (linestyle != SketchLineStyle.SLS_FILLED ? 2.0F : 0.0F));
spikegap = SubsetAttr.ConvertFloat(lsubsetattr.EvalVars(sspikegap), 0.0F);
gapleng = SubsetAttr.ConvertFloat(lsubsetattr.EvalVars(sgapleng), 0.0F);
spikeheight = SubsetAttr.ConvertFloat(lsubsetattr.EvalVars(sspikeheight), 0.0F);
gapleng = SubsetAttr.ConvertFloat(lsubsetattr.EvalVars(sgapleng), 0.0F);
strokecolour = SubsetAttr.ConvertColour(lsubsetattr.EvalVars(sstrokecolour), defaultcolor);
Dsubsetname = lsubsetattr.subsetname;
SetUpBasicStroke();
}
/////////////////////////////////////////////
void SetUpBasicStroke()
{
if (linestyle == SketchLineStyle.SLS_FILLED)
{
if (strokewidth != 0.0F)
TN.emitWarning("nonzero strokewidth " + strokewidth + " on filled line");
}
else
{
if (strokewidth == 0.0F && strokecolour != null)
TN.emitWarning("zero strokewidth on line style; use colour=null; colour was " + strokecolour.toString());
}
if (spikeheight != 0.0F)
{
if ((linestyle != SketchLineStyle.SLS_PITCHBOUND) && (linestyle != SketchLineStyle.SLS_CEILINGBOUND))
TN.emitWarning("spikes only on pitch and ceiling bounds please");
}
// setup the basicstroke
if (strokewidth != 0.0F)
{
// dotted
float mitrelimit = strokewidth * 5.0F;
if ((gapleng != 0.0F) && (spikeheight == 0.0F))
{
float[] dash = new float[2];
dash[0] = spikegap - gapleng;
if (dash[0] < 0)
TN.emitError("Dash phase (spikegap - gaplength) is negative)");
dash[1] = gapleng;
linestroke = new BasicStroke(strokewidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, mitrelimit, dash, dash[0] / 2);
}
else
linestroke = new BasicStroke(strokewidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, mitrelimit);
}
}
/////////////////////////////////////////////
LineStyleAttr(int llinestyle)
{
linestyle = llinestyle;
Dsubsetname = "LineStyleAttr_int_llinestyle";
}
/////////////////////////////////////////////
float GetStrokeWidth()
{
return strokewidth;
}
/////////////////////////////////////////////
void SetColor(Color lcolour)//Used when you want to override the color, eg when colouring by altitude
{
strokecolour = lcolour;
}
}
tunnelx-20190701/src/TunnelXMLparsebase.java 0000664 0001750 0001750 00000006602 13531571147 020253 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// FoUndation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
class TunnelXMLparsebase
{
String[] attnamestack = new String[50];
String[] attvalstack = new String[50];
String[] elemstack = new String[20];
int[] iposstack = new int[20];
int istack = 0;
/////////////////////////////////////////////
String SeStack(String name)
{
for (int i = (istack != 0 ? iposstack[istack - 1] : 0) - 1; i >= 0; i--)
{
if (attnamestack[i].equals(name))
return attvalstack[i];
}
return null;
}
/////////////////////////////////////////////
String SeStack(String name, String defalt)
{
String res = SeStack(name);
return (res == null ? defalt : res);
}
/////////////////////////////////////////////
double DeStack(String name)
{
String snumber = SeStack(name);
if (snumber == null)
throw new RuntimeException("no number with attribute name: " + name);
return Double.parseDouble(snumber);
}
/////////////////////////////////////////////
double DeStack(String name, double defalt)
{
String snumber = SeStack(name);
if (snumber == null)
return defalt;
return Double.parseDouble(snumber);
}
/////////////////////////////////////////////
int IeStack(String name)
{
String snumber = SeStack(name);
if (snumber == null)
throw new RuntimeException("no number with attribute name: " + name);
return Integer.parseInt(snumber);
}
/////////////////////////////////////////////
int IeStack(String name, int defalt)
{
String snumber = SeStack(name);
if (snumber == null)
return defalt;
return Integer.parseInt(snumber);
}
/////////////////////////////////////////////
boolean ElStack(String name)
{
for (int i = istack - 1; i >= 0; i--)
{
if (elemstack[i].equals(name))
return true;
}
return false;
}
/////////////////////////////////////////////
void StackDump()
{
for (int i = istack - 1; i >= 0; i--)
{
System.out.print("stackdump-- " + elemstack[i] + ":");
for (int j = (i != 0 ? iposstack[i - 1] : 0); j < iposstack[i]; j++)
System.out.print(" " + attnamestack[j] + "=" + attvalstack[j]);
System.out.println("");
}
}
/////////////////////////////////////////////
public void startElementAttributesHandled(String name, boolean binlineclose)
{
}
/////////////////////////////////////////////
public void characters(String pstr)
{
}
/////////////////////////////////////////////
public void endElementAttributesHandled(String name)
{
}
/////////////////////////////////////////////
void SetUpBase()
{
istack = 0;
}
};
tunnelx-20190701/src/SketchGrid.java 0000664 0001750 0001750 00000012611 13531571147 016563 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2005 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.awt.geom.Point2D;
import java.awt.geom.Line2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.Graphics2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.Dimension;
/////////////////////////////////////////////
class SketchGrid
{
float xorig = 0.0F;
float yorig = 0.0F;
float[] gridspacing = new float[20];
int[] gridlineslimit = new int[20];
int ngridspacing = 0; // the sizes of the above dynamic arrays
int igridspacing = 0; // the chosen index of the grid spacing
float gridspace = 1.0F;
// a temporary copy of the grid origin which can be set and reset
float txorig = 0.0F;
float tyorig = 0.0F;
// the region the lines are drawn in
float xlo, xhi, ylo, yhi;
int ixlo, ixhi, iylo, iyhi; // the index positions of the lines
GeneralPath gpgrid = new GeneralPath();
/////////////////////////////////////////////
SketchGrid(float lxorig, float lyorig)
{
xorig = lxorig;
txorig = lxorig;
yorig = lyorig;
tyorig = lyorig;
}
/////////////////////////////////////////////
public void SetGridSpacing(int gsoffset)
{
float mwid = Math.max(xhi - xlo, yhi - ylo);
int ligridspacing;
for (ligridspacing = 0; ligridspacing < ngridspacing; ligridspacing++)
{
float lgridspace = gridspacing[ligridspacing] * TN.CENTRELINE_MAGNIFICATION;
if (mwid / lgridspace < gridlineslimit[ligridspacing])
break;
}
// set the values incl the offset
igridspacing = Math.max(0, Math.min(ngridspacing - 1, ligridspacing + gsoffset));
gridspace = gridspacing[igridspacing] * TN.CENTRELINE_MAGNIFICATION;
assert gridspace != 0.0;
// set the index positions
// xlo < ixlo * gridspace + xorig
ixlo = (int)Math.floor((xlo - txorig) / gridspace) + 1;
ixhi = (int)Math.floor((xhi - txorig) / gridspace);
iylo = (int)Math.floor((ylo - tyorig) / gridspace) + 1;
iyhi = (int)Math.floor((yhi - tyorig) / gridspace);
if (igridspacing == gridlineslimit.length - 1)
{
int gridlinelimit = gridlineslimit[igridspacing];
int xdi = ((ixhi - ixlo) - gridlinelimit) / 2;
if (xdi > 0)
{
ixlo += xdi;
ixhi -= xdi;
}
int ydi = ((iyhi - iylo) - gridlinelimit) / 2;
if (ydi > 0)
{
iylo += ydi;
iyhi -= ydi;
}
}
}
/////////////////////////////////////////////
public void GenerateMetreGrid()
{
gpgrid.reset();
for (int i = ixlo; i <= ixhi; i++)
{
gpgrid.moveTo(i * gridspace + txorig, ylo);
gpgrid.lineTo(i * gridspace + txorig, yhi);
}
for (int i = iylo; i <= iyhi; i++)
{
gpgrid.moveTo(xlo, i * gridspace + tyorig);
gpgrid.lineTo(xhi, i * gridspace + tyorig);
}
}
/////////////////////////////////////////////
boolean ClosestGridPoint(Point2D res, double ptx, double pty, double scale)
{
int ix = (int)Math.floor((ptx - txorig) / gridspace + 0.5F);
int iy = (int)Math.floor((pty - tyorig) / gridspace + 0.5F);
if ((ix < ixlo) || (ix > ixhi) || (iy < iylo) || (iy > iyhi))
return false;
res.setLocation(ix * gridspace + txorig, iy * gridspace + tyorig);
double md = Math.max(Math.abs(res.getX() - ptx), Math.abs(res.getY() - pty));
return ((scale == -1.0) || (md < scale));
}
/////////////////////////////////////////////
Point2D.Float gridscrcorner = new Point2D.Float();
Point2D.Float scrcorner = new Point2D.Float();
void SetUntransRanges(float tx, float ty, AffineTransform currtrans, boolean bfirst) throws NoninvertibleTransformException
{
scrcorner.setLocation(tx, ty);
currtrans.inverseTransform(scrcorner, gridscrcorner);
float x = (float)gridscrcorner.getX();
float y = (float)gridscrcorner.getY();
if (bfirst || (x < xlo))
xlo = x;
if (bfirst || (x > xhi))
xhi = x;
if (bfirst || (y < ylo))
ylo = y;
if (bfirst || (y > yhi))
yhi = y;
}
/////////////////////////////////////////////
void UpdateGridCoords(Dimension csize, AffineTransform currtrans, boolean bhasrotation, SketchBackgroundPanel backgroundpanel)
{
try
{
SetUntransRanges(0.0F, 0.0F, currtrans, true);
SetUntransRanges(csize.width, csize.height, currtrans, false);
if (bhasrotation)
{
SetUntransRanges(csize.width, 0.0F, currtrans, false);
SetUntransRanges(0.0F, csize.height, currtrans, false);
}
}
catch (NoninvertibleTransformException ex)
{;}
int pigridspacing = igridspacing;
SetGridSpacing(backgroundpanel.gsoffset);
if (pigridspacing != igridspacing)
backgroundpanel.tfgridspacing.setText(String.valueOf(gridspacing[igridspacing]));
GenerateMetreGrid();
}
};
tunnelx-20190701/src/WarpPiece.java 0000664 0001750 0001750 00000014020 13531571147 016407 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2009 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.util.List;
import java.awt.geom.Point2D;
import java.awt.geom.GeneralPath;
// class used for warping a path when FuseNodes is used, either in plan or elevation case
/////////////////////////////////////////////
class WarpPiece
{
static final int WARP_NORMALWARP = 0;
static final int WARP_SHEARWARP = 1;
static final int WARP_ZWARP = 2;
int iwarp;
// the line from and line to
OnePathNode pnstart;
OnePathNode pnend;
OnePathNode npnstart;
OnePathNode npnend;
// initial vector
double xv;
double yv;
double vsq;
// final vector
double nxv;
double nyv;
double nvsq;
// translation vector for shear warp
double xt = 0.0;
double yt = 0.0;
/////////////////////////////////////////////
void SetUpVectors()
{
// initial vector
xv = pnend.pn.getX() - pnstart.pn.getX();
yv = pnend.pn.getY() - pnstart.pn.getY();
vsq = xv * xv + yv * yv;
// final vector
nxv = npnend.pn.getX() - npnstart.pn.getX();
nyv = npnend.pn.getY() - npnstart.pn.getY();
nvsq = nxv * nxv + nyv * nyv;
}
/////////////////////////////////////////////
// construct from one end path drag (bug could do total move)
WarpPiece(OnePathNode pnfrom, OnePathNode pnto, OnePath axop, int liwarp)
{
iwarp = liwarp;
pnstart = axop.pnstart;
pnend = axop.pnend;
npnstart = (axop.pnstart == pnfrom ? pnto : axop.pnstart);
npnend = (axop.pnend == pnfrom ? pnto : axop.pnend);
xt = pnto.pn.getX() - pnfrom.pn.getX();
yt = pnto.pn.getY() - pnfrom.pn.getY();
SetUpVectors();
}
/////////////////////////////////////////////
WarpPiece(OnePathNode lpnstart, OnePathNode lpnend, OnePathNode lnpnstart, OnePathNode lnpnend)
{
iwarp = WARP_ZWARP;
pnstart = lpnstart;
pnend = lpnend;
npnstart = lnpnstart;
npnend = lnpnend;
SetUpVectors();
}
/////////////////////////////////////////////
void WarpPoint(Point2D res, double x, double y)
{
// translation case (if endpoints match).
if ((vsq == 0.0) || (nvsq == 0.0))
{
if ((vsq != 0.0) || (nvsq != 0.0))
TN.emitWarning("Bad warp: only one axis vector is zero length");
res.setLocation(x + xt, y + yt);
}
// by shearing
else if (iwarp == WARP_SHEARWARP)
{
double vix = x - pnstart.pn.getX();
double viy = y - pnstart.pn.getY();
double lam = (vix * xv + viy * yv) / vsq;
res.setLocation(x + lam * xt, y + lam * yt);
}
else if (iwarp == WARP_ZWARP)
{
if ((xv == 0.0) || (nxv == 0.0))
TN.emitWarning("zwarp on zero x axis");
double vix = x - pnstart.pn.getX();
double viy = y - pnstart.pn.getY();
double lam = (xv != 0.0 ? vix / xv : (vix * xv + viy * yv) / vsq); // goes to other warp when zero
//float ay = (float)pnstart.pn.getY() + lam * yv;
double dy = viy - lam * yv;
res.setLocation(npnstart.pn.getX() + lam * nxv, npnstart.pn.getY() + lam * nyv + dy);
}
// rotation case (one endpoint matches)
else
{
assert (iwarp == WARP_NORMALWARP);
double vix = x - pnstart.pn.getX();
double viy = y - pnstart.pn.getY();
double lam = (vix * xv + viy * yv) / vsq;
double plam = (vix * (-yv) + viy * (xv)) / vsq;
res.setLocation(npnstart.pn.getX() + lam * nxv + plam * (-nyv), npnstart.pn.getY() + lam * nyv + plam * (nxv));
}
}
/////////////////////////////////////////////
OnePath WarpPathS(OnePath op)
{
assert pnstart == op.pnstart;
assert pnend == op.pnend;
float[] pco = op.GetCoords();
OnePath res = new OnePath(npnstart);
Point2D pt = new Point2D.Float();
for (int i = 1; i < op.nlines; i++)
{
WarpPoint(pt, pco[i * 2], pco[i * 2 + 1]);
res.LineTo((float)pt.getX(), (float)pt.getY());
}
res.EndPath(npnend);
res.CopyPathAttributes(op);
return res;
}
/////////////////////////////////////////////
OnePathNode WarpElevationNode(OnePathNode opn, List nopelevarr, List opelevarr, Point2D ptspare)
{
System.out.println("node " + opn.pn.getX() + "," + opn.pn.getY());
if (opn == pnstart)
return npnstart;
if (opn == pnend)
return npnend;
for (int i = 0; i < nopelevarr.size(); i++)
{
if (opn == opelevarr.get(i).pnstart)
return nopelevarr.get(i).pnstart;
if (opn == opelevarr.get(i).pnend)
return nopelevarr.get(i).pnend;
}
WarpPoint(ptspare, opn.pn.getX(), opn.pn.getY());
System.out.println(" tonode " + ptspare.getX() + "," + ptspare.getY());
return new OnePathNode((float)ptspare.getX(), (float)ptspare.getY(), 0.0F);
}
/////////////////////////////////////////////
void WarpElevationBatch(List res, List opelevarr)
{
Point2D ptspare = new Point2D.Float();
assert res.isEmpty();
for (int j = 0; j < opelevarr.size(); j++)
{
OnePath op = opelevarr.get(j);
float[] pco = op.GetCoords();
System.out.println("web " + j + " " + op.nlines + " x " + pco[0]);
OnePath nop = new OnePath(WarpElevationNode(op.pnstart, res, opelevarr, ptspare));
for (int i = 1; i < op.nlines; i++)
{
WarpPoint(ptspare, pco[i * 2], pco[i * 2 + 1]);
nop.LineTo((float)ptspare.getX(), (float)ptspare.getY());
}
nop.EndPath(WarpElevationNode(op.pnend, res, opelevarr, ptspare));
nop.CopyPathAttributes(op);
res.add(nop);
}
}
};
tunnelx-20190701/src/TodeNode.java 0000664 0001750 0001750 00000140165 13531571147 016243 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2010 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JToggleButton;
import javax.swing.JTextField;
import javax.swing.JLabel;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Line2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.AffineTransform;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.GridLayout;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
/////////////////////////////////////////////
class DoubleArray
{
double[] arr = null;
int sz = 0;
void add(double val)
{
if (arr == null)
arr = new double[2];
else if (sz == arr.length)
{
double[] larr = arr;
arr = new double[larr.length * 2];
for (int i = 0; i < larr.length; i++)
arr[i] = larr[i];
}
arr[sz] = val;
sz++;
}
double pop()
{
sz--;
return arr[sz];
}
int size()
{
return sz;
}
double get(int i)
{
assert ((i >= 0) && (i < sz));
return arr[i];
}
void sort()
{
if (sz != 0)
Arrays.sort(arr, 0, sz);
}
public String toString()
{
StringBuffer sb = new StringBuffer();
for (int i = 0; i < sz; i++)
sb.append((i == 0 ? "" : " ") + String.format("%.3f", get(i)));
return sb.toString();
}
public String toStringRel()
{
StringBuffer sb = new StringBuffer();
for (int i = 0; i < sz; i++)
sb.append((i == 0 ? "" : " ") + String.format("%.3f", get(i) - get(0)));
return sb.toString();
}
}
/////////////////////////////////////////////
/////////////////////////////////////////////
class IntensityWedge
{
double t0;
double e0;
double t1;
double e1;
double slope;
IntensityWedge(double lt0, double le0, double lt1, double le1)
{
t0 = lt0;
e0 = le0;
t1 = lt1;
e1 = le1;
slope = (e1 - e0) / (t1 - t0);
}
/////////////////////////////////////////////
double GetIntensityW(double eT)
{
assert (t0 <= eT) && (eT <= t1);
double lam = (eT - t0) / (t1 - t0);
return e0 * (1.0 - lam) + e1 * lam;
}
/////////////////////////////////////////////
IntensityWedge(IntensityWedge rightwedge, double tsplit)
{
assert ((tsplit > rightwedge.t0) && (tsplit < rightwedge.t1));
t0 = rightwedge.t0;
e0 = rightwedge.e0;
t1 = tsplit;
e1 = rightwedge.GetIntensityW(tsplit);
slope = rightwedge.slope;
assert VerifySlope();
rightwedge.t0 = tsplit;
rightwedge.e0 = e1;
assert rightwedge.VerifySlope();
}
/////////////////////////////////////////////
boolean VerifySlope()
{
double slediff = Math.abs((t1 - t0) * slope - (e1 - e0));
if (slediff < 0.001) // for very small changes in e value
return true;
double lslope = (e1 - e0) / (t1 - t0);
if (Math.abs(lslope - slope) <= 0.01)
return true;
System.out.println(this + " " + (t0 - t1) + " " + (e0 - e1) + " " + lslope + " " + slope);
return false;
}
/////////////////////////////////////////////
double GetExponentialAvgW(double eT, double efac, double lt1)
{
assert ((lt1 > t0) && (lt1 <= t1));
// integral from t0 to lt1 of [(t - t0) + e0] exp((t - eT) efac)
double b = Math.exp((lt1 - eT) * efac) * (lt1 * slope - slope / efac + (e0 - t0 * slope)) / efac;
double a = Math.exp((t0 - eT) * efac) * (t0 * slope - slope / efac + (e0 - t0 * slope)) / efac;
return b - a;
}
/////////////////////////////////////////////
public String toString()
{
return String.format("(%.3f,%.2f %.3f,%.2f)", t0, e0, t1, e1);
}
}
/////////////////////////////////////////////
/////////////////////////////////////////////
class IntensityEnvelope
{
List wedges = new ArrayList();
double emin;
double emax;
double epeak = 0.0;
double tpeak = 0.0;
/////////////////////////////////////////////
double GetIntensity(double eT)
{
for (int i = 0; i < wedges.size(); i++)
{
if ((wedges.get(i).t0 <= eT) && (eT < wedges.get(i).t1))
return wedges.get(i).GetIntensityW(eT);
}
return 0.0;
}
/////////////////////////////////////////////
// not used
double GetExponentialAverage(double eT, double efac)
{
double result = 0.0;
for (int i = 0; i < wedges.size(); i++)
{
IntensityWedge wedge = wedges.get(i);
if (wedge.t0 >= eT)
break;
result += wedge.GetExponentialAvgW(eT, efac, Math.min(eT, wedge.t1));
}
return result;
}
/////////////////////////////////////////////
double GetLastPeak(double eT, double peakfac)
{
double peakexp = epeak * Math.exp((tpeak - eT) * peakfac);
for (int i = 0; i < wedges.size(); i++)
{
IntensityWedge wedge = wedges.get(i);
if (wedge.t0 >= eT)
break;
if (wedge.e0 > 0.0)
{
double e0exp = wedge.e0 * Math.exp((wedge.t0 - eT) * peakfac);
if (e0exp > peakexp)
{
epeak = wedge.e0;
tpeak = wedge.t0;
peakexp = e0exp;
}
}
if (wedge.t1 <= eT)
{
double e1exp = wedge.e1 * Math.exp((wedge.t1 - eT) * peakfac);
if (e1exp > peakexp)
{
epeak = wedge.e1;
tpeak = wedge.t1;
peakexp = e1exp;
}
}
else
{
double le1 = wedge.GetIntensityW(eT);
double le1exp = le1;
if (le1exp > peakexp)
{
epeak = le1;
tpeak = eT;
peakexp = le1exp;
}
}
}
return epeak;
}
/////////////////////////////////////////////
void SeteextremesL(double t, double e, boolean bFirst)
{
if (bFirst)
{
emin = e;
emax = e;
tpeak = t;
}
else if (e < emin)
{
emin = e;
if (-emin > emax)
tpeak = t;
}
else if (e > emax)
{
emax = e;
if (emax > -emin)
tpeak = t;
}
}
void Seteextremes()
{
for (int i = 0; i < wedges.size(); i++)
{
IntensityWedge wedge = wedges.get(i);
SeteextremesL(wedge.t0, wedge.e0, (i == 0));
SeteextremesL(wedge.t1, wedge.e1, false);
}
}
/////////////////////////////////////////////
boolean VerifyWedges()
{
for (int i = 0; i < wedges.size(); i++)
{
assert wedges.get(i).VerifySlope();
assert wedges.get(i).t0 < wedges.get(i).t1;
if (i != 0)
assert wedges.get(i - 1).t1 <= wedges.get(i).t0;
}
return true;
}
/////////////////////////////////////////////
void AddWedge(IntensityWedge lnewwedge, double toffset)
{
// should build offset into the algorithm
IntensityWedge newwedge = new IntensityWedge(lnewwedge.t0 + toffset, lnewwedge.e0, lnewwedge.t1 + toffset, lnewwedge.e1);
newwedge.slope = newwedge.slope;
newwedge.VerifySlope();
// verification measures
double te0m = newwedge.t0 - 1.0;
double ee0m = GetIntensity(te0m);
double ee0 = GetIntensity(newwedge.t0) + newwedge.e0;
double tehalf = newwedge.t0 * 0.6 + newwedge.t1 * 0.4;
double eehalf = GetIntensity(tehalf) + newwedge.GetIntensityW(tehalf);
double ten1 = newwedge.t0 * 0.001 + newwedge.t1 * 0.999;
double een1 = GetIntensity(ten1) + newwedge.GetIntensityW(ten1);
double ee1 = GetIntensity(newwedge.t1);
double te1p = newwedge.t1 + 1.0;
double ee1p = GetIntensity(te1p);
AddWedgeV(newwedge);
//System.out.println("Env: " + this);
assert VerifyWedges();
// verification values
assert Math.abs(ee0m - GetIntensity(te0m)) < 0.001;
assert Math.abs(ee0 - GetIntensity(newwedge.t0)) < 0.001;
assert Math.abs(eehalf - GetIntensity(tehalf)) < 0.001;
assert Math.abs(een1 - GetIntensity(ten1)) < 0.001;
assert Math.abs(ee1 - GetIntensity(newwedge.t1)) < 0.001;
assert Math.abs(ee1p - GetIntensity(te1p)) < 0.001;
}
/////////////////////////////////////////////
void AddWedgeV(IntensityWedge newwedge)
{
// full outer wedge cases
if ((wedges.size() == 0) || (wedges.get(wedges.size() - 1).t1 <= newwedge.t0))
{
wedges.add(newwedge);
return;
}
if (newwedge.t1 <= wedges.get(0).t0)
{
wedges.add(0, newwedge);
return;
}
// find wedges
int i0;
for (i0 = 0; i0 < wedges.size(); i0++)
{
if (newwedge.t0 < wedges.get(i0).t1)
break;
}
assert (i0 < wedges.size());
int i1;
for (i1 = wedges.size() - 1; i1 >= 0; i1--)
{
if (wedges.get(i1).t0 < newwedge.t1)
break;
}
// wedge in gap
if (i1 == i0 - 1)
{
wedges.add(i0, newwedge);
return;
}
assert (i0 <= i1);
// create partial outer wedge left
if (newwedge.t0 < wedges.get(i0).t0)
{
assert ((i0 == 0) || (wedges.get(i0 - 1).t1 <= newwedge.t0));
IntensityWedge outerwedge = new IntensityWedge(newwedge.t0, newwedge.e0, wedges.get(i0).t0, newwedge.GetIntensityW(wedges.get(i0).t0));
wedges.add(i0, outerwedge);
i0++;
i1++;
}
// split wedge left
else if (newwedge.t0 > wedges.get(i0).t0)
{
IntensityWedge leftwedge = new IntensityWedge(wedges.get(i0), newwedge.t0);
wedges.add(i0, leftwedge);
i1++;
i0++;
assert VerifyWedges();
}
// create partial outer wedge right
if (wedges.get(i1).t1 < newwedge.t1)
{
assert ((i1 == wedges.size() - 1) || (newwedge.t1 < wedges.get(i1 + 1).t0));
IntensityWedge outerwedge = new IntensityWedge(wedges.get(i1).t1, newwedge.GetIntensityW(wedges.get(i1).t1), newwedge.t1, newwedge.e1);
wedges.add(i1 + 1, outerwedge);
}
// split wedge right
if (wedges.get(i1).t1 > newwedge.t1)
{
IntensityWedge leftwedge = new IntensityWedge(wedges.get(i1), newwedge.t1);
wedges.add(i1, leftwedge);
assert VerifyWedges();
}
// displace intermediate wedges
for (int i = i0; i <= i1; i++)
{
IntensityWedge wedge = wedges.get(i);
assert ((newwedge.t0 <= wedge.t0) && (wedge.t1 <= newwedge.t1));
wedge.e0 += newwedge.GetIntensityW(wedge.t0);
wedge.e1 += newwedge.GetIntensityW(wedge.t1);
wedge.slope += newwedge.slope;
assert wedge.VerifySlope();
// gap filling wedge
if ((i != i0) && (wedges.get(i - 1).t1 < wedges.get(i).t0))
{
IntensityWedge gapwedge = new IntensityWedge(wedges.get(i - 1).t1, newwedge.GetIntensityW(wedges.get(i - 1).t1), wedge.t0, newwedge.GetIntensityW(wedge.t0));
gapwedge.slope = newwedge.slope;
assert gapwedge.VerifySlope();
wedges.add(i, gapwedge);
i++;
i1++;
}
}
}
/////////////////////////////////////////////
static void Test()
{
Random ran = new Random();
ran.setSeed(854345);
for (int j = 0; j < 20; j++)
{
IntensityEnvelope ie = new IntensityEnvelope();
for (int i = 0; i < 20; i++)
{
double t0 = ran.nextDouble();
IntensityWedge wedge = new IntensityWedge(t0, ran.nextDouble() * 2 - 1, t0 + ran.nextDouble(), ran.nextDouble() * 2 - 1);
//System.out.println("Wedge: " + wedge);
ie.AddWedge(wedge, ran.nextDouble());
}
}
}
/////////////////////////////////////////////
public String toString()
{
StringBuffer sb = new StringBuffer();
for (int i = 0; i < wedges.size(); i++)
sb.append((i == 0 ? "" : " ") + wedges.get(i));
return sb.toString();
}
};
/////////////////////////////////////////////
/////////////////////////////////////////////
class TodeNode
{
OnePathNode opn;
DoubleArray spiketimes = new DoubleArray();
List outgoingfibres = new ArrayList();
List incomingfibres = new ArrayList();
boolean bprecodedspikes = false; // allowed to have spikes in the future
IntensityEnvelope refactoryenvelope = new IntensityEnvelope();
double nodethreshold = 1.0;
double adaptivequotient = 0.0;
List incomingsettings = new ArrayList();
double nextspike = -1.0;
double externalnodeintensity = 0.0;
double refactorynodeintensity = 0.0;
double nodeintensity = 0.0; // sum of the above two
IntensityEnvelope currentenvelope = new IntensityEnvelope();
/////////////////////////////////////////////
TodeNode(OnePathNode lopn)
{
opn = lopn;
}
/////////////////////////////////////////////
void RecalcEnvelope()
{
currentenvelope.wedges.clear();
for (TodeFibre todefibre : incomingfibres)
{
for (int i = 0; i < todefibre.fromnode.spiketimes.size(); i++)
{
for (IntensityWedge wedge : todefibre.intensityenvelope.wedges)
currentenvelope.AddWedge(wedge, todefibre.fromnode.spiketimes.get(i) + todefibre.timelength);
}
}
for (int i = 0; i < spiketimes.size(); i++)
{
for (IntensityWedge wedge : refactoryenvelope.wedges)
currentenvelope.AddWedge(wedge, spiketimes.get(i));
}
}
/////////////////////////////////////////////
void NextSpike(double T)
{
nextspike = -1.0;
for (IntensityWedge wedge : currentenvelope.wedges)
{
if (wedge.e0 >= nodethreshold)
{
nextspike = wedge.t0;
break;
}
if (wedge.e1 >= nodethreshold)
{
double lam = (nodethreshold - wedge.e0) / (wedge.e1 - wedge.e0);
nextspike = wedge.t0 * (1.0 - lam) + wedge.t1 * lam;
break;
}
}
assert ((nextspike == -1.0) || (nextspike > T));
}
}
/////////////////////////////////////////////
/////////////////////////////////////////////
class TodeFibre
{
TodeNode fromnode;
TodeNode tonode;
double timelength;
IntensityEnvelope intensityenvelope = new IntensityEnvelope();
double timelinelengthfac = 1.0;
OnePath op;
Double[] opseglengths; // for drawing the spike on the path
double closestspiketimelength = 0.0; //
/////////////////////////////////////////////
TodeFibre(OnePath lop, TodeNode lfromnode, TodeNode ltonode)
{
op = lop;
fromnode = lfromnode;
tonode = ltonode;
fromnode.outgoingfibres.add(this);
tonode.incomingfibres.add(this);
// visualization stuff
opseglengths = new Double[op.nlines];
for (int i = 0; i < op.nlines; i++)
opseglengths[i] = (i == 0 ? 0.0 : opseglengths[i - 1]) + op.MeasureSegmentLength(i);
}
/////////////////////////////////////////////
void SetPosD(Point2D spos, Point2D stan, double dst)
{
int j = 0;
for ( ; j < opseglengths.length - 1; j++)
if (opseglengths[j] >= dst)
break;
double ljm1 = (j == 0 ? 0.0 : opseglengths[j-1]);
double tr = (dst - ljm1) / (opseglengths[j] - ljm1);
op.EvalSeg(spos, stan, j, tr);
}
}
/////////////////////////////////////////////
class PosSpikeViz
{
Point2D spos = new Point2D.Double();
Point2D stan = new Point2D.Double();
}
/////////////////////////////////////////////
/////////////////////////////////////////////
class TodeNodeCalc
{
List todenodes = new ArrayList();
List todefibres = new ArrayList();
double T = 0.0;
List todenodesnextspikes = new ArrayList();
IntensityEnvelope iefastattack;
IntensityEnvelope iefastsuppress;
IntensityEnvelope ieslowsuppress;
IntensityEnvelope ieslowattack;
IntensityEnvelope iestandardrefactory;
double chardisprand[] = null; // some variance in the wordmode distances
/////////////////////////////////////////////
void MakeDefaultIntensityEnvelopes()
{
iefastattack = new IntensityEnvelope();
iefastattack.wedges.add(new IntensityWedge(0.0, 0.0, 0.1, 1.1));
iefastattack.wedges.add(new IntensityWedge(0.1, 1.1, 0.8, 0.0));
iefastattack.Seteextremes();
iefastsuppress = new IntensityEnvelope();
iefastsuppress.wedges.add(new IntensityWedge(0.0, 0.0, 0.1, -1.5));
iefastsuppress.wedges.add(new IntensityWedge(0.1, -1.5, 1.5, -1.4));
iefastsuppress.wedges.add(new IntensityWedge(1.5, -1.4, 2.1, 0.0));
iefastsuppress.Seteextremes();
ieslowsuppress = new IntensityEnvelope();
ieslowsuppress.wedges.add(new IntensityWedge(0.0, 0.0, 0.1, -1.5));
ieslowsuppress.wedges.add(new IntensityWedge(0.1, -1.5, 5.5, -1.4));
ieslowsuppress.wedges.add(new IntensityWedge(5.5, -1.4, 7.1, 0.0));
ieslowsuppress.Seteextremes();
ieslowattack = new IntensityEnvelope();
ieslowattack.wedges.add(new IntensityWedge(0.0, 0.0, 0.5, 1.1));
ieslowattack.wedges.add(new IntensityWedge(0.5, 1.1, 0.8, 0.0));
ieslowattack.Seteextremes();
// back in time slightly to suppress the spike that was there
iestandardrefactory = new IntensityEnvelope();
iestandardrefactory.wedges.add(new IntensityWedge(-0.0001, -10.0, 0.9, -5.0));
iestandardrefactory.wedges.add(new IntensityWedge(0.9, -5.0, 1.1, 0.0));
iestandardrefactory.Seteextremes();
chardisprand = new double[26];
Random ran = new Random();
ran.setSeed(1854345);
for (int i = 0; i < chardisprand.length; i++)
chardisprand[i] = ran.nextDouble();
}
/////////////////////////////////////////////
void RecalculateAll()
{
for (TodeNode todenode : todenodes)
{
if (!todenode.bprecodedspikes)
{
while ((todenode.spiketimes.size() != 0) && (todenode.spiketimes.get(todenode.spiketimes.size() - 1) > T))
todenode.spiketimes.pop();
}
}
for (TodeNode todenode : todenodes)
todenode.RecalcEnvelope();
NextSpikeAll();
}
/////////////////////////////////////////////
void NextSpikeAll()
{
todenodesnextspikes.clear();
for (TodeNode todenode : todenodes)
{
todenode.NextSpike(T);
if (todenode.nextspike != -1.0)
{
if (!todenodesnextspikes.isEmpty() && (todenodesnextspikes.get(0).nextspike > todenode.nextspike))
todenodesnextspikes.clear();
if (todenodesnextspikes.isEmpty() || (todenodesnextspikes.get(0).nextspike == todenode.nextspike))
todenodesnextspikes.add(todenode);
}
}
}
/////////////////////////////////////////////
void AdvanceTime(double advance)
{
double Tnext = T + advance;
if (todenodesnextspikes.isEmpty() || (todenodesnextspikes.get(0).nextspike > Tnext))
{
T = Tnext;
return;
}
T = todenodesnextspikes.get(0).nextspike;
for (TodeNode todenode : todenodesnextspikes)
{
// set the spike
todenode.spiketimes.add(T);
// add the intensities which result
for (TodeFibre todefibre : todenode.outgoingfibres)
{
for (IntensityWedge wedge : todefibre.intensityenvelope.wedges)
todefibre.tonode.currentenvelope.AddWedge(wedge, T + todefibre.timelength);
}
for (IntensityWedge wedge : todenode.refactoryenvelope.wedges)
todenode.currentenvelope.AddWedge(wedge, T);
// how close did any incoming spikes miss this target
for (TodeFibre todefibre : todenode.incomingfibres)
{
todefibre.closestspiketimelength = 0.0;
for (int i = 0; i < todefibre.fromnode.spiketimes.size(); i++)
{
double lclosestspiketimelength = T - (todefibre.fromnode.spiketimes.get(i) + todefibre.timelength + todefibre.intensityenvelope.tpeak);
if ((i == 0) || (Math.abs(lclosestspiketimelength) < Math.abs(todefibre.closestspiketimelength)))
todefibre.closestspiketimelength = lclosestspiketimelength;
}
}
}
//RecalculateAll(); // would redo the partial calculation above
NextSpikeAll();
}
/////////////////////////////////////////////
TodeNode FindTodeNode(OnePathNode opn)
{
for (TodeNode tn : todenodes)
if (tn.opn == opn)
return tn;
TodeNode ntn = new TodeNode(opn);
todenodes.add(ntn);
return ntn;
}
/////////////////////////////////////////////
void ApplySettingsToNodeFibes(TodeNode todenode, String drawlab)
{
String[] params = drawlab.split("[\\s,]+");
boolean bwordmode = false;
boolean brelative = true;
double rwordmodemintime = 0;
double rwordmodemaxtime = 0;
double rwordmodegap = 0;
double llastspiketime = 0.0;
try
{
for (int i = 0; i < params.length; i++)
{
//System.out.println(i + "::" + params[i]);
String param = params[i];
if (bwordmode)
{
llastspiketime += rwordmodegap; // may need to randomize this
todenode.spiketimes.add(llastspiketime);
for (int j = 0; j < param.length(); j++)
{
int iletter = Character.getNumericValue(param.charAt(j)) - Character.getNumericValue('a');
double rletter = (iletter + chardisprand[iletter] * 0.3) / 26.0;
double rgap = rwordmodemintime * (1.0 - rletter) + rwordmodemaxtime * rletter;
llastspiketime += rgap;
todenode.spiketimes.add(llastspiketime);
}
todenode.bprecodedspikes = true;
}
else if (param.equals("wordmode"))
{
i++;
rwordmodemintime = Float.parseFloat(params[i]);
i++;
rwordmodemaxtime = Float.parseFloat(params[i]);
i++;
rwordmodegap = Float.parseFloat(params[i]);
bwordmode = true;
}
else if (param.equals("threshold"))
{
i++;
todenode.nodethreshold = Float.parseFloat(params[i]);
}
else if (param.equals("adaptive"))
{
i++;
todenode.adaptivequotient = Float.parseFloat(params[i]);
}
else if (param.equals("absolute"))
{
brelative = false;
}
else if (param.equals("slowattack"))
{
for (TodeFibre todefibre : todenode.incomingfibres)
{
if (todefibre.intensityenvelope == iefastattack)
todefibre.intensityenvelope = ieslowattack;
}
}
else
{
double rparam = Float.parseFloat(param);
if (brelative)
llastspiketime += rparam;
else
llastspiketime = rparam;
todenode.spiketimes.add(llastspiketime);
todenode.bprecodedspikes = true;
}
}
}
catch (NumberFormatException e)
{
TN.emitWarning("Error parsing: " + drawlab);
}
todenode.spiketimes.sort();
}
/////////////////////////////////////////////
TodeNodeCalc(List vpaths)
{
MakeDefaultIntensityEnvelopes();
for (OnePath op : vpaths)
{
TodeNode tonode = FindTodeNode(op.pnend);
if (op.linestyle != SketchLineStyle.SLS_CONNECTIVE)
todefibres.add(new TodeFibre(op, FindTodeNode(op.pnstart), tonode));
else if (op.plabedl != null)
tonode.incomingsettings.add(op);
}
// Set default intensity envelopes of incoming fibres by fibre type
for (TodeNode todenode : todenodes)
{
int nposfibres = 0;
for (TodeFibre todefibre : todenode.incomingfibres)
{
if (todefibre.op.linestyle == SketchLineStyle.SLS_WALL)
{
todefibre.intensityenvelope = ieslowsuppress;
todefibre.timelinelengthfac = 0.2;
}
else
{
todefibre.intensityenvelope = iefastattack;
nposfibres++;
}
todefibre.timelength = todefibre.op.linelength * todefibre.timelinelengthfac / TN.CENTRELINE_MAGNIFICATION; // linear distance; opseglengths[-1] would be spline length
}
todenode.nodethreshold = nposfibres + 0.01;
todenode.refactoryenvelope = iestandardrefactory;
// this could also make use of the order of the incoming connective line with label
for (OnePath op : todenode.incomingsettings)
ApplySettingsToNodeFibes(todenode, op.plabedl.drawlab);
}
RecalculateAll();
NextSpikeAll();
}
/////////////////////////////////////////////
// this function calculates spikes and intensity independently of the nextspike calculation, and should agree with it
List spikelist = new ArrayList();
int nspikelist = 0;
int nodeswithintensity = 0;
int spikesinfuture = 0;
boolean PosSpikes()
{
nspikelist = 0;
nodeswithintensity = 0;
spikesinfuture = 0;
for (TodeNode todenode : todenodes)
{
todenode.externalnodeintensity = 0.0;
for (TodeFibre todefibre : todenode.incomingfibres)
{
for (int i = 0; i < todefibre.fromnode.spiketimes.size(); i++)
{
double st = T - todefibre.fromnode.spiketimes.get(i);
if (st < 0.0)
{
assert todefibre.fromnode.bprecodedspikes;
spikesinfuture++;
continue; // only can happen for precoded trains
}
// spike on the fibre
if (st < todefibre.timelength)
{
if (nspikelist == spikelist.size())
spikelist.add(new PosSpikeViz());
PosSpikeViz psv = spikelist.get(nspikelist);
double dst = st / todefibre.timelength * todefibre.opseglengths[todefibre.opseglengths.length - 1];
todefibre.SetPosD(psv.spos, psv.stan, dst);
nspikelist++;
continue;
}
double est = st - todefibre.timelength;
todenode.externalnodeintensity += todefibre.intensityenvelope.GetIntensity(est);
}
}
// add in the refactory intensities from the spikes here
todenode.refactorynodeintensity = 0.0;
for (int i = 0; i < todenode.spiketimes.size(); i++)
{
double st = T - todenode.spiketimes.get(i);
if (st < 0.0)
continue; // only can happen for precoded trains
todenode.refactorynodeintensity += todenode.refactoryenvelope.GetIntensity(st);
}
if ((todenode.externalnodeintensity != 0.0) || (todenode.refactorynodeintensity != 0.0))
nodeswithintensity++;
todenode.nodeintensity = todenode.externalnodeintensity + todenode.refactorynodeintensity;
}
return ((nspikelist != 0) || (nodeswithintensity != 0) || (spikesinfuture != 0));
}
}
/////////////////////////////////////////////
class TodeNodePanel extends JPanel
{
SketchDisplay sketchdisplay;
JButton buttgeneratetodes = new JButton("Gen Todes");
JTextField tfpathlength = new JTextField("", 5);
JButton buttoutputenvelope = new JButton("OutEnv");
JButton buttoutputtrain = new JButton("OutTrain");
JButton buttadvance = new JButton("Advance");
JButton buttadapt = new JButton("Adapt");
JTextField tfadvancetime = new JTextField("5.0", 5);
JToggleButton buttanimate = new JToggleButton("Anim");
JTextField tfanimtime = new JTextField("0.02", 5);
JLabel labtime = new JLabel("T:");
JTextField tftime = new JTextField(5);
Thread animthread = null;
boolean bnextfaster = false;
int spiralsegspercircuit = 20;
int nspirals = 4;
GeneralPath[] gpspirals;
int nsplayvals = 30;
GeneralPath[] gpsplaysnegative;
Shape acspike = null;
LineStyleAttr lsaspikeout = null;
LineStyleAttr lsaspike = null;
LineStyleAttr lsanegsplay = null;
double prevT = 0.0;
TodeNodeCalc tnc;
Color lightgreen = new Color(190, 255, 190);
/////////////////////////////////////////////
double GetNewLength(OnePath op, double timelinelengthfac, double mu, OnePath nop)
{
float[] pco = op.GetCoords();
double x0 = pco[0];
double y0 = pco[1];
double x1 = pco[op.nlines * 2];
double y1 = pco[op.nlines * 2 + 1];
double vx = x1 - x0;
double vy = y1 - y0;
double vlen = Math.sqrt(vx*vx + vy*vy);
double xp = x0;
double yp = y0;
double newleng = 0.0;
for (int i = 1; i <= op.nlines; i++)
{
double xn = pco[i * 2];
double yn = pco[i * 2 + 1];
double xfdot = (vy * (xn - x1) - vx * (yn - y1)) / vlen;
xn += vy * xfdot * mu / vlen;
yn += -vx * xfdot * mu / vlen;
double xpn = xn - xp;
double ypn = yn - yp;
newleng += Math.sqrt(xpn*xpn + ypn*ypn);
if ((nop != null) && (i != op.nlines))
nop.LineTo((float)xn, (float)yn);
xp = xn;
yp = yn;
}
return newleng * timelinelengthfac / TN.CENTRELINE_MAGNIFICATION;
}
/////////////////////////////////////////////
void SetNewLength(TodeFibre todefibre, double targetlength)
{
double faclo = -0.9;
double fachi = 3.0;
double newlenglo = GetNewLength(todefibre.op, todefibre.timelinelengthfac, faclo, null);
double newlenghi = GetNewLength(todefibre.op, todefibre.timelinelengthfac, fachi, null);
if ((targetlength < newlenglo) || (targetlength > newlenghi))
{
System.out.println("Target length outside range: " + newlenglo + " " + newlenghi);
return;
}
// the maths are too complex to solve faster than this binary search
while (newlenghi - newlenglo > 0.001)
{
double facmid = (faclo + fachi) / 2;
double newlengmid = GetNewLength(todefibre.op, todefibre.timelinelengthfac, facmid, null);
if (newlengmid < targetlength)
{
faclo = facmid;
newlenglo = newlengmid;
}
else
{
fachi = facmid;
newlenghi = newlengmid;
}
}
// now make the path
OnePath nop = new OnePath(todefibre.op.pnstart);
double newleng = GetNewLength(todefibre.op, todefibre.timelinelengthfac, (faclo + fachi) / 2, nop);
nop.EndPath(todefibre.op.pnend);
nop.CopyPathAttributes(todefibre.op);
List pthstoremove = new ArrayList();
List pthstoadd = new ArrayList();
pthstoremove.add(todefibre.op);
pthstoadd.add(nop);
sketchdisplay.sketchgraphicspanel.CommitPathChanges(pthstoremove, pthstoadd);
sketchdisplay.sketchgraphicspanel.RedrawBackgroundView();
}
/////////////////////////////////////////////
void BuildSpirals()
{
if (SketchLineStyle.strokew == -1.0F)
return;
double spiralw = SketchLineStyle.strokew * 2.2;
gpspirals = new GeneralPath[spiralsegspercircuit * nspirals + 1];
for (int j = 0; j < gpspirals.length; j++)
{
gpspirals[j] = new GeneralPath();
gpspirals[j].moveTo(0.0F, 0.0F);
}
for (int i = 1; i < gpspirals.length; i++)
{
double lam = i * 1.0 / spiralsegspercircuit; // exagerate the spirals on the positive side
double x = TN.degsin(lam * 360) * lam * spiralw;
double y = -TN.degcos(lam * 360) * lam * spiralw;
for (int j = i; j < gpspirals.length; j++)
gpspirals[j].lineTo((float)x, (float)y);
}
acspike = new Ellipse2D.Double(-spiralw * 2.2, -spiralw * 2.2, spiralw * 4.4, spiralw * 4.4);
lsaspikeout = new LineStyleAttr(SketchLineStyle.SLS_DETAIL, 2.5F*SketchLineStyle.strokew, 0, 0, 0, Color.white);
lsaspike = new LineStyleAttr(SketchLineStyle.SLS_DETAIL, 2.0F*SketchLineStyle.strokew, 0, 0, 0, Color.red);
lsanegsplay = new LineStyleAttr(SketchLineStyle.SLS_DETAIL, 0.5F*SketchLineStyle.strokew, 0, 0, 0, Color.yellow);
gpsplaysnegative = new GeneralPath[nsplayvals + 1];
double radfull = spiralw * 3.0;
double radhalf = spiralw * 1.5;
for (int i = 0; i < gpsplaysnegative.length; i++)
{
double lamrad = (i + 1) * 1.0 / gpsplaysnegative.length;
double rad = lamrad * radfull;
gpsplaysnegative[i] = new GeneralPath();
for (int j = 0; j < 18; j++)
{
double vx = TN.degcos(j * 20);
double vy = TN.degsin(j * 20);
if ((j % 2) == 0)
{
gpsplaysnegative[i].moveTo(0.0F, 0.0F);
gpsplaysnegative[i].lineTo((float)(vx * rad), (float)(vy * rad));
}
else if (rad > radhalf)
{
gpsplaysnegative[i].moveTo((float)(vx * radhalf), (float)(vy * radhalf));
gpsplaysnegative[i].lineTo((float)(vx * rad), (float)(vy * rad));
}
}
}
}
/////////////////////////////////////////////
TodeNodePanel(SketchDisplay lsketchdisplay)
{
sketchdisplay = lsketchdisplay;
BuildSpirals();
tftime.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e)
{
try
{
UpdateT(Float.parseFloat(tftime.getText()));
}
catch (NumberFormatException ne)
{;}
sketchdisplay.sketchgraphicspanel.repaint();
}});
buttgeneratetodes.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent e) { GenerateTodes(); } } );
buttoutputenvelope.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent e) { OutputEnvelope(sketchdisplay.sketchgraphicspanel.currgenpath, false); } } );
buttoutputtrain.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent e) { OutputEnvelope(sketchdisplay.sketchgraphicspanel.currgenpath, true); } } );
buttadvance.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent e) { AdvanceEventB(); } } );
buttadapt.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent e) { AdaptPhase(); } } );
buttanimate.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e)
{
if (buttanimate.isSelected() && (animthread == null))
{
animthread = new Thread(new AdvanceNodeThread());
animthread.start();
}
if (!buttanimate.isSelected() && (animthread != null))
animthread.interrupt();
}});
tfadvancetime.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent e) { AdvanceEventB(); } } );
tfpathlength.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event)
{
try
{
double targetlength= Float.parseFloat(tfpathlength.getText());
TodeFibre todefibre = FindTodeFibre(sketchdisplay.sketchgraphicspanel.currgenpath);
if (todefibre != null)
SetNewLength(todefibre, targetlength);
}
catch (NumberFormatException e)
{;}
}});
setLayout(new GridLayout(0, 2));
add(buttgeneratetodes);
add(tfpathlength);
add(buttadapt);
add(new JLabel());
add(buttoutputenvelope);
add(buttoutputtrain);
add(buttadvance);
add(tfadvancetime);
add(buttanimate);
add(tfanimtime);
add(labtime);
add(tftime);
// IntensityEnvelope.Test();
}
/////////////////////////////////////////////
void GenerateTodes()
{
tnc = null;
if (sketchdisplay.sketchgraphicspanel.currgenpath != null)
{
sketchdisplay.sketchgraphicspanel.SelectConnectedSetsFromSelection();
if (!sketchdisplay.sketchgraphicspanel.vactivepaths.isEmpty())
{
tnc = new TodeNodeCalc(sketchdisplay.sketchgraphicspanel.vactivepaths);
sketchdisplay.sketchgraphicspanel.ClearSelection(true);
sketchdisplay.sketchgraphicspanel.repaint();
}
}
if (tnc == null)
tnc = new TodeNodeCalc(sketchdisplay.sketchgraphicspanel.tsketch.vpaths);
tftime.setText(String.format("%.3f", tnc.T));
prevT = -1.0;
sketchdisplay.sketchgraphicspanel.repaint();
}
/////////////////////////////////////////////
TodeFibre FindTodeFibre(OnePath op)
{
if ((op == null) || (tnc == null))
return null;
for (TodeFibre todefibre : tnc.todefibres)
{
if (todefibre.op == op)
return todefibre;
}
return null;
}
/////////////////////////////////////////////
void OutputEnvelope(OnePath op, boolean btrain)
{
TodeFibre todefibre = FindTodeFibre(op);
if (todefibre == null)
return;
TodeNode todenode = todefibre.fromnode;
tfpathlength.setText(String.format("%.3f", todefibre.timelength));
if (btrain)
{
if (todenode != null)
System.out.println("SpikesRel: " + todenode.spiketimes.toStringRel());
return;
}
if (todefibre != null)
{
System.out.println("Length: " + todefibre.timelength);
System.out.println("IntensityEnvelope: " + todefibre.intensityenvelope);
}
if (todenode != null)
{
System.out.println("RefactoryEnvelope: " + todenode.refactoryenvelope);
System.out.println("Spikes: " + todenode.spiketimes);
System.out.println("SpikesRel: " + todenode.spiketimes.toStringRel());
if (todenode.nextspike != -1.0)
System.out.println("Next spike: " + todenode.nextspike);
System.out.println("CurrentIntensity: " + todenode.nodeintensity);
System.out.println("CurrentEnvelope: ");
for (IntensityWedge wedge : todenode.currentenvelope.wedges)
System.out.println(" " + wedge);
}
}
/////////////////////////////////////////////
void AdvanceEventB()
{
bnextfaster = true;
if (animthread == null)
AdvanceEvent();
}
/////////////////////////////////////////////
void AdvanceEvent()
{
if (tnc == null)
return;
double advancetime = (!bnextfaster ? 0.02 : 1.0);
try
{
advancetime = Float.parseFloat(!bnextfaster ? tfanimtime.getText() : tfadvancetime.getText());
}
catch (NumberFormatException ne)
{;}
bnextfaster = false;
tnc.AdvanceTime(advancetime);
tftime.setText(String.format("%.3f", tnc.T));
sketchdisplay.sketchgraphicspanel.repaint();
}
/////////////////////////////////////////////
void AdaptPhase()
{
System.out.println("Adapt");
for (TodeNode todenode : tnc.todenodes)
{
if (todenode.adaptivequotient != 0.0)
{
System.out.println("Adaptive " + todenode.adaptivequotient);
for (TodeFibre todefibre : todenode.incomingfibres)
System.out.println(todefibre.closestspiketimelength);
}
}
}
/////////////////////////////////////////////
void UpdateT(double lT)
{
if (lT < tnc.T)
{
tnc.T = lT;
tnc.RecalculateAll();
}
else
{
while (lT > tnc.T)
tnc.AdvanceTime(lT - tnc.T);
}
tftime.setText(String.format("%.3f", tnc.T));
sketchdisplay.sketchgraphicspanel.repaint();
}
/////////////////////////////////////////////
class AdvanceNodeThread implements Runnable
{
/////////////////////////////////////////////
public void run()
{
try
{
while (true)
{
AdvanceEvent();
Thread.sleep(50);
}
}
catch (InterruptedException ie)
{;}
animthread = null;
}
}
/////////////////////////////////////////////
// 1 - 1 / (1 + x)
int asymd(double val, double valsca, int len)
{
double kap = 1.0 - 1.0 / (1.0 + Math.abs(val / valsca));
int res = (int)(kap * (len - 1) + 0.9);
assert ((res >= 0) && (res < len));
return res;
}
/////////////////////////////////////////////
void painttodenode(GraphicsAbstraction ga)
{
if (tnc == null)
return;
boolean bsomeaction = tnc.PosSpikes();
if (!bsomeaction && buttanimate.isSelected())
buttanimate.setSelected(false);
// draw the spirals on the nodes
AffineTransform at = ga.g2d.getTransform();
for (TodeNode todenode : tnc.todenodes)
{
if (todenode.nodeintensity == 0.0)
continue;
ga.g2d.translate(todenode.opn.pn.getX(), todenode.opn.pn.getY());
// draw any positive external node intensity
if ((todenode.externalnodeintensity > 0.0) && (todenode.externalnodeintensity > todenode.nodeintensity))
{
int nivalue = asymd(todenode.externalnodeintensity, todenode.nodethreshold, gpspirals.length);
GeneralPath gppos = gpspirals[nivalue];
ga.drawShape(gppos, SketchLineStyle.activepnlinestyleattr, lightgreen);
}
// draw any positive node intensity
if (todenode.nodeintensity > 0.0)
{
int nivalue = asymd(todenode.nodeintensity, todenode.nodethreshold, gpspirals.length);
GeneralPath gppos = gpspirals[nivalue];
ga.drawShape(gppos, SketchLineStyle.activepnlinestyleattr, Color.green);
}
// draw any negative external node intensity
if (todenode.externalnodeintensity < 0.0)
{
int nivalue = asymd(-todenode.externalnodeintensity, todenode.nodethreshold, gpspirals.length);
GeneralPath gppos = gpspirals[nivalue];
ga.drawShape(gppos, SketchLineStyle.activepnlinestyleattr, Color.red);
}
// draw any negative negative refactory splay
if ((todenode.nodeintensity < 0.0) && (todenode.refactorynodeintensity < 0.0))
{
int nivalue = (int)(gpsplaysnegative.length * Math.abs(todenode.refactorynodeintensity / (todenode.refactoryenvelope.emin + 0.01)) + 0.9);
GeneralPath gppos = gpsplaysnegative[Math.min(nivalue, gpsplaysnegative.length - 1)];
ga.drawShape(gppos, lsanegsplay);
}
ga.g2d.setTransform(at);
}
// draw the spikes on the fibres
for (int i = 0; i < tnc.nspikelist; i++)
{
PosSpikeViz psv = tnc.spikelist.get(i);
double spikel = SketchLineStyle.strokew * 2.2 / psv.stan.distance(0.0, 0.0);
Line2D lnspike = new Line2D.Double(psv.spos.getX(), psv.spos.getY(), psv.spos.getX() - psv.stan.getX() * spikel, psv.spos.getY() - psv.stan.getY() * spikel);
ga.drawShape(lnspike, lsaspikeout);
ga.drawShape(lnspike, lsaspike);
}
// highlight the nodes spiked since last paint
for (TodeNode todenode : tnc.todenodes)
{
if (todenode.spiketimes.size() == 0)
continue;
double tspike = todenode.spiketimes.get(todenode.spiketimes.size() - 1);
if ((tspike > prevT) && (tspike <= tnc.T))
{
ga.g2d.translate(todenode.opn.pn.getX(), todenode.opn.pn.getY());
ga.g2d.setColor(Color.yellow);
ga.g2d.fill(acspike);
ga.g2d.setTransform(at);
}
}
prevT = tnc.T;
}
}
tunnelx-20190701/src/SurvexLoaderNew.java 0000664 0001750 0001750 00000076030 13531571147 017636 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2008 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.Stack;
import java.util.Collections;
import java.util.Collection;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
//
//
// SurvexLoaderNew
//
//
/////////////////////////////////////////////
/////////////////////////////////////////////
class SVXline
{
String cmd;
String sline;
String comment;
/////////////////////////////////////////////
SVXline(String lcmd, String lsline, String lcomment)
{
cmd = lcmd;
sline = lsline;
comment = lcomment;
}
/////////////////////////////////////////////
boolean IsCalibration()
{
if (cmd == null)
return false;
return ("*calibrate".equals(cmd) || "*units".equals(cmd) || "*date".equals(cmd) || "*team".equals(cmd));
}
/////////////////////////////////////////////
public String toString()
{
if (cmd == null)
{
if (comment == null)
return sline;
return sline + comment;
}
if (comment == null)
return cmd + " " + sline;
return cmd + " " + sline + comment;
}
/////////////////////////////////////////////
SVXline(String lsline)
{
sline = lsline.trim();
// comment should chew up previous whitespace
int ic = sline.indexOf(";");
if (ic != -1)
{
while ((ic > 0) && (sline.charAt(ic - 1) <= '\u0020'))
ic--;
comment = sline.substring(ic);
sline = sline.substring(0, ic);
}
else
comment = null;
if ((sline.length() != 0) && (sline.charAt(0) == '*'))
{
int ie = 0;
while (ie < sline.length())
{
if (sline.charAt(ie) <= '\u0020')
break;
ie++;
}
cmd = sline.substring(0, ie).toLowerCase();
sline = sline.substring(ie).trim();
sline = sline.replace("\"", "");
}
else
cmd = null;
}
}
/////////////////////////////////////////////
/////////////////////////////////////////////
class SurvexLoaderNew
{
Map > eqmap = null;
Map > eqlmap = null;
// used for interpreting svx text
List vlegs = null;
List vfixes = null;
List vanonymouses = null;
Vec3 avgfix;
Map osmap = null;
List vfilebeginblocklegs = null;
Map osfileblockmap = null;
Vec3d sketchLocOffset;
Stack statrec = null;
int npieces = 0;
int nstationsdone = 0;
// allow for loading the centreline as an elevation
// ;IMPORT_AS_ELEVATION 90
boolean bprojectedelevation = false;
float projectedelevationvalue = 0.0F;
boolean btopextendedelevation = false;
OneLeg filebeginblockrootleg = null;
List filebeginblocklegstack = null; // starts out as null and initialized at first entry
/////////////////////////////////////////////
public SurvexLoaderNew()
{
}
/////////////////////////////////////////////
void DumpEQs()
{
List< Set > Dss = new ArrayList< Set >();
for (Set lss : eqmap.values())
{
if (!Dss.contains(lss))
System.out.println("PPP: " + lss);
Dss.add(lss);
}
}
/////////////////////////////////////////////
void AddEquate(String prefixd, String sline, LegLineFormat llf)
{
//System.out.println("EQQ: " + svxbatch.prefix + " " + svxline.sline);
Set v0 = null;
for (String eqel : sline.split("\\s+"))
{
String peqel = prefixd + llf.ApplyCasePreserveMode(eqel); //.toLowerCase();
if (v0 != null)
{
Set v = eqmap.get(peqel);
if (v != null)
{
v0.addAll(v);
for (String p : v)
eqmap.put(p, v0);
}
else
{
v0.add(peqel);
eqmap.put(peqel, v0);
}
}
else
{
v0 = eqmap.get(peqel);
if (v0 == null)
{
v0 = new HashSet();
v0.add(peqel);
eqmap.put(peqel, v0);
}
}
// put the mapping into the SVXbatch prefix
if (eqlmap != null)
{
int lld = peqel.lastIndexOf('.');
String lprefixd = llf.ApplyCasePreserveMode(peqel.substring(0, lld + 1)); //.toLowerCase();
Set vel = eqlmap.get(lprefixd);
if (vel == null)
{
vel = new HashSet();
eqlmap.put(lprefixd, vel);
}
vel.add(peqel);
}
}
}
/////////////////////////////////////////////
// lsline is the actual line of the *include to which calcIncludeFile was applied
void ReadSurvexRecurseIncludeOnly(StringBuilder sb, FileAbstraction loadfile, String lsline, String lcomment, FileAbstraction upperloadfile) throws IOException
{
LineInputStream lis = new LineInputStream(loadfile.GetInputStream(), loadfile, null, null);
sb.append("*file_begin \"");
sb.append(loadfile.getAbsolutePath());
sb.append("\" \"");
sb.append(lsline);
sb.append("\"");
if (lcomment != null)
sb.append(lcomment);
sb.append(TN.nl);
while (lis.FetchNextLineNoSplit())
{
String sline = lis.GetLine();
if (sline.matches("(?i)\\s*\\*include\\s.*"))
{
SVXline svxline = new SVXline(sline);
assert "*include".equals(svxline.cmd);
FileAbstraction includefile = FileAbstraction.calcIncludeFile(loadfile, svxline.sline, false);
ReadSurvexRecurseIncludeOnly(sb, includefile, svxline.sline, svxline.comment, loadfile);
}
else
{
sb.append(sline);
sb.append(TN.nl);
}
}
sb.append("*file_end");
sb.append(" \"");
sb.append(loadfile.getAbsolutePath());
sb.append("\" \"");
sb.append(upperloadfile != null ? upperloadfile.getAbsolutePath() : ""); // this is included to make it easier to scan through and find what file we are now in.
sb.append("\"");
sb.append(TN.nl);
lis.inputstream.close();
}
/////////////////////////////////////////////
public String LoadSVX(FileAbstraction loadfile)
{
StringBuilder sb = new StringBuilder();
try
{ ReadSurvexRecurseIncludeOnly(sb, loadfile, "", null, null); }
catch (IOException e)
{ TN.emitError(e.toString()); };
return sb.toString();
}
/////////////////////////////////////////////
// pulls stuff into vlegs (the begin-end recursion). The recursion is over the *begin/*end, not the *file_begin, *file_end
void InterpretSvxTextRecurse(String prefixd, LineInputStream lis, LegLineFormat initLLF, int depth)
{
if (filebeginblocklegstack == null)
{
filebeginblocklegstack = new ArrayList();
filebeginblockrootleg = new OneLeg("__ROOT__", "__ROOT__", 0, "--root--");
filebeginblocklegstack.add(filebeginblockrootleg);
vfilebeginblocklegs.add(filebeginblockrootleg);
}
OneLeg currentfilebeginblockleg = filebeginblocklegstack.get(filebeginblocklegstack.size() - 1);
// make working copy (will be from new once the header is right).
LegLineFormat CurrentLegLineFormat = new LegLineFormat(initLLF);
while (lis.FetchNextLine())
{
// concatennate case when there is a space after the *
if (lis.w[0].equals("*") && (lis.iwc >= 2))
{
lis.w[0] = lis.w[0] + lis.w[1];
for (int i = 2; i < lis.iwc; i++)
lis.w[i - 1] = lis.w[i];
lis.w[lis.iwc - 1] = "";
lis.iwc--;
}
if (lis.w[0].equals(""))
{
// magic code which we can stick at the start to cause the centreline to be converted to a projected elevation
if (lis.comment.trim().startsWith("IMPORT_AS_ELEVATION"))
{
projectedelevationvalue = Float.valueOf(lis.comment.trim().substring(19).trim());
bprojectedelevation = true;
}
}
else if (lis.w[0].equalsIgnoreCase("*calibrate"))
CurrentLegLineFormat.StarCalibrate(lis.w[1], lis.w[2], lis.w[3], lis);
else if (lis.w[0].equalsIgnoreCase("*units"))
{
int ist = 2;
while (lis.w[ist].equalsIgnoreCase("dx") || lis.w[ist].equalsIgnoreCase("dy") || lis.w[ist].equalsIgnoreCase("dz") ||
lis.w[ist].equalsIgnoreCase("compass") || lis.w[ist].equalsIgnoreCase("backcompass") || lis.w[ist].equalsIgnoreCase("clino") || lis.w[ist].equalsIgnoreCase("backclino"))
ist++;
for (int iist = 1; iist < ist; iist++)
CurrentLegLineFormat.StarUnits(lis.w[iist], lis.w[ist], lis.w[ist + 1], lis);
}
else if (lis.w[0].equalsIgnoreCase("*case"))
{
if (lis.w[1].equalsIgnoreCase("preserve"))
CurrentLegLineFormat.casepreservemode = 0;
else if (lis.w[1].equalsIgnoreCase("toupper"))
CurrentLegLineFormat.casepreservemode = 1;
else if (lis.w[1].equalsIgnoreCase("tolower"))
CurrentLegLineFormat.casepreservemode = -1;
else
lis.emitError("Unrecognized *case mode "+lis.w[1]);
}
else if (lis.w[0].equalsIgnoreCase("*set"))
CurrentLegLineFormat.StarSet(lis.w[1], lis.w[2], lis);
else if (lis.w[0].equalsIgnoreCase("*data"))
{
if (!CurrentLegLineFormat.StarDataNormal(lis.w, lis.iwc))
TN.emitWarning("Bad *data line: " + lis.GetLine());
}
else if (lis.w[0].equalsIgnoreCase("*fix"))
{
OneLeg oleg = CurrentLegLineFormat.ReadFix(lis.w, lis);
if (oleg != null)
{
oleg.stto = prefixd + CurrentLegLineFormat.ApplyCasePreserveMode(oleg.stto); //.toLowerCase();
vfixes.add(oleg);
}
}
else if (lis.w[0].equalsIgnoreCase("*alias"))
{
if (!(lis.w[1].equalsIgnoreCase("station") && lis.w[2].equals("-") && lis.w[3].equals("..")))
TN.emitWarning("Unrecognized *alias command");
}
else if (lis.w[0].equalsIgnoreCase("*date"))
CurrentLegLineFormat.bb_svxdate = lis.w[1];
else if (lis.w[0].equalsIgnoreCase("*title"))
CurrentLegLineFormat.bb_svxtitle = lis.w[1];
else if (lis.w[0].equalsIgnoreCase("*flags"))
CurrentLegLineFormat.StarFlags(lis.w, lis.iwc);
else if (lis.w[0].equalsIgnoreCase("*team"))
{
if (lis.w[1].equalsIgnoreCase("notes"))
CurrentLegLineFormat.bb_teamnotes = lis.remainder2.trim();
else if (lis.w[1].equalsIgnoreCase("tape"))
CurrentLegLineFormat.bb_teamtape = lis.remainder2.trim();
else if (lis.w[1].equalsIgnoreCase("insts"))
CurrentLegLineFormat.bb_teaminsts = lis.remainder2.trim();
else if (lis.w[1].equalsIgnoreCase("pics"))
CurrentLegLineFormat.bb_teampics = lis.remainder2.trim();
else
; // TN.emitMessage("Unknown *team " + lis.remainder1);
CurrentLegLineFormat.UpdateTotalTeam();
}
else if (lis.w[0].equalsIgnoreCase("*begin"))
{
String nprefixd;
if (lis.w[1].equals("")) // blank begin case
{
// no longer an issue due to ignoring structure now
// all we need to maintain track of really are flags surface
//TN.emitMessage("empty *begin in " + prefixd);
nprefixd = prefixd;
filebeginblocklegstack.add(filebeginblocklegstack.get(filebeginblocklegstack.size() - 1)); // pointer to same leg that gets rolled back with the next *end
}
else
{
nprefixd = prefixd + CurrentLegLineFormat.ApplyCasePreserveMode(lis.w[1])/*.toLowerCase()*/ + ".";
OneLeg lcurrentfilebeginblockleg = new OneLeg(CurrentLegLineFormat.ApplyCasePreserveMode(currentfilebeginblockleg.stto), nprefixd, vfilebeginblocklegs.size(), "--begincase--");
vfilebeginblocklegs.add(lcurrentfilebeginblockleg);
filebeginblocklegstack.add(lcurrentfilebeginblockleg);
currentfilebeginblockleg.lowerfilebegins.add(lcurrentfilebeginblockleg);
}
InterpretSvxTextRecurse(nprefixd, lis, CurrentLegLineFormat, depth + 1); // recurse down (first step in recursion is to clone CurrentLegLineFormat)
}
// second exit point here
else if (lis.w[0].equalsIgnoreCase("*end"))
{
if (depth == 0)
TN.emitWarning("Too many *ends for the *begin blocks");
String currentfileended = filebeginblocklegstack.get(filebeginblocklegstack.size() - 1).stto;
if (!currentfileended.equals(currentfilebeginblockleg.stto))
TN.emitError("disagreement between include and begin trees!!! "+currentfilebeginblockleg.stto);
filebeginblocklegstack.remove(filebeginblocklegstack.size() - 1);
return; // out of recursion
}
else if (lis.w[0].equalsIgnoreCase("*include"))
TN.emitWarning("word should have been stripped");
else if (lis.w[0].equalsIgnoreCase("*file_begin"))
{
OneLeg lcurrentfilebeginblockleg = new OneLeg(CurrentLegLineFormat.ApplyCasePreserveMode(currentfilebeginblockleg.stto), lis.w[1], vfilebeginblocklegs.size()+1, lis.w[2]);
vfilebeginblocklegs.add(lcurrentfilebeginblockleg);
filebeginblocklegstack.add(lcurrentfilebeginblockleg);
currentfilebeginblockleg.lowerfilebegins.add(lcurrentfilebeginblockleg);
currentfilebeginblockleg = lcurrentfilebeginblockleg;
}
else if (lis.w[0].equalsIgnoreCase("*file_end"))
{
assert currentfilebeginblockleg.stto.equals(lis.w[1]);
filebeginblocklegstack.remove(filebeginblocklegstack.size() - 1);
currentfilebeginblockleg = filebeginblocklegstack.get(filebeginblocklegstack.size() - 1);
}
else if (lis.w[0].equalsIgnoreCase("*entrance"))
; // ignore.
else if (lis.w[0].equalsIgnoreCase("*instrument"))
; // ignore.
else if (lis.w[0].equalsIgnoreCase("*export"))
; // ignore.
else if (lis.w[0].equalsIgnoreCase("*equate"))
{
SVXline svxline = new SVXline(lis.GetLine());
AddEquate(prefixd, svxline.sline, CurrentLegLineFormat);
}
else if (lis.w[0].equalsIgnoreCase("*sd"))
; // ignore.
else if (lis.w[0].equalsIgnoreCase("*cs"))
; // ignore.
else if (lis.w[0].equalsIgnoreCase("*ref"))
; // ignore.
else if (lis.w[0].equalsIgnoreCase("*require"))
; // ignore.
else if (lis.w[0].equalsIgnoreCase("*infer")) // can be infer exports on to stop the errors being generated from survex
; // ignore.
else if (lis.w[0].startsWith("*"))
TN.emitWarning("Unknown command: " + lis.w[0]);
// used to be ==2. want to use the ignoreall term in the *data normal...
else if ((lis.iwc >= 2) || ((CurrentLegLineFormat.newlineindex != -1) && (lis.iwc >= 1)) || (CurrentLegLineFormat.bnosurvey && (lis.iwc >= 1)))
{
OneLeg oleg = CurrentLegLineFormat.ReadLeg(lis.w, lis);
if (oleg != null)
{
if (oleg.stfrom != null)
oleg.stfrom = prefixd + oleg.stfrom; //.toLowerCase();
if (oleg.stto != null)
oleg.stto = prefixd + oleg.stto; //.toLowerCase();
if ((oleg.stto != null) && (oleg.stfrom != null))
vlegs.add(oleg);
else if ((oleg.stto != null) || (oleg.stfrom != null))
vanonymouses.add(oleg);
else
TN.emitWarning("fully anonymous leg found");
oleg.llcurrentfilebeginblockleg = currentfilebeginblockleg;
currentfilebeginblockleg.lowerfilebegins.add(oleg); // mix in the legs we have here so we can find the C of G for each of these stations corresponding to a section of the cave
}
}
else
lis.emitWarning("Too few argumentss: " + lis.GetLine());
}
// exit point when run out of text
if (depth != 0)
TN.emitWarning("Data ended with *begin blocks still open");
}
/////////////////////////////////////////////
void InterpretSvxText(String svxtext)
{
vlegs = new ArrayList();
vfixes = new ArrayList();
vanonymouses = new ArrayList();
osmap = new HashMap();
eqmap = new HashMap >();
vfilebeginblocklegs = new ArrayList();
osfileblockmap = new HashMap();
LineInputStream lis = new LineInputStream(svxtext, null);
LegLineFormat llf = new LegLineFormat();
llf.btopextendedelevation = btopextendedelevation;
InterpretSvxTextRecurse("", lis, llf, 0);
avgfix = new Vec3(0.0F, 0.0F, 0.0F);
for (OneLeg ol : vfixes)
avgfix.PlusEquals(ol.mlegvec);
if (vfixes.size() != 0)
avgfix.TimesEquals(1.0F / vfixes.size());
// group the equates into the map
for (Set vs : eqmap.values())
{
String osn = Collections.min(vs);
OneStation osc = new OneStation(osn);
for (String s : vs)
osmap.put(s, osc);
}
// put the station objects into the legs
for (OneLeg ol : vlegs)
{
if (ol.stfrom != null) // superfluous
{
String lstfrom = ol.stfrom; //.toLowerCase();
ol.osfrom = osmap.get(lstfrom);
if (ol.osfrom == null)
{
ol.osfrom = new OneStation(ol.stfrom);
osmap.put(lstfrom, ol.osfrom);
}
}
String lstto = ol.stto; //.toLowerCase();
ol.osto = osmap.get(lstto);
if (ol.osto == null)
{
ol.osto = new OneStation(ol.stto);
osmap.put(lstto, ol.osto);
}
}
// put the station objects into the legs
for (OneLeg ol : vanonymouses)
{
if (ol.stto == null)
{
assert (ol.stfrom != null);
String lstfrom = ol.stfrom; //.toLowerCase();
ol.osfrom = osmap.get(lstfrom);
if (ol.osfrom == null)
{
ol.osfrom = new OneStation(ol.stfrom);
osmap.put(lstfrom, ol.osfrom);
}
ol.osto = new OneStation("anonymous_station");
}
else
{
assert (ol.stfrom == null);
String lstto = ol.stto; //.toLowerCase();
ol.osto = osmap.get(lstto);
if (ol.osto == null)
{
ol.osto = new OneStation(ol.stfrom);
osmap.put(lstto, ol.osto);
}
ol.osfrom = new OneStation("anonymous_station");
}
}
// put station object in the fixes
for (OneLeg olf : vfixes)
{
assert (olf.stfrom == null);
String lstto = olf.stto; //.toLowerCase();
olf.osto = osmap.get(lstto);
if (olf.osto == null)
{
olf.osto = new OneStation(olf.stto);
osmap.put(lstto, olf.osto);
}
}
TN.emitMessage("Num Legs: " + vlegs.size() + " EQQ: " + eqmap.size() + " SS: " + osmap.values().size() + " " + avgfix.toString());
// bfilebeginmode tree of legs
for (OneLeg ol : vfilebeginblocklegs)
{
ol.osfrom = osfileblockmap.get(ol.stfrom);
if (ol.osfrom == null)
{
ol.osfrom = new OneStation(ol.stfrom);
osfileblockmap.put(ol.stfrom, ol.osfrom);
}
ol.osto = osfileblockmap.get(ol.stto);
if (ol.osto == null)
{
ol.osto = new OneStation(ol.stto);
osfileblockmap.put(ol.stto, ol.osto);
}
}
}
/////////////////////////////////////////////
class posentry extends Vec3d
{
String sname;
posentry(String[] w)
{
assert w[0].equals("");
if (w.length == 4)
sname = "";
else
{
assert (w.length == 5);
sname = w[4];
}
x = Double.parseDouble(w[1]);
y = Double.parseDouble(w[2]);
z = Double.parseDouble(w[3]);
}
}
/////////////////////////////////////////////
boolean LoadPosFile(LineInputStream lis, Vec3 appsketchLocOffset) throws IOException
{
lis.FetchNextLineNoSplit();
System.out.println("POSLINE0: " + lis.GetLine());
// ( -19.97, -0.88, -64.00 ) 204.110_bidet.1
// load all the stations first so we can average them
sketchLocOffset = (appsketchLocOffset == null ? new Vec3d(0.0, 0.0, 0.0) : new Vec3d(appsketchLocOffset.x, appsketchLocOffset.y, appsketchLocOffset.z));
List posentries = new ArrayList();
while (lis.FetchNextLineNoSplit())
{
String[] w = lis.GetLine().split("[\\s,()]+");
posentry pe = new posentry(w);
posentries.add(pe);
if (appsketchLocOffset == null)
sketchLocOffset.PlusEquals(pe);
}
if ((posentries.size() != 0) && (appsketchLocOffset == null))
sketchLocOffset.TimesEquals(1.0 / posentries.size());
int serrs0 = 0;
for (posentry pe : posentries)
{
OneStation os = osmap.get(pe.sname);
if (os != null)
{
if (os.Loc == null)
os.Loc = new Vec3((float)(pe.x - sketchLocOffset.x), (float)(pe.y - sketchLocOffset.y), (float)(pe.z - sketchLocOffset.z));
else if (!((Math.abs(os.Loc.x + sketchLocOffset.x - pe.x) <= 0.01) && (Math.abs(os.Loc.y + sketchLocOffset.y - pe.y) <= 0.01) && (Math.abs(os.Loc.z + sketchLocOffset.z - pe.z) <= 0.01)))
{
TN.emitWarning("DUPlicate pos: " + pe.sname + ": " + Math.abs(os.Loc.x + sketchLocOffset.x - pe.x) + " " + Math.abs(os.Loc.y + sketchLocOffset.y - pe.y) + " " + Math.abs(os.Loc.z + sketchLocOffset.z - pe.z));
assert (Math.abs(os.Loc.x + sketchLocOffset.x - pe.x) <= 0.01) && (Math.abs(os.Loc.y + sketchLocOffset.y - pe.y) <= 0.01) && (Math.abs(os.Loc.z + sketchLocOffset.z - pe.z) <= 0.01);
}
}
else if (!pe.sname.equals("") && (serrs0++ < 10))
TN.emitWarning("unable to match pos station: '" + pe.sname + "'"); // might be a naked fix
}
if (serrs0 > 10)
TN.emitWarning("... and " + serrs0 + " more unable to match pos station");
int serrs1 = 0;
for (OneStation os : osmap.values())
if ((os.Loc == null) && (serrs1++ < 10))
TN.emitWarning("** Station not POS applied: " + os.name);
if (serrs1 > 10)
TN.emitWarning("... and " + serrs1 + " more Station not POS applied");
for (OneStation os : osmap.values())
{
if (os.Loc == null)
return !TN.emitWarning("Station not POS applied: " + os.name);
}
return true;
}
// range values of the box (used for perspective projections
float volxlo, volxhi;
float volylo, volyhi;
float volzlo, volzhi;
/////////////////////////////////////////////
boolean MergeVol(float x, float y, float z, boolean bFirst)
{
//System.out.println(" x=" + x + " y=" + y + " z=" + z + " " + bFirst);
if (bFirst || (x < volxlo))
volxlo = x;
if (bFirst || (x > volxhi))
volxhi = x;
if (bFirst || (y < volylo))
volylo = y;
if (bFirst || (y > volyhi))
volyhi = y;
if (bFirst || (z < volzlo))
volzlo = z;
if (bFirst || (z > volzhi))
volzhi = z;
return false;
}
/////////////////////////////////////////////
Vec3 GoLeg(Vec3 vf, OneLeg ol, int sign)
{
if (!btopextendedelevation)
return new Vec3(vf.x + ol.mlegvec.x * sign, vf.y + ol.mlegvec.y * sign, vf.z + ol.mlegvec.z * sign);
int xsign = (ol.btopextendedelevationflip ? -1 : 1);
return new Vec3(vf.x + ol.mlegvec.x * xsign, vf.y + ol.mlegvec.y * sign, vf.z + ol.mlegvec.z * sign);
}
/////////////////////////////////////////////
void CalcPosStack()
{
while (!statrec.isEmpty())
{
OneStation os = statrec.pop();
for (OneLeg ol : os.olconn)
{
if (ol.bnosurvey)
continue;
if ((os == ol.osfrom) && (ol.osto.Loc == null))
{
nstationsdone++;
OneStation osn = ol.osto;
osn.Loc = GoLeg(os.Loc, ol, +1);
statrec.push(osn);
}
if ((os == ol.osto) && (ol.osfrom.Loc == null))
{
nstationsdone++;
OneStation osn = ol.osfrom;
osn.Loc = GoLeg(os.Loc, ol, -1);
statrec.push(osn);
}
}
}
}
/////////////////////////////////////////////
int CalcStationPositions(boolean bfilebeginmode)
{
// build up the network of stations
int npieces = 0;
int nfixpieces = 0;
statrec = new Stack();
List lvlegs = (bfilebeginmode ? vfilebeginblocklegs : vlegs);
for (OneLeg ol : lvlegs)
{
ol.osfrom.olconn.add(ol);
ol.osto.olconn.add(ol);
}
if (!bfilebeginmode)
{
for (OneLeg ol : vanonymouses)
ol.osfrom.olconn.add(ol);
}
if (!bfilebeginmode)
{
for (OneLeg olf : vfixes)
{
if ((olf.osto != null) && (olf.osto.Loc == null))
{
olf.osto.Loc = new Vec3((float)(olf.mlegvec.x - sketchLocOffset.x), (float)(olf.mlegvec.y - sketchLocOffset.y), (float)(olf.mlegvec.z - sketchLocOffset.z));
statrec.push(olf.osto);
nstationsdone++;
}
}
}
if (!statrec.isEmpty())
{
CalcPosStack();
npieces++;
}
if (!bfilebeginmode && (vanonymouses.size() != 0) && (lvlegs.size() != 0) && (vanonymouses.get(0).flinenumber < lvlegs.get(0).flinenumber) && (vanonymouses.get(0).osfrom != null) && (vanonymouses.get(0).osfrom.Loc == null))
{
// repeat of the code below but allows us to set the fixed point on the anonymous station in preference if it came earlier in the file
// which is how the toporobot file sets it by convention
OneLeg ol = vanonymouses.get(0);
TN.emitWarning("making station calculations for a ANON disconnected component of the survey at station "+ol.osfrom.name);
ol.osfrom.Loc = new Vec3((float)npieces * 1000.0F, 0.0F, 0.0F);
statrec.push(ol.osfrom);
nstationsdone++;
npieces++;
CalcPosStack();
}
for (OneLeg ol : lvlegs)
{
if ((ol.osfrom != null) && (ol.osfrom.Loc == null))
{
TN.emitWarning("making station calculations for a disconnected component of the survey at station "+ol.osfrom.name);
ol.osfrom.Loc = new Vec3((float)npieces * 1000.0F, 0.0F, 0.0F);
statrec.push(ol.osfrom);
nstationsdone++;
npieces++;
CalcPosStack();
}
}
return npieces;
}
/////////////////////////////////////////////
void ConstructWireframe(List lvlegs, List lvstations)
{
lvlegs.addAll(vlegs);
Set sstations = new HashSet();
sstations.addAll(osmap.values());
lvstations.addAll(sstations);
// make the bounding box values, just containing the real legs
boolean bFirst = true;
for (OneStation os : sstations)
{
if (os.Loc != null)
bFirst = MergeVol(os.Loc.x, os.Loc.y, os.Loc.z, bFirst);
else
System.out.println("SST missing: " + os.name);
}
System.out.println("Volume range [" + volxlo + ", " + volxhi + "] [" + volylo + ", " + volyhi + "] [" + (volzlo) + ", " + volzhi + "]");
}
/////////////////////////////////////////////
/////////////////////////////////////////////
// this is where we match the positions and discard vlegs already accounted for
boolean ThinDuplicateLegs(List vnodes, List vpaths)
{
Map cnodemaps = new HashMap();
for (OnePathNode opn : vnodes)
{
if (opn.IsCentrelineNode())
cnodemaps.put(opn.pnstationlabel, opn);
}
if (cnodemaps.isEmpty())
return true;
float tol = 0.01F;
List lvlegs = vlegs;
vlegs = new ArrayList();
for (OneLeg ol : lvlegs)
{
if (ol.osfrom == null)
continue;
OnePathNode eopnfrom = cnodemaps.get(ol.osfrom.name);
OnePathNode eopnto = cnodemaps.get(ol.osto.name);
if (eopnfrom != null)
{
System.out.println(" " + Math.abs(ol.osfrom.station_opn.pn.getX() - eopnfrom.pn.getX()) + " " + Math.abs(ol.osfrom.station_opn.pn.getY() - eopnfrom.pn.getY()) + " " + Math.abs(ol.osfrom.station_opn.zalt - eopnfrom.zalt));
if ((Math.abs(ol.osfrom.station_opn.pn.getX() - eopnfrom.pn.getX()) > tol) || (Math.abs(ol.osfrom.station_opn.pn.getY() - eopnfrom.pn.getY()) > tol) || (Math.abs(ol.osfrom.station_opn.zalt - eopnfrom.zalt) > tol))
return false;
ol.osfrom.station_opn = eopnfrom;
}
if (eopnto != null)
{
System.out.println(" t " + Math.abs(ol.osto.station_opn.pn.getX() - eopnto.pn.getX()) + " " + Math.abs(ol.osto.station_opn.pn.getY() - eopnto.pn.getY()) + " " + Math.abs(ol.osto.station_opn.zalt - eopnto.zalt));
if ((Math.abs(ol.osto.station_opn.pn.getX() - eopnto.pn.getX()) > tol) || (Math.abs(ol.osto.station_opn.pn.getY() - eopnto.pn.getY()) > tol) || (Math.abs(ol.osto.station_opn.zalt - eopnto.zalt) > tol))
return false;
ol.osto.station_opn = eopnto;
}
if ((eopnfrom == null) || (eopnto == null)) // || the nodes exist, but there's no corresponding leg in the list
vlegs.add(ol);
}
return true;
}
static int DDD = 3;
/////////////////////////////////////////////
String FindStationTitle(OnePath op)
{
//String lpnlabtail = op.plabedl.centrelinetail.replaceAll("[|^]", ".");
//String lpnlabhead = op.plabedl.centrelinehead.replaceAll("[|^]", ".");
String lpnlabtail = (op.pnstart != null ? op.pnstart.pnstationlabel.replaceAll("[|^]", ".") : "");
// this has had null; don't know how.
String lpnlabhead = (op.pnend != null ? op.pnend.pnstationlabel.replaceAll("[|^]", ".") : "");
if (op.pnend == null)
System.out.println("FSSSST nll " + lpnlabtail);
String res1 = null;
for (OneLeg ol : vlegs)
{
// I don't know if we're doing all the equates properly here
// op.plabedl.centrelinetail op.plabedl.centrelinehead but with [|^] converted to .
if ((ol.stfrom != null) && !ol.svxtitle.equals(""))
{
boolean bfrom = ol.osfrom.name.equalsIgnoreCase(lpnlabtail);
boolean bto = ol.osto.name.equalsIgnoreCase(lpnlabhead);
if (bfrom && bto)
return ol.svxtitle;
if (bfrom || bto)
res1 = ol.svxtitle; // captures one end
}
}
/*
System.out.println("Failed to match up " + lpnlabtail + " -- " + lpnlabhead);
System.out.println("\n****");
System.out.println(res1);
for (OneLeg ol : vlegs)
{
if (ol.stfrom != null)
System.out.println(" " + ol.osfrom.name + " " + ol.osto.name);
}
//if (DDD-- < 0)
System.exit(0);
*/
return res1;
}
}
tunnelx-20190701/src/SketchBackgroundPanel.java 0000664 0001750 0001750 00000037244 13531571147 020746 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2004 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JRadioButton;
import javax.swing.ButtonGroup;
import javax.swing.JTextField;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JComboBox;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.awt.geom.Point2D;
import java.util.List;
import java.util.ArrayList;
/////////////////////////////////////////////
class SketchBackgroundPanel extends JPanel
{
SketchDisplay sketchdisplay;
JCheckBox cbshowbackground;
JCheckBox cbshowgrid;
JCheckBox cbsnaptogrid;
// tells us the grid spacing.
JTextField tfgridspacing = new JTextField("");
int gsoffset = 0;
JComboBox cbbackimage = new JComboBox();
List tsvpathsframescbelements = new ArrayList(); // parallel to the list
List tsvpathsframescbelementsS = new ArrayList(); // parallel to the list; used to prevent multiple equal strings getting into the combobox, which prevents it working;
// the correct implementation would have been to add OnePaths into the combobox and apply the toString function to get the names
/////////////////////////////////////////////
ActionListener cbbackimageAL = new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
System.out.println("cbbackimageSEL " + cbbackimage.getSelectedIndex() + " " + event.getActionCommand());
int i = cbbackimage.getSelectedIndex();
if (i != -1)
{
OnePath op = tsvpathsframescbelements.get(i);
if (op.IsSketchFrameConnective())
{
sketchdisplay.sketchlinestyle.pthstyleareasigtab.LoadSketchFrameDef(op.plabedl.sketchframedef, false);
if (!op.plabedl.sketchframedef.sfsketch.equals(""))
{
sketchdisplay.sketchgraphicspanel.tsketch.opframebackgrounddrag = op;
sketchdisplay.sketchlinestyle.pthstyleareasigtab.UpdateSFView(op, false);
}
else
sketchdisplay.sketchgraphicspanel.SelectSingle(op); // select it for the subset kind
}
else
{
assert op.IsSurvexLabel();
sketchdisplay.sketchgraphicspanel.SelectSingle(op); // select it for the subset kind
//sketchdisplay.ImportCentrelineLabel(true); // this causes a crash
}
}
}
};
/////////////////////////////////////////////
class radbuttpress implements ActionListener
{
int lgsoffset;
radbuttpress(int llgsoffset)
{
lgsoffset = llgsoffset;
}
public void actionPerformed(ActionEvent event)
{
gsoffset = lgsoffset;
sketchdisplay.sketchgraphicspanel.RedoBackgroundView();
}
};
/////////////////////////////////////////////
void SetGridOrigin(boolean btocurrent)
{
if (btocurrent)
{
if (sketchdisplay.sketchgraphicspanel.currgenpath != null)
{
Point2D pn = sketchdisplay.sketchgraphicspanel.currgenpath.pnstart.pn;
sketchdisplay.sketchgraphicspanel.sketchgrid.txorig = (float)pn.getX();
sketchdisplay.sketchgraphicspanel.sketchgrid.tyorig = (float)pn.getY();
}
}
else
{
sketchdisplay.sketchgraphicspanel.sketchgrid.txorig = sketchdisplay.sketchgraphicspanel.sketchgrid.xorig;
sketchdisplay.sketchgraphicspanel.sketchgrid.tyorig = sketchdisplay.sketchgraphicspanel.sketchgrid.yorig;
}
sketchdisplay.sketchgraphicspanel.RedoBackgroundView();
}
/////////////////////////////////////////////
boolean UploadBackgroundFile()
{
OnePath op = sketchdisplay.sketchgraphicspanel.tsketch.opframebackgrounddrag;
if (op == null)
return TN.emitWarning("Must have background image visible");
if (op.plabedl.sketchframedef.pframeimage != null)
{
String filename = op.plabedl.sketchframedef.sfsketch;
filename = filename.replace("\\", "|");
filename = filename.replace("/", "|");
System.out.println("TO uploadedfile " + filename);
String target = TN.troggleurl + "jgtuploadfile"; // for now
FileAbstraction uploadedfile = NetConnection.uploadFile(FileAbstraction.MakeOpenableFileAbstraction(target), "backgroundimage", filename, op.plabedl.sketchframedef.pframeimage.GetImage(true), null);
System.out.println("uploadedfile " + uploadedfile);
if (uploadedfile.localurl != null)
{
op.plabedl.sketchframedef.sfsketch = uploadedfile.getPath();
op.plabedl.sketchframedef.SetSketchFrameFiller(sketchdisplay.mainbox, sketchdisplay.sketchgraphicspanel.tsketch.realposterpaperscale, sketchdisplay.sketchgraphicspanel.tsketch.sketchLocOffset, sketchdisplay.sketchgraphicspanel.tsketch.sketchfile);
if (op == sketchdisplay.sketchgraphicspanel.currgenpath)
sketchdisplay.sketchlinestyle.pthstyleareasigtab.UpdateSFView(op, true);
UpdateBackimageCombobox(55); // magic number forces update of dropdown box
sketchdisplay.sketchgraphicspanel.RedrawBackgroundView();
}
}
return true;
}
/////////////////////////////////////////////
void NewBackgroundFile()
{
TN.emitMessage("calling NewBackgroundFile " + sketchdisplay.sketchgraphicspanel.tsketch.sketchfile);
SvxFileDialog sfiledialog = SvxFileDialog.showOpenDialog(TN.currentDirectoryIMG, sketchdisplay, SvxFileDialog.FT_BITMAP, false);
if ((sfiledialog == null) || (sfiledialog.svxfile == null))
return;
String imfilename = null;
if (sfiledialog.svxfile.localfile != null)
{
TN.currentDirectoryIMG = sfiledialog.svxfile;
try
{
imfilename = FileAbstraction.GetImageFileName(sketchdisplay.sketchgraphicspanel.tsketch.sketchfile.getParentFile(), sfiledialog.svxfile);
}
catch (IOException ie)
{ ie.printStackTrace(); TN.emitWarning(ie.toString()); };
}
else if (sfiledialog.svxfile.localurl != null)
{
try
{
//imfilename = sfiledialog.svxfile.localurl.toString();
imfilename = FileAbstraction.GetImageFileName(sketchdisplay.sketchgraphicspanel.tsketch.sketchfile, sfiledialog.svxfile);
}
catch (IOException ie)
{ ie.printStackTrace(); TN.emitWarning(ie.toString()); };
}
if (imfilename == null)
return;
OnePath prevcurrpath = sketchdisplay.sketchgraphicspanel.currgenpath;
sketchdisplay.sketchgraphicspanel.ClearSelection(true);
sketchdisplay.sketchgraphicspanel.repaint();
System.out.println("YYYYY " + imfilename);
OnePath gop = sketchdisplay.sketchgraphicspanel.MakeConnectiveLineForData(0, 1.0F); // this is made temporarily to hold the sketchframedef on
//sketchdisplay.sketchgraphicspanel.RedrawBackgroundView();
gop.plabedl.sketchframedef.sfsketch = imfilename;
gop.plabedl.sketchframedef.sfscaledown = 1.0F;
gop.plabedl.sketchframedef.sfrotatedeg = 0.0F;
gop.plabedl.sketchframedef.sfxtrans = (sketchdisplay.sketchgraphicspanel.tsketch.sketchLocOffset.x / TN.CENTRELINE_MAGNIFICATION);
gop.plabedl.sketchframedef.sfytrans = -(sketchdisplay.sketchgraphicspanel.tsketch.sketchLocOffset.y / TN.CENTRELINE_MAGNIFICATION);
gop.plabedl.sketchframedef.SetSketchFrameFiller(sketchdisplay.mainbox, sketchdisplay.sketchgraphicspanel.tsketch.realposterpaperscale, sketchdisplay.sketchgraphicspanel.tsketch.sketchLocOffset, sketchdisplay.sketchgraphicspanel.tsketch.sketchfile);
sketchdisplay.sketchlinestyle.pthstyleareasigtab.UpdateSFView(gop, true);
sketchdisplay.sketchgraphicspanel.tsketch.opframebackgrounddrag = gop;
gop.plabedl.sketchframedef.MaxCentreOnScreenButt(sketchdisplay.sketchgraphicspanel.getSize(), true, 1.0, sketchdisplay.sketchgraphicspanel.tsketch.sketchLocOffset, sketchdisplay.sketchgraphicspanel.currtrans);
sketchdisplay.sketchlinestyle.pthstyleareasigtab.UpdateSFView(gop, true);
OnePath ggop = gop.plabedl.sketchframedef.MakeBackgroundOutline(1.0, sketchdisplay.sketchgraphicspanel.tsketch.sketchLocOffset);
ggop.CopyPathAttributes(gop);
assert ggop.plabedl.sketchframedef.IsImageType();
List pthstoadd = new ArrayList();
pthstoadd.add(ggop);
sketchdisplay.sketchgraphicspanel.CommitPathChanges(null, pthstoadd);
// sketchdisplay.sketchgraphicspanel.FrameBackgroundOutline(null);
sketchdisplay.sketchgraphicspanel.tsketch.opframebackgrounddrag = ggop;
sketchdisplay.sketchlinestyle.pthstyleareasigtab.UpdateSFView(ggop, true);
if (sketchdisplay.bottabbedpane.getSelectedIndex() == 1)
UpdateBackimageCombobox(4);
if (!sketchdisplay.miShowBackground.isSelected())
sketchdisplay.miShowBackground.doClick();
sketchdisplay.sketchgraphicspanel.RedrawBackgroundView();
}
/////////////////////////////////////////////
// with this case we're removing the action listener to avoid any events firing that are not from mouse clicks
synchronized void UpdateBackimageCombobox(int iy) // the iy does nothing -- just for debug printing
{
OnePath tsvpathsframescbelementssel = sketchdisplay.sketchgraphicspanel.tsketch.opframebackgrounddrag;
List ltsvpathsframescbelements = sketchdisplay.sketchgraphicspanel.tsvpathsframesall;
boolean baddselelement = ((tsvpathsframescbelementssel != null) && !ltsvpathsframescbelements.contains(tsvpathsframescbelementssel));
// check if the values have changed
assert tsvpathsframescbelements.size() == cbbackimage.getItemCount();
boolean btoupdate = (tsvpathsframescbelements.size() != ltsvpathsframescbelements.size() + (baddselelement ? 1 : 0));
if (iy == 55)
btoupdate = true;
int isel = -1;
if (!btoupdate)
{
for (int i = 0; i < ltsvpathsframescbelements.size(); i++)
{
if (tsvpathsframescbelements.get(i) != ltsvpathsframescbelements.get(i))
{
btoupdate = true;
break;
}
if (tsvpathsframescbelements.get(i) == tsvpathsframescbelementssel)
isel = i;
}
if (baddselelement && !btoupdate)
{
if (tsvpathsframescbelements.get(ltsvpathsframescbelements.size()) != tsvpathsframescbelementssel)
btoupdate = true;
else
isel = ltsvpathsframescbelements.size();
}
}
if (btoupdate)
{
tsvpathsframescbelements.clear();
tsvpathsframescbelements.addAll(ltsvpathsframescbelements);
if (baddselelement)
tsvpathsframescbelements.add(tsvpathsframescbelementssel);
// create distinct strings
tsvpathsframescbelementsS.clear();
for (OnePath op : tsvpathsframescbelements)
{
String ssval;
if (op.IsSketchFrameConnective())
{
if (!op.plabedl.sketchframedef.sfsketch.equals(""))
ssval = TN.shortenString(op.plabedl.sketchframedef.sfsketch, 35);
else
ssval = "Subset colours " + op.plabedl.sketchframedef.submapping.size();
}
else
{
assert op.IsSurvexLabel();
ssval = "Survex label";
}
int i = 1;
String lssval = ssval;
while (tsvpathsframescbelementsS.contains(lssval))
lssval = ssval + " (" + (++i) + ")";
tsvpathsframescbelementsS.add(lssval);
}
assert tsvpathsframescbelements.size() == tsvpathsframescbelementsS.size();
// suppress the action listener
cbbackimage.removeActionListener(cbbackimageAL);
cbbackimage.removeAllItems();
for (int i = 0; i < tsvpathsframescbelements.size(); i++)
{
// must give all entries different names because the implementation of setSelectedIndex is setSelectedItem
cbbackimage.addItem(tsvpathsframescbelementsS.get(i));
if (tsvpathsframescbelements.get(i) == tsvpathsframescbelementssel)
isel = i;
}
if (isel != cbbackimage.getSelectedIndex())
cbbackimage.setSelectedIndex(isel);
cbbackimage.addActionListener(cbbackimageAL);
}
else if (isel != cbbackimage.getSelectedIndex())
{
// suppress the action listener
cbbackimage.removeActionListener(cbbackimageAL);
cbbackimage.setSelectedIndex(isel);
cbbackimage.addActionListener(cbbackimageAL);
}
assert (isel == -1 || (tsvpathsframescbelements.get(isel) == tsvpathsframescbelementssel));
assert isel == cbbackimage.getSelectedIndex();
}
/////////////////////////////////////////////
SketchBackgroundPanel(SketchDisplay lsketchdisplay)
{
sketchdisplay = lsketchdisplay;
// grid spacing controls
JPanel pangridspacingc = new JPanel(new GridLayout(1, 0));
ButtonGroup buttgp = new ButtonGroup();
for (int i = -1; i <= 1; i++)
{
JRadioButton radbutt = new JRadioButton("", (i == 0));
radbutt.addActionListener(new radbuttpress(i));
buttgp.add(radbutt);
pangridspacingc.add(radbutt);
}
tfgridspacing.setEditable(false);
pangridspacingc.add(tfgridspacing);
// impossible to get checkboxmenu items to reflect at these places (which would have been ideal)
// maybe it should update the word on the button
cbshowbackground = new JCheckBox("Show Background", true);
cbshowbackground.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event)
{ if (sketchdisplay.miShowBackground.isSelected() != cbshowbackground.isSelected())
{ sketchdisplay.miShowBackground.doClick();
}
} } );
cbshowgrid = new JCheckBox("Show Grid", true);
cbshowgrid.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event)
{ if (sketchdisplay.miShowGrid.isSelected() != cbshowgrid.isSelected())
{ sketchdisplay.miShowGrid.doClick();
}
} } );
cbsnaptogrid = new JCheckBox("Snap to Grid", false);
cbsnaptogrid.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event)
{ if (sketchdisplay.miSnapToGrid.isSelected() != cbsnaptogrid.isSelected())
{ sketchdisplay.miSnapToGrid.doClick();
}
} } );
cbbackimage.addActionListener(cbbackimageAL);
setLayout(new BorderLayout());
JPanel panupper = new JPanel(new BorderLayout());
JPanel panuppersec = new JPanel(new GridLayout(0, 2));
panuppersec.add(cbshowbackground);
panuppersec.add(new JButton(sketchdisplay.acaAddImage));
panuppersec.add(new JButton(sketchdisplay.acaMoveBackground));
panuppersec.add(new JButton(sketchdisplay.acaReloadImage));
panupper.add(panuppersec, BorderLayout.NORTH);
panupper.add(cbbackimage, BorderLayout.SOUTH);
JPanel panlower = new JPanel(new GridLayout(0, 2));
panlower.add(cbsnaptogrid);
panlower.add(cbshowgrid);
panlower.add(new JLabel("Grid spacing (lo-hi)"));
panlower.add(pangridspacingc);
panlower.add(new JButton(sketchdisplay.acvSetGridOrig));
panlower.add(new JButton(sketchdisplay.acvResetGridOrig));
add(panupper, BorderLayout.NORTH);
add(panlower, BorderLayout.SOUTH);
}
};
tunnelx-20190701/src/Vec3d.java 0000664 0001750 0001750 00000003560 13531571147 015503 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2008 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
//
//
// Vec3d - double version of Vec3
//
//
class Vec3d
{
public double x;
public double y;
public double z;
/////////////////////////////////////////////
public Vec3d()
{
x = 0.0;
y = 0.0;
z = 0.0;
}
/////////////////////////////////////////////
public String toString()
{
return String.valueOf(x) + " " + String.valueOf(y) + " " + String.valueOf(z);
}
/////////////////////////////////////////////
Vec3d(double lx, double ly, double lz)
{
x = lx;
y = ly;
z = lz;
}
/////////////////////////////////////////////
Vec3d(String w0, String w1, String w2)
{
x = Double.parseDouble(w0);
y = Double.parseDouble(w1);
z = Double.parseDouble(w2);
}
/////////////////////////////////////////////
public void PlusEquals(Vec3d a)
{
x += a.x;
y += a.y;
z += a.z;
}
/////////////////////////////////////////////
public void TimesEquals(double f)
{
x *= f;
y *= f;
z *= f;
}
}
tunnelx-20190701/src/PtrelLn.java 0000664 0001750 0001750 00000047465 13531571147 016133 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Line2D;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
//
//
//
//
//
/////////////////////////////////////////////
// point relative to line
/////////////////////////////////////////////
class PtrelSLn
{
Line2D.Double axis;
double vax, vay; // vector
double lgsq, lg; // length.
double lam0, lam1; // vector displaced endpoints of the axis.
double pvax, pvay; // perp vector
double pad; // perp axis displacement.
PtrelSLn(Line2D.Double laxis)
{
axis = laxis;
vax = axis.getX2() - axis.getX1();
vay = axis.getY2() - axis.getY1();
lgsq = vax * vax + vay * vay;
//check for point1 being the same as point2 else get divide by zero errors.
//functions calling this should also check
if(lgsq != 0)
{
lg = Math.sqrt(lgsq);
lam0 = (vax * axis.getX1() + vay * axis.getY1()) / lgsq;
lam1 = (vax * axis.getX2() + vay * axis.getY2()) / lgsq;
pvax = -vay;
pvay = vax;
pad = (pvax * axis.getX1() + pvay * axis.getY1()) / lgsq;
}
}
};
/////////////////////////////////////////////
// by pairs
class PtrelPLn
{
OnePath cp;
OnePath crp;
PtrelSLn ax0;
PtrelSLn ax1;
// mutable values
double destx;
double desty;
double geoweight; // additional weighting derived from the position of the point to line line
double disttoaxis;
// proxdistance weights at the end pathnodes of a path
double proxdistw0;
double proxdistw1;
/////////////////////////////////////////////
PtrelPLn(OnePath lcp, OnePath lcrp)
{
cp = lcp;
crp = lcrp;
}
/////////////////////////////////////////////
void MakePtlAxes()
{
Line2D.Double lax0 = new Line2D.Double(cp.pnstart.pn, cp.pnend.pn);
Line2D.Double lax1 = new Line2D.Double(crp.pnstart.pn, crp.pnend.pn);
ax0 = new PtrelSLn(lax0);
ax1 = new PtrelSLn(lax1);
}
/////////////////////////////////////////////
// calculates a weighting according to how on the face we are
// this weight by orientation doesn't seem to help much, and in fact stops things on corners being pulled along enough
double CalcGeoWeightFacing(double lam, double pd)
{
// distance of point from the ax0 line.
double c = Math.abs(pd - ax0.pad) * ax0.lg;
// distance of point along the ax0 line from closest point.
double a = (lam - ax0.lam0) * ax0.lg;
double b = (lam - ax0.lam1) * ax0.lg;
double lgeoweight = 10000;
if (c > 0.0001)
lgeoweight = Math.abs(Math.atan(b / c) - Math.atan(a / c)) / c;
else if ((Math.abs(a) > 0.0001) && (Math.abs(b) > 0.0001) && ((a < 0) == (b < 0)))
lgeoweight = Math.abs(1 / a - 1 / b);
if (lgeoweight > 10000)
lgeoweight = 10000;
return lgeoweight;
}
/////////////////////////////////////////////
double CalcGeoWeightDistanceSQ(double lam, double pd)
{
// distance of point from the ax0 line.
double c = Math.abs(pd - ax0.pad) * ax0.lg;
disttoaxis = c;
// distance of point along the ax0 line from closest point.
double d = 0.0;
if (lam < ax0.lam0)
d = (ax0.lam0 - lam) * ax0.lg;
else if (lam > ax0.lam1)
d = (lam - ax0.lam1) * ax0.lg;
double lgeoweight = c * c + d * d;
return ax0.lg / (10.0 + lgeoweight);
}
/////////////////////////////////////////////
void TransformPt(double x, double y)
{
//check for either ax0 or ax1 lines having zero length else get divide by zero errors.
if ((ax0.lgsq!=0) && (ax1.lgsq!=0))
{
double lam = (ax0.vax * x + ax0.vay * y) / ax0.lgsq;
double pd = (ax0.pvax * x + ax0.pvay * y) / ax0.lgsq;
// calculate the geoweight.
// geoweight = CalcGeoWeightFacing(lam, pd); // this one not so good for it
geoweight = CalcGeoWeightDistanceSQ(lam, pd);
// find the destination point
double dlam = lam - ax0.lam0 + ax1.lam0;
// factor out changes in width (same idea independently thought out from Walls)
double wdfac = ax0.lg / ax1.lg;
double dpd = (pd - ax0.pad) * wdfac + ax1.pad;
destx = dlam * ax1.vax + dpd * ax1.pvax;
desty = dlam * ax1.vay + dpd * ax1.pvay;
}
//if ax0 or ax1 are zero length set weight to zero so contribution ignored
else
{
destx = 0;
desty = 0;
geoweight = 0;
}
}
};
/////////////////////////////////////////////
// there's a proximity engine, and this class balances out the
// weights of all the proximities to discover the warping
class PtrelLn
{
// corresponding arrays of path nodes.
Map opnMap = new HashMap();
List wptrel = new ArrayList();
double destx;
double desty;
double destz;
ProximityDerivation pd = null;
Set cenconnnodes = new HashSet(); // set of nodes connected to the centreline
AffineTransform ucavgtrans = new AffineTransform(); // applied to the unconnected pieces
double realposterpaperscale;
Vec3 sketchLocOffsetFrom;
Vec3 sketchLocOffsetTo;
/////////////////////////////////////////////
PtrelLn()
{;}
/////////////////////////////////////////////
void PrepareProximity(OneSketch isketch)
{
pd = new ProximityDerivation(isketch);
pd.parainstancequeue.bDropdownConnectiveTraversed = true;
pd.parainstancequeue.bCentrelineTraversed = true;
pd.parainstancequeue.fcenlinelengthfactor = 10.0F; // factor of length added to centreline connections (to deal with vertical line cases)
//clpaths = lclpaths;
// extract correspondences between the nodes of the endpoints.
// as well as the corresponding distortions.
opnMap.clear();
for (PtrelPLn wptreli : wptrel)
{
wptreli.MakePtlAxes();
opnMap.put(wptreli.cp.pnstart, wptreli.crp.pnstart);
opnMap.put(wptreli.cp.pnend, wptreli.crp.pnend);
}
}
/////////////////////////////////////////////
void PrepareForUnconnectedNodes(List vnodes)
{
// find the centreline nodes; reset the proxdists
RefPathO srefpathconn = new RefPathO(); // reused object
List lcenconnnodes = new ArrayList();
for (OnePathNode opn : vnodes)
{
if (opn.IsCentrelineNode())
{
cenconnnodes.add(opn);
lcenconnnodes.add(opn);
}
}
assert pd.ncentrelinenodes == cenconnnodes.size();
while (!lcenconnnodes.isEmpty())
{
OnePathNode copn = lcenconnnodes.remove(lcenconnnodes.size() - 1);
srefpathconn.ccopy(copn.ropconn);
do
{
OnePath cop = srefpathconn.op;
assert copn == srefpathconn.ToNode();
OnePathNode ocopn = srefpathconn.FromNode();
if (!cenconnnodes.contains(ocopn))
{
cenconnnodes.add(ocopn);
lcenconnnodes.add(ocopn);
}
}
while (!srefpathconn.AdvanceRoundToNode(copn.ropconn));
}
TN.emitMessage("There are " + pd.ncentrelinenodes + " centreline nodes and " + cenconnnodes.size() + " centreline connected nodes out of " + vnodes.size() + " nodes.");
}
/////////////////////////////////////////////
boolean WarpOver(double x, double y, double z, float lam)
{
if (wptrel == null)
{ destx = x; desty = y; destz = z; return true; }
double sweight = 0;
double sdestx = 0;
double sdesty = 0;
double sdestz = 0;
for (PtrelPLn wptreli : wptrel)
{
wptreli.TransformPt(x, y);
if (lam > 1.0F)
lam = 1.0F;
if (lam < 0.0F)
lam = 0.0F;
double aproxdist = wptreli.proxdistw0 * (1.0 - lam) + wptreli.proxdistw1 * lam;
double proxweight = 1.0 / (1.0 + aproxdist * aproxdist);
if ((wptreli.proxdistw0 == -1.0) || (wptreli.proxdistw1 == -1.0))
proxweight = 0.0;
// we just fiddle for something that might work
// (is there a better way to combine these two measures??!)
// multiplying them makes a big weight on one make the thing into a big weight
// double rweight = (proxweight + wptrel[i].weight) * wptrel[i].ax0.lgsq;
// double rweight = (proxweight) * wptrel[i].ax0.lgsq;
double rweight = (proxweight) * wptreli.geoweight;
//System.out.println(wptrel[i].proxdistw0 + " " + wptrel[i].proxdistw1 + " " + wptrel[i].disttoaxis);
// double rweight = wptrel[i].geoweight;
sweight += rweight;
sdestx += rweight * wptreli.destx;
sdesty += rweight * wptreli.desty;
sdestz += rweight * z;
}
if (sweight == 0.0) // bail out if no correspondences
{
destx = x;
desty = y;
destz = z;
System.out.println("no weight (lack of connection?)");
return false;
}
destx = sdestx / sweight;
desty = sdesty / sweight;
destz = sdestz / sweight;
return true;
}
/////////////////////////////////////////////
OnePathNode[] cennodes = null; //new OnePathNode[12]; // limit the number of nodes we average over. (null means no limit)
// it seems not to work at all if you restrict the number of centre path nodes it links to.
void SetNodeProxWeights(OnePathNode opn, int proxto)
{
if (wptrel == null) // bail out in no correspondences case
return;
pd.ShortestPathsToCentrelineNodes(opn, cennodes, null);
for (int i = 0; i < wptrel.size(); i++)
{
OnePath opc = wptrel.get(i).cp;
// maybe average does work, though small segments near
// a node will get pulled much harder
// float nodew = (opc.pnstart.proxdist + opc.pnend.proxdist) / 2;
double nodew = (opc.pnstart.proxdist * opc.pnend.proxdist);
if ((opc.pnstart.proxdist == -1.0) || (opc.pnend.proxdist == -1.0))
nodew = -1.0;
if ((proxto & 1) != 0)
wptrel.get(i).proxdistw0 = nodew;
if ((proxto & 2) != 0)
wptrel.get(i).proxdistw1 = nodew;
}
// reset for next application
for (OnePathNode lopn : pd.parainstancequeue.proxdistsetlist)
lopn.proxdist = -1.0;
pd.parainstancequeue.proxdistsetlist.clear();
}
/////////////////////////////////////////////
void Extendallnodes(List vnodes)
{
int lastprogress = -1;
for (int j = 0; j < vnodes.size(); j++)
{
OnePathNode opn = vnodes.get(j);
if (!cenconnnodes.contains(opn))
{
assert !opnMap.containsKey(opn);
OnePathNode dopn = new OnePathNode(0.0F, 0.0F, 0.0F);
ucavgtrans.transform(opn.pn, dopn.pn); // over-writes the origin position
opnMap.put(opn, dopn);
TN.emitWarning(" unconn-node " + j);
}
else if (!opnMap.containsKey(opn))
{
SetNodeProxWeights(opn, 3);
boolean bD = WarpOver(opn.pn.getX(), opn.pn.getY(), opn.zalt, 0.0F);
OnePathNode dopn = new OnePathNode((float)destx, (float)desty, (float)destz);
if (!bD)
TN.emitWarning(" bad node " + j);
opnMap.put(opn, dopn);
}
int progress = (20*j) / vnodes.size();
if (progress > lastprogress)
{
lastprogress = progress;
TN.emitMessage(Integer.toString(5*progress) + "% complete");
}
}
}
/////////////////////////////////////////////
Point2D.Float spnF = new Point2D.Float(); // used for mapping the avgtransform to
Point2D.Float spnT = new Point2D.Float(); // used for mapping the avgtransform to
OnePath WarpPathD(OnePath path, String limportfromname)
{
// Must Also map over all the subsets, if there are any made to avoid XC subsets merging
// new endpoint nodes
OnePathNode npnstart = opnMap.get(path.pnstart);
OnePathNode npnend = opnMap.get(path.pnend);
OnePath res = new OnePath(npnstart);
float[] pco = path.GetCoords();
assert cenconnnodes.contains(path.pnstart) == cenconnnodes.contains(path.pnend);
if (!cenconnnodes.contains(path.pnstart))
{
for (int i = 1; i < path.nlines; i++)
{
spnF.setLocation(pco[i * 2], pco[i * 2 + 1]);
ucavgtrans.transform(spnF, spnT);
res.LineTo((float)spnT.getX(), (float)spnT.getY());
}
}
else
{
SetNodeProxWeights(path.pnstart, 1);
SetNodeProxWeights(path.pnend, 2);
float partlinelength = 0.0F;
for (int i = 1; i < path.nlines; i++)
{
float vx = pco[i * 2] - pco[i * 2 - 2];
float vy = pco[i * 2 + 1] - pco[i * 2 - 1];
partlinelength += (float)Math.sqrt(vx * vx + vy * vy);
float lam = partlinelength / path.linelength;
WarpOver(pco[i * 2], pco[i * 2 + 1], 0.0F, lam);
res.LineTo((float)destx, (float)desty);
}
}
res.EndPath(npnend);
res.CopyPathAttributes(path);
if ((res.plabedl != null) && (res.plabedl.sketchframedef != null))
res.plabedl.sketchframedef.ConvertTransformImportSketchWarp(path, res, realposterpaperscale, sketchLocOffsetFrom, sketchLocOffsetTo);
res.importfromname = limportfromname;
return res;
}
/////////////////////////////////////////////
void CalcAvgTransform(AffineTransform avgtrans, SketchFrameDef sketchframedef, OneSketch tsketch, OneSketch asketch)
{
// we're working on the diagram as a unit, rather than averaging across the change on all the legs.
// so we find the centre of gravity of each.
// then average expansion from the c of g. and the rotational components around this,
// to the centre of each line weighted by its length.
// centre of gravity
double cgxf = 0.0F;
double cgyf = 0.0F;
double tlengf = 0.0F;
double cgxt = 0.0F;
double cgyt = 0.0F;
double tlengt = 0.0F;
// first find the centres of gravity.
for (PtrelPLn wptreli : wptrel)
{
OnePath cp = wptreli.cp;
OnePath crp = wptreli.crp;
double lengf = cp.pnstart.pn.distance(cp.pnend.pn);
double lengt = crp.pnstart.pn.distance(crp.pnend.pn);
cgxf += lengf * (cp.pnend.pn.getX() + cp.pnstart.pn.getX()) / 2;
cgyf += lengf * (cp.pnend.pn.getY() + cp.pnstart.pn.getY()) / 2;
tlengf += lengf;
cgxt += lengt * (crp.pnend.pn.getX() + crp.pnstart.pn.getX()) / 2;
cgyt += lengt * (crp.pnend.pn.getY() + crp.pnstart.pn.getY()) / 2;
tlengt += lengt;
}
if (tlengf != 0.0F)
{
cgxf /= tlengf;
cgyf /= tlengf;
}
if (tlengt != 0.0F)
{
cgxt /= tlengt;
cgyt /= tlengt;
}
// now find average scale and rotation relative to these c of g.
double tleng = 0.0F;
double tscale = 0.0F;
double trot = 0.0F;
for (PtrelPLn wptreli : wptrel)
{
OnePath cp = wptreli.cp;
OnePath crp = wptreli.crp;
double leng = cp.pnstart.pn.distance(cp.pnend.pn);
double lengr = crp.pnstart.pn.distance(crp.pnend.pn);
double aleng = (leng + lengr) / 2;
double cxf = (cp.pnend.pn.getX() + cp.pnstart.pn.getX()) / 2 - cgxf;
double cyf = (cp.pnend.pn.getY() + cp.pnstart.pn.getY()) / 2 - cgyf;
double cflq = cxf * cxf + cyf * cyf;
double cxt = (crp.pnend.pn.getX() + crp.pnstart.pn.getX()) / 2 - cgxt;
double cyt = (crp.pnend.pn.getY() + crp.pnstart.pn.getY()) / 2 - cgyt;
double ctlq = cxt * cxt + cyt * cyt;
tscale += aleng * (cflq != 0.0 ? Math.sqrt(ctlq / cflq) : 1.0);
double cxr = cxf * cxt + cyf * cyt;
double cyr = cxf * cyt - cyf * cxt;
double ang = (cxr != 0 ? Math.atan(cyr / cxr) : 0.0); // alt should be +- PI/2
trot += ang * aleng;
tleng += aleng;
}
if (tleng != 0)
{
tscale /= tleng;
trot /= tleng;
}
// transform, conijugated with the translation.
TN.emitMessage("Avg transform scale " + tscale + " translate " + (cgxt - cgxf) + " " + (cgyt - cgyf) + " rot " + trot);
avgtrans.setToIdentity();
avgtrans.translate(cgxt, cgyt);
avgtrans.scale(tscale, tscale);
avgtrans.rotate(trot);
avgtrans.translate(-cgxf, -cgyf);
if (sketchframedef != null)
{
assert (sketchframedef != null) && (tsketch != null);
sketchframedef.sfscaledown = (float)(tsketch.realposterpaperscale / tscale);
sketchframedef.sfrotatedeg = -(float)Math.toDegrees(trot);
sketchframedef.sfelevrotdeg = 0.0F;
sketchframedef.sfelevvertplane = "";
// From UpdateSketchFrame()
// Lots of effort to extract the transform required
AffineTransform lpframesketchtrans = new AffineTransform();
lpframesketchtrans.translate(-tsketch.sketchLocOffset.x * TN.CENTRELINE_MAGNIFICATION, +tsketch.sketchLocOffset.y * TN.CENTRELINE_MAGNIFICATION);
lpframesketchtrans.scale(tsketch.realposterpaperscale / sketchframedef.sfscaledown, tsketch.realposterpaperscale / sketchframedef.sfscaledown);
lpframesketchtrans.rotate(-Math.toRadians(sketchframedef.sfrotatedeg));
lpframesketchtrans.translate(asketch.sketchLocOffset.x * TN.CENTRELINE_MAGNIFICATION, -asketch.sketchLocOffset.y * TN.CENTRELINE_MAGNIFICATION);
double dx = avgtrans.getTranslateX() - lpframesketchtrans.getTranslateX();
double dy = avgtrans.getTranslateY() - lpframesketchtrans.getTranslateY();
sketchframedef.sfxtrans = dx / (tsketch.realposterpaperscale * TN.CENTRELINE_MAGNIFICATION);
sketchframedef.sfytrans = dy / (tsketch.realposterpaperscale * TN.CENTRELINE_MAGNIFICATION);
/*double[] flatmatrix = new double[6];
avgtrans.getMatrix(flatmatrix);
System.out.println("\navgtrans ");
for (int i = 0; i < 6; i++)
System.out.println(" "+flatmatrix[i]);
lpframesketchtrans = new AffineTransform();
lpframesketchtrans.translate((-tsketch.sketchLocOffset.x + sketchframedef.sfxtrans * tsketch.realposterpaperscale) * TN.CENTRELINE_MAGNIFICATION, (+tsketch.sketchLocOffset.y + sketchframedef.sfytrans * tsketch.realposterpaperscale) * TN.CENTRELINE_MAGNIFICATION);
lpframesketchtrans.scale(tsketch.realposterpaperscale / sketchframedef.sfscaledown, tsketch.realposterpaperscale / sketchframedef.sfscaledown);
lpframesketchtrans.rotate(-Math.toRadians(sketchframedef.sfrotatedeg));
lpframesketchtrans.translate(asketch.sketchLocOffset.x * TN.CENTRELINE_MAGNIFICATION, -asketch.sketchLocOffset.y * TN.CENTRELINE_MAGNIFICATION);
lpframesketchtrans.getMatrix(flatmatrix);
System.out.println("\n--- lpframesketchtrans ");
for (int i = 0; i < 6; i++)
System.out.println(" "+flatmatrix[i]);
*/
// lpframesketchtrans.translate((-tsketch.sketchLocOffset.x + sketchframedef.sfxtrans * tsketch.realpaperscale) * TN.CENTRELINE_MAGNIFICATION, (+tsketch.sketchLocOffset.sketchLocOffset.y + sketchframedef.sfytrans * tsketch.sketchLocOffset.realpaperscale) * TN.CENTRELINE_MAGNIFICATION);
}
}
/////////////////////////////////////////////
/////////////////////////////////////////////
boolean ExtractCentrelinePathCorrespondence(OneSketch asketch, OneSketch osdest)
{
// new correspondence engine
MatchSketchCentrelines msc = new MatchSketchCentrelines();
if (!msc.CorrespMatching(asketch.vpaths, osdest.vpaths))
{
TN.emitWarning("no corresponding centrelines found2");
return false;
}
int nmisscorresp = 0;
for (PrefixLeg plf : msc.prefixlegsfrom)
{
if (plf.pltmember != null)
wptrel.add(new PtrelPLn(plf.op, plf.pltmember.op));
else
{
nmisscorresp++;
if (nmisscorresp <= 10)
TN.emitWarning("No centreline corresponding to " + "tail=" + plf.op.plabedl.centrelinetail + " head=" + plf.op.plabedl.centrelinehead);
}
}
if (nmisscorresp > 10)
TN.emitWarning("No centreline corresponding to ... " + (nmisscorresp - 10) + " more.");
// false if no correspondence
if (wptrel.isEmpty())
{
TN.emitWarning("no corresponding centrelines found1");
return false;
}
return true;
}
};
tunnelx-20190701/src/Vec3.java 0000664 0001750 0001750 00000013235 13531571147 015337 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
//
//
// Vec3
//
//
class Vec3
{
public float x;
public float y;
public float z;
/////////////////////////////////////////////
public Vec3()
{
x = 0.0F;
y = 0.0F;
z = 0.0F;
}
/////////////////////////////////////////////
public String toString()
{
return String.valueOf(x) + " " + String.valueOf(y) + " " + String.valueOf(z);
}
/////////////////////////////////////////////
Vec3(String w0, String w1, String w2)
{
SetXYZ(Float.parseFloat(w0), Float.parseFloat(w1), Float.parseFloat(w2));
}
/////////////////////////////////////////////
public Vec3(float lx, float ly, float lz)
{
SetXYZ(lx, ly, lz);
}
/////////////////////////////////////////////
public boolean isZero()
{
if (x == 0 && y == 0 && z == 0) return true;
else return false;
}
/////////////////////////////////////////////
public float Dot(Vec3 a)
{
return x * a.x + y * a.y + z * a.z;
}
/////////////////////////////////////////////
public void Diff(Vec3 a, Vec3 b)
{
x = b.x - a.x;
y = b.y - a.y;
z = b.z - a.z;
}
/////////////////////////////////////////////
public void Sum(Vec3 a, Vec3 b)
{
x = b.x + a.x;
y = b.y + a.y;
z = b.z + a.z;
}
/////////////////////////////////////////////
public void PlusEquals(Vec3 a)
{
x += a.x;
y += a.y;
z += a.z;
}
/////////////////////////////////////////////
public void TimesEquals(float f)
{
x *= f;
y *= f;
z *= f;
}
/////////////////////////////////////////////
public void Negate()
{
x = -x;
y = -y;
z = -z;
}
/////////////////////////////////////////////
public void Cross(Vec3 a, Vec3 b)
{
x = a.y * b.z - a.z * b.y;
y = -a.x * b.z + a.z * b.x;
z = a.x * b.y - a.y * b.x;
}
/////////////////////////////////////////////
public float Len()
{
float sqlen = x * x + y * y + z * z;
return((float)(Math.sqrt(sqlen)));
}
/////////////////////////////////////////////
public void Norm()
{
float sqlen = x * x + y * y + z * z;
float fac = (sqlen == 0.0F ? 1.0F : (float)(1.0F / Math.sqrt(sqlen)));
x *= fac;
y *= fac;
z *= fac;
}
/////////////////////////////////////////////
public void SetXYZ(float lx, float ly, float lz)
{
x = lx;
y = ly;
z = lz;
}
/////////////////////////////////////////////
public void SetXYZ(Vec3 a)
{
SetXYZ(a.x, a.y, a.z);
}
/////////////////////////////////////////////
public int ConvCompress(boolean bNegate)
{
float sqlen = x * x + y * y + z * z;
float fac = (sqlen == 0.0F ? 1.0F : (float)(1.0F / Math.sqrt(sqlen))) * (bNegate ? -1 : 1);
float nx = x * fac;
float ny = y * fac;
float nz = z * fac;
int inx = Math.max(0, Math.min(255, (int)(nx * 127 + (nx > 0.0F ? 0.5F : -0.5F)) + 128));
int iny = Math.max(0, Math.min(255, (int)(ny * 127 + (ny > 0.0F ? 0.5F : -0.5F)) + 128));
int inz = Math.max(0, Math.min(255, (int)(nz * 127 + (nz > 0.0F ? 0.5F : -0.5F)) + 128));
int insz = (nz >= 0.0F ? 0 : 128);
int res = (insz | (inx << 8) | (iny << 16) | (inz << 24));
return res;
}
/////////////////////////////////////////////
void ConvDecompress(int c)
{
int inx = (255 & (c >> 8));
int iny = (255 & (c >> 16));
int inz = (255 & (c >> 24));
x = (inx - 128) / 127.0F;
y = (iny - 128) / 127.0F;
z = (inz - 128) / 127.0F;
Norm();
}
/////////////////////////////////////////////
static int ConvCompressInvert(int c)
{
int inx = (255 & (c >> 8));
int iny = (255 & (c >> 16));
int inz = (255 & (c >> 24));
int iinx = 256 -inx;
int iiny = 256 - iny;
int iinz = 256 - inz;
int iinsz = (((c & 128) == 0) ? 128 : 0);
int res = (iinsz | (iinx << 8) | (iiny << 16) | (iinz << 24));
return res;
}
/////////////////////////////////////////////
public void SetAlong(float lambda, Vec3 vf, Vec3 vt)
{
float mlam = 1.0F - lambda;
SetXYZ(vf.x * mlam + vt.x * lambda, vf.y * mlam + vt.y * lambda, vf.z * mlam + vt.z * lambda);
}
/////////////////////////////////////////////
public void SetOnSphere(float fx, float fy)
{
float dsq = fx * fx + fy * fy;
if (dsq > 1.0F)
{
float d = (float)(Math.sqrt(dsq));
SetXYZ(fx / d, fy / d, 0.0F);
}
else
SetXYZ(fx, fy, (float)(Math.sqrt(1.0F - dsq)));
}
/////////////////////////////////////////////
public static double Arg(double x, double y)
{
double theta;
if (x != 0.0F)
{
theta = Math.atan(y / x);
if (x <= 0.0F)
theta += Math.PI;
}
else
{
if (y >= 0.0F)
theta = Math.PI / 2;
else
theta = -Math.PI / 2;
}
if (theta < 0.0F)
theta += Math.PI * 2;
if (theta > Math.PI * 2)
theta -= Math.PI * 2;
return theta;
}
/////////////////////////////////////////////
public static float DegArg(double x, double y)
{
return (float)(Math.toDegrees(Arg(x, y)));
}
}
tunnelx-20190701/src/ConnectiveAreaSigTabPane.java 0000664 0001750 0001750 00000041252 13531571147 021323 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2004 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JToggleButton;
import javax.swing.JTextField;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import java.awt.geom.AffineTransform;
import java.awt.Insets;
import java.util.Map;
import java.io.IOException;
/////////////////////////////////////////////
class ConnectiveAreaSigTabPane extends JPanel
{
JComboBox areasignals = new JComboBox();
SketchLineStyle sketchlinestyle;
JButton jbcancel = new JButton("Cancel Area-signal");
// we can choose to print just one view on one sheet of paper
JButton tfmaxbutt = new JButton("Max");
JButton tfcentrebutt = new JButton("Centr");
JButton tfsketchcopybutt = new JButton("Sketch");
JButton tfimagecopybutt = new JButton("Image");
JButton tfsubstylecopybutt = new JButton("Style");
JButton tfsubmappingcopybutt = new JButton("Copy");
JButton tfsubmappingpastebutt = new JButton("Paste");
JButton tfsetsubsetlower = new JButton("S-lo");
JButton tfsetsubsetupper = new JButton("S-up");
JButton tfshiftground = new JButton("-");
JTextArea tfsubmapping = new JTextArea();
JScrollPane jsp = new JScrollPane(tfsubmapping);
// this is used to modify the treeview which we see
// it's a bad hidden modal thing, but for now till we think of something better.
SketchFrameDef sketchframedefCopied = new SketchFrameDef();
// use these for parsing the text in the submapping textarea
TunnelXMLparse txp = new TunnelXMLparse();
TunnelXML tunnXML = new TunnelXML();
String copiedsubmapping = "";
/////////////////////////////////////////////
boolean SketchCopyButt()
{
// ultimately this should use the same algorithm for finding the sketch name as we do for raw images
OneSketch asketch = sketchlinestyle.sketchdisplay.mainbox.tunnelfilelist.GetSelectedSketchLoad();
if (asketch == null)
return TN.emitWarning("No sketch found");
String st = null;
try
{
st = FileAbstraction.GetImageFileName(sketchlinestyle.sketchdisplay.sketchgraphicspanel.tsketch.sketchfile.getParentFile(), asketch.sketchfile);
}
catch (IOException ie)
{ return TN.emitWarning(ie.toString()); };
if (st == null)
return TN.emitWarning("No file found to be recorded (maybe you need to save it)");
st = TN.loseSuffix(st);
OnePath op = sketchlinestyle.sketchdisplay.sketchgraphicspanel.currgenpath;
if (st != null)
op.plabedl.sketchframedef.sfsketch = st;
else
return TN.emitWarning("No file found to be recorded (maybe you need to save it)");
sketchlinestyle.pthstyleareasigtab.LoadSketchFrameDef(op.plabedl.sketchframedef, true);
sketchlinestyle.sketchdisplay.sketchgraphicspanel.tsketch.opframebackgrounddrag = op;
PtrelLn ptrelln = new PtrelLn();
boolean bcorrespsucc = ptrelln.ExtractCentrelinePathCorrespondence(asketch, sketchlinestyle.sketchdisplay.sketchgraphicspanel.tsketch);
if (bcorrespsucc)
{
TN.emitMessage("Correspondence found -- repositioning");
AffineTransform avgtrans = new AffineTransform();
ptrelln.CalcAvgTransform(avgtrans, op.plabedl.sketchframedef, sketchlinestyle.sketchdisplay.sketchgraphicspanel.tsketch, asketch);
}
UpdateSFView(op, true);
return true;
}
/////////////////////////////////////////////
void StyleCopyButt()
{
SubsetAttrStyle sascurrent = sketchlinestyle.sketchdisplay.subsetpanel.sascurrent;
OnePath op = sketchlinestyle.sketchdisplay.sketchgraphicspanel.currgenpath;
op.plabedl.sketchframedef.sfstyle = sascurrent.stylename;
UpdateSFView(op, true);
}
/////////////////////////////////////////////
void UpdateSFView(OnePath op, boolean bsketchchanged)
{
tfsubmapping.setText(op.plabedl.sketchframedef.GetToTextV());
tfsubmapping.setCaretPosition(0);
op.SetSubsetAttrs(sketchlinestyle.sketchdisplay.subsetpanel.sascurrent, null); // font changes
op.plabedl.sketchframedef.SetSketchFrameFiller(sketchlinestyle.sketchdisplay.mainbox, sketchlinestyle.sketchdisplay.sketchgraphicspanel.tsketch.realposterpaperscale, sketchlinestyle.sketchdisplay.sketchgraphicspanel.tsketch.sketchLocOffset, sketchlinestyle.sketchdisplay.sketchgraphicspanel.tsketch.sketchfile);
sketchlinestyle.sketchdisplay.sketchgraphicspanel.RedoBackgroundView();
if (bsketchchanged)
sketchlinestyle.sketchdisplay.sketchgraphicspanel.SketchChanged(bsketchchanged ? SketchGraphics.SC_CHANGE_STRUCTURE : SketchGraphics.SC_CHANGE_SAS);
}
/////////////////////////////////////////////
void LoadSketchFrameDef(SketchFrameDef lsketchframedefCopied, boolean bAll)
{
sketchframedefCopied.Copy(lsketchframedefCopied, bAll);
sketchlinestyle.sketchdisplay.subsetpanel.SubsetSelectionChanged(true);
//sketchlinestyle.sketchdisplay.subsetpanel.sascurrent.TreeListFrameDefCopiedSubsets(sketchframedefCopied);
//sketchlinestyle.sketchdisplay.sketchgraphicspanel.SketchChanged(SketchGraphics.SC_CHANGE_SAS);
}
/////////////////////////////////////////////
void StyleMappingCopyButt(boolean bcopypaste)
{
OnePath op = sketchlinestyle.sketchdisplay.sketchgraphicspanel.currgenpath;
if ((op == null) || (op.linestyle != SketchLineStyle.SLS_CONNECTIVE) || (op.plabedl == null) || (op.plabedl.barea_pres_signal != SketchLineStyle.ASE_SKETCHFRAME) || (op.plabedl.sketchframedef == null))
{
TN.emitWarning("Can't execute StyleMappingCopyButt");
return;
}
txp.sketchframedef.submapping.clear();
if (bcopypaste)
{
copiedsubmapping = tfsubmapping.getText();
tfsubmappingpastebutt.setToolTipText(copiedsubmapping);
}
String erm = tunnXML.ParseString(txp, (bcopypaste ? tfsubmapping.getText() : copiedsubmapping));
// if successful, copy it into the path and then back
if (erm == null)
{
op.plabedl.sketchframedef.Copy(txp.sketchframedef, true);
UpdateSFView(op, !bcopypaste);
if (bcopypaste)
LoadSketchFrameDef(op.plabedl.sketchframedef, true);
}
else
TN.emitWarning("Failed to parse: " + erm);
sketchlinestyle.sketchdisplay.sketchgraphicspanel.tsketch.opframebackgrounddrag = op;
if (!bcopypaste)
{
if (op.plabedl.sketchframedef.IsImageType())
sketchlinestyle.sketchdisplay.sketchgraphicspanel.FrameBackgroundOutline();
}
if (sketchlinestyle.sketchdisplay.bottabbedpane.getSelectedIndex() == 1)
sketchlinestyle.sketchdisplay.backgroundpanel.UpdateBackimageCombobox(3);
}
/////////////////////////////////////////////
void MaxCentreOnScreenButtB(boolean bmaxcen)
{
// find the area which this line corresponds to. (have to search the areas to find it).
OnePath op = sketchlinestyle.sketchdisplay.sketchgraphicspanel.currgenpath;
if ((op == null) || (op.plabedl == null) || (op.plabedl.sketchframedef == null))
return;
sketchlinestyle.sketchdisplay.sketchgraphicspanel.ClearSelection(false);
sketchlinestyle.sketchdisplay.sketchgraphicspanel.repaint();
op.plabedl.sketchframedef.MaxCentreOnScreenButt(sketchlinestyle.sketchdisplay.sketchgraphicspanel.getSize(), bmaxcen, sketchlinestyle.sketchdisplay.sketchgraphicspanel.tsketch.realposterpaperscale, sketchlinestyle.sketchdisplay.sketchgraphicspanel.tsketch.sketchLocOffset, sketchlinestyle.sketchdisplay.sketchgraphicspanel.currtrans);
sketchlinestyle.sketchdisplay.sketchgraphicspanel.tsketch.opframebackgrounddrag = op;
if (op.plabedl.sketchframedef.IsImageType())
sketchlinestyle.sketchdisplay.sketchgraphicspanel.FrameBackgroundOutline();
UpdateSFView(op, true);
}
/////////////////////////////////////////////
ConnectiveAreaSigTabPane(SketchLineStyle lsketchlinestyle)
{
super(new BorderLayout());
sketchlinestyle = lsketchlinestyle;
txp.sketchframedef = new SketchFrameDef();
JPanel ntop = new JPanel(new BorderLayout());
ntop.add(new JLabel("Area Signals", JLabel.CENTER), BorderLayout.NORTH);
JPanel pie = new JPanel();
pie.add(areasignals);
pie.add(jbcancel);
ntop.add(pie, BorderLayout.CENTER);
JPanel pimpfields = new JPanel(new GridLayout(0, 5));
pimpfields.add(tfmaxbutt);
pimpfields.add(tfcentrebutt);
pimpfields.add(tfshiftground);
pimpfields.add(tfsketchcopybutt);
pimpfields.add(tfimagecopybutt);
pimpfields.add(tfsubstylecopybutt);
pimpfields.add(tfsubmappingcopybutt);
pimpfields.add(tfsubmappingpastebutt);
pimpfields.add(tfsetsubsetlower);
pimpfields.add(tfsetsubsetupper);
ntop.add(pimpfields, BorderLayout.SOUTH);
add(ntop, BorderLayout.NORTH);
add(jsp, BorderLayout.CENTER);
tfmaxbutt.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { MaxCentreOnScreenButtB(true); } } );
tfcentrebutt.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { MaxCentreOnScreenButtB(false); } } );
tfsketchcopybutt.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { SketchCopyButt(); } } );
tfsubstylecopybutt.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { StyleCopyButt(); } } );
tfimagecopybutt.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { AddImage(); } } );
tfsubmappingcopybutt.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { StyleMappingCopyButt(true); } } );
tfsubmappingpastebutt.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { StyleMappingCopyButt(false); } } );
tfsetsubsetlower.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { SetSubsetLoHi(true); } } );
tfsetsubsetupper.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { SetSubsetLoHi(false); } } );
Insets smallbuttinsets = new Insets(2, 3, 2, 3);
tfmaxbutt.setToolTipText("Maximize viewed sketch in framed area");
tfmaxbutt.setMargin(smallbuttinsets);
tfcentrebutt.setToolTipText("Centre viewed sketch in framed area");
tfcentrebutt.setMargin(smallbuttinsets);
tfsketchcopybutt.setToolTipText("Copy selected sketch from mainbox to framed area");
tfsketchcopybutt.setMargin(smallbuttinsets);
tfsubstylecopybutt.setToolTipText("Copy selected style to apply to framed sketch");
tfsubstylecopybutt.setMargin(smallbuttinsets);
tfimagecopybutt.setToolTipText("Load image as framed sketch or background");
tfimagecopybutt.setMargin(smallbuttinsets);
tfsubmappingcopybutt.setToolTipText("Copy selected style to apply to framed sketch");
tfsubmappingcopybutt.setMargin(smallbuttinsets);
tfsubmappingpastebutt.setToolTipText("Paste copied parameters into framed sketch");
tfsubmappingpastebutt.setMargin(smallbuttinsets);
tfsetsubsetlower.setToolTipText("Select subset style for assignment");
tfsetsubsetlower.setMargin(smallbuttinsets);
tfsetsubsetupper.setToolTipText("Assign upper subset for style");
tfsetsubsetupper.setMargin(smallbuttinsets);
}
/////////////////////////////////////////////
void SetSubmappingSettings()
{
OnePath op = sketchlinestyle.sketchdisplay.sketchgraphicspanel.currgenpath;
if ((op == null) || (op.plabedl == null) || (op.plabedl.sketchframedef == null))
return;
Map submapping = op.plabedl.sketchframedef.submapping;
for (String ssubset : submapping.keySet())
{
if (submapping.get(ssubset).equals(""))
{
tfsetsubsetupper.setEnabled(true);
return;
}
}
tfsetsubsetupper.setEnabled(false);
}
/////////////////////////////////////////////
void SetSubsetLoHi(boolean bsetsubsetlohi)
{
OnePath op = sketchlinestyle.sketchdisplay.sketchgraphicspanel.currgenpath;
Map submapping = op.plabedl.sketchframedef.submapping;
if (bsetsubsetlohi)
{
if (sketchlinestyle.sketchdisplay.selectedsubsetstruct.vsselectedsubsetsP.isEmpty())
{
if (submapping.containsKey("default"))
submapping.put("Your subset here", "");
else
submapping.put("default", "");
}
else
{
for (String ssubset : sketchlinestyle.sketchdisplay.selectedsubsetstruct.vsselectedsubsetsP)
submapping.put(ssubset, "");
}
}
else
{
String ssubsetupper = sketchlinestyle.sketchdisplay.selectedsubsetstruct.GetFirstSubset();
if (ssubsetupper != null)
{
for (String ssubset : submapping.keySet())
{
if (submapping.get(ssubset).equals(""))
submapping.put(ssubset, ssubsetupper);
}
}
}
SetSubmappingSettings();
UpdateSFView(op, true);
}
/////////////////////////////////////////////
void UpdateAreaSignals(String[] areasignames, int nareasignames)
{
areasignals.removeAllItems();
for (int i = 0; i < nareasignames; i++)
areasignals.addItem(areasignames[i]);
}
/////////////////////////////////////////////
void SetFrameSketchInfoText(OnePath op)
{
boolean bbuttenabled = false;
boolean bareaenabled = false;
if ((op != null) && (op.plabedl.barea_pres_signal == SketchLineStyle.ASE_SKETCHFRAME))
{
if (op.plabedl.sketchframedef == null)
op.plabedl.sketchframedef = new SketchFrameDef();
tfsubmapping.setText(op.plabedl.sketchframedef.GetToTextV());
tfsubmapping.setCaretPosition(0);
bbuttenabled = true;
bareaenabled = true;
}
if ((op != null) && (op.plabedl.barea_pres_signal == SketchLineStyle.ASE_ZSETRELATIVE))
{
tfsubmapping.setText(String.valueOf(op.plabedl.nodeconnzsetrelative));
bareaenabled = true;
}
tfmaxbutt.setEnabled(bbuttenabled);
tfcentrebutt.setEnabled(bbuttenabled);
tfsketchcopybutt.setEnabled(bbuttenabled);
tfsubstylecopybutt.setEnabled(bbuttenabled);
tfimagecopybutt.setEnabled(bbuttenabled);
tfsubmappingcopybutt.setEnabled(bbuttenabled);
tfsubmappingpastebutt.setEnabled(bbuttenabled);
tfsetsubsetlower.setEnabled(bbuttenabled);
if (bbuttenabled)
SetSubmappingSettings();
else
tfsetsubsetupper.setEnabled(false);
if (!bareaenabled)
tfsubmapping.setText(""); // this has fired IllegalStateException: Attempt to mutate in notification, since it's already been set otherwise
tfsubmapping.setEnabled(bareaenabled);
}
/////////////////////////////////////////////
// This function replecates NewBackgroundFile, which creates the path in the first place
// in the future this will be adding a sketch too--
void AddImage()
{
SvxFileDialog sfiledialog = SvxFileDialog.showOpenDialog(TN.currentDirectory, sketchlinestyle.sketchdisplay, SvxFileDialog.FT_BITMAP, false);
if ((sfiledialog == null) || (sfiledialog.svxfile == null))
return;
FileAbstraction fa = sfiledialog.getSelectedFileA(SvxFileDialog.FT_BITMAP, false);
if (fa.localurl == null)
TN.currentDirectory = fa;
OnePath op = sketchlinestyle.sketchdisplay.sketchgraphicspanel.currgenpath;
if ((op.plabedl == null) || (op.plabedl.sketchframedef == null))
return;
try
{
op.plabedl.sketchframedef.sfsketch = FileAbstraction.GetImageFileName(sketchlinestyle.sketchdisplay.sketchgraphicspanel.tsketch.sketchfile.getParentFile(), sfiledialog.svxfile);
}
catch (IOException ie)
{ TN.emitWarning(ie.toString()); };
op.plabedl.sketchframedef.sfscaledown = 1.0F;
op.plabedl.sketchframedef.sfrotatedeg = 0.0F;
op.plabedl.sketchframedef.sfxtrans = (float)(sketchlinestyle.sketchdisplay.sketchgraphicspanel.tsketch.sketchLocOffset.x / TN.CENTRELINE_MAGNIFICATION);
op.plabedl.sketchframedef.sfytrans = -(float)(sketchlinestyle.sketchdisplay.sketchgraphicspanel.tsketch.sketchLocOffset.y / TN.CENTRELINE_MAGNIFICATION);
UpdateSFView(op, true);
MaxCentreOnScreenButtB(true);
if (!sketchlinestyle.sketchdisplay.miShowBackground.isSelected())
sketchlinestyle.sketchdisplay.miShowBackground.doClick();
}
};
tunnelx-20190701/src/WireframeDisplay.java 0000664 0001750 0001750 00000014306 13531571147 020006 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JCheckBoxMenuItem;
import java.awt.Graphics;
import java.awt.FileDialog;
import java.awt.BorderLayout;
import java.io.IOException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowAdapter;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
//
//
// WireframeDisplay
//
//
// this class contains the whole outer set of options and buttons
class WireframeDisplay extends JFrame
{
// the panel which holds the wireframe 3D graphics
WireframeGraphics wiregraphicspanel;
DateSliderControl dateslidercontrol;
boolean[] bmiStationNamesState = new boolean[2];
JCheckBoxMenuItem miCentreline = new JCheckBoxMenuItem("Centreline", true);
JCheckBoxMenuItem miStationNames = new JCheckBoxMenuItem("StationNames", true);
JCheckBoxMenuItem miAxes = new JCheckBoxMenuItem("Axes", true);
JCheckBoxMenuItem miDepthCols = new JCheckBoxMenuItem("Depth Colours", true);
JCheckBoxMenuItem miZFixed = new JCheckBoxMenuItem("Z Fixed", true);
/////////////////////////////////////////////
// local classes
/////////////////////////////////////////////
class AutoViewMenuItem extends JMenuItem implements ActionListener
{
float zfRotX, zfRotZ;
AutoViewMenuItem(String label, float lzfRotX, float lzfRotZ)
{
super(label);
zfRotX = lzfRotX;
zfRotZ = lzfRotZ;
addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
wiregraphicspanel.SetAutomaticView(zfRotX, zfRotZ);
}
};
/////////////////////////////////////////////
ItemListener WireframeRepaint = new ItemListener()
{
public void itemStateChanged(ItemEvent e)
{
wiregraphicspanel.repaint();
}
};
/////////////////////////////////////////////
// inactivate case
class WireframeHide extends WindowAdapter implements ActionListener
{
public void windowClosing(WindowEvent e)
{
bmiStationNamesState[wiregraphicspanel.bEditable ? 0 : 1] = miStationNames.isSelected();
setVisible(false);
}
public void actionPerformed(ActionEvent e)
{
bmiStationNamesState[wiregraphicspanel.bEditable ? 0 : 1] = miStationNames.isSelected();
setVisible(false);
}
}
/////////////////////////////////////////////
// slider on bottom for the amount of cave up to a date
class DateSliderControl extends JSlider implements ChangeListener
{
WireframeGraphics wiregraphicspanel;
DateSliderControl(WireframeGraphics lwiregraphicspanel)
{
super(0, 100, 100);
wiregraphicspanel = lwiregraphicspanel;
addChangeListener(this);
}
public void stateChanged(ChangeEvent e)
{
int slv = getValue();
wiregraphicspanel.depthcol.SetDateLimit(slv / 100.0);
wiregraphicspanel.repaint();
}
}
/////////////////////////////////////////////
// set up the arrays
WireframeDisplay()
{
super("Wireframe Display");
wiregraphicspanel = new WireframeGraphics(this);
dateslidercontrol = new DateSliderControl(wiregraphicspanel);
// set up display
getContentPane().add(wiregraphicspanel, BorderLayout.CENTER);
getContentPane().add(dateslidercontrol, BorderLayout.SOUTH);
// setup the display menu responses
miCentreline.addItemListener(WireframeRepaint);
miStationNames.addItemListener(WireframeRepaint);
miAxes.addItemListener(WireframeRepaint);
miDepthCols.addItemListener(WireframeRepaint);
miZFixed.addItemListener(WireframeRepaint);
// build the layout of the menu bar
JMenuBar menubar = new JMenuBar();
JMenu menufile = new JMenu("File");
JMenuItem doneitem = new JMenuItem("Close");
doneitem.addActionListener(new WireframeHide());
addWindowListener(new WireframeHide());
menufile.add(doneitem);
menubar.add(menufile);
JMenu menuview = new JMenu("View");
menuview.add(miZFixed);
menuview.add(new AutoViewMenuItem("DownZ", (float)Math.PI / 2, (float)Math.PI / 2));
menuview.add(new AutoViewMenuItem("DownX", (float)Math.PI / 4, (float)Math.PI / 4));
menuview.add(new AutoViewMenuItem("DownY", (float)Math.PI * 3 / 4, (float)Math.PI / 4));
menuview.add(new AutoViewMenuItem("Max", -1.0F, -1.0F));
menubar.add(menuview);
JMenu menudisplay = new JMenu("Display");
menudisplay.add(miCentreline);
menudisplay.add(miStationNames);
menudisplay.add(miAxes);
menudisplay.add(miDepthCols);
menubar.add(menudisplay);
setJMenuBar(menubar);
bmiStationNamesState[0] = true;
bmiStationNamesState[1] = false;
pack();
setSize(400, 400);
}
/////////////////////////////////////////////
void ActivateWireframeDisplay(String lname)
{
miStationNames.setSelected(bmiStationNamesState[wiregraphicspanel.bEditable ? 0 : 1]);
setTitle(lname);
toFront();
wiregraphicspanel.ReformMatrix();
wiregraphicspanel.MaximizeView();
wiregraphicspanel.ReformView();
wiregraphicspanel.UpdateDepthCol();
setVisible(true);
}
/////////////////////////////////////////////
void RefreshWireDisplay()
{
if (isVisible())
{
wiregraphicspanel.ReformView();
wiregraphicspanel.repaint();
}
}
}
tunnelx-20190701/src/SVGPaths.java 0000664 0001750 0001750 00000007503 13531571147 016177 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2006 Martin Green, Julian Todd
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.util.List;
import java.io.IOException;
import java.lang.String;
import java.awt.geom.PathIterator;
class SVGPaths
{
private float tunnelunit = 0.1F; //length of tunnel unit in meters
private float xoffset = 0F;
private float yoffset = 0F;
private int id = 0; //The next id to use
public SVGPaths(LineOutputStream los, List vpaths) throws IOException
{
WriteHeader(los);
for (OnePath op : vpaths)
WritePath(los, op);
WriteFooter(los);
}
// open and close
void WriteHeader(LineOutputStream los) throws IOException
{
TNXML.chconvleng = TNXML.chconvlengWSP; // a complete hack to stop &space; getting in here
assert false; // not used
los.WriteLine("\n");
los.WriteLine("");
los.WriteLine(TNXML.xcomopen(0, "svg", "xmlns", "http://www.w3.org/2000/svg", "version", "1.1"));
los.WriteLine(TNXML.xcomtext(1, "title", "Tunnels Paths"));
los.WriteLine(TNXML.xcomtext(1, "desc", "This file solely contains the definitions of paths for Tunnel, you need a view.svg file to see anything."));
los.WriteLine(TNXML.xcomopen(1, "defs"));
}
void WriteFooter(LineOutputStream los) throws IOException
{
los.WriteLine(TNXML.xcomclose(1, "defs"));
los.WriteLine(TNXML.xcomclose(0, "svg"));
TNXML.chconvleng = TNXML.chconvlengWSP;
}
static float[] coords = new float[6]; //Used to get the position of line segments
void WritePath(LineOutputStream los, OnePath op) throws IOException
{
//Set svg id to path
String sid = new String(String.valueOf(this.id));
op.svgid = this.id;
this.id=this.id+1;
//Generate list of linestyles and classes
String classes = new String(SketchLineStyle.shortlinestylenames[op.linestyle]);
for (int j = 0; j < op.vssubsets.size(); j++)
classes = classes + " " + SketchLineStyle.shortlinestylenames[op.linestyle] + op.vssubsets.get(j);
//Generate d the list of commands to generate points
String d = op.svgdvalue(0.0F, 0.0F);
//Set parameters and attributes based on if the heights are set
int numparam=0;
// It's poss that after UpdateZnodes all nodes are set
//if (op.pnstart.bzaltset)
// numparam = 10;
//else
numparam = 6;//need to determine why bzaltset is not set on 'update node z'
//If you update z alt and change the 6 to 10 it does give all z heights
String parameters[] = {"id", sid, "class", classes, "d", d, "z0", String.valueOf(op.pnstart.zalt), "z1", String.valueOf(op.pnend.zalt)};
//Determine if the path has funny attributes
if (op.plabedl!=null)
{
los.WriteLine(TNXML.xcomopenN(2, "path", parameters, numparam));
op.plabedl.WriteXML(los,3,false);
los.WriteLine(TNXML.xcomclose(2, "path"));
}
else
{
los.WriteLine(TNXML.xcomN(2, "path", parameters, numparam));
}
}
}
tunnelx-20190701/src/WireframeGraphics.java 0000664 0001750 0001750 00000033111 13531571147 020134 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Color;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseEvent;
import java.awt.event.ActionEvent;
import java.util.List;
import java.util.ArrayList;
import java.util.SortedSet;
import java.util.TreeSet;
//
//
// WireframeGraphics
//
//
class WireframeGraphics extends JPanel implements MouseListener, MouseMotionListener
{
WireframeDisplay wireframedisplay;
DepthCol depthcol = new DepthCol();
List vstations = new ArrayList();
List vlegs = new ArrayList();
boolean bEditable = false;
// recordings of active objects
OneStation vstationactive = null;
OneStation vstationactivesel = null;
// current rotation
Matrix3D mat = new Matrix3D();
Matrix3D invmat = new Matrix3D();
// main centre offset
Vec3 coff = new Vec3();
// quaternion rotations
Quaternion qnow = new Quaternion();
Quaternion qmdown = new Quaternion();
Quaternion qmdrag = new Quaternion();
Vec3 vmdown = new Vec3();
Vec3 vmdrag = new Vec3();
// Zfixed rotations
float zfRotZ = (float)Math.PI / 2;
float zfRotX = (float)Math.PI / 2;
float zfRotZdown = 0.0F;
float zfRotXdown = 0.0F;
int tcmx; // mouse coordinates used for dragging the tube cone
int tcmy;
Matrix3D rotmat = new Matrix3D();
Matrix3D invrotmat = new Matrix3D();
float diameter = 20.0F;
Dimension csize = new Dimension(0, 0);
int xoc = 0;
int yoc = 0;
// values used by the dynamic rotate and scale
// old and new offsets
Vec3 ocoff = new Vec3();
Vec3 ncoff = new Vec3();
float xfac;
int prevx = 0;
int prevy = 0;
float prevdiameter = 0.0F;
// screen vectors
Vec3 sxvec = new Vec3();
Vec3 syvec = new Vec3();
Vec3 szvec = new Vec3();
// the axes
WireAxes wireaxes = new WireAxes();
// mouse motion state
final static int M_NONE = 0;
final static int M_DYN_ROTATE = 1;
final static int M_DYN_TRANSLATE = 2;
final static int M_DYN_SCALE = 3;
final static int M_SEL_STATIONS = 4;
int momotion = M_NONE;
// types of repainting
boolean bNeedsClearing = false;
boolean bNeedsRedrawing = false; //(maybe only redrawing a little piece of the pic)
/////////////////////////////////////////////
WireframeGraphics(WireframeDisplay lwireframedisplay)
{
super(true); // doublebuffered
setBackground(TN.skeBackground);
setForeground(TN.wfmLeg);
addMouseListener(this);
addMouseMotionListener(this);
wireframedisplay = lwireframedisplay;
}
/////////////////////////////////////////////
void UpdateDepthCol()
{
for (int i = 0; i < vstations.size(); i++)
{
OneStation os = vstations.get(i);
depthcol.AbsorbRange(os, (i == 0));
}
SortedSet legdates = new TreeSet();
for (OneLeg ol : vlegs)
legdates.add(ol.svxdate);
depthcol.svxdates.clear();
depthcol.svxdates.addAll(legdates);
depthcol.datelimit = (depthcol.svxdates.isEmpty() ? "" : depthcol.svxdates.get(depthcol.svxdates.size() - 1));
}
/////////////////////////////////////////////
public void paintComponent(Graphics g)
{
// test if resize has happened
if ((getSize().height != csize.height) || (getSize().width != csize.width))
ReformView();
setBackground(TN.wfmBackground);
/* if (bNeedsClearing)
{
g.clearRect(0, 0, csize.width, csize.height);
bNeedsClearing = false;
}
else if (!bNeedsRedrawing)
return;
bNeedsRedrawing = false;
*/
//g.clearRect(0, 0, csize.width, csize.height);
g.setColor(TN.wfmBackground);
g.fillRect(0, 0, csize.width, csize.height);
// draw the legs
if (wireframedisplay.miCentreline.isSelected())
{
for (OneLeg ol : vlegs)
{
if (ol.osfrom != null)
{
ol.paintW(g, !bEditable, (wireframedisplay.miDepthCols.isSelected() ? depthcol : null));
}
}
}
// draw the stations
if (wireframedisplay.miStationNames.isSelected() && !((momotion == M_DYN_ROTATE) || (momotion == M_DYN_TRANSLATE) || (momotion == M_DYN_SCALE)))
{
for (OneStation os : vstations)
if (os != vstationactive)
os.paintW(g, false, false);
}
if (vstationactive != null)
vstationactive.paintW(g, true, !bEditable);
// draw the axes
if (wireframedisplay.miAxes.isSelected())
wireaxes.paintW(g);
}
/////////////////////////////////////////////
void ReformMatrix()
{
// first reform the matrix
csize.width = getSize().width;
csize.height = getSize().height;
// first calculate the scale
int minwidth = Math.min(csize.width, csize.height);
if (minwidth == 0)
minwidth = 1;
xfac = minwidth / diameter;
// centre of screen
xoc = csize.width / 2;
yoc = csize.height / 2;
mat.unit();
mat.translate(coff.x, coff.y, coff.z);
rotmat.SetQuat(qnow.x, qnow.y, qnow.z, qnow.w);
mat.mult(rotmat);
mat.scale(xfac, -xfac, xfac);
mat.translate(xoc, yoc, 0);
sxvec.SetXYZ(rotmat.xx, rotmat.xy, rotmat.xz);
syvec.SetXYZ(rotmat.yx, rotmat.yy, rotmat.yz);
szvec.SetXYZ(rotmat.zx, rotmat.zy, rotmat.zz);
// inverse matrix
invmat.unit();
invmat.translate(-xoc, -yoc, 0);
invmat.scale(1.0F / xfac, 1.0F / (-xfac), 1.0F / xfac);
invrotmat.SetQuat(qnow.x, qnow.y, qnow.z, -qnow.w);
invmat.mult(invrotmat);
invmat.translate(-coff.x, -coff.y, -coff.z);
}
/////////////////////////////////////////////
void ReformView()
{
bNeedsClearing = true;
ReformMatrix();
// axes position
wireaxes.ReformAxes(rotmat, csize, xoc, yoc, xfac);
// now transform the stations and points of the XSections
for (OneStation os : vstations)
os.SetTLoc(mat);
}
/////////////////////////////////////////////
/////////////////////////////////////////////
/////////////////////////////////////////////
/////////////////////////////////////////////
void ReCentre(int mx, int my)
{
// find centre depth
int izlo = 0;
int izhi = -1;
for (OneStation os : vstations)
{
// scan only the stations that are on the screen
// (ignores legs, unfortunately). Could make this a menu switch.
if ((os.TLocX > -10) && (os.TLocX < csize.width + 10) && (os.TLocY > -10) && (os.TLocY < csize.height + 10))
{
int iz = os.TLocZ;
if ((izhi == -1) && (izlo == 0))
{
izlo = iz;
izhi = iz;
}
else
{
if (iz < izlo)
izlo = iz;
if (iz > izhi)
izhi = iz;
}
}
}
int mz = (izlo + izhi) / 2;
ncoff.x = -(mx * invmat.xx + my * invmat.xy + mz * invmat.xz + invmat.xo);
ncoff.y = -(mx * invmat.yx + my * invmat.yy + mz * invmat.yz + invmat.yo);
ncoff.z = -(mx * invmat.zx + my * invmat.zy + mz * invmat.zz + invmat.zo);
ReformView();
}
/////////////////////////////////////////////
/////////////////////////////////////////////
void MaximizeView()
{
// probably this ought to be calculating directly from the point
// positions without using the ReformView information.
if (vstations.isEmpty())
return;
float fxlo = 0.0F;
float fxhi = 0.0F;
float fylo = 0.0F;
float fyhi = 0.0F;
boolean bfirst = true;
for (OneStation os : vstations)
{
float fx = sxvec.Dot(os.Loc);
float fy = syvec.Dot(os.Loc);
if (bfirst || (fx < fxlo))
fxlo = fx;
if (bfirst || (fx > fxhi))
fxhi = fx;
if (bfirst || (fy < fylo))
fylo = fy;
if (bfirst || (fy > fyhi))
fyhi = fy;
bfirst = false;
}
// do the centring
float fcx = -(fxhi + fxlo) / 2;
float fcy = -(fyhi + fylo) / 2;
coff.SetXYZ(fcx * sxvec.x + fcy * syvec.x, fcx * sxvec.y + fcy * syvec.y, fcx * sxvec.z + fcy * syvec.z);
// do the scaling
float fxd = Math.max(fxhi - fxlo, 0.1F);
float fyd = Math.max(fyhi - fylo, 0.1F);
diameter = ((csize.width / fxd < csize.height / fyd) ? fxd : fyd) * 1.2F;
}
/////////////////////////////////////////////
void CalcQView()
{
float LzfRotX = zfRotX - ((int)(zfRotX / (float)Math.PI) + (zfRotX < 0.0F ? -1 : 0)) * (float)Math.PI;
float LzfRotZ = zfRotZ - ((int)(zfRotZ / (float)Math.PI) + (zfRotZ < 0.0F ? -1 : 0)) * (float)Math.PI;
qmdown.SetXYZ(0.0F, 0.0F, (float)Math.cos(LzfRotX));
qmdrag.SetXYZ(-(float)Math.cos(LzfRotZ), 0.0F, 0.0F);
qnow.Mult(qmdown, qmdrag);
}
/////////////////////////////////////////////
public void SetAutomaticView(float lzfRotX, float lzfRotZ)
{
if (lzfRotX != -1.0)
{
zfRotX = lzfRotX;
zfRotZ = lzfRotZ;
CalcQView();
}
else
MaximizeView();
ReformView();
repaint();
}
/////////////////////////////////////////////
// mouse events
/////////////////////////////////////////////
/////////////////////////////////////////////
public void mouseMoved(MouseEvent e) {;}
public void mouseClicked(MouseEvent e) {;}
public void mouseEntered(MouseEvent e) {;};
public void mouseExited(MouseEvent e) {;};
/////////////////////////////////////////////
public void mousePressed(MouseEvent e)
{
// if a point is already being dragged, then this second mouse press will delete it.
if (momotion != M_NONE)
{
vstationactive = null;
momotion = M_NONE;
repaint();
return;
}
int x = e.getX();
int y = e.getY();
// selection types (right mouse)
if (e.isMetaDown())
{
momotion = M_SEL_STATIONS;
if (!bEditable && (momotion != M_SEL_STATIONS))
momotion = M_NONE;
}
// select the motion type (left mouse)
else
{
if (e.isShiftDown())
momotion = M_DYN_TRANSLATE;
else if (e.isControlDown())
momotion = M_DYN_SCALE;
else
momotion = M_DYN_ROTATE;
}
// act on the motion type
switch(momotion)
{
case M_DYN_SCALE:
case M_DYN_TRANSLATE:
ReCentre(x, y);
ocoff.SetXYZ(coff.x, coff.y, coff.z);
prevx = x;
prevy = y;
prevdiameter = diameter;
break;
case M_DYN_ROTATE:
ReCentre(xoc, yoc);
coff.SetXYZ(ncoff.x, ncoff.y, ncoff.z);
prevx = x;
prevy = y;
if (!wireframedisplay.miZFixed.isSelected())
{
vmdown.SetOnSphere((float)(x - xoc) * 2 / csize.width, -(float)(y - yoc) * 2 / csize.height);
qmdown.SetFrom(qnow);
}
else
{
zfRotXdown = zfRotX;
zfRotZdown = zfRotZ;
}
break;
case M_SEL_STATIONS:
{
vstationactivesel = null;
int rdistsq = TN.XSinteractiveSensitivitySQ;
for (OneStation vstation : vstations)
{
int idistsq = vstation.sqDist(x, y);
if (idistsq < rdistsq)
{
rdistsq = idistsq;
vstationactivesel = vstation;
}
}
vstationactive = vstationactivesel;
if (vstationactive != null)
repaint();
else
momotion = M_NONE;
}
break;
default:
break;
}
}
/////////////////////////////////////////////
public void mouseDragged(MouseEvent e)
{
int x = e.getX();
int y = e.getY();
// act on the motion type
float lambda;
switch(momotion)
{
case M_DYN_ROTATE:
if (!wireframedisplay.miZFixed.isSelected())
{
vmdrag.SetOnSphere((float)(x - xoc) * 2 / csize.width, -(float)(y - yoc) * 2 / csize.height);
qmdrag.VecRot(vmdown, vmdrag);
qnow.Mult(qmdown, qmdrag);
}
else
{
zfRotX = zfRotXdown + (float)Math.PI * (x - prevx) / csize.width;
zfRotZ = zfRotZdown + (float)Math.PI * (y - prevy) / csize.height;
CalcQView();
}
ReformView();
repaint();
break;
case M_DYN_SCALE:
lambda = 1.0F + ((float)Math.abs(x - prevx) / csize.width) * 2.0F;
if (x > prevx)
lambda = 1.0F / lambda;
diameter = prevdiameter * lambda;
coff.SetAlong(lambda, ncoff, ocoff);
ReformView();
repaint();
break;
case M_DYN_TRANSLATE:
{
float lx = (x - prevx) / xfac;
float ly = -(y - prevy) / xfac;
coff.SetXYZ(ocoff.x + lx * sxvec.x + ly * syvec.x,
ocoff.y + lx * sxvec.y + ly * syvec.y,
ocoff.z + lx * sxvec.z + ly * syvec.z);
ReformView();
repaint();
}
break;
case M_SEL_STATIONS:
{
OneStation vsaOld = vstationactive;
vstationactive = ((vstationactivesel.sqDist(x, y) < TN.XSinteractiveSensitivitySQ) ? vstationactivesel : null);
if (vstationactive != vsaOld)
{
bNeedsRedrawing = true;
repaint();
}
}
break;
case M_NONE:
break;
default:
break;
}
}
/////////////////////////////////////////////
public void mouseReleased(MouseEvent e)
{
int x = e.getX();
int y = e.getY();
switch(momotion)
{
case M_SEL_STATIONS:
vstationactivesel = null;
vstationactive = null;
break;
case M_DYN_ROTATE:
case M_DYN_SCALE:
case M_DYN_TRANSLATE:
break;
case M_NONE:
return;
default:
break;
}
momotion = M_NONE;
bNeedsRedrawing = true;
repaint(); // get the labels back.
}
}
tunnelx-20190701/src/WireAxes.java 0000664 0001750 0001750 00000007446 13531571147 016275 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.awt.Graphics;
import java.awt.Dimension;
/////////////////////////////////////////////
class WireAxes
{
Matrix3D axesmat = new Matrix3D();
int ax0x = 0, ax0y = 0;
int axXx = 0, axXy = 0;
int axYx = 0, axYy = 0;
int axZx = 0, axZy = 0;
boolean bXbY = true, bXbZ = true, bYbZ = true;
int axScaLy = 0, axScaLyD = 0, axScaLxlo = 0, axScaLxN = 0;
float xfac; // records for the paintw case
float[] scaleRG = { 0.5F, 1.0F, 5.0F, 10.0F, 50.0F, 100.0F, 500.0F, 1000.0F };
/////////////////////////////////////////////
void ReformAxes(Matrix3D rotmat, Dimension csize, float xoc, float yoc, float lxfac)
{
xfac = lxfac;
axesmat.SetFrom(rotmat);
float afac = Math.min(csize.width, csize.height) / 10.0F;
axesmat.scale(afac, -afac, afac * 1.3F);
float fax0x = xoc / 4.0F;
float fax0y = yoc * (7.0F / 4.0F);
ax0x = (int)(fax0x + 0.5F);
ax0y = (int)(fax0y + 0.5F);
axXx = (int)(fax0x + axesmat.xx + 0.5F);
axXy = (int)(fax0y + axesmat.yx + 0.5F);
axYx = (int)(fax0x + axesmat.xy + 0.5F);
axYy = (int)(fax0y + axesmat.yy + 0.5F);
axZx = (int)(fax0x + axesmat.xz + 0.5F);
axZy = (int)(fax0y + axesmat.yz + 0.5F);
bXbY = (axesmat.zx < axesmat.zy);
bXbZ = (axesmat.zx < axesmat.zz);
bYbZ = (axesmat.zy < axesmat.zz);
axScaLy = (int)(yoc * (7.5F / 4.0F) + 0.5F);
axScaLyD = (int)(yoc * (0.1F / 4.0F) + 0.5F);
axScaLxN = Math.max((int)((2 * afac + 0.5F) / xfac), 1);
axScaLxlo = (int)(fax0x - afac + 0.5F);
}
/////////////////////////////////////////////
void paintW(Graphics g)
{
if (axesmat.zz < 0.0F)
{
g.setColor(TN.wfdaxesZ);
g.drawLine(ax0x, ax0y, axZx, axZy);
}
g.setColor(TN.wfdaxesXY);
g.drawLine(ax0x, ax0y, axXx, axXy);
g.drawLine(ax0x, ax0y, axYx, axYy);
if (axesmat.zz >= 0.0F)
{
g.setColor(TN.wfdaxesZ);
g.drawLine(ax0x, ax0y, axZx, axZy);
}
// draw the scale bars
// step up rate (by fixed if too many bits).
boolean bTooWide = (axScaLxN > 120);
int sbstep = (axScaLxN < 20 ? 1 : (!bTooWide ? 5 : axScaLxN));
int axScaLxNL = (int)(axScaLxN / sbstep) * sbstep;
g.setColor(!bTooWide ? TN.wfdaxesZ : TN.wfdaxesXY);
g.drawLine(axScaLxlo, axScaLy, axScaLxlo + (int)(axScaLxNL * xfac + 0.5F), axScaLy);
// draw the double size ones
if ((sbstep <= 5) && (axScaLxNL >= 5))
{
g.setColor(TN.wfdaxesXY);
for (int sb = 0; sb <= axScaLxNL; sb += 5)
{
int xi = axScaLxlo + (int)(sb * xfac + 0.5F);
g.drawLine(xi, axScaLy - axScaLyD * 2, xi, axScaLy + axScaLyD * 2);
}
}
g.setColor(!bTooWide ? TN.wfdaxesZ : TN.wfdaxesXY);
for (int sb = 0; sb <= axScaLxNL; sb += sbstep)
{
int xi = axScaLxlo + (int)(sb * xfac + 0.5F);
g.drawLine(xi, axScaLy - axScaLyD, xi, axScaLy + axScaLyD);
}
}
/////////////////////////////////////////////
/////////////////////////////////////////////
};
tunnelx-20190701/src/TunnelLoader.java 0000664 0001750 0001750 00000005606 13531571147 017136 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.io.IOException;
import java.util.List;
//
//
// TunnelLoader
//
//
/////////////////////////////////////////////
/////////////////////////////////////////////
class TunnelLoader
{
TunnelXMLparse txp;
TunnelXML tunnXML;
/////////////////////////////////////////////
/////////////////////////////////////////////
boolean LoadSketchFile(OneSketch tsketch, boolean bwritemessage)
{
assert !tsketch.bsketchfileloaded;
tsketch.SetupSK();
FileAbstraction tfile = tsketch.sketchfile;
String fnamess = TN.loseSuffix(tfile.getName());
txp.SetUp(fnamess, FileAbstraction.FA_FILE_XML_SKETCH);
tsketch.bsketchfilechanged = false;
if (txp.bSymbolType)
{
tsketch.bSymbolType = true;
tsketch.sketchsymbolname = TN.loseSuffix(tfile.getName());
}
txp.tunnelsketch = tsketch;
boolean bloaded = tunnXML.ParseFile(txp, tfile);
if (bwritemessage)
TN.emitMessage("Loaded sketch (" + tsketch.sketchfile.getName() + "): project(" + tsketch.tunnelprojectloaded + "), user(" + tsketch.tunneluserloaded + "), date(" + tsketch.tunneldateloaded + "), tunnelversion(" + tsketch.tunnelversionloaded + ")");
return bloaded;
}
/////////////////////////////////////////////
void LoadFontcolour(FileAbstraction tfile)
{
try
{
System.out.println("Loading font colours:" + tfile.getName());
txp.SetUp(TN.loseSuffix(tfile.getName()), FileAbstraction.FA_FILE_XML_FONTCOLOURS);
tunnXML.ParseFile(txp, tfile);
}
catch (NullPointerException e)
{
TN.emitWarning(e.toString());
e.printStackTrace();
};
}
/////////////////////////////////////////////
/////////////////////////////////////////////
public TunnelLoader(boolean lbSymbolType, SketchLineStyle sketchlinestyle)
{
txp = new TunnelXMLparse();
txp.bSymbolType = lbSymbolType;
txp.sketchlinestyle = sketchlinestyle; // for loading up the fontcolours
tunnXML = new TunnelXML();
}
};
tunnelx-20190701/src/LegLineFormat.java 0000664 0001750 0001750 00000071127 13531571147 017233 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.util.List;
import java.util.ArrayList;
//
//
// LegLineFormat
//
//
public class LegLineFormat// implements Cloneable
{
static int DEGREES = 0;
static int GRADS = 1;
static int PERCENT = 2;
static float TAPEFAC_M = 1.0F;
static float TAPEFAC_CM = 0.01F;
static float TAPEFAC_FT = 0.3048F;
String datatype = "normal"; // or diving, cartesian, nosurvey, passage
boolean bnosurvey = false;
boolean bcartesian = false;
boolean bbaddataline = false;
boolean bpassage = false;
boolean bsurface = false;
boolean bduplicate = false;
boolean bsplay = false;
int fromindex = 0;
int toindex = 1;
int casepreservemode = -1; // -1=lower, 0=preserve, 1=upper
int tapeindex = 2;
float tapenegoffset = 0.0F;
float tapefac = 1.0F;
int compassindex = 3;
int backcompassindex = -1;
float compassnegoffset = 0.0F;
float backcompassnegoffset = 0.0F;
float compassnegoffsetdeclination = 0.0F; // a secondary offset value (separates the calibration from the magnetic wandering (declination))
int compassfac = DEGREES;
int clinoindex = 4;
int backclinoindex = -1;
float clinonegoffset = 0.0F;
int clinofac = DEGREES;
int dxindex = -1;
int dyindex = -1;
int dzindex = -1;
float dxfac = 1.0F;
float dyfac = 1.0F;
float dzfac = 1.0F;
int depthindex = -1;
int fromdepthindex = -1;
int todepthindex = -1;
float depthnegoffset = 0;
float depthfac = 1.0F;
int stationindex = -1;
int leftindex = -1;
int rightindex = -1;
int upindex = -1;
int downindex = -1;
// this tells where the newline can be fit into the format
// (to account for those two-line type records).
int newlineindex = -1;
String sdecimal = null;
String sblank = null; // this may need to be mapped into the word splitter.
String snames = null;
// attributes carried over from those crappy blank begin blocks that are completely crap!
String bb_svxdate = "";
String bb_svxtitle = "";
String bb_teamtape = "";
String bb_teampics = "";
String bb_teaminsts = "";
String bb_teamnotes = "";
List totalteam = new ArrayList();
StringBuffer sb_totalteam = new StringBuffer();
// local data used for multi-line (diving) type data.
String lstation = null;
float ldepth = 0;
float lcompass = 0;
float ltape = 0;
float ldx = 0;
float ldy = 0;
float ldz = 0;
boolean btopextendedelevation = false;
boolean btopextflipleg = false;
int currnewlineindex = 0;
FileAbstraction currfile; // not used
/////////////////////////////////////////////
LegLineFormat() // constructs the default one.
{;}
/////////////////////////////////////////////
LegLineFormat(LegLineFormat f)
{
if (f != null)
{
datatype = f.datatype;
bnosurvey = f.bnosurvey;
bcartesian = f.bcartesian;
bpassage = f.bpassage;
bsurface = f.bsurface;
bduplicate = f.bduplicate;
bsplay = f.bsplay;
bbaddataline = f.bbaddataline;
fromindex = f.fromindex;
toindex = f.toindex;
casepreservemode = f.casepreservemode;
tapeindex = f.tapeindex;
tapenegoffset = f.tapenegoffset;
tapefac = f.tapefac;
compassindex = f.compassindex;
backcompassindex = f.backcompassindex;
compassnegoffset = f.compassnegoffset;
backcompassnegoffset = f.backcompassnegoffset;
compassnegoffsetdeclination = f.compassnegoffsetdeclination;
compassfac = f.compassfac;
clinoindex = f.clinoindex;
backclinoindex = f.backclinoindex;
clinonegoffset = f.clinonegoffset;
clinofac = f.clinofac;
dxindex = f.dxindex;
dyindex = f.dyindex;
dzindex = f.dzindex;
dxfac = f.dxfac;
dyfac = f.dyfac;
dzfac = f.dzfac;
newlineindex = f.newlineindex;
stationindex = f.stationindex;
depthindex = f.depthindex;
fromdepthindex = f.fromdepthindex;
todepthindex = f.todepthindex;
depthnegoffset = f.depthnegoffset;
depthfac = f.depthfac;
leftindex = f.leftindex;
rightindex = f.rightindex;
upindex = f.upindex;
downindex = f.downindex;
sdecimal = f.sdecimal;
sblank = f.sblank;
snames = f.snames;
btopextendedelevation = f.btopextendedelevation;
bb_svxdate = f.bb_svxdate;
bb_svxtitle = f.bb_svxtitle;
bb_teamtape = f.bb_teamtape;
bb_teampics = f.bb_teampics;
bb_teaminsts = f.bb_teaminsts;
bb_teamnotes = f.bb_teamnotes;
UpdateTotalTeam();
}
}
/////////////////////////////////////////////
void AddToTotalTeam(String steam)
{
if (steam.length() == 0)
return;
if (steam.equalsIgnoreCase("both") || steam.equalsIgnoreCase("none"))
return;
int iand = steam.indexOf(" and ");
if (iand != -1)
{
AddToTotalTeam(steam.substring(0, iand));
AddToTotalTeam(steam.substring(iand + 5));
return;
}
int iand1 = steam.indexOf("&");
if (iand1 == -1)
iand1 = steam.indexOf("+");
if (iand1 == -1)
iand1 = steam.indexOf(",");
if (iand1 != -1)
{
AddToTotalTeam(steam.substring(0, iand1).trim());
AddToTotalTeam(steam.substring(iand1 + 1).trim());
return;
}
steam = steam.trim();
for (String lteam : totalteam)
if (steam.equalsIgnoreCase(lteam))
return;
totalteam.add(steam);
}
/////////////////////////////////////////////
void UpdateTotalTeam()
{
totalteam.clear();
AddToTotalTeam(bb_teamnotes);
AddToTotalTeam(bb_teampics);
AddToTotalTeam(bb_teaminsts);
AddToTotalTeam(bb_teamtape);
sb_totalteam.setLength(0);
for (String t : totalteam)
{
if (sb_totalteam.length() != 0)
sb_totalteam.append(", ");
sb_totalteam.append(t);
}
}
/////////////////////////////////////////////
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append(datatype);
int im0 = Math.max(fromindex, toindex);
int im1 = Math.max(clinoindex, compassindex);
int im2 = Math.max(backclinoindex, backcompassindex);
int im3 = tapeindex;
int im = Math.max(Math.max(im0, im1), Math.max(im2, im3));
for (int i = 0; i <= im; i++)
{
if (i == fromindex)
sb.append(" from");
else if (i == toindex)
sb.append(" to");
else if (i == tapeindex)
sb.append(" tape");
else if (i == compassindex)
sb.append(" compass");
else if (i == clinoindex)
sb.append(" clino");
else if (i == backcompassindex)
sb.append(" backcompass");
else if (i == backclinoindex)
sb.append(" backclino");
else if (i == dxindex)
sb.append(" dx");
else if (i == dyindex)
sb.append(" dy");
else if (i == dzindex)
sb.append(" dz");
else if (i == depthindex)
sb.append(" depth");
else if (i == fromdepthindex)
sb.append(" fromdepth");
else if (i == todepthindex)
sb.append(" todepth");
else if (i == stationindex)
sb.append(" station");
else if (i == newlineindex)
sb.append(" newline");
else if (i == leftindex)
sb.append(" left");
else if (i == rightindex)
sb.append(" right");
else if (i == upindex)
sb.append(" up");
else if (i == downindex)
sb.append(" down");
else
sb.append(" ignore");
}
sb.append(" ignoreall");
return sb.toString();
}
/////////////////////////////////////////////
// this substitutes characters in these strings with ones that make them parsable.
String ApplySet(String field)
{
// deal with the blank conversions.
if (sblank != null)
{
for (int i = 0; i < sblank.length(); i++)
field = field.replace(sblank.charAt(i), ' ');
}
// deal with the decimal conversions.
if (sdecimal != null)
{
for (int i = 0; i < sdecimal.length(); i++)
field = field.replace(sdecimal.charAt(i), '.');
}
return field;
}
/////////////////////////////////////////////
String ApplyCasePreserveMode(String s)
{
if (s == null)
return s;
if (casepreservemode == -1)
return s.toLowerCase();
if (casepreservemode == -1)
return s.toUpperCase();
return s;
}
/////////////////////////////////////////////
float ReadCompass(String ws, boolean bback)
{
String acompass = ApplySet(ws);
if (acompass.equalsIgnoreCase("-") || acompass.equals(""))
return OneLeg.INVALID_COMPASSCLINO;
float compass = GetFLval(acompass) - (bback ? backcompassnegoffset : compassnegoffset) - compassnegoffsetdeclination;
if (compassfac == GRADS)
compass *= 360.0F / 400.0F;
while (compass < 0.0F)
compass += 360.0F;
while (compass > 360.0F)
compass -= 360.0F;
return compass;
}
/////////////////////////////////////////////
float ReadClino(String ws)
{
float clino;
String aclino = ApplySet(ws);
if (aclino.equalsIgnoreCase("-"))
return OneLeg.INVALID_COMPASSCLINO;
if (aclino.equalsIgnoreCase("up") || aclino.equalsIgnoreCase("u") || aclino.equalsIgnoreCase("+V"))
clino = 90.0F;
else if (aclino.equalsIgnoreCase("down") || aclino.equalsIgnoreCase("d") || aclino.equalsIgnoreCase("-V"))
clino = -90.0F;
else if (aclino.equalsIgnoreCase("h") || aclino.equalsIgnoreCase("level"))
clino = 0.0F;
else
{
clino = GetFLval(aclino);
clino -= clinonegoffset; // is there a different setting for backclino?
if (clinofac == GRADS)
clino *= 360.0F / 400.0F;
if (clinofac == PERCENT)
clino = (float)TN.percentdeg(clino);
}
return clino;
}
/////////////////////////////////////////////
OneLeg ReadLeg(String w[], LineInputStream lis)
{
try
{
// normal leg format with everything there.
if ((newlineindex == -1) && (stationindex == -1))
{
if (w[toindex].equals("-"))
w[toindex] = null; // discarding splay station
else if (w[toindex].startsWith("-") && w[toindex].endsWith("-"))
w[toindex] = null; // discarding splay station
else if (w[toindex].equals(".") || w[toindex].equals("..") || w[toindex].equals("..."))
w[toindex] = null; // discarding splay station
if (w[fromindex].equals("-"))
w[fromindex] = null; // discarding splay station
else if (w[fromindex].equals(".") || w[fromindex].equals("..") || w[fromindex].equals("..."))
w[fromindex] = null; // discarding splay station
// case of just a leg but with no measurements on it
if (bnosurvey)
return new OneLeg(ApplyCasePreserveMode(w[fromindex]), ApplyCasePreserveMode(w[toindex]), this);
if (bbaddataline)
{
lis.emitWarning("ignoring line due to bad *data format");
return null;
}
if (bcartesian)
{
float dx = GetFLval(ApplySet(w[dxindex])) * dxfac;
float dy = GetFLval(ApplySet(w[dyindex])) * dyfac;
float dz = GetFLval(ApplySet(w[dzindex])) * dzfac;
return new OneLeg(dx, dy, dz, ApplyCasePreserveMode(w[fromindex]), ApplyCasePreserveMode(w[toindex]), this);
}
String atape = ApplySet(w[tapeindex]);
float tape = (GetFLval(atape) - tapenegoffset) * tapefac;
float compass = ReadCompass(w[compassindex], false);
float backcompass = (backcompassindex == -1 ? OneLeg.INVALID_COMPASSCLINO : ReadCompass(w[backcompassindex], true));
// clino data exists
if (clinoindex != -1)
{
float clino = ReadClino(w[clinoindex]);
float backclino = (backclinoindex == -1 ? OneLeg.INVALID_COMPASSCLINO : ReadClino(w[backclinoindex]));
if ((compass == OneLeg.INVALID_COMPASSCLINO) && (backcompass == OneLeg.INVALID_COMPASSCLINO))
{
if ((clino != -90.0F) && (clino != 90.0F))
TN.emitWarning("Error, blank compass on non-vertical leg " + w[0] + " " + w[1] + " " + w[2] + " " + w[3] + " " + w[4] + " " + w[5]);
}
if (btopextendedelevation)
btopextflipleg = w[5].equals(TN.flipCLINEsignal);
OneLeg ol = new OneLeg(ApplyCasePreserveMode(w[fromindex]), ApplyCasePreserveMode(w[toindex]), tape, compass, backcompass, clino, backclino, this);
ol.flinenumber = lis.nlineno; // used for determining whether the anonymous leg comes first so as to set it in a topo file to the fixed point
return ol;
}
else
assert backclinoindex == -1;
// case where clino not needed in diving data
if ((fromdepthindex != -1) && (todepthindex != -1))
{
String afromdepth = ApplySet(w[fromdepthindex]);
float fromdepth = GetFLval(afromdepth);
String atodepth = ApplySet(w[fromdepthindex]);
float todepth = GetFLval(atodepth);
//TN.emitMessage("LDIVING " + w[fromindex] + " " + w[toindex] + " " + tape + " " + compass + " " + fromdepth + " " + todepth);
if ((compass == OneLeg.INVALID_COMPASSCLINO) && (backcompass != OneLeg.INVALID_COMPASSCLINO)) // unlikely to do good backsights in diving data
compass = backcompass;
return new OneLeg(ApplyCasePreserveMode(w[fromindex]), ApplyCasePreserveMode(w[toindex]), tape, compass, fromdepth, todepth, this);
}
}
// new case of single station disclosed on line
if ((newlineindex == -1) && (stationindex != -1))
{
if (bnosurvey && (stationindex != -1))
return new OneLeg(ApplyCasePreserveMode(w[stationindex]), null, this);
}
// cope with some difficult format that spans more than one line.
if ((stationindex != -1) && (newlineindex != -1))
{
// load the station and build the return value if we have a follow on.
int nextnewlineindex = (currnewlineindex == 0 ? newlineindex : w.length);
String lnewstation = null;
float lnewdepth = -1.0F;
if ((stationindex < nextnewlineindex) && (stationindex >= currnewlineindex)) // currnewlineindex is 0 in this case.
lnewstation = w[stationindex - currnewlineindex];
// probably assumes when depthindex == -1 it's not >= currnewlineindex
if ((depthindex < nextnewlineindex) && (depthindex >= currnewlineindex)) // currnewlineindex is 0 in this case.
{
String adepth = ApplySet(w[depthindex - currnewlineindex]);
lnewdepth = (GetFLval(adepth) + depthnegoffset) * depthfac;
}
// build the result.
OneLeg olres = null;
if ((lnewstation != null) && (lstation != null)) // and the rest.
{
if (bcartesian)
{
olres = new OneLeg(ldx, ldy, ldz, ApplyCasePreserveMode(lstation), ApplyCasePreserveMode(lnewstation), this);
//TN.emitMessage("DIVING cart " + lstation + " " + lnewstation + " " + ltape + " " + lcompass + " " + ldepth + " " + lnewdepth);
}
else
{
olres = new OneLeg(ApplyCasePreserveMode(lstation), ApplyCasePreserveMode(lnewstation), ltape, lcompass, ldepth, lnewdepth, this);
//TN.emitMessage("DIVING " + lstation + " " + lnewstation + " " + ltape + " " + lcompass + " " + ldepth + " " + lnewdepth);
}
// should clear all the fields.
}
// copy over the new labels.
if (lnewstation != null)
{
lstation = lnewstation;
ldepth = lnewdepth;
}
// get tape and compass.
if ((tapeindex < nextnewlineindex) && (tapeindex >= currnewlineindex)) // currnewlineindex is 0 in this case.
{
String atape = ApplySet(w[tapeindex - currnewlineindex]);
ltape = (GetFLval(atape) + tapenegoffset) * tapefac;
}
if ((compassindex < nextnewlineindex) && (compassindex >= currnewlineindex)) // currnewlineindex is 0 in this case.
{
String acompass = ApplySet(w[compassindex - currnewlineindex]);
boolean bcblank = (acompass.equalsIgnoreCase("-") || acompass.equals(""));
lcompass = (bcblank ? 0.0F : GetFLval(acompass)) - compassnegoffset - compassnegoffsetdeclination;
if (compassfac == GRADS)
lcompass *= 360.0F / 400.0F;
}
if (bcartesian)
{
if ((dxindex < nextnewlineindex) && (dxindex >= currnewlineindex))
ldx = GetFLval(ApplySet(w[dxindex - currnewlineindex])) * dxfac;
if ((dyindex < nextnewlineindex) && (dyindex >= currnewlineindex))
ldy = GetFLval(ApplySet(w[dyindex - currnewlineindex])) * dyfac;
if ((dzindex < nextnewlineindex) && (dzindex >= currnewlineindex))
ldz = GetFLval(ApplySet(w[dzindex - currnewlineindex])) * dzfac;
}
// update the lineindex.
currnewlineindex = (currnewlineindex == 0 ? (newlineindex + 1) : 0);
// not properly implemented case (errors not mapping across lines).
return olres;
}
// we should be loading these in as cross-section objects
if (datatype.equalsIgnoreCase("passage"))
{
//System.out.println("PASSAGE:: " + lis.GetLine());
return null;
}
TN.emitWarning("Can't do format " + datatype);
}
catch (NumberFormatException e)
{
lis.emitError("Number Format");
}
return null;
}
/////////////////////////////////////////////
OneLeg ReadFix(String w[], LineInputStream lis)
{
try
{
int i = (w[2].equalsIgnoreCase("reference") ? 3 : 2);
float fx = GetFLval(w[i]) * tapefac;
float fy = GetFLval(w[i + 1]) * tapefac;
float fz = GetFLval(w[i + 2]) * tapefac;
return new OneLeg(ApplyCasePreserveMode(w[1]), fx, fy, fz, this); // fix type
}
catch (NumberFormatException e)
{
lis.emitError("Number Format");
}
return null;
}
/////////////////////////////////////////////
public void StarCalibrate(String scaltype, String scalval, String sfacval, LineInputStream lis)
{
try
{
float fval = GetFLval(scalval);
if (scaltype.equalsIgnoreCase("tape"))
tapenegoffset = fval * tapefac;
else if (scaltype.equalsIgnoreCase("compass"))
compassnegoffset = fval;
else if (scaltype.equalsIgnoreCase("backcompass"))
backcompassnegoffset = fval;
else if (scaltype.equalsIgnoreCase("declination"))
compassnegoffsetdeclination = fval;
else if (scaltype.equalsIgnoreCase("clino") || scaltype.equalsIgnoreCase("clinometer"))
clinonegoffset = fval;
else if (scaltype.equalsIgnoreCase("depth"))
{
depthnegoffset = fval;
if (!sfacval.equals(""))
{
float facval = GetFLval(sfacval);
depthfac = facval;
}
}
else
TN.emitWarning("bad *Calibrate type " + scaltype);
}
catch (NumberFormatException e)
{
lis.emitError("Number Format");
}
}
/////////////////////////////////////////////
float GetFLval(String s)
{
if (s.equals("+0_0"))
return 0.0F;
float res = Float.parseFloat(s);
return res;
}
/////////////////////////////////////////////
public void StarUnits(String sunitype, String sunitval1, String sunitval2, LineInputStream lis)
{
String sunitval = sunitval1;
float fac = 1.0F;
if (!sunitval2.equals(""))
{
sunitval = sunitval2;
try {
fac = GetFLval(sunitval1);
} catch (NumberFormatException e) {
TN.emitWarning("got trouble with *units");
lis.emitWarning(e.toString());
}
}
if (sunitype.equalsIgnoreCase("length") || sunitype.equalsIgnoreCase("tape"))
{
if (sunitval.equalsIgnoreCase("metres") || sunitval.equalsIgnoreCase("meters"))
tapefac = TAPEFAC_M * fac;
else if (sunitval.equalsIgnoreCase("cm"))
tapefac = TAPEFAC_CM * fac;
else if (sunitval.equalsIgnoreCase("feet"))
tapefac = TAPEFAC_FT * fac;
else
TN.emitWarning("don't know *Units length " + sunitval1 + "," + sunitval2);
}
else if (sunitype.equalsIgnoreCase("bearing") || sunitype.equalsIgnoreCase("compass"))
{
assert sunitval2.equals("") || (fac == 1.0);
if (sunitval.equalsIgnoreCase("degrees"))
compassfac = DEGREES;
else if (sunitval.equalsIgnoreCase("grads"))
compassfac = GRADS;
else
TN.emitWarning("don't know *Units bearing " + sunitval1 + "," + sunitval2);
}
else if (sunitype.equalsIgnoreCase("gradient") || sunitype.equalsIgnoreCase("clino"))
{
assert sunitval2.equals("") || (fac == 1.0);
if (sunitval.equalsIgnoreCase("degrees"))
clinofac = DEGREES;
else if (sunitval.equalsIgnoreCase("grads"))
clinofac = GRADS;
else if (sunitval.equalsIgnoreCase("percent"))
clinofac = PERCENT;
else
TN.emitWarning("don't know *Units gradient " + sunitval1 + "," + sunitval2);
}
else if (sunitype.equalsIgnoreCase("dx"))
{
if (sunitval.equalsIgnoreCase("metres") || sunitval.equalsIgnoreCase("meters"))
dxfac = TAPEFAC_M * fac;
else
TN.emitWarning("don't know *Units dx " + sunitval1 + "," + sunitval2);
}
else if (sunitype.equalsIgnoreCase("dy"))
{
if (sunitval.equalsIgnoreCase("metres") || sunitval.equalsIgnoreCase("meters"))
dyfac = TAPEFAC_M * fac;
else
TN.emitWarning("don't know *Units dy " + sunitval1 + "," + sunitval2);
}
else if (sunitype.equalsIgnoreCase("dz"))
{
if (sunitval.equalsIgnoreCase("metres") || sunitval.equalsIgnoreCase("meters"))
dzfac = TAPEFAC_M * fac;
else
TN.emitWarning("don't know *Units dz " + sunitval1 + "," + sunitval2);
}
else
TN.emitWarning("don't know *Units type: " + sunitype);
}
/////////////////////////////////////////////
public void StarSet(String sfield, String setting, LineInputStream lis)
{
if (sfield.equalsIgnoreCase("decimal"))
sdecimal = setting;
else if (sfield.equalsIgnoreCase("blank"))
sblank = setting;
else if (sfield.equalsIgnoreCase("names"))
snames = setting;
else
TN.emitWarning("don't know *set " + sfield + " " + setting);
}
/////////////////////////////////////////////
public void StarFlags(String[] w, int iw)
{
int i = 1;
boolean bflag = true;
if (w[1].equalsIgnoreCase("not"))
{
bflag = false;
i = 2;
}
if (w[i].equalsIgnoreCase("surface"))
bsurface = bflag;
else if (w[i].equalsIgnoreCase("duplicate"))
bduplicate = bflag;
else if (w[i].equalsIgnoreCase("splay"))
bsplay = bflag;
else
System.out.println(" unrecognized StarFlags " + w[1]);
}
/////////////////////////////////////////////
// This is programmed to work on the one known example of *Data.
public boolean StarDataNormal(String[] w, int iw)
{
if (w[1].equalsIgnoreCase("default"))
{
w[1] = "normal";
w[2] = "from";
w[3] = "to";
w[4] = "tape";
w[5] = "compass";
w[6] = "clino";
iw = 7;
}
datatype = w[1];
bnosurvey = datatype.equalsIgnoreCase("nosurvey");
bcartesian = datatype.equalsIgnoreCase("cartesian");
bpassage = datatype.equalsIgnoreCase("normal") || datatype.equalsIgnoreCase("passage") || datatype.equalsIgnoreCase("diving");
if (!bnosurvey && !bcartesian && !bpassage)
TN.emitError("Unrecognized *data command: " + datatype);
bbaddataline = false;
// first kill stupid - symbol people keep putting into their commands
if (w[2].equals("-"))
{
TN.emitMessage("Removing stupid '-' symbol from *data Normal line");
for (int i = 3; i < iw; i++)
w[i - 1] = w[i];
iw--;
}
int lfromindex = -1;
int ltoindex = -1;
int ltapeindex = -1;
int lcompassindex = -1;
int lclinoindex = -1;
int lbackcompassindex = -1;
int lbackclinoindex = -1;
int ldxindex = -1;
int ldyindex = -1;
int ldzindex = -1;
int lstationindex = -1;
int lnewlineindex = -1;
int ldepthindex = -1;
int lfromdepthindex = -1;
int ltodepthindex = -1;
int lleftindex = -1;
int lrightindex = -1;
int lupindex = -1;
int ldownindex = -1;
int i;
for (i = 2; i < iw; i++)
{
if (w[i].equalsIgnoreCase("from"))
{
if (lfromindex != -1)
break;
lfromindex = i - 2;
}
else if (w[i].equalsIgnoreCase("to"))
{
if (ltoindex != -1)
break;
ltoindex = i - 2;
}
else if (w[i].equalsIgnoreCase("length") || w[i].equalsIgnoreCase("tape"))
{
if (ltapeindex != -1)
break;
ltapeindex = i - 2;
}
else if (w[i].equalsIgnoreCase("compass") || w[i].equalsIgnoreCase("bearing"))
{
if (lcompassindex != -1)
break;
lcompassindex = i - 2;
}
else if (w[i].equalsIgnoreCase("backcompass") || w[i].equalsIgnoreCase("backbearing"))
{
if (lbackcompassindex != -1)
break;
lbackcompassindex = i - 2;
}
else if (w[i].equalsIgnoreCase("clino") || w[i].equalsIgnoreCase("gradient"))
{
if (lclinoindex != -1)
break;
lclinoindex = i - 2;
}
else if (w[i].equalsIgnoreCase("backclino") || w[i].equalsIgnoreCase("backgradient"))
{
if (lbackclinoindex != -1)
break;
lbackclinoindex = i - 2;
}
else if (w[i].equalsIgnoreCase("ignore"))
;
else if (w[i].equalsIgnoreCase("ignoreall"))
;
else if (w[i].equalsIgnoreCase("description"))
;
else if (w[i].equalsIgnoreCase("remarks"))
;
else if (w[i].equalsIgnoreCase("newline"))
{
if (lnewlineindex != -1)
break;
lnewlineindex = i - 2;
}
else if (w[i].equalsIgnoreCase("dx") || w[i].equalsIgnoreCase("easting"))
{
if (ldxindex != -1)
break;
ldxindex = i - 2;
}
else if (w[i].equalsIgnoreCase("dy") || w[i].equalsIgnoreCase("northing"))
{
if (ldyindex != -1)
break;
ldyindex = i - 2;
}
else if (w[i].equalsIgnoreCase("dz") || w[i].equalsIgnoreCase("altitude"))
{
if (ldzindex != -1)
break;
ldzindex = i - 2;
}
// from becomes station.
else if (w[i].equalsIgnoreCase("station"))
{
if (lstationindex != -1)
break;
lstationindex = i - 2;
}
else if (w[i].equalsIgnoreCase("depth"))
{
if (ldepthindex != -1)
break;
ldepthindex = i - 2;
}
else if (w[i].equalsIgnoreCase("fromdepth"))
{
if (lfromdepthindex != -1)
break;
lfromdepthindex = i - 2;
}
else if (w[i].equalsIgnoreCase("todepth"))
{
if (ltodepthindex != -1)
break;
ltodepthindex = i - 2;
}
else if (w[i].equalsIgnoreCase("left"))
{
if (lleftindex != -1)
break;
lleftindex = i - 2;
}
else if (w[i].equalsIgnoreCase("right"))
{
if (lrightindex != -1)
break;
lrightindex = i - 2;
}
else if (w[i].equalsIgnoreCase("up"))
{
if (lupindex != -1)
break;
lupindex = i - 2;
}
else if (w[i].equalsIgnoreCase("down"))
{
if (ldownindex != -1)
break;
ldownindex = i - 2;
}
else
{
TN.emitWarning("!!! " + w[i] + " " + i);
break;
}
}
// incomplete.
if (i != iw)
{
bbaddataline = true;
return false;
}
boolean bstandardform = ((lfromindex != -1) && (ltoindex != -1) && (ltapeindex != -1) && (lcompassindex != -1) && (lclinoindex != -1));
boolean bcartesianform = (bcartesian && (ldxindex != -1) && (ldyindex != -1) && (ldzindex != -1));
boolean bdivingform = ((ltapeindex != -1) && (lcompassindex != -1) && (ldepthindex != -1) && (lstationindex != -1) && (lnewlineindex != -1));
boolean bldivingform = ((lfromindex != -1) && (ltoindex != -1) && (ltapeindex != -1) && (lcompassindex != -1) && (lfromdepthindex != -1) && (ltodepthindex != -1));
boolean bllussform = ((lstationindex != -1) && (lnewlineindex != -1) && (ltapeindex != -1) && (lcompassindex != -1) && (lclinoindex != -1));
boolean blpassageform = ((lstationindex != -1) && (lleftindex != -1) && (lrightindex != -1) && (lupindex != -1) && (ldownindex != -1));
boolean blbnosurvey = (bnosurvey && ((lstationindex != -1) || ((lfromindex != -1) && (ltoindex != -1))) && (ltapeindex == -1) && (lcompassindex == -1) && (lfromdepthindex == -1) && (ltodepthindex == -1));
// bad line
if (!bstandardform && !bcartesianform && !bdivingform && !bldivingform && !blpassageform && !blbnosurvey && !bllussform)
{
TN.emitMessage("Indexes, station:" + lstationindex + " from:" + lfromindex + " to:" + ltoindex + " NEWLINE:" + lnewlineindex + " tape:" + ltapeindex + " compass:" + lcompassindex + " clino:" + lclinoindex + " bnosurvey="+bnosurvey);
bbaddataline = true;
return false;
}
fromindex = lfromindex;
toindex = ltoindex;
tapeindex = ltapeindex;
compassindex = lcompassindex;
clinoindex = lclinoindex;
backcompassindex = lbackcompassindex;
backclinoindex = lbackclinoindex;
dxindex = ldxindex;
dyindex = ldyindex;
dzindex = ldzindex;
stationindex = lstationindex;
depthindex = ldepthindex;
fromdepthindex = lfromdepthindex;
todepthindex = ltodepthindex;
newlineindex = lnewlineindex;
leftindex = lleftindex;
rightindex = lrightindex;
upindex = lupindex;
downindex = ldownindex;
bbaddataline = false;
return true;
}
/////////////////////////////////////////////
/////////////////////////////////////////////
}
tunnelx-20190701/src/PathLabelDecode.java 0000664 0001750 0001750 00000043555 13531571147 017507 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.io.StringReader;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.awt.Graphics;
import java.awt.FontMetrics;
import java.awt.Font;
import java.awt.Color;
import java.awt.geom.Line2D;
//import java.awt.geom.Line2D.Float;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Rectangle2D.Float;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.Shape;
import java.awt.geom.GeneralPath;
////////////////////////////////////////////////////////////////////////////////
class PathLabelElement
{
String text;
float xcelloffset = 0.0F;
float xcelloffsettop = 0.0F;
float ycelloffset = 0.0F;
int yiline;
boolean bcontinuation = false;
boolean btextwidthset = false;
boolean btextheightset = false;
boolean btextwidthtopset = false;
boolean bfontmagnifyset = false;
float ftextjustify = -1.0F; // 0.0 left, 0.5 centre, 1.0 right
float textwidth;
float textheight;
float textwidthtop;
float fontmagnify = 1.0F;
float defaultden; // for carrying over between lines
Rectangle2D textrect = null;
Shape textshape = null;
static int HZT_HORIZONTAL_WIDTH = 0;
static int HZT_VERTICAL_WIDTH = 1;
static int HZT_TOPLINE_WIDTH = 2;
static int HZT_FONTMAGNIFY = 3;
////////////////////////////////////////////////////////////////////////////////
PathLabelElement(String ltext, float ldefaultden, float ldefaultftextjustify)
{
defaultden = ldefaultden;
ftextjustify = ldefaultftextjustify;
// works out if it is a genuine new line
if (ltext.startsWith(";"))
{
bcontinuation = true;
text = ltext.substring(1).trim();
}
else
text = ltext.trim();
// extract the width coding of %dd/dddd%
while (text.indexOf('%') == 0)
{
if (text.startsWith("%left%"))
{
ftextjustify = 0.0F;
text = text.substring(6).trim();
continue;
}
if (text.startsWith("%centre%") || text.startsWith("%center%"))
{
ftextjustify = 0.5F;
text = text.substring(8).trim();
continue;
}
if (text.startsWith("%right%"))
{
ftextjustify = 1.0F;
text = text.substring(7).trim();
continue;
}
int islashps = text.indexOf('/', 1);
int ipercps = text.indexOf('%', 1);
if ((ipercps == -1) || (islashps == -1) || !(islashps < ipercps))
break;
int numstart = 1;
// h = horizontal width
// v = vertical width
// t = top line width (for doing triangles, as in North Arrow)
// f = make the font bigger
int ihoriztype = HZT_HORIZONTAL_WIDTH;
if (text.charAt(numstart) == 'v')
{
ihoriztype = HZT_VERTICAL_WIDTH;
numstart++;
}
else if (text.charAt(numstart) == 't')
{
ihoriztype = HZT_TOPLINE_WIDTH;
numstart++;
}
else if (text.charAt(numstart) == 'h')
{
ihoriztype = HZT_HORIZONTAL_WIDTH;
numstart++;
}
else if (text.charAt(numstart) == 'f')
{
ihoriztype = HZT_FONTMAGNIFY;
numstart++;
}
else
ihoriztype = HZT_HORIZONTAL_WIDTH; // default case
float textdim = -1.0F;
String numstr = text.substring(numstart, islashps).trim();
String denstr = text.substring(islashps + 1, ipercps).trim();
// extract the numbers
try
{
float num = (float)Double.parseDouble(numstr); // compilation error with Float
if (!denstr.equals("")) // carry the default value over when empty
defaultden = (float)Double.parseDouble(denstr);
if ((num < 0.0) || (defaultden <= 0.0))
break;
textdim = TN.CENTRELINE_MAGNIFICATION * num / defaultden;
text = text.substring(ipercps + 1).trim();
}
catch (NumberFormatException e)
{ break; }
if (ihoriztype == HZT_HORIZONTAL_WIDTH)
{
btextwidthset = true;
textwidth = textdim;
}
else if (ihoriztype == HZT_TOPLINE_WIDTH)
{
btextwidthtopset = true;
textwidthtop = textdim;
}
else if (ihoriztype == HZT_FONTMAGNIFY)
{
bfontmagnifyset = true;
fontmagnify = textdim / TN.CENTRELINE_MAGNIFICATION;
}
else
{
assert ihoriztype == HZT_VERTICAL_WIDTH;
btextheightset = true;
textheight = textdim;
}
}
// then a string of %blackrect% or %whiterect% will make the scalebar pieces rather than write the text
}
////////////////////////////////////////////////////////////////////////////////
void MakeTextRect(float xpos, float ypos)
{
textrect = new Rectangle2D.Float(xpos + xcelloffset, ypos - ycelloffset, textwidth, textheight);
if ((textwidthtop != textwidth) || (xcelloffset != xcelloffsettop))
{
GeneralPath gp = new GeneralPath();
gp.moveTo(xpos + xcelloffsettop, ypos - ycelloffset);
gp.lineTo(xpos + xcelloffsettop + textwidthtop, ypos - ycelloffset);
gp.lineTo(xpos + xcelloffset + textwidth, ypos + textheight - ycelloffset);
gp.lineTo(xpos + xcelloffset, ypos + textheight - ycelloffset);
gp.closePath();
textshape = gp;
}
else
textshape = textrect;
}
};
////////////////////////////////////////////////////////////////////////////////
class PathLabelDecode
{
// if it's a set of symbols
List vlabsymb = new ArrayList();
// the area symbol
int iarea_pres_signal = 0; // combobox lookup
int barea_pres_signal = SketchLineStyle.ASE_KEEPAREA; // 0 normal, 1 dropdown, 2 hole, 3 kill area, 55 sketchframe
// when barea_pres_signal is ASE_SKETCHFRAME, sketchframe
SketchFrameDef sketchframedef = null;
// when barea_pres_signal is ASE_ZSETRELATIVE
float nodeconnzsetrelative = 0.0F;
// the label drawing
String sfontcode = "";
LabelFontAttr labfontattr = null;
Color color = null;
// could set a font everywhere with the change of the style
float fnodeposxrel = -1.0F;
float fnodeposyrel = -1.0F;
boolean barrowpresent = false;
boolean bboxpresent = false;
String drawlab = "";
// values used by a centreline
String centrelinetail = null;
String centrelinehead = null;
String centrelineelev = null;
// linesplitting of the drawlabel (using lazy evaluation)
List vdrawlablns = new ArrayList();
int yilines = 0;
// these could be used for mouse click detection (for dragging of labels)
private String drawlab_bak = "";
private Font font_bak = null;
Font font = null;
private float fnodeposxrel_bak;
private float fnodeposyrel_bak;
private float x_bak;
private float y_bak;
float fmdescent;
float lnspace;
float drawlabxoff;
float drawlabyoff;
float drawlabxwid;
private float drawlabyhei;
/*private */float[] arrc = null; // store of the arrow endpoint coords
Line2D[] arrowdef = null;
Rectangle2D rectdef = null;
/////////////////////////////////////////////
PathLabelDecode()
{
}
/////////////////////////////////////////////
public String toString()
{
assert false;
return "tail=" + (centrelinetail == null ? "" : centrelinetail) + " head=" + (centrelinehead == null ? "" : centrelinehead);
}
/////////////////////////////////////////////
PathLabelDecode(PathLabelDecode o)
{
iarea_pres_signal = o.iarea_pres_signal;
barea_pres_signal = o.barea_pres_signal;
if (barea_pres_signal == SketchLineStyle.ASE_SKETCHFRAME) // iarea_pres_signal is the index into the combobox, b is the code.
sketchframedef = new SketchFrameDef(o.sketchframedef);
nodeconnzsetrelative = o.nodeconnzsetrelative;
vlabsymb.addAll(o.vlabsymb);
drawlab = o.drawlab;
sfontcode = o.sfontcode;
fnodeposxrel = o.fnodeposxrel;
fnodeposyrel = o.fnodeposyrel;
barrowpresent = o.barrowpresent;
bboxpresent = o.bboxpresent;
centrelinehead = o.centrelinehead;
centrelinetail = o.centrelinetail;
centrelineelev = o.centrelineelev;
}
/////////////////////////////////////////////
// reverse of decoding for saving
void WriteXML(LineOutputStream los, int indent) throws IOException
{
WriteXML(los, indent, true);
}
/////////////////////////////////////////////
boolean IsCentrelineType()
{
if (centrelinehead != null)
{
assert ((centrelinetail != null));
assert (centrelineelev == null);
return true;
}
assert (centrelinetail == null);
return false;
}
/////////////////////////////////////////////
void WriteXML(LineOutputStream los, int indent, boolean pathcodes) throws IOException
{
if (pathcodes)
los.WriteLine(TNXML.xcomopen(indent, TNXML.sPATHCODES));
if (IsCentrelineType())
los.WriteLine(TNXML.xcom(indent + 1, TNXML.sCL_STATIONS, TNXML.sCL_TAIL, centrelinetail, TNXML.sCL_HEAD, centrelinehead));
if (centrelineelev != null)
los.WriteLine(TNXML.xcom(indent + 1, TNXML.sCL_STATIONS, TNXML.sCL_ELEV, centrelineelev));
if (drawlab != null)
{
if (barrowpresent || bboxpresent)
los.WriteLine(TNXML.xcomtext(indent + 1, TNXML.sPC_TEXT, TNXML.sLTEXTSTYLE, sfontcode, TNXML.sPC_NODEPOSXREL, String.valueOf(fnodeposxrel), TNXML.sPC_NODEPOSYREL, String.valueOf(fnodeposyrel), TNXML.sPC_ARROWPRES, (barrowpresent ? "1" : "0"), TNXML.sPC_BOXPRES, (bboxpresent ? "1" : "0"), TNXML.xmanglxmltext(drawlab)));
else
los.WriteLine(TNXML.xcomtext(indent + 1, TNXML.sPC_TEXT, TNXML.sLTEXTSTYLE, sfontcode, TNXML.sPC_NODEPOSXREL, String.valueOf(fnodeposxrel), TNXML.sPC_NODEPOSYREL, String.valueOf(fnodeposyrel), TNXML.xmanglxmltext(drawlab)));
}
// the area signal
if (iarea_pres_signal != 0)
{
if (barea_pres_signal == SketchLineStyle.ASE_SKETCHFRAME) // iarea_pres_signal is the index into the combobox, b is the code.
sketchframedef.WriteXML(SketchLineStyle.areasignames[iarea_pres_signal], los, indent + 1);
else if (barea_pres_signal == SketchLineStyle.ASE_ZSETRELATIVE)
los.WriteLine(TNXML.xcom(indent + 1, TNXML.sPC_AREA_SIGNAL, TNXML.sAREA_PRESENT, SketchLineStyle.areasignames[iarea_pres_signal], TNXML.sASIG_NODECONN_ZSETRELATIVE, String.valueOf(nodeconnzsetrelative)));
else
los.WriteLine(TNXML.xcom(indent + 1, TNXML.sPC_AREA_SIGNAL, TNXML.sAREA_PRESENT, SketchLineStyle.areasignames[iarea_pres_signal]));
}
// the symbols
for (String rname : vlabsymb)
los.WriteLine(TNXML.xcom(indent + 1, TNXML.sPC_RSYMBOL, TNXML.sLRSYMBOL_NAME, rname));
if (pathcodes)
los.WriteLine(TNXML.xcomclose(indent, TNXML.sPATHCODES));
}
/////////////////////////////////////////////
// used for accessing the fontmetrics function
static BufferedImage fm_image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
static Graphics fm_g = fm_image.getGraphics();
/////////////////////////////////////////////
static float arrowheadlength = 5.0F;
static float arrowheadwidth = 3.0F;
static float arrowtailstart = 1.5F;
/////////////////////////////////////////////
void UpdateLabel(float x, float y, float xend, float yend)
{
assert ((drawlab != null) && (drawlab.length() != 0));
font = (labfontattr == null ? SketchLineStyle.defaultfontlab : labfontattr.fontlab);
// find what aspects of the text need updating
boolean blabelchanged = !drawlab.equals(drawlab_bak);
boolean bfontchanged = (font_bak != font);
boolean bposchanged = ((fnodeposxrel_bak != fnodeposxrel) || (fnodeposyrel_bak != fnodeposyrel) || (x_bak != x) || (y_bak != y));
// break up the label string
if (blabelchanged)
{
vdrawlablns.clear();
int ps = 0;
float defaultden = -1.0F;
float defaultftextjustify = 0.0F;
for (String sple : drawlab.trim().split("\\n"))
{
sple = sple.replaceAll("\\t", " "); // can't handle tabs properly
PathLabelElement ple = new PathLabelElement(sple, defaultden, defaultftextjustify);
defaultden = ple.defaultden;
defaultftextjustify = ple.ftextjustify;
vdrawlablns.add(ple);
}
drawlab_bak = drawlab;
for (PathLabelElement ple : vdrawlablns)
{
if (ple.bcontinuation && (yilines != 0))
yilines--;
ple.yiline = yilines;
yilines++;
}
}
// we break up the string into lines
FontMetrics fm = (blabelchanged || bfontchanged || bposchanged ? fm_g.getFontMetrics(font) : null);
// for using few functions from the given GraphicsAbstraction which may be overwritten but not fully implemented
if (blabelchanged || bfontchanged)
{
lnspace = fm.getAscent() + 0*fm.getLeading();
drawlabyhei = lnspace * (yilines - 1) + fm.getAscent();
fmdescent = fm.getDescent();
drawlabxwid = 0.0F;
drawlabyhei = 0.0F;
PathLabelElement pleprev = null;
for (PathLabelElement ple : vdrawlablns)
{
if (!ple.btextwidthset)
ple.textwidth = fm.stringWidth(ple.text);
if (!ple.btextwidthtopset)
ple.textwidthtop = ple.textwidth;
if (!ple.btextheightset)
{
ple.textheight = lnspace;
if (ple.bfontmagnifyset)
ple.textheight = lnspace * ple.fontmagnify; // for when we make the font bigger (for titles, etc)
}
if (ple.bcontinuation && (pleprev != null))
{
ple.xcelloffset = pleprev.xcelloffset + pleprev.textwidth;
ple.xcelloffsettop = pleprev.xcelloffsettop + pleprev.textwidthtop;
ple.ycelloffset = pleprev.ycelloffset;
}
else
{
ple.xcelloffset = 0.0F;
ple.xcelloffsettop = 0.0F;
ple.ycelloffset = -drawlabyhei;
drawlabyhei += ple.textheight;
}
drawlabxwid = Math.max(drawlabxwid, ple.xcelloffset + ple.textwidth);
pleprev = ple;
//System.out.println(":" + i + ":" + ple.textwidth + "~" + ple.textheight + " " + ple.text);
}
font_bak = font;
}
if (blabelchanged || bfontchanged || bposchanged)
{
// we find the point for the string
drawlabxoff = -drawlabxwid * (fnodeposxrel + 1) / 2;
drawlabyoff = drawlabyhei * (fnodeposyrel - 1) / 2;
PathLabelElement pleprev = null;
for (PathLabelElement ple : vdrawlablns)
{
ple.MakeTextRect(x + drawlabxoff, y + drawlabyoff);
pleprev = ple;
}
// should be made by merging the textrect rectangles
rectdef = new Rectangle2D.Float(x + drawlabxoff, y + drawlabyoff, drawlabxwid, drawlabyhei);
fnodeposxrel_bak = fnodeposxrel;
fnodeposyrel_bak = fnodeposyrel;
x_bak = x;
y_bak = y;
}
// now relay the positions of the lines
if (barrowpresent && ((arrc == null) || (arrc[0] != x) || (arrc[1] != xend) || (arrc[2] != y) || (arrc[3] != yend)))
{
if (arrc == null)
arrc = new float[4];
arrc[0] = x;
arrc[1] = xend;
arrc[2] = y;
arrc[3] = yend;
if (arrowdef == null)
arrowdef = new Line2D.Float[3];
float xv = xend - x;
float yv = yend - y;
float ln = (float)Math.sqrt(xv * xv + yv * yv);
if (ln <= arrowtailstart)
return;
float xvu = xv / ln;
float yvu = yv / ln;
arrowdef[0] = new Line2D.Float(x + xvu * arrowtailstart, y + yvu * arrowtailstart, xend, yend);
arrowdef[1] = new Line2D.Float(xend - xvu * arrowheadlength + yvu * arrowheadwidth, yend - yvu * arrowheadlength - xvu * arrowheadwidth, xend, yend);
arrowdef[2] = new Line2D.Float(xend - xvu * arrowheadlength - yvu * arrowheadwidth, yend - yvu * arrowheadlength + xvu * arrowheadwidth, xend, yend);
}
}
};
// fancy spread stuff (to be refactored later)
/*
String labspread = TNXML.xrawextracttext(plabel, TNXML.sSPREAD);
if (labspread == null)
{
int ps = plabel.indexOf(TNXML.sLRSYMBOL);
int pe = plabel.indexOf("/>");
// standard label drawing
// (this shall take
and changes)
if ((ps == -1) || (pe == -1))
ga.drawString(plabel, (float)pnstart.pn.getX(), (float)pnstart.pn.getY());
return;
}
, (plabedl.labfontattr == null ? SketchLineStyle.defaultfontlab : plabedl.labfontattr.fontlab)
// implements the spread label drawing.
if ((nlines == 0) || (labspread.length() < 2))
{
ga.drawString(labspread, (float)pnstart.pn.getX(), (float)pnstart.pn.getY());
return;
}
// update the label points only when necessary.
int currlabelcode = (bSplined ? nlines : -nlines);
if ((currlabelcode != prevlabelcode) || (vlabelpoints == null) || (vlabelpoints.size() != labspread.length()))
{
TN.emitMessage("spreading text");
prevlabelcode = currlabelcode;
float[] pco = GetCoords(); // not spline for now.
// measure lengths
float[] lengp = new float[nlines + 1];
lengp[0] = 0.0F;
for (int i = 1; i <= nlines; i++)
{
float xv = pco[i * 2] - pco[i * 2 - 2];
float yv = pco[i * 2 + 1] - pco[i * 2 - 1];
lengp[i] = lengp[i - 1] + (float)Math.sqrt(xv * xv + yv * yv);
}
// make up the labelpoints array.
if (vlabelpoints == null)
vlabelpoints = new ArrayList();
vlabelpoints.setSize(labspread.length()); // appears not to be a function in ArrayList
// find the locations.
int il = 1;
for (int j = 0; j < labspread.length(); j++)
{
float lenb = lengp[nlines] * j / (labspread.length() - 1);
while ((il < nlines) && (lengp[il] < lenb))
il++;
// find the lambda along this line.
float lamden = lengp[il] - lengp[il - 1];
float lam = (lamden != 0.0F ? (lengp[il] - lenb) / lamden : 0.0F);
float tx = lam * pco[il * 2 - 2] + (1.0F - lam) * pco[il * 2];
float ty = lam * pco[il * 2 - 1] + (1.0F - lam) * pco[il * 2 + 1];
if (vlabelpoints.get(j) == null)
vlabelpoints.set(j, new Point2D.Float());
vlabelpoints.get(j).setLocation(tx, ty);
}
}
for (int i = 0; i < labspread.length(); i++)
{
Point2D pt = vlabelpoints.get(i);
ga.drawString(labspread.substring(i, i + 1), (float)pt.getX(), (float)pt.getY());
}
*/
tunnelx-20190701/src/SubsetAttr.java 0000664 0001750 0001750 00000023166 13531571147 016643 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2007 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.awt.BasicStroke;
import java.awt.Font;
import java.awt.Color;
import java.util.Map;
import java.util.HashMap;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.List;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/////////////////////////////////////////////
class SubsetAttr
{
// This is used to run variables available in all the parameters
// so we can change the settings of the colours or all the linestyles and fonts at
// once, if they refer to a variable rather than an absolute setting.
// May in future handle expressions.
Map vvarsettings = new HashMap(); // variable->value
static Color coldefalt = new Color(0);
String subsetname = null;
String uppersubset = null;
SubsetAttr uppersubsetattr = null;
SortedMap subsetsdownmap = new TreeMap();
boolean bViewhidden = false; // tsvpathsviz - would mean it doesn't get into tsvpathsviz
String sareamaskcolour = null;
String sareacolour = null;
Color areamaskcolour = null;
Color areacolour = null;
LineStyleAttr[] linestyleattrs = new LineStyleAttr[LineStyleAttr.Nlinestyles];
LineStyleAttr[] shadowlinestyleattrs = new LineStyleAttr[LineStyleAttr.Nlinestyles];
Map labelfontsmap = new HashMap();
Map subautsymbolsmap = new HashMap();
/////////////////////////////////////////////
SubsetAttr(String lsubsetname)
{
subsetname = lsubsetname;
}
/////////////////////////////////////////////
static List alreadyusedeval = new ArrayList();
String EvalVars(String str)
{
alreadyusedeval.clear();
if (str == null)
return str;
while (str.indexOf('$') != -1)
{
//String Dstr = str;
int naue = alreadyusedeval.size();
Matcher mdvar = Pattern.compile("(\\$\\w+);?").matcher(str);
while (mdvar.find())
{
if (!alreadyusedeval.contains(mdvar.group(1)) && vvarsettings.containsKey(mdvar.group(1)))
alreadyusedeval.add(mdvar.group(1));
}
if (naue == alreadyusedeval.size())
break;
while (naue < alreadyusedeval.size())
{
// escape the leading $
str = str.replaceAll("\\" + alreadyusedeval.get(naue) + ";?", vvarsettings.get(alreadyusedeval.get(naue)));
naue++;
}
//System.out.println("Variable substitution: " + Dstr + " => " + str);
}
// substitute
if (uppersubsetattr != null)
return uppersubsetattr.EvalVars(str);
// need to evaluate equations here, eg "1.5 * 7"
str = str.trim();
//System.out.println(str + " from- " + toString());
//assert str.matches("#[0-9A-Fa-f]{8}|[\\d\\.\\-]*$");
return str;
}
/////////////////////////////////////////////
static Color ConvertColour(String coldef, Color defalt)
{
if (coldef == null)
return defalt;
if (coldef.equalsIgnoreCase("none"))
return null;
if (!coldef.startsWith("#"))
TN.emitError("Colour value should be hex starting with #: " + coldef);
int col = 0;
try
{ col = (int)Long.parseLong(coldef.substring(1), 16); }
catch (NumberFormatException nfe)
{ TN.emitError("Hex number format exception: "+coldef.substring(1)); }
return new Color(col, ((col & 0xff000000) != 0));
}
/////////////////////////////////////////////
// this will in future be string tokenizing on * / ( and ) to evaluate equations
static float ConvertFloat(String fdef, float defalt)
{
if (fdef == null)
return defalt;
fdef = fdef.trim();
assert fdef.matches("[\\d\\.\\-]+$");
return Float.parseFloat(fdef);
}
/////////////////////////////////////////////
// just for consistency
static String ConvertString(String sdef, String defalt)
{
if (sdef == null)
return defalt;
return sdef.trim();
}
/////////////////////////////////////////////
// used for copying over SubsetAttrStyles
SubsetAttr(SubsetAttr lsa)
{
subsetname = lsa.subsetname;
uppersubset = lsa.uppersubset;
sareamaskcolour = lsa.sareamaskcolour;
sareacolour = lsa.sareacolour;
areamaskcolour = lsa.areamaskcolour;
areacolour = lsa.areacolour;
// copy defined fonts
for (LabelFontAttr lfa : lsa.labelfontsmap.values())
labelfontsmap.put(lfa.labelfontname, new LabelFontAttr(lfa, this));
// copy over defined linestyles things
for (int i = 0; i < LineStyleAttr.Nlinestyles; i++)
{
linestyleattrs[i] = (lsa.linestyleattrs[i] != null ? new LineStyleAttr(lsa.linestyleattrs[i]) : null);
shadowlinestyleattrs[i] = (lsa.shadowlinestyleattrs[i] != null ? new LineStyleAttr(lsa.shadowlinestyleattrs[i]) : null);
}
// list of symbols.
for (SymbolStyleAttr ssa : lsa.subautsymbolsmap.values())
subautsymbolsmap.put(ssa.symbolname, new SymbolStyleAttr(ssa));
// list of variables.
vvarsettings.putAll(lsa.vvarsettings);
}
/////////////////////////////////////////////
void SetVariable(String svar, String sval)
{
if (!svar.matches("\\$\\w+$"))
TN.emitError("variables must begin with $ and only contain letters and numbers:" + svar + " -> " + sval);
if (sval.matches(".*\\" + svar + "\\W"))
TN.emitError("variables must not contain self-references:" + svar + " -> " + sval);
if (sval.equals(TNXML.sATTR_VARIABLE_VALUE_CLEAR))
vvarsettings.remove(svar);
else
vvarsettings.put(svar, sval);
}
/////////////////////////////////////////////
void SetLinestyleAttr(int llinestyle, String lsstrokewidth, String lsspikegap, String lsgapleng, String lsspikeheight, String lsstrokecolour, String lsshadowstrokewidth, String lsshadowstrokecolour)
{
if ((llinestyle == SketchLineStyle.SLS_INVISIBLE) || (llinestyle == SketchLineStyle.SLS_CONNECTIVE))
TN.emitWarning("only renderable linestyles please");
linestyleattrs[llinestyle] = new LineStyleAttr(llinestyle, lsstrokewidth, lsspikegap, lsgapleng, lsspikeheight, lsstrokecolour, subsetname);
shadowlinestyleattrs[llinestyle] = new LineStyleAttr(llinestyle, lsshadowstrokewidth, "0", "0", "0", lsshadowstrokecolour, subsetname);
}
/////////////////////////////////////////////
static Color defaltareamaskcolour = new Color(1.0F, 1.0F, 1.0F, 0.55F);
static Color defaltareacolour = new Color(0.8F, 0.9F, 0.9F, 0.4F);
void FillMissingAttribs() // this function is called recursing down the tree in order
{
//System.out.println("FillMissingAttribsFillMissingAttribs " + subsetname);
// pull unset defaults down from the upper case
if ((sareamaskcolour == null) && (uppersubsetattr != null))
sareamaskcolour = uppersubsetattr.sareamaskcolour;
if ((sareacolour == null) && (uppersubsetattr != null))
sareacolour = uppersubsetattr.sareacolour;
areamaskcolour = SubsetAttr.ConvertColour(EvalVars(sareamaskcolour), defaltareamaskcolour);
areacolour = SubsetAttr.ConvertColour(EvalVars(sareacolour), defaltareacolour);
if (uppersubsetattr != null)
{
for (LabelFontAttr llfa : uppersubsetattr.labelfontsmap.values())
{
if (!labelfontsmap.containsKey(llfa.labelfontname))
labelfontsmap.put(llfa.labelfontname, new LabelFontAttr(llfa, this));
}
}
// fill in the missing font attributes in each case
for (LabelFontAttr lfa : labelfontsmap.values())
lfa.FillMissingAttribsLFA(uppersubsetattr != null ? uppersubsetattr.labelfontsmap.get(lfa.labelfontname) : null);
// fill in the missing symbol attributes
for (SymbolStyleAttr ssa : subautsymbolsmap.values())
ssa.FillMissingAttribsSSA(uppersubsetattr != null ? uppersubsetattr.subautsymbolsmap.get(ssa.symbolname) : null);
// copy in any symbols that aren't there already
if (uppersubsetattr != null)
{
for (SymbolStyleAttr ussa : uppersubsetattr.subautsymbolsmap.values())
{
if (!subautsymbolsmap.containsKey(ussa.symbolname))
subautsymbolsmap.put(ussa.symbolname, ussa);
}
for (LabelFontAttr ulfa : uppersubsetattr.labelfontsmap.values())
{
if (!labelfontsmap.containsKey(ulfa.labelfontname))
labelfontsmap.put(ulfa.labelfontname, ulfa);
}
}
// copy over defined linestyles things and fill in gaps
for (int i = 0; i < LineStyleAttr.Nlinestyles; i++)
{
if ((i == SketchLineStyle.SLS_INVISIBLE) || (i == SketchLineStyle.SLS_CONNECTIVE))
continue;
if (linestyleattrs[i] == null)
linestyleattrs[i] = (uppersubsetattr != null ? new LineStyleAttr(uppersubsetattr.linestyleattrs[i]) : new LineStyleAttr(i));
if (shadowlinestyleattrs[i] == null)
shadowlinestyleattrs[i] = (uppersubsetattr != null ? new LineStyleAttr(uppersubsetattr.shadowlinestyleattrs[i]) : new LineStyleAttr(i));
linestyleattrs[i].Construct(this, Color.black);
shadowlinestyleattrs[i].Construct(this, null);
}
}
/////////////////////////////////////////////
public String toString()
{
return (bViewhidden ? ("[X] " + subsetname) : subsetname);
}
};
tunnelx-20190701/src/OneSArea.java 0000664 0001750 0001750 00000046565 13531571147 016210 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.awt.geom.Line2D;
import java.awt.geom.Area;
import java.awt.geom.Point2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.AffineTransform;
import java.io.IOException;
import java.awt.BasicStroke;
import java.awt.image.BufferedImage;
import java.awt.Color;
import java.awt.TexturePaint;
import java.awt.Rectangle;
import java.util.List;
import java.util.ArrayList;
//
//
// OneSArea
//
//
/////////////////////////////////////////////
class OneSArea implements Comparable
{
// defines the area.
GeneralPath gparea = null; // if null then nothing should be done with it.
DelTriangulation Dgptriangulation = null; // experimental
Area aarea = null;
Rectangle2D rboundsarea = null;
float zalt = 0.0F;
float icollam = 0.0F;
boolean bareavisiblesubset = false;
List vssubsetattrs = new ArrayList(); // SubsetAttr (in parallel) from the current style
SubsetAttr subsetattr = null; // one chosen from the vector above
// array of RefPathO.
List refpaths = new ArrayList();
List refpathsub = new ArrayList(); // subselection without the trees.
List connpathrootscen = new ArrayList(); // used to free up pointer to an area, and for centrelines when they are drawn on top of areas
int nconnpathremaining; // the index into connpathrootscen where AttachRemainingCentrelines was called, so we know what not to add as associations in the select areas
// ConnectiveComponentAreas this area is in
List ccalist = new ArrayList();
// these are used to mark the areas for inclusion in sketchsymbolareas. more efficient than setting false it as a booleans.
// int iamark = 0;
// static int iamarkl = 1;
int distinctoaid; // used for the comparator as this is in a hashset
static int Sdistinctoaid = 1;
// used in the quality rendering for signaling which edges can be drawn once areas on both sides have been done.
boolean bHasrendered = false;
// maximized around the contour for right precedence
// ASE_ type
int iareapressig = SketchLineStyle.ASE_KEEPAREA; // 0-1 normal, 3 column(rock), 2 pitchhole
List opsketchframedefs = null; // when iareapressig is SketchLineStyle.ASE_SKETCHFRAME, and we have a framed sketch. This object specifies the transformations
// used for refering to the area in SVG files
String svgid = null;
GeneralPath gpzslicedarea = null;
/////////////////////////////////////////////
void paintHatchW(GraphicsAbstraction ga, int isa)
{
if (gparea != null)
ga.drawHatchedArea(this, isa);
}
/////////////////////////////////////////////
// we're going to use this to help sort vareas. the zalt values better not change throughout the age of this object
public int compareTo(OneSArea osa)
{
if (zalt != osa.zalt)
return (zalt - osa.zalt < 0.0F ? -1 : 1);
return distinctoaid - osa.distinctoaid; // was: return hashCode() - osa.hashCode(), which caused errors when two distinct areas had the same hashcode and the second didn't make it into vsareas
}
/////////////////////////////////////////////
// find which subsets this area is in, by looking at the surrounding edges
// this is different to the isubsetcode thing; something between these two is redundant
// not used.
void DecideSubsets(List lvssubsets)
{
assert lvssubsets.isEmpty();
for (RefPathO rpo : refpathsub)
{
// find the intersection between these sets (using string equalities)
List pvssub = rpo.op.vssubsets;
if (!lvssubsets.isEmpty())
{
for (int j = lvssubsets.size() - 1; j >= 0; j--)
{
if (!pvssub.contains(lvssubsets.get(j)))
lvssubsets.remove(j);
}
if (lvssubsets.isEmpty())
break;
}
else
lvssubsets.addAll(pvssub);
}
}
/////////////////////////////////////////////
int SetSubsetAttrsA(boolean bremakesubset, SubsetAttrStyle sas)
{
if (bremakesubset)
{
vssubsetattrs.clear();
int i = 0;
for (RefPathO rpo : refpathsub)
{
// find the intersection between these sets (using string equalities)
List pvssub = rpo.op.vssubsetattrs;
if (i != 0)
{
for (int j = vssubsetattrs.size() - 1; j >= 0; j--)
{
if (!pvssub.contains(vssubsetattrs.get(j)))
vssubsetattrs.remove(j);
}
}
else
vssubsetattrs.addAll(pvssub);
i++;
}
// no overlapping values, find default
if (!vssubsetattrs.isEmpty())
subsetattr = vssubsetattrs.get(vssubsetattrs.size() - 1); // gets last one (could choose the highest priority one -- eg one that forces to hide)
else
subsetattr = sas.sadefault;
assert subsetattr != null;
}
// set the visibility flag
bareavisiblesubset = true;
for (RefPathO rpo : refpaths)
{
if (!rpo.op.bpathvisiblesubset)
bareavisiblesubset = false;
}
return (bareavisiblesubset ? 1 : 0);
}
/////////////////////////////////////////////
// this function should be a generic one on general paths
/////////////////////////////////////////////
// it looks tempting to do this on the refpaths, but since that list is
// equivalent to the general path, it might as well be keopt simple and not piecewise
static float[] CText = new float[4];
static float[] CTdir = new float[4];
/////////////////////////////////////////////
static void CommitTriplet(float xp, float yp, float x, float y, float xn, float yn, boolean bFirst)
{
boolean bleft = (bFirst || (x <= CText[0]));
boolean bup = (bFirst || (y >= CText[1]));
boolean bright = (bFirst || (x >= CText[2]));
boolean bdown = (bFirst || (y <= CText[3]));
if (bleft || bup || bright || bdown)
{
float vpx = xp - x;
float vpy = yp - y;
float vnx = xn - x;
float vny = yn - y;
float vextd = vpx * vny - vpy * vnx;
float vdot = vpx * vnx + vpy * vpy;
if (bleft)
{
CText[0] = x;
CTdir[0] = vextd;
}
if (bup)
{
CText[1] = y;
CTdir[1] = vextd;
}
if (bright)
{
CText[2] = x;
CTdir[2] = vextd;
}
if (bdown)
{
CText[3] = y;
CTdir[3] = vextd;
}
}
}
/////////////////////////////////////////////
static float[] Fcoords = new float[6];
static float FxL1, FyL1;
static float FxP2, FyP2;
static float FxP1, FyP1;
static float FxP0, FyP0;
/////////////////////////////////////////////
static int FindOrientationReliable(GeneralPath gp)
{
PathIterator pi = gp.getPathIterator(null);
int np = -1;
while (true)
{
int curvtype = pi.currentSegment(Fcoords);
if (curvtype == PathIterator.SEG_CLOSE)
break;
np++;
assert (np != 0) || (curvtype == PathIterator.SEG_MOVETO);
FxP2 = FxP1; FyP2 = FyP1;
FxP1 = FxP0; FyP1 = FyP0;
if (curvtype == PathIterator.SEG_CUBICTO)
{
FxP0 = Fcoords[4];
FyP0 = Fcoords[5];
}
else
{
FxP0 = Fcoords[0];
FyP0 = Fcoords[1];
}
if (np == 1)
{
FxL1 = FxP0;
FyL1 = FyP0;
}
if (np >= 2)
CommitTriplet(FxP2, FyP2, FxP1, FyP1, FxP0, FyP0, (np == 2));
pi.next();
}
//assert (Fcoords[0] == FcoordsL0[0]) && (Fcoords[1] == FcoordsL0[1]);
CommitTriplet(FxP1, FyP1, FxP0, FyP0, FxL1, FyL1, false);
if (np <= 2)
return 0;
boolean bpos = ((CTdir[0] >= 0.0) && (CTdir[1] >= 0.0) && (CTdir[2] >= 0.0) && (CTdir[3] >= 0.0));
boolean bneg = ((CTdir[0] <= 0.0) && (CTdir[1] <= 0.0) && (CTdir[2] <= 0.0) && (CTdir[3] <= 0.0));
if (bpos != bneg)
return (bpos ? 1 : -1);
return 0;
}
/////////////////////////////////////////////
void Setkapointers()
{
// we should perform the hard task of reflecting certain paths in situ.
for (RefPathO refpath : refpaths)
{
// get the ref path.
if (refpath.bFore)
{
assert refpath.op.karight == null;
refpath.op.karight = this;
}
else
{
assert refpath.op.kaleft == null;
refpath.op.kaleft = this;
}
}
}
/////////////////////////////////////////////
void SetkapointersClear()
{
// we should perform the hard task of reflecting certain paths in situ.
for (RefPathO refpath : refpaths)
{
// get the ref path.
if (refpath.bFore)
{
assert refpath.op.karight == this;
refpath.op.karight = null;
}
else
{
assert refpath.op.kaleft == this;
refpath.op.kaleft = null;
}
}
for (OnePath op : connpathrootscen)
{
// this assertion can fail if we've changed a line type from centreline to wall. In these cases we should delete and add in instead as it changes the structure of the drawing
assert (op.linestyle == SketchLineStyle.SLS_CONNECTIVE) || ((op.linestyle == SketchLineStyle.SLS_CENTRELINE) && (op.kaleft == this) && (op.karight == this));
if (op.kaleft == this)
op.kaleft = null;
if (op.karight == this)
op.karight = null;
}
for (ConnectiveComponentAreas cca : ccalist)
{
assert cca.vconnareas.contains(this);
cca.vconnareas.remove(this);
for (OnePath cop : cca.vconnpaths)
{
assert (cop.kaleft != this);
assert (cop.karight != this);
}
}
}
/////////////////////////////////////////////
/* void LinkZslicedArea()
{
// go round and append paths on these just like that.
// then plot with the trimmed areas and so on.
// simplify the trimmed area plotting
// also decide whether the OnePathNode is within the selection
gpzslicedarea = null;
new GeneralPath(GeneralPath.WIND_EVEN_ODD);
// use the gpzsliced paths done by the MakeTilted area
void MakeTilted(double zlo, double zhi, double scaTiltZ, AffineTransform currtrans)
// we should perform the hard task of reflecting certain paths in situ.
boolean bfirst = true;
for (RefPathO refpath : refpathsub)
{
// if going forwards, then everything works
if (refpath.bFore)
{
gparea.append(refpath.op.gp, !bfirst); // the second parameter is continuation, and avoids repeats at the moveto
bfirst = false;
continue;
}
// specially decode it if reversed
if ((pco == null) || (pco.length < refpath.op.nlines * 6 + 2));
pco = new float[refpath.op.nlines * 6 + 2];
// this gives an array that is interspersed with the control points
refpath.op.ToCoordsCubic(pco);
// now put in the reverse coords.
if (bfirst)
{
gparea.moveTo(pco[refpath.op.nlines * 6], pco[refpath.op.nlines * 6 + 1]);
bfirst = false;
}
for (int i = refpath.op.nlines - 1; i >= 0; i--)
{
int i6 = i * 6;
if ((pco[i6 + 2] == pco[i6]) && (pco[i6 + 3] == pco[i6 + 1])) // and the next point too.
gparea.lineTo(pco[i6], pco[i6 + 1]);
else
gparea.curveTo(pco[i6 + 4], pco[i6 + 5], pco[i6 + 2], pco[i6 + 3], pco[i6], pco[i6 + 1]);
}
}
gparea.closePath();
}
*/
/////////////////////////////////////////////
static float[] pco = null;
// this makes a mess out of reversing a general path
void LinkArea()
{
assert gparea == null;
gparea = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
// we should perform the hard task of reflecting certain paths in situ.
boolean bfirst = true;
for (RefPathO refpath : refpathsub)
{
// if going forwards, then everything works
if (refpath.bFore)
{
gparea.append(refpath.op.gp, !bfirst); // the second parameter is continuation, and avoids repeats at the moveto
bfirst = false;
continue;
}
// specially decode it if reversed
if ((pco == null) || (pco.length < refpath.op.nlines * 6 + 2));
pco = new float[refpath.op.nlines * 6 + 2];
// this gives an array that is interspersed with the control points
refpath.op.ToCoordsCubic(pco);
// now put in the reverse coords.
if (bfirst)
{
gparea.moveTo(pco[refpath.op.nlines * 6], pco[refpath.op.nlines * 6 + 1]);
bfirst = false;
}
for (int i = refpath.op.nlines - 1; i >= 0; i--)
{
int i6 = i * 6;
if ((pco[i6 + 2] == pco[i6]) && (pco[i6 + 3] == pco[i6 + 1])) // and the next point too.
gparea.lineTo(pco[i6], pco[i6 + 1]);
else
gparea.curveTo(pco[i6 + 4], pco[i6 + 5], pco[i6 + 2], pco[i6 + 3], pco[i6], pco[i6 + 1]);
}
}
gparea.closePath();
}
/////////////////////////////////////////////
void SetCentrelineThisArea(OnePath op, boolean bremaining)
{
assert op.linestyle == SketchLineStyle.SLS_CENTRELINE;
assert op.karight == op.kaleft;
if (op.karight != null)
{
if (compareTo(op.karight) <= 0)
{
assert zalt <= op.karight.zalt;
return;
}
assert zalt >= op.karight.zalt;
boolean bD = op.karight.connpathrootscen.remove(op);
assert bD;
}
op.karight = this;
op.kaleft = this;
connpathrootscen.add(op);
assert !bremaining || (connpathrootscen.size() > nconnpathremaining);
}
/////////////////////////////////////////////
void MarkCentrelineRoot(OnePath op, boolean bFore)
{
OnePathNode opn = (bFore ? op.pnstart : op.pnend);
assert opn.IsCentrelineNode();
// track round the centreline node
OnePath opC = op;
boolean bForeC = bFore;
do
{
if (!bForeC)
{
bForeC = !opC.bapfrfore;
opC = opC.apforeright;
}
else
{
bForeC = !opC.baptlfore;
opC = opC.aptailleft;
}
assert opn == (bForeC ? opC.pnstart : opC.pnend);
if (opC.linestyle == SketchLineStyle.SLS_CENTRELINE)
SetCentrelineThisArea(opC, false);
}
while (!((opC == op) && (bForeC == bFore))); // end of do loop
}
/////////////////////////////////////////////
// construction from wherever
OneSArea(OnePath lop, boolean lbFore) // edge scans to the right
{
// loop round to the start.
OnePath op = lop;
boolean bFore = lbFore;
assert lop.AreaBoundingType();
iareapressig = SketchLineStyle.ASE_KEEPAREA; // reset in the loop if anything found
opsketchframedefs = null;
zalt = 0.0F; // default
distinctoaid = Sdistinctoaid++;
do
{
// gone wrong.
if (op == null)
break;
refpaths.add(new RefPathO(op, bFore));
// jumps to the next segment on the next node
OnePathNode opnN = (bFore ? op.pnend : op.pnstart);
if (bFore)
{
bFore = !op.bapfrfore;
op = op.apforeright;
}
else
{
bFore = !op.baptlfore;
op = op.aptailleft;
}
assert opnN == (bFore ? op.pnstart : op.pnend);
// go round that segment until we find an area bounding type
while (!op.AreaBoundingType())
{
// look for any area killing symbols
if ((op.linestyle == SketchLineStyle.SLS_CONNECTIVE) && (op.plabedl != null))
{
if ((op.plabedl.barea_pres_signal != SketchLineStyle.ASE_HCOINCIDE) && (op.plabedl.barea_pres_signal != SketchLineStyle.ASE_ZSETRELATIVE) && (op.plabedl.barea_pres_signal != SketchLineStyle.ASE_ELEVATIONPATH))
iareapressig = Math.max(iareapressig, op.plabedl.barea_pres_signal);
if (op.IsSketchFrameConnective())
{
if (opsketchframedefs == null)
opsketchframedefs = new ArrayList();
opsketchframedefs.add(op);
}
}
// mark the connective types anyway, as a root-start.
if (op.linestyle == SketchLineStyle.SLS_CONNECTIVE)
{
if (!bFore)
op.karight = this;
else
op.kaleft = this;
connpathrootscen.add(op);
}
if (op.linestyle == SketchLineStyle.SLS_CENTRELINE)
SetCentrelineThisArea(op, false);
if (!bFore)
{
bFore = !op.bapfrfore;
op = op.apforeright;
}
else
{
bFore = !op.baptlfore;
op = op.aptailleft;
}
assert opnN == (bFore ? op.pnstart : op.pnend);
} // endwhile (!op.AreaBoundingType())
}
while (!((op == lop) && (bFore == lbFore))); // end of do loop
// set the pointers from paths to this area
Setkapointers();
if (op == null)
{
assert false;
return;
}
// now make the refpathsub by copying over and removing duplicates (as we track down the back side of a tree).
for (int i = 0; i < refpaths.size(); i++)
{
OnePath opsi = refpaths.get(i).op;
OnePath opsl = (refpathsub.isEmpty() ? null : refpathsub.get(refpathsub.size() - 1).op);
if (opsi != opsl)
refpathsub.add(refpaths.get(i));
else
refpathsub.remove(refpathsub.size() - 1);
}
// tree duplicates between the beginning and the end
while ((refpathsub.size() >= 2) && (refpathsub.get(0).op == refpathsub.get(refpathsub.size() - 1).op))
{
refpathsub.remove(refpathsub.size() - 1);
refpathsub.remove(0);
}
// this builds the general path which defines the area
// set up the area if something is empty.
if (refpathsub.isEmpty())
{
iareapressig = SketchLineStyle.ASE_KILLAREA; // don't render (outer tree?)
return; // it turned out to be just a tree
}
// now we construct the general path from the list of untreed areas
LinkArea();
try
{
aarea = new Area(gparea);
}
catch (java.lang.InternalError e) // this is to see a very rare failure in the area generating algorithm
{
TN.emitWarning("Library Error creating Area from boundary");
System.out.println(e.toString());
//System.out.println("Number of nodes " + gparea.);
System.out.println("bounding box " + gparea.getBounds2D());
aarea = null;
}
//if (refpathsub.size() != refpaths.size())
// TN.emitMessage("pathedges " + refpathsub.size() + " over total path edges " + refpaths.size());
rboundsarea = gparea.getBounds();
// set the zaltitude by finding the average height
// (altitude must have been set from the linking already)
float szalt = 0.0F;
for (RefPathO rpo : refpathsub)
szalt += rpo.ToNode().zalt;
if (refpathsub.size() != 0)
zalt = szalt / refpathsub.size();
for (int i = connpathrootscen.size() - 1; i >= 0; i--)
{
OnePath llop = connpathrootscen.get(i);
if (llop.pnstart.IsCentrelineNode())
MarkCentrelineRoot(llop, true);
else if (llop.pnend.IsCentrelineNode())
MarkCentrelineRoot(llop, false);
}
nconnpathremaining = connpathrootscen.size();
}
//////////////////////////////////////////
float GetAvgLocIcollam(double x, double y)
{
double tot = 0.0;
double wtot = 0.0;
for (RefPathO rpo : refpathsub)
{
OnePathNode opn = rpo.ToNode();
double xd = opn.pn.getX() - x;
double yd = opn.pn.getY() - y;
double radsq = xd * xd + yd * yd;
if (radsq == 0.0)
return opn.icollam;
double w = 1 / radsq;
tot += w;
wtot += opn.icollam * w;
}
return (float)(tot != 0.0 ? wtot / tot : 1.0);
}
//////////////////////////////////////////
void setId(String id)
{
this.svgid = id;
}
//////////////////////////////////////////
String getId()
{
return this.svgid;
}
}
tunnelx-20190701/src/SketchSymbolAreas.java 0000664 0001750 0001750 00000035337 13531571147 020131 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.awt.geom.GeneralPath;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.Rectangle;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.JProgressBar;
/////////////////////////////////////////////
// to have this being automatically updating, we'd need to be able to kill off areas
// as soon as something changed to a connective line associated with it.
class SketchSymbolAreas
{
// there will be another thread working through this, and more than just these lists
List vconncom = new ArrayList();
// these are overlapping groups of componentareas that need to have their symbols laid out all at once
List vconncommutual = new ArrayList();
/////////////////////////////////////////////
// make list of areas, and the joined area.
// get connective paths to connect to this object
/////////////////////////////////////////////
static ConnectiveComponentAreas ccaplaceholder = new ConnectiveComponentAreas(false);
static void GetConnCompPath(List lvconnpaths, OnePath op)
{
// spread through this connected component completely
// We used to spread within the sector at each node we meet,
// but now we only spread round nodes that only have connective pieces on them.
assert op.linestyle == SketchLineStyle.SLS_CONNECTIVE;
assert op.pthcca == null;
assert lvconnpaths.isEmpty();
List lconnpathsrpstack = new ArrayList();
lconnpathsrpstack.add(new RefPathO(op, false)); // going both directions
lconnpathsrpstack.add(new RefPathO(op, true));
lvconnpaths.add(op);
RefPathO rpocopy = new RefPathO();
op.pthcca = SketchSymbolAreas.ccaplaceholder;
while (!lconnpathsrpstack.isEmpty())
{
// scan round and check if this is a fully connective type node
RefPathO rpolast = lconnpathsrpstack.remove(lconnpathsrpstack.size() - 1);
rpocopy.ccopy(rpolast);
do
{
if ((rpocopy.op.linestyle != SketchLineStyle.SLS_CONNECTIVE) && (rpocopy.op.linestyle != SketchLineStyle.SLS_CENTRELINE))
break;
}
while (!rpocopy.AdvanceRoundToNode(rpolast));
if (!rpocopy.cequals(rpolast))
continue;
// all connective; advance round again and add all these connective edges
do
{
if (rpocopy.op.IsDropdownConnective())
;
else if (rpocopy.op.linestyle == SketchLineStyle.SLS_CENTRELINE)
;
else if (rpocopy.op.pthcca == null)
{
assert !lvconnpaths.contains(rpocopy.op);
rpocopy.op.pthcca = SketchSymbolAreas.ccaplaceholder;
lconnpathsrpstack.add(new RefPathO(rpocopy.op, !rpocopy.bFore));
lvconnpaths.add(rpocopy.op);
}
// if we can connect to it, it should be in this list already
else
{
assert rpocopy.op.pthcca == SketchSymbolAreas.ccaplaceholder;
assert lvconnpaths.contains(rpocopy.op);
}
}
while (!rpocopy.AdvanceRoundToNode(rpolast));
}
assert op.pthcca == SketchSymbolAreas.ccaplaceholder;
}
/////////////////////////////////////////////
static void GetConnComp(List lvconnpaths, SortedSet lvconnareas, OnePath op, SortedSet Dvsareas)
{
assert op.linestyle == SketchLineStyle.SLS_CONNECTIVE;
assert op.pthcca == null;
assert lvconnpaths.isEmpty() && lvconnareas.isEmpty();
GetConnCompPath(lvconnpaths, op);
// now we have all the components, we make the set of areas for this component.
for (OnePath sop : lvconnpaths)
{
assert sop.pthcca == SketchSymbolAreas.ccaplaceholder; // was an assignment
if ((sop.kaleft != null) && !lvconnareas.contains(sop.kaleft)) // usually such a small set, this should work
{
//assert Dvsareas.contains(sop.kaleft); // these shouldn't matter as it's just a connective
lvconnareas.add(sop.kaleft);
}
// (both sides should be the same, so this should be unnecessary)
if ((sop.karight != null) && !lvconnareas.contains(sop.karight))
{
//assert Dvsareas.contains(sop.karight);
lvconnareas.add(sop.karight);
}
}
for (OneSArea Dosa : lvconnareas)
assert Dvsareas.contains(Dosa); // check
}
/////////////////////////////////////////////
void MakeConnectiveComponents(List vpaths, SortedSet Dvsareas)
{
List lvconnpaths = new ArrayList();
List lvconnpathsrem = new ArrayList();
SortedSet lvconnareas = new TreeSet();
for (OnePath op : vpaths)
{
assert op.pthcca != SketchSymbolAreas.ccaplaceholder;
if (op.linestyle != SketchLineStyle.SLS_CONNECTIVE)
continue;
if (op.pthcca != null)
continue;
if (op.IsDropdownConnective())
continue;
if (op.vpsymbols.isEmpty())
continue;
// vpsymbols is actual symbols from fontcolours; plabedl.vlabsymb would be about symbols requested
// if (!((op.linestyle == SketchLineStyle.SLS_CONNECTIVE) && (op.pthcca == null) && !op.IsDropdownConnective() && !op.vpsymbols.isEmpty()))
// continue;
GetConnComp(lvconnpaths, lvconnareas, op, Dvsareas);
/*for (OnePath Dop : lvconnpaths)
assert vpaths.contains(Dop); // check
for (OneSArea Dosa : lvconnareas)
assert Dvsareas.contains(Dosa); // check
*/
// remove connected paths that don't have any symbols on them
for (int j = lvconnpaths.size() - 1; j >= 0; j--)
{
OnePath opj = lvconnpaths.get(j);
if (opj.vpsymbols.isEmpty())
{
assert opj.pthcca == SketchSymbolAreas.ccaplaceholder;
opj.pthcca = null;
OnePath lop = lvconnpaths.remove(lvconnpaths.size() - 1); // copy last element into deleted element slot
if (j != lvconnpaths.size())
lvconnpaths.set(j, lop);
lvconnpathsrem.add(opj);
}
}
// find or make component with this set of areas
ConnectiveComponentAreas mcca = null;
for (ConnectiveComponentAreas lmcca : vconncom)
{
if ((lmcca.vconnareas.size() == lvconnareas.size()) && lmcca.vconnareas.containsAll(lvconnareas))
{
mcca = lmcca;
break;
}
}
if (mcca == null)
{
mcca = new ConnectiveComponentAreas(lvconnpaths, lvconnpathsrem, lvconnareas);
vconncom.add(mcca);
}
else
{
mcca.vconnpaths.addAll(lvconnpaths);
mcca.vconnpathsrem.addAll(lvconnpathsrem);
}
// copy in all the pthcca values
for (OnePath sop : lvconnpaths)
{
assert sop.pthcca == SketchSymbolAreas.ccaplaceholder;
sop.pthcca = mcca;
}
lvconnpaths.clear();
lvconnpathsrem.clear();
lvconnareas.clear();
}
}
/////////////////////////////////////////////
void CollectMutuallyOverlappingComponents()
{
assert vconncommutual.isEmpty();
List ccastack = new ArrayList();
int Dconmtotal = 0;
int Damtotal = 0;
for (ConnectiveComponentAreas cca : vconncom)
{
if (cca.pvconncommutual != null)
continue;
assert ccastack.isEmpty();
ccastack.add(cca);
MutualComponentArea conncommutual = new MutualComponentArea();
while (!ccastack.isEmpty())
{
ConnectiveComponentAreas scca = ccastack.remove(ccastack.size() - 1);
if (scca.pvconncommutual == null)
{
conncommutual.MergeIn(scca);
for (ConnectiveComponentAreas occa : scca.overlapcomp)
{
if (occa.pvconncommutual == null)
ccastack.add(occa);
else
assert (occa.pvconncommutual == conncommutual);
}
}
else
assert (scca.pvconncommutual == conncommutual);
}
Dconmtotal += conncommutual.ccamutual.size();
Damtotal += conncommutual.osamutual.size(); // won't exceed number of areas since each is in one mutual only.
vconncommutual.add(conncommutual);
}
assert Dconmtotal == vconncom.size();
}
/////////////////////////////////////////////
void CollectOverlappingComponents()
{
// find overlapping components
for (int i = 0; i < vconncom.size(); i++) // had used iterators, but they're not copyable
{
ConnectiveComponentAreas cca = vconncom.get(i);
cca.overlapcomp.add(cca); // always overlaps with self
for (int j = i + 1; j < vconncom.size(); j++)
{
ConnectiveComponentAreas cca1 = vconncom.get(j);
if (cca.Overlaps(cca1))
{
cca.overlapcomp.add(cca1);
cca1.overlapcomp.add(cca);
}
}
}
}
/////////////////////////////////////////////
// (re)make all the connected symbol areas
void MakeSSA(List vpaths, SortedSet vsareas)
{
// reset everything
for (OnePath op : vpaths)
op.pthcca = null;
for (OneSArea osa : vsareas)
osa.ccalist.clear();
vconncom.clear();
vconncommutual.clear();
MakeConnectiveComponents(vpaths, vsareas);
CollectOverlappingComponents();
CollectMutuallyOverlappingComponents();
TN.emitMessage("connective compnents: " + vconncom.size() + " mutuals: " + vconncommutual.size());
//for (ConnectiveComponentAreas cca : vconncom)
// TN.emitMessage("compnents overlap: " + cca.overlapcomp.size());
}
}
/////////////////////////////////////////////
/////////////////////////////////////////////
class SymbolLayoutProcess
{
MainBox mainbox;
static int TNnumberofthreads = 4;
Thread[] slpthreads = null;
MutualComponentAreaScratch[] mcascratches = null; // defer build
JProgressBar visiprogressbar;
List lvconncommutual;
int ivconncommutual;
int nactivethreads = 0; // used to tell when we are finishing the final thread
boolean bcalculating = false;
/////////////////////////////////////////////
SymbolLayoutProcess(MainBox lmainbox)
{
mainbox = lmainbox;
}
/////////////////////////////////////////////
class MakeSymbLayoutThread implements Runnable
{
MutualComponentAreaScratch mcascratch;
/////////////////////////////////////////////
MakeSymbLayoutThread(MutualComponentAreaScratch lmcascratch)
{
mcascratch = lmcascratch;
}
/////////////////////////////////////////////
// might have two threads going simultaneously
public void run()
{
while (true)
{
int i = NextMCA();
if (i < 0)
{
if (i == -2)
CleaningUpAfterCalculation();
break;
}
lvconncommutual.get(i).LayoutMutualSymbols(mcascratch); // all symbols in this batch (sets isymbolstolayout to 2)
}
}
}
/////////////////////////////////////////////
synchronized boolean SetupForCalculation()
{
if (bcalculating)
{
TN.emitWarning("Still calculating symbol layout -- forcing off");
bcalculating = false; // to force it
return false;
}
bcalculating = true;
return true;
}
/////////////////////////////////////////////
void CleaningUpAfterCalculation()
{
if (visiprogressbar != null)
{
visiprogressbar.setValue(0);
visiprogressbar.setStringPainted(false);
mainbox.sketchdisplay.selectedsubsetstruct.SetSubsetVisibleCodeStringsT(mainbox.sketchdisplay.selectedsubsetstruct.elevset.selevsubset, mainbox.sketchdisplay.sketchgraphicspanel.tsketch);
if (lvconncommutual.size() == mainbox.sketchdisplay.sketchgraphicspanel.tsketch.sksya.vconncommutual.size())
mainbox.sketchdisplay.sketchgraphicspanel.SketchChanged(mainbox.sketchdisplay.sketchgraphicspanel.SC_UPDATE_SYMBOLS);
mainbox.sketchdisplay.sketchgraphicspanel.RedoBackgroundView();
}
bcalculating = false;
}
/////////////////////////////////////////////
synchronized int NextMCA()
{
if (ivconncommutual < lvconncommutual.size())
{
if (visiprogressbar != null)
{
visiprogressbar.setValue((ivconncommutual * 100) / lvconncommutual.size());
visiprogressbar.repaint();
if (((ivconncommutual + 10) % 20) == 0)
mainbox.sketchdisplay.sketchgraphicspanel.RedoBackgroundView();
}
return ivconncommutual++;
}
nactivethreads--;
if (nactivethreads == 0)
return -2;
return -1;
}
/////////////////////////////////////////////
void UpdateSymbolLayout(List llvconncommutual, JProgressBar lvisiprogressbar)
{
if (!SetupForCalculation())
return;
lvconncommutual = llvconncommutual;
visiprogressbar = lvisiprogressbar;
// deferred setup
if (slpthreads == null)
slpthreads = new Thread[TNnumberofthreads];
if (mcascratches == null)
{
mcascratches = new MutualComponentAreaScratch[TNnumberofthreads];
for (int i = 0; i < TNnumberofthreads; i++)
mcascratches[i] = new MutualComponentAreaScratch();
}
visiprogressbar = lvisiprogressbar;
llvconncommutual = lvconncommutual;
ivconncommutual = 0;
// make the threads
for (int i = 0; i < TNnumberofthreads; i++)
slpthreads[i] = new Thread(new MakeSymbLayoutThread(mcascratches[i]));
nactivethreads = TNnumberofthreads;
for (int i = 0; i < TNnumberofthreads; i++)
slpthreads[i].start();
// wait till all complete if not based on progress bar (ie not triggered by UI)
if (lvisiprogressbar == null)
{
try
{
for (int i = 0; i < TNnumberofthreads; i++)
slpthreads[i].join();
}
catch (InterruptedException e)
{
System.out.print(e);
}
}
}
};
tunnelx-20190701/src/OneStation.java 0000664 0001750 0001750 00000005773 13531571147 016632 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.awt.Graphics;
import java.util.List;
import java.util.ArrayList;
//
//
// OneStation
//
//
class OneStation
{
// unique identifier
public String name;
// location and flag used to set the location
Vec3 Loc = null;
Vec3 tLoc = new Vec3();
// transformed for viewing points
public int TLocX = 0;
public int TLocY = 0;
public int TLocZ = 0;
// connections to other legs
List olconn = new ArrayList();
// position set for calculating location
boolean bPositionSet = false;
OnePathNode station_opn = null; // used in the ImportCentrelineLabel routine
/////////////////////////////////////////////
public OneStation(String lname)
{
name = lname;
if (name.indexOf("..") != -1)
TN.emitError("we have a double-dot in a station name, (probably because you are using a single dot station name somewhere) " + lname);
}
/////////////////////////////////////////////
float AngDiff(float ang)
{
if (ang < 0.0F)
ang += 360.0F;
if (ang > 360.0F)
ang -= 360.0F;
return Math.min(ang, 360.0F - ang);
}
/////////////////////////////////////////////
// transformed for viewing points
void SetTLoc(Matrix3D mat)
{
tLoc.x = Loc.x * mat.xx + Loc.y * mat.xy + Loc.z * mat.xz + mat.xo;
tLoc.y = Loc.x * mat.yx + Loc.y * mat.yy + Loc.z * mat.yz + mat.yo;
tLoc.z = Loc.x * mat.zx + Loc.y * mat.zy + Loc.z * mat.zz + mat.zo;
TLocX = (int)tLoc.x;
TLocY = (int)tLoc.y;
TLocZ = (int)tLoc.z;
}
/////////////////////////////////////////////
int sqDist(int mx, int my)
{
int dx = TLocX - mx;
int dy = TLocY - my;
return dx * dx + dy * dy;
}
/////////////////////////////////////////////
// used in wireframe graphics.
void paintW(Graphics g, boolean bActive, boolean bLong)
{
g.setColor(bActive ? TN.wfmpointActive : TN.wfmpointInactive);
g.drawRect(TLocX - TN.xsgPointSize, TLocY - TN.xsgPointSize, 2 * TN.xsgPointSize, 2 * TN.xsgPointSize);
g.setColor(bActive ? TN.wfmnameActive : TN.wfmnameInactive);
g.drawString(name, TLocX + TN.xsgPointSize * 2, TLocY + TN.xsgPointSize * 2);
}
}
tunnelx-20190701/src/ProximityDerivation.java 0000664 0001750 0001750 00000036763 13531571147 020603 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2004 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.awt.geom.Line2D;
import java.awt.geom.GeneralPath;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;
import java.util.PriorityQueue;
/////////////////////////////////////////////
class parainstance implements Comparable
{
double sdist;
double zdisp;
OnePathNode opn;
/////////////////////////////////////////////
parainstance(double lsdist, double lzdisp, OnePathNode lopn)
{
sdist = lsdist;
zdisp = lzdisp;
opn = lopn;
}
/////////////////////////////////////////////
public int compareTo(parainstance pi)
{
double ll = sdist - pi.sdist;
return (ll < 0.0 ? -1 : (ll > 0.0 ? 1 : 0));
}
}
/////////////////////////////////////////////
class Parainstancequeue
{
PriorityQueue prioqueue = new PriorityQueue();
List proxdistsetlist = new ArrayList(); // list of nodes that have been visited so their proxdists can be reset
// may be able to replace proxdistsetlist with a map from OnePathNode to Double, so can get rid of the proxdist
// these settings determine which types of the path are traversed
// the requirements differ when we are morphing or setting the z values
boolean bDropdownConnectiveTraversed = true;
boolean bCentrelineTraversed = true; // when false, would we also want to abolish linking through centreline nodes as well?
boolean bAreasTraversed = true; // tries to link across areas with a straight line to the nodes in the area
double fcenlinelengthfactor = 10.0; // factor of length added to centreline connections (to deal with vertical line cases)
boolean bhcoincideLinesActive;
/////////////////////////////////////////////
RefPathO Dsrefpathconn = new RefPathO();
void AddNode(OnePathNode opn, double dist, double zdisp)
{
opn.proxdist = dist;
proxdistsetlist.add(opn);
if (bAreasTraversed)
{
Dsrefpathconn.ccopy(opn.ropconn);
do
{
AddNodeAreaCrossings(Dsrefpathconn, opn, dist, zdisp);
}
while (!Dsrefpathconn.AdvanceRoundToNode(opn.ropconn));
}
Dsrefpathconn.ccopy(opn.ropconn);
do
{
AddNodePathsConnections(Dsrefpathconn, opn, dist, zdisp);
}
while (!Dsrefpathconn.AdvanceRoundToNode(opn.ropconn));
}
void AddNodeAreaCrossings(RefPathO srefpathconn, OnePathNode opn, double dist, double zdisp)
{
OnePath op = srefpathconn.op;
if (op.linestyle == SketchLineStyle.SLS_CENTRELINE)
return;
if (op.linestyle == SketchLineStyle.SLS_CONNECTIVE)
return;
OneSArea osa = (srefpathconn.bFore ? op.karight : op.kaleft);
if (osa == null)
return;
GeneralPath gpconnline = new GeneralPath();
for (RefPathO rpo : osa.refpaths)
{
OnePathNode opo = (rpo.bFore ? rpo.op.pnend : rpo.op.pnstart);
if (opo.proxdist != -1.0)
continue;
// gpconnline.clear();
// gpconnline.moveTo(opn.pn.getX(), opn.pn.getY());
// gpconnline.lineTo(opo.pn.getX(), opo.pn.getY());
// gpconnline.subtract(osa.aarea);
// System.out.println(" "+connlin.isEmpty());
// if (gpconnline.isEmpty())
{
double vx = opo.pn.getX() - opn.pn.getX();
double vy = opo.pn.getY() - opn.pn.getY();
double addd = Math.sqrt(vx*vx + vy*vy);
prioqueue.offer(new parainstance(dist + addd, zdisp, opo));
}
}
}
void AddNodePathsConnections(RefPathO srefpathconn, OnePathNode opn, double dist, double zdisp)
{
OnePathNode opo = srefpathconn.FromNode();
OnePath op = srefpathconn.op;
assert opn == srefpathconn.ToNode();
if (opo.proxdist != -1.0)
return;
double addd;
double addzdisp;
// line is either zero length or not connected
if (op.IsDropdownConnective())
{
if (!bDropdownConnectiveTraversed)
return;
addd = 0.0;
addzdisp = 0.0;
}
// adjust the value so that centrelines don't get used for connecting in favour
else if (op.linestyle == SketchLineStyle.SLS_CENTRELINE)
{
if (!bCentrelineTraversed)
return;
addd = op.linelength * fcenlinelengthfactor;
addzdisp = 0.0;
}
else if (op.IsZSetNodeConnective())
{
addd = op.linelength;
addzdisp = (opo == op.pnstart ? op.plabedl.nodeconnzsetrelative : -op.plabedl.nodeconnzsetrelative);
}
else if (op.IsSketchFrameConnective())
{
addd = op.linelength;
addzdisp = (opo == op.pnstart ? op.plabedl.sketchframedef.sfnodeconnzsetrelative : -op.plabedl.sketchframedef.sfnodeconnzsetrelative);
}
// standard addition
else
{
addd = op.linelength;
addzdisp = 0.0;
}
prioqueue.offer(new parainstance(dist + addd, zdisp + addzdisp, opo));
}
}
/////////////////////////////////////////////
// weights from centrelines
/////////////////////////////////////////////
class ProximityDerivation
{
List vnodes; // OnePathNode
List vpaths; // OnePath
OneSketch os;
int ncentrelinenodes = 0;
Parainstancequeue parainstancequeue;
double distmincnode = 0.0;
double distmaxcnode = 0.0;
double distmax = 0.0;
RefPathO srefpathconn = new RefPathO(); // reused object
/////////////////////////////////////////////
ProximityDerivation(OneSketch los)
{
// make the array parallel to the nodes
os = los;
vnodes = os.vnodes;
vpaths = os.vpaths;
parainstancequeue = new Parainstancequeue();
// find the centreline nodes; reset the proxdists
ncentrelinenodes = 0;
for (OnePathNode opn : vnodes)
{
opn.proxdist = -1.0;
if (opn.IsCentrelineNode())
ncentrelinenodes++;
}
}
/////////////////////////////////////////////
void ShortestPathsToCentrelineNodesSetup(OnePathNode sopn, OnePath sop)
{
assert ((sopn == null) != (sop == null));
assert parainstancequeue.proxdistsetlist.isEmpty();
for (OnePathNode opn : vnodes)
assert opn.proxdist == -1.0;
// make the queue and eat through it.
distmincnode = -1.0;
distmaxcnode = -1.0;
distmax = 0.0;
// start on node or midpoint of path
assert parainstancequeue.prioqueue.isEmpty();
if (sopn != null)
parainstancequeue.AddNode(sopn, distmax, 0.0);
else
{
distmax = sop.linelength / 2;
parainstancequeue.AddNode(sop.pnstart, distmax, 0.0);
parainstancequeue.AddNode(sop.pnend, distmax, 0.0);
}
}
/////////////////////////////////////////////
// generates the full shortest path diagram from this node
int ShortestPathsToCentrelineNodes(OnePathNode sopn, OnePathNode[] cennodes, double[] zdispcennodes)
{
assert (zdispcennodes == null) || (zdispcennodes.length == cennodes.length);
ShortestPathsToCentrelineNodesSetup(sopn, null);
// eat through the queue
int icennodes = 0;
OnePathNode substitutecennode = sopn;
double substitutecennodezdisp = 0.0;
while (!parainstancequeue.prioqueue.isEmpty())
{
parainstance pi = parainstancequeue.prioqueue.poll();
if (pi.opn.proxdist != -1.0)
continue;
distmax = pi.sdist;
parainstancequeue.AddNode(pi.opn, distmax, pi.zdisp);
if (pi.opn.IsCentrelineNode())
{
distmaxcnode = distmax;
// we're looking for the closest centreline nodes
// or grab the one with the lowest value in the sort if none emerge in this connected component
if (cennodes != null)
{
if (zdispcennodes != null)
zdispcennodes[icennodes] = pi.zdisp;
cennodes[icennodes++] = pi.opn;
if (icennodes == cennodes.length)
break; // we've now got enough centreline nodes
}
}
else if ((cennodes != null) && (icennodes == 0) && (substitutecennode.compareTo(pi.opn) > 0))
{
substitutecennode = pi.opn;
substitutecennodezdisp = pi.zdisp;
}
}
parainstancequeue.prioqueue.clear();
if (cennodes != null)
{
// use the default topleft node if no centreline nodes were found to tie to
if (icennodes == 0)
{
if (zdispcennodes != null)
zdispcennodes[0] = substitutecennodezdisp;
cennodes[0] = substitutecennode;
icennodes = 1;
}
for (int i = icennodes; i < cennodes.length; i++)
cennodes[icennodes++] = null;
}
return icennodes;
}
/////////////////////////////////////////////
OnePath EstSubsetToCen(OnePath op, OnePathNode copn, boolean bdatetype)
{
assert copn.IsCentrelineNode();
assert bdatetype || op.vssubsets.isEmpty();
double xmv = (op.pnstart.pn.getX() + op.pnend.pn.getX()) / 2 - copn.pn.getX();
double ymv = (op.pnstart.pn.getY() + op.pnend.pn.getY()) / 2 - copn.pn.getY();
double maxdot = 0.0;
OnePath res = null;
// pick an edge by closest dot-product
srefpathconn.ccopy(copn.ropconn);
do
{
OnePath cop = srefpathconn.op;
// if bdatetype should select one with a __date__ thing in it for sure
if ((srefpathconn.op.linestyle == SketchLineStyle.SLS_CENTRELINE) && !srefpathconn.op.vssubsets.isEmpty())
{
assert copn == srefpathconn.ToNode();
OnePathNode ocopn = srefpathconn.FromNode();
double xcv = (ocopn.pn.getX() - copn.pn.getX());
double ycv = (ocopn.pn.getY() - copn.pn.getY());
double ldot = Math.abs(xcv * xmv + ycv * ymv);
if ((res == null) || (ldot > maxdot))
res = cop;
}
}
while (!srefpathconn.AdvanceRoundToNode(copn.ropconn));
return res;
}
/////////////////////////////////////////////
// generates the full shortest path diagram from this node
OnePath EstClosestCenPath(OnePath op, boolean bdatetype)
{
ShortestPathsToCentrelineNodesSetup(null, op);
// eat through the queue
OnePath opres = null;
while (!parainstancequeue.prioqueue.isEmpty())
{
parainstance pi = parainstancequeue.prioqueue.poll();
if (pi.opn.proxdist == -1.0)
{
distmax = pi.sdist;
parainstancequeue.AddNode(pi.opn, distmax, 0.0);
if (pi.opn.IsCentrelineNode())
{
OnePath cop = EstSubsetToCen(op, pi.opn, bdatetype);
if (cop != null)
{
opres = cop;
parainstancequeue.prioqueue.clear();
break;
}
}
}
}
// reset for next application
for (OnePathNode lopn : parainstancequeue.proxdistsetlist)
lopn.proxdist = -1.0;
parainstancequeue.proxdistsetlist.clear();
return opres;
}
/////////////////////////////////////////////
void PrintProxOneNode(OnePathNode[] copn)
{
for (int j = 0; j < copn.length; j++)
{
OnePathNode cpn = copn[j];
if (cpn != null)
{
System.out.print(", ");
System.out.print(vnodes.indexOf(cpn));
System.out.print(", ");
System.out.print(cpn.pnstationlabel);
System.out.print(", ");
System.out.print(cpn.proxdist);
}
else
System.out.print(", -1, , -1");
}
// reset for next application
for (OnePathNode lopn : parainstancequeue.proxdistsetlist)
lopn.proxdist = -1.0;
parainstancequeue.proxdistsetlist.clear();
}
/////////////////////////////////////////////
// generates the full shortest path diagram from this node
void PrintCNodeProximity(int nnodes) // number of nodes we print
{
System.out.println("****** BEGIN PRINT PROXIMITIES ******");
// centrelinenodes by dist
OnePathNode[] copn = new OnePathNode[Math.min(ncentrelinenodes, nnodes)];
for (OnePathNode opn : vnodes)
opn.proxdist = -1.0;
// work through each of the nodes and calculate for them.
for (int i = 0; i < vnodes.size(); i++)
{
OnePathNode opn = vnodes.get(i);
if (opn.IsCentrelineNode())
{
System.out.print("station, ");
System.out.print(i);
System.out.print(", ");
System.out.print(opn.pnstationlabel);
}
else
{
ShortestPathsToCentrelineNodes(opn, copn, null);
System.out.print("node, ");
System.out.print(i);
PrintProxOneNode(copn);
}
System.out.println(""); // newline
}
// do the labels
for (OnePath op : vpaths)
{
if ((op.linestyle == SketchLineStyle.SLS_CONNECTIVE) && (op.plabedl != null) && !op.plabedl.drawlab.equals(""))
{
ShortestPathsToCentrelineNodes(op.pnstart, copn, null);
System.out.print("label, ");
System.out.print(op.plabedl.sfontcode);
System.out.print(", ");
System.out.print(op.plabedl.drawlab.replace('\n', ' '));
PrintProxOneNode(copn);
System.out.println(""); // newline
}
}
System.out.println("****** END PRINT PROXIMITIES ******");
}
/////////////////////////////////////////////
// generates the full shortest path diagram from this node
void SetZaltsFromCNodesByInverseSquareWeight(OneSketch los)
{
parainstancequeue.bDropdownConnectiveTraversed = false;
parainstancequeue.bCentrelineTraversed = false;
// reset all the connective nodes ones
for (OnePathNode opn : vnodes)
{
opn.proxdist = -1.0;
if (opn.pnstationlabel == OnePathNode.strConnectiveNode)
opn.pnstationlabel = null;
assert ((opn.pnstationlabel == null) || !opn.pnstationlabel.equals(OnePathNode.strConnectiveNode));
}
// just averages over 4 nodes
assert os == los;
int ncopn = Math.max(1, Math.min(ncentrelinenodes, 4));
OnePathNode[] copn = new OnePathNode[ncopn];
double[] zdispcennodes = new double[ncopn];
// set all the unset zalts
boolean bfirst = true;
for (OnePathNode opn : vnodes)
{
if (!opn.IsCentrelineNode())
{
ShortestPathsToCentrelineNodes(opn, copn, zdispcennodes);
double tweight = 0.0;
double zaltsum = 0.0;
for (int j = 0; j < copn.length; j++)
{
OnePathNode cpn = copn[j];
if (cpn == null)
{
if (j == 0)
{
tweight = 1.0;
zaltsum = 0.0;
}
break;
}
assert cpn.proxdist != -1.0;
if (cpn.proxdist == 0.0) // station node case
{
tweight = 1.0;
assert zdispcennodes[j] == 0.0;
zaltsum = cpn.zalt + zdispcennodes[j];
break;
}
double weight = 1.0 / (cpn.proxdist * cpn.proxdist);
zaltsum += (cpn.zalt + zdispcennodes[j]) * weight;
tweight += weight;
}
if (tweight == 0.0)
tweight = 1.0;
opn.zalt = (float)(zaltsum / tweight);
// reset for next application
for (OnePathNode lopn : parainstancequeue.proxdistsetlist)
{
assert lopn.proxdist >= 0.0;
lopn.proxdist = -1.0;
}
parainstancequeue.proxdistsetlist.clear();
}
if ((os.zaltlo > opn.zalt) || bfirst)
os.zaltlo = opn.zalt;
if ((os.zalthi < opn.zalt) || bfirst)
os.zalthi = opn.zalt;
bfirst = false;
}
}
};
tunnelx-20190701/src/ConnectiveLabelTabPane.java 0000664 0001750 0001750 00000017000 13531571147 021021 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2004 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.CardLayout;
import java.awt.Font;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JToggleButton;
import javax.swing.JTextField;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JRadioButton;
import javax.swing.ButtonGroup;
import javax.swing.AbstractAction;
import javax.swing.undo.UndoManager;
import javax.swing.InputMap;
import javax.swing.KeyStroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
/////////////////////////////////////////////
class ConnectiveLabelTabPane extends JPanel
{
JPanel labelstylepanel;
JComboBox fontstyles = new JComboBox();
List lfontstyles = new ArrayList();
JButton jbcancel = new JButton("Cancel Label");
JTextArea labtextfield = new JTextArea("how goes\n there");
JScrollPane scrollpanetextfield = new JScrollPane(labtextfield);
UndoManager labtextfieldundo = new UndoManager();
JPanel labelpospanel;
JCheckBox jcbarrowpresent = new JCheckBox("Arrow");
JCheckBox jcbboxpresent = new JCheckBox("Box");
// the positioning of the text
JTextField tfxrel = new JTextField();
JTextField tfyrel = new JTextField();
JPanel surveyfilterpanel;
JTextField tfsurveyfilterfile = new JTextField();
JCheckBox jcbsurveyfilterfile = new JCheckBox("Transitive");
CardLayout vcardlayouttoppanel = new CardLayout();
JPanel toppanel;
// these codes could be expended later; they are numbered 0-4 clockwise from bottom left
static String[] rppos = { "-1", "0", "1" };
/////////////////////////////////////////////
class surveyfontstyledetector implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
int lifontcode = fontstyles.getSelectedIndex();
String lsfontcode = (lifontcode == -1 ? "default" : lfontstyles.get(lifontcode));
vcardlayouttoppanel.show(toppanel, (lsfontcode.equals("survey") ? "surveyfilterpanel" : "labelpospanel"));
}
};
/////////////////////////////////////////////
class radbut implements ActionListener
{
String xrel;
String yrel;
radbut(int ipos)
{
xrel = rppos[(ipos % 3)];
yrel = rppos[2 - (ipos / 3)];
}
public void actionPerformed(ActionEvent e)
{
tfxrel.setText(xrel);
tfyrel.setText(yrel);
tfxrel.postActionEvent();
}
}
ButtonGroup buttgroup = new ButtonGroup();
JRadioButton[] rbposes = new JRadioButton[10];
radbut[] radbuts = new radbut[9];
surveyfontstyledetector sfsd = new surveyfontstyledetector();
SortedMap fontssortedmap = new TreeMap();
/////////////////////////////////////////////
void ReloadLabelsCombo(SubsetAttrStyle sascurrent)
{
fontssortedmap.clear();
for (SubsetAttr sa : sascurrent.msubsets.values())
{
for (LabelFontAttr lfa : sa.labelfontsmap.values())
{
if (!fontssortedmap.containsKey(lfa.labelfontname))
fontssortedmap.put(lfa.labelfontname, String.format("%s (%s)", lfa.labelfontname, sa.subsetname));
}
}
fontstyles.removeActionListener(sfsd);
fontstyles.removeAllItems();
lfontstyles.clear();
for (Map.Entry foename : fontssortedmap.entrySet())
{
fontstyles.addItem(foename.getKey()); // the value has the subset in brackets, but subsets will in future be common to most styles
//fontstyles.addItem(foename.getValue());
lfontstyles.add(foename.getKey());
}
fontstyles.addActionListener(sfsd);
}
/////////////////////////////////////////////
void setTextPosCoords(float fxrel, float fyrel)
{
int ix = (fxrel == -1.0F ? 0 : (fxrel == 0.0F ? 1 : (fxrel == 1.0F ? 2 : -1)));
int iy = (fyrel == -1.0F ? 2 : (fyrel == 0.0F ? 1 : (fyrel == 1.0F ? 0 : -1)));
if ((ix != -1) && (iy != -1))
{
rbposes[ix + iy * 3].setSelected(true);
tfxrel.setText(rppos[ix]);
tfyrel.setText(rppos[2 - iy]);
}
else
{
rbposes[9].setSelected(true);
tfxrel.setText(String.valueOf(fxrel));
tfyrel.setText(String.valueOf(fyrel));
}
}
/////////////////////////////////////////////
void Setlabtextfield(String txt)
{
labtextfield.setText(txt);
labtextfieldundo.discardAllEdits();
}
/////////////////////////////////////////////
ConnectiveLabelTabPane()
{
super(new BorderLayout());
labtextfield.getDocument().addUndoableEditListener(labtextfieldundo);
KeyStroke keyctlz = KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.CTRL_MASK);
labtextfield.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.CTRL_MASK), "controlzundo");
labtextfield.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Y, KeyEvent.CTRL_MASK), "controlyredo");
labtextfield.getActionMap().put("controlzundo", new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
if (labtextfieldundo.canUndo())
labtextfieldundo.undo();
}
});
labtextfield.getActionMap().put("controlyredo", new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
if (labtextfieldundo.canRedo())
labtextfieldundo.redo();
}
});
labelpospanel = new JPanel(new GridLayout(1, 3));
JPanel fsp1 = new JPanel(new GridLayout(2, 1));
fsp1.add(jcbarrowpresent);
fsp1.add(jcbboxpresent);
labelpospanel.add(fsp1);
JPanel fsp3 = new JPanel(new GridLayout(3, 3));
for (int i = 0; i < 10; i++)
{
rbposes[i] = new JRadioButton("");
buttgroup.add(rbposes[i]);
if (i != 9)
{
radbuts[i] = new radbut(i);
rbposes[i].addActionListener(radbuts[i]);
fsp3.add(rbposes[i]);
}
}
labelpospanel.add(fsp3);
JPanel fsp2 = new JPanel(new GridLayout(2, 1));
fsp2.add(tfxrel);
fsp2.add(tfyrel);
labelpospanel.add(fsp2);
surveyfilterpanel = new JPanel(new GridLayout(2, 1));
JPanel sfpupper = new JPanel(new GridLayout(1, 3));
sfpupper.add(new JLabel("File filter:"));
sfpupper.add(jcbsurveyfilterfile);
surveyfilterpanel.add(sfpupper);
surveyfilterpanel.add(tfsurveyfilterfile);
toppanel = new JPanel(vcardlayouttoppanel);
toppanel.add(labelpospanel, "labelpospanel");
toppanel.add(surveyfilterpanel, "surveyfilterpanel");
vcardlayouttoppanel.show(toppanel, "labelpospanel");
labelstylepanel = new JPanel();
labelstylepanel.add(fontstyles);
labelstylepanel.add(jbcancel);
add(toppanel, BorderLayout.NORTH);
add(scrollpanetextfield, BorderLayout.CENTER);
add(labelstylepanel, BorderLayout.SOUTH);
}
};
tunnelx-20190701/src/SvxFileDialog.java 0000664 0001750 0001750 00000025415 13531571147 017242 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.io.File;
import javax.swing.JFrame;
import javax.swing.filechooser.*;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;
import javax.swing.JOptionPane;
import javax.swing.JApplet;
/////////////////////////////////////////////
class SvxFileFilter extends FileFilter
{
StringBuffer desc = new StringBuffer();
String[] ftext;
/////////////////////////////////////////////
SvxFileFilter(String ftname, String[] lftext)
{
ftext = lftext;
// make the description
desc.append(ftname);
desc.append(" Files (");
for (int i = 0; i < ftext.length; i++)
{
if (i != 0)
desc.append(", ");
desc.append("*.");
desc.append(ftext[i]);
}
desc.append(")");
}
/////////////////////////////////////////////
SvxFileFilter(String namedirectory)
{
desc.append(namedirectory);
ftext = null;
}
/////////////////////////////////////////////
public boolean accept(File file)
{
if (file.isDirectory())
return true;
if (ftext == null)
return false;
String suff = TN.getSuffix(file.getName()); // need a coherent interface for this function.
if ((suff == null) || suff.equals("") || (suff.charAt(0) != '.'))
return false;
suff = suff.substring(1);
for (int i = 0; i < ftext.length; i++)
if (suff.equalsIgnoreCase(ftext[i]))
return true;
return false;
}
/////////////////////////////////////////////
public String getDescription()
{
return desc.toString();
}
};
/////////////////////////////////////////////
/////////////////////////////////////////////
// the loading dialog
public class SvxFileDialog extends JFileChooser
{
static final int FT_ANY = 0;
static final int FT_SVX = 1;
static final int FT_XSECTION_PREVIEW = 2;
static final int FT_SYMBOLS = 3;
static final int FT_VRML = 4;
static final int FT_BITMAP = 5;
static final int FT_TH2 = 6;
static final int FT_XMLSKETCH = 7;
static final int FT_DIRECTORY = 8;
static final int FT_VECTOR = 9;
static String[] ftnames = { "Any",
"SVX/DistoX",
"XSection Preview",
"Symbols",
"VRML",
"Bitmap",
"Therion sketch",
"Tunnel sketch",
"Directory",
"Vector" };
static String[][] ftexts = { { "*" },
{ "svx", "txt", "top" },
{ "??" },
{ "??" },
{ "wrl" },
{ "png", "jpg", "jpeg", "bmp", "gif" },
{ "th2" },
{ "xml" },
{ "??" },
{ "svg", "xml" } };
FileAbstraction svxfile = null;
FileAbstraction tunneldirectory = null;
boolean bReadCommentedXSections;
/////////////////////////////////////////////
SvxFileDialog(FileAbstraction currentDirectory)
{
super(currentDirectory.localfile);
if (!currentDirectory.getName().equals(""))
setSelectedFile(currentDirectory.localfile); // filechooser function
}
/////////////////////////////////////////////
FileAbstraction getCurrentDirectoryA()
{
return FileAbstraction.MakeDirectoryFileAbstractionF(getCurrentDirectory());
}
/////////////////////////////////////////////
// this fixes up the suffix when someone types it in wrong
FileAbstraction getSelectedFileA(int ftype, boolean bsaving)
{
File fil = getSelectedFile();
String fsel = fil.toString();
//int fselxfiletype = fil.xfiletype; // doesn't work because selected file is File not FileAbstraction
String suff = TN.getSuffix(fil.getName());
if (ftype == FT_DIRECTORY)
{
if (!fsel.endsWith("/"))
fsel = fsel + "/"; // the dialog box removes necessary trailing slashes when we abuse it to enter in URLs
tunneldirectory = FileAbstraction.MakeOpenableFileAbstraction(fsel);
if (!tunneldirectory.isDirectory())
return null;
tunneldirectory.xfiletype = FileAbstraction.FA_DIRECTORY;
tunneldirectory.bIsDirType = true;
return tunneldirectory;
}
// append correct suffixes if the user failed to add them
else if (ftype == FT_SVX)
{
if (!suff.equalsIgnoreCase(TN.SUFF_SVX))
TN.emitWarning("wrong suffix for SVX file");
assert !bsaving; // we don't save svx files yet
//assert fselxfiletype == FA_FILE_SVX;
}
else if (ftype == FT_XMLSKETCH)
{
if (!suff.equalsIgnoreCase(TN.SUFF_XML))
{
TN.emitWarning("wrong suffix for XML file");
if (bsaving)
{
TN.emitWarning("setting suffix of file to .xml");
fsel = fsel + TN.SUFF_XML;
//fselxfiletype = FA_FILE_XML_SKETCH;
}
}
//else
// assert fselxfiletype == FileAbstraction.FA_FILE_XML_SKETCH;
}
svxfile = FileAbstraction.MakeOpenableFileAbstraction(fsel);
//svxfile.xfiletype = fselxfiletype;
return svxfile;
}
/////////////////////////////////////////////
void SetFileFil(int ftype)
{
SvxFileFilter sff = (ftype != FT_DIRECTORY ? new SvxFileFilter(ftnames[ftype], ftexts[ftype]) : new SvxFileFilter(ftnames[ftype]));
//TN.emitMessage(sff.getDescription());
try
{
addChoosableFileFilter(sff);
setFileFilter(sff);
}
catch (NullPointerException e)
{
TN.emitWarning(e.toString());
}
}
/////////////////////////////////////////////
static SvxFileDialog showOpenDialog(FileAbstraction currentDirectory, JApplet frame, int ftype, boolean bAuto)
{
System.out.println("Can't do this from an applet");
return null;
}
/////////////////////////////////////////////
static SvxFileDialog showOpenDialog(FileAbstraction currentDirectory, JFrame frame, int ftype, boolean bAuto)
{
// weird getting the suffix of a directory?
// maybe something's bee posted into it
String lsuff = TN.getSuffix(currentDirectory.getName());
boolean bBlankFile = (!lsuff.equalsIgnoreCase(TN.SUFF_SVX) && !currentDirectory.getName().equals(""));
//SvxFileDialog sfd = new SvxFileDialog((bBlankFile ? currentDirectory.getParentFile() : currentDirectory));
SvxFileDialog sfd = new SvxFileDialog(currentDirectory);
sfd.SetFileFil(ftype);
sfd.svxfile = null;
sfd.tunneldirectory = null;
sfd.setDialogTitle("Open " + ftnames[ftype] + "File");
sfd.setFileSelectionMode(ftype != FT_DIRECTORY ? JFileChooser.FILES_ONLY : JFileChooser.DIRECTORIES_ONLY);
FileAbstraction file;
if (!bAuto)
{
if (sfd.showOpenDialog(frame) != JFileChooser.APPROVE_OPTION)
return null;
file = sfd.getSelectedFileA(ftype, false);
}
else
file = currentDirectory;
// directory type
TN.emitMessage("ft type=" + ftype + " " + FT_DIRECTORY + " " + file + " isDirectory=" + file.isDirectory());
if (ftype == FT_DIRECTORY)
{
if ((file.localurl == null) && !file.isDirectory()) // adding in localurl condition as real hack to get the tutorial loading
return null;
sfd.tunneldirectory = file;
sfd.tunneldirectory.xfiletype = FileAbstraction.FA_DIRECTORY;
sfd.tunneldirectory.bIsDirType = true;
return sfd;
}
// get rid of directories
if ((file.localurl == null) && file.isDirectory())
return null;
String suff = TN.getSuffix(file.getName());
sfd.bReadCommentedXSections = (suff.equalsIgnoreCase(TN.SUFF_SVX) || suff.equalsIgnoreCase(TN.SUFF_TOP));
TN.emitMessage(currentDirectory.toString() + " kkkkk " + suff + " " + ftype + " " + suff.equalsIgnoreCase(TN.SUFF_SVX));
if ((ftype == FT_TH2) || suff.equalsIgnoreCase(TN.SUFF_WALLS))
{
sfd.svxfile = file;
return sfd;
}
if (ftype == FT_BITMAP)
{
sfd.svxfile = file;
sfd.svxfile.xfiletype = FileAbstraction.FA_FILE_IMAGE;
return sfd;
}
if (suff.equalsIgnoreCase(TN.SUFF_SVX))
{
sfd.svxfile = file;
sfd.svxfile.xfiletype = FileAbstraction.FA_FILE_SVX;
TN.emitWarning("shouldbesuffsvx " + sfd.svxfile.xfiletype);
return sfd;
}
if (suff.equalsIgnoreCase(TN.SUFF_TXT))
{
sfd.svxfile = file;
sfd.svxfile.xfiletype = file.GetFileType();
if (sfd.svxfile.xfiletype == FileAbstraction.FA_FILE_POCKET_TOPO)
return sfd;
}
if (suff.equalsIgnoreCase(TN.SUFF_TOP))
{
sfd.svxfile = file;
sfd.svxfile.xfiletype = file.GetFileType();
if (sfd.svxfile.xfiletype == FileAbstraction.FA_FILE_POCKET_BINTOP)
return sfd;
}
if (suff.equalsIgnoreCase(TN.SUFF_XML) && (ftype == FT_XMLSKETCH))
{
sfd.svxfile = file;
//sfd.svxfile.xfiletype = FileAbstraction.FA_FILE_XML_SKETCH; (look it up?)
return sfd;
}
TN.emitWarning("Unknown File Type on:" + file.getName());
JOptionPane.showMessageDialog(frame, "Unknown File Type on:" + file.getName());
return null;
}
/////////////////////////////////////////////
static SvxFileDialog showSaveDialog(FileAbstraction currentDirectory, JApplet frame, int ftype, boolean bauto)
{
return null;
}
/////////////////////////////////////////////
static SvxFileDialog showSaveDialog(FileAbstraction currentDirectory, JFrame frame, int ftype, boolean bauto)
{
FileAbstraction savetype = null;
if (currentDirectory.localurl != null)
currentDirectory = TN.currentDirectory;
else if (currentDirectory.getName().equals(""))
currentDirectory = currentDirectory;
else
currentDirectory = FileAbstraction.MakeDirectoryAndFileAbstraction(currentDirectory.getParentFile(), TN.setSuffix(currentDirectory.getName(), "." + ftexts[ftype][0]));
SvxFileDialog sfd = new SvxFileDialog(currentDirectory);
sfd.SetFileFil(ftype);
sfd.svxfile = null;
sfd.tunneldirectory = null;
sfd.setDialogTitle("Save " + ftnames[ftype] + "File");
sfd.setFileSelectionMode(ftype != FT_DIRECTORY ? JFileChooser.FILES_ONLY : JFileChooser.DIRECTORIES_ONLY);
if (!bauto && (sfd.showSaveDialog(frame) != JFileChooser.APPROVE_OPTION))
return null;
FileAbstraction file = sfd.getSelectedFileA(ftype, true);
return sfd;
}
}
tunnelx-20190701/src/RefPathO.java 0000664 0001750 0001750 00000003562 13531571147 016211 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
/////////////////////////////////////////////
class RefPathO
{
OnePath op;
boolean bFore;
RefPathO()
{;};
RefPathO(OnePath lop, boolean lbFore)
{
op = lop;
bFore = lbFore;
}
void ccopy(RefPathO rpo)
{
op = rpo.op;
bFore = rpo.bFore;
}
RefPathO(RefPathO rpo)
{
ccopy(rpo);
}
boolean cequals(RefPathO rpo)
{
return ((op == rpo.op) && (bFore == rpo.bFore));
}
OneSArea GetCrossArea()
{
return (bFore ? op.kaleft : op.karight);
}
OnePathNode ToNode()
{
return (bFore ? op.pnend : op.pnstart);
}
OnePathNode FromNode()
{
return (bFore ? op.pnstart : op.pnend);
}
boolean AdvanceRoundToNode(RefPathO rpmatch) // cycles around the ToNode
{
assert ToNode() == rpmatch.ToNode();
if (bFore)
{
bFore = op.bapfrfore;
op = op.apforeright;
}
else
{
bFore = op.baptlfore;
op = op.aptailleft;
}
assert ToNode() == rpmatch.ToNode();
return cequals(rpmatch);
}
};
tunnelx-20190701/src/MainBox.java 0000664 0001750 0001750 00000062106 13531571147 016075 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2002 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JScrollPane;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JMenuBar;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JApplet;
import java.lang.ClassLoader;
import java.util.List;
import java.util.ArrayList;
import javax.swing.text.BadLocationException;
// The tilt coding stuff
// Be able to switch between two sketches in the same SketchDisplay (the background one)
// Be able to save more than one sketch in the same file (the imported ones
// to do:
// see ElevWarp.java for more todos
// save to url makes it green
// do whole list of tunnel files available at same time
// sort out backgrounds
// the survex file open to do its own removing of http: crud from the front
// bring in background images through this
// open with http on command line should work
// new sketch is made relative to the disk??
// the tree in the tunnel file list can be used to import images
// and it should refresh
// and it should open sketches directly from it.
// then we can lose the list view.
// save as from http file should work
// upload and upload as... should post up to directory
// upload rendered image should do something in troggle (some kind of workspace)
// upload background images for sure
// cached background images that have been pulled down
// when the browser thing is working, we can emulate it in tunnel (mainbox?)
// fix lookup for symbols location
// comments in symbols directory
// reloadfontcolours
/////////////////////////////////////////////
/////////////////////////////////////////////
// the main frame
public class MainBox
extends JFrame
// extends JApplet // AppletConversion
{
// the parameters used in this main box
// the survey tree
TunnelFileList tunnelfilelist;
TunnelLoader tunnelloader;
JCheckBoxMenuItem miViewSymbolsList;
JCheckBoxMenuItem miNetConnection;
JTextArea textareaerrors = new JTextArea("Errors and warnings here\n========================\n");
List allfontcolours = new ArrayList();
// this could be moved into TunnelFileList
List ftsketches = new ArrayList();
// this could be a map
List vgsymbolstsketches = new ArrayList();
InstantHelp instanthelp = null;
// the default treeroot with list of symbols.
FileAbstraction vgsymbolsdirectory;
// single xsection window and wireframe display
WireframeDisplay wireframedisplay = new WireframeDisplay();
// sketch display window
SketchDisplay sketchdisplay;
// for handling multi-threaded layouts of symbols
static SymbolLayoutProcess symbollayoutprocess;
NetConnection netconnection = new NetConnection(this);
/////////////////////////////////////////////
void MainRefresh()
{
tunnelfilelist.RemakeTFList();
}
/////////////////////////////////////////////
void MainOpen(FileAbstraction fileauto, int ftype)
{
if (fileauto != null)
TN.emitMessage("Auto load: " + fileauto + " of type: " + ftype);
//if (bAuto)
// TN.emitMessage("Auto load: " + TN.currentDirectory + " of type: " + ftype);
// Everything is svxfile
SvxFileDialog sfiledialog = (fileauto == null ? SvxFileDialog.showOpenDialog(TN.currentDirectory, this, ftype, false) : SvxFileDialog.showOpenDialog(fileauto, this, ftype, true));
if ((sfiledialog == null) || ((sfiledialog.svxfile == null) && (sfiledialog.tunneldirectory == null)))
return;
String soname = (sfiledialog.tunneldirectory == null ? sfiledialog.svxfile.getName() : sfiledialog.tunneldirectory.getName());
int il = soname.indexOf('.');
if (il != -1)
soname = soname.substring(0, il);
// put the tunnel in
String filetunnname = soname.replace(' ', '_').replace('\t', '_'); // can't cope with spaces.
// loading directly from a tunnel directory tree
if (sfiledialog.tunneldirectory != null)
{
try
{
if ((sfiledialog.tunneldirectory.localfile != null) && sfiledialog.tunneldirectory.isDirectory())
TN.currentDirectory = sfiledialog.tunneldirectory;
tunnelfilelist.AddTreeDirectory(sfiledialog.tunneldirectory);
int nfl = allfontcolours.size();
sfiledialog.tunneldirectory.FindFilesOfDirectory(ftsketches, allfontcolours);
tunnelfilelist.RemakeTFList(); // do it here so the list entries get sorted out quickly before they get caught out
// this whole preview function needs dealing with; poss to remove the situation that it handles multiple lists
for (int i = nfl; i < allfontcolours.size(); i++)
tunnelloader.LoadFontcolour(allfontcolours.get(i));
}
catch (IOException ie)
{
TN.emitWarning(ie.toString());
ie.printStackTrace();
}
catch (NullPointerException e)
{
TN.emitWarning(e.toString());
e.printStackTrace();
};
// update any symbols information that may have showed up in the process
if (sketchdisplay.sketchlinestyle.bsubsetattributesneedupdating)
sketchdisplay.sketchlinestyle.UpdateSymbols(false);
}
// loading a survex file
else if (sfiledialog.svxfile.xfiletype == FileAbstraction.FA_FILE_SVX)
{
if (sfiledialog.svxfile.localfile != null)
TN.currentDirectory = sfiledialog.svxfile.getParentFile();
TN.emitMessage("Do the SVX loading: " + ftype);
NewSketch(sfiledialog.svxfile, sfiledialog.svxfile.getSketchName() + "-sketch", (sketchdisplay.subsetpanel.jcbsubsetstyles.getItemCount() != 0 ? 0 : -1));
TN.emitMessage("import centerline: ");
if (sketchdisplay.ImportSketchCentrelineFile(sfiledialog))
{
TN.emitMessage("import survex centrline: ");
sketchdisplay.ImportCentrelineLabel("normal");
sketchdisplay.sketchgraphicspanel.MaxAction(2);
TN.emitMessage("Done");
}
}
// (unintentionally different from the xfiletype thing above) It doesn't know if the XML actually contains a sketch
else if (ftype == SvxFileDialog.FT_XMLSKETCH)
{
sfiledialog.svxfile.xfiletype = sfiledialog.svxfile.GetFileType(); // part of the constructor?
if (sfiledialog.svxfile.localfile != null)
TN.currentDirectory = sfiledialog.svxfile.getParentFile();
if ((sfiledialog.svxfile.xfiletype == FileAbstraction.FA_FILE_XML_SKETCH))
{
OneSketch tsketch = new OneSketch(sfiledialog.svxfile);
if (GetActiveTunnelSketches() == vgsymbolstsketches)
{
tsketch.sketchsymbolname = tsketch.sketchfile.getName();
tsketch.bSymbolType = true;
}
GetActiveTunnelSketches().add(tsketch);
tunnelfilelist.RemakeTFList();
tunnelfilelist.tflist.setSelectedIndex(tunnelfilelist.isketche - 1);
tunnelfilelist.UpdateSelect(true); // doubleclicks it.
TN.emitMessage(" -EEE- " + GetActiveTunnelSketches().size());
}
else
TN.emitError("Skipping file of unrecognized type "+sfiledialog.svxfile.xfiletype);
}
// loading a pocket topo file
else if ((sfiledialog.svxfile.xfiletype == FileAbstraction.FA_FILE_POCKET_TOPO) || (sfiledialog.svxfile.xfiletype == FileAbstraction.FA_FILE_POCKET_BINTOP))
{
if (sfiledialog.svxfile.localfile != null)
TN.currentDirectory = sfiledialog.svxfile.getParentFile();
TN.emitMessage("Do the POCKETTOPO loading: " + ftype);
NewSketch(sfiledialog.svxfile, sfiledialog.svxfile.getSketchName() + "-sketch", (sketchdisplay.subsetpanel.jcbsubsetstyles.getItemCount() != 0 ? 0 : -1));
TN.emitMessage("import centreline: ");
if (sketchdisplay.ImportSketchCentrelineFile(sfiledialog))
{
TN.emitMessage("worked: Now importing actual centreline"); // this could be a menu option?
sketchdisplay.ImportCentrelineLabel("nosurvex"); // the plan
sketchdisplay.ImportCentrelineLabel("TOPelevation"); // the elevation
sketchdisplay.subsetpanel.SetSubsetStyleFromString("pockettopo");
sketchdisplay.sketchgraphicspanel.MaxAction(2);
}
}
else
TN.emitError("can't do this type any more no more: " + ftype);
//MainRefresh();
}
/////////////////////////////////////////////
void MainSaveAll()
{
for (OneSketch lsketch : ftsketches)
lsketch.SaveSketch();
for (OneSketch lsketch : vgsymbolstsketches)
lsketch.SaveSketch();
tunnelfilelist.tflist.repaint();
}
/////////////////////////////////////////////
void MainExit()
{
if (JOptionPane.showConfirmDialog(this, "Are you sure you want to quit?", "Quit?", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
System.exit(0);
}
/////////////////////////////////////////////
public void emitErrorMessageLine(String mess, boolean btofront)
{
textareaerrors.append(mess);
if (btofront)
toFront();
int lc = textareaerrors.getLineCount() - 1;
try
{
textareaerrors.setSelectionStart(textareaerrors.getLineStartOffset(lc));
textareaerrors.setSelectionEnd(textareaerrors.getLineEndOffset(lc));
}
catch (BadLocationException e)
{;}
}
/////////////////////////////////////////////
/////////////////////////////////////////////
// build a sketch window.
void ViewSketch(OneSketch activesketch)
{
if (activesketch != null)
{
boolean bloaded = true; ;
if (!activesketch.bsketchfileloaded)
bloaded = tunnelloader.LoadSketchFile(activesketch, true);
if (bloaded)
sketchdisplay.ActivateSketchDisplay(activesketch, true);
}
tunnelfilelist.tflist.repaint();
}
/////////////////////////////////////////////
// make a new sketch
void NewSketch(FileAbstraction fanewsketchdir, String lname, int subsetstyleindex)
{
// if new symbols type we should be able to edit the name before creating.
// determin if this is the sketch type (needs refining)
OneSketch tsketch = new OneSketch(FileAbstraction.GetUniqueSketchFileName(fanewsketchdir, GetActiveTunnelSketches(), lname));
if (GetActiveTunnelSketches() == vgsymbolstsketches)
{
tsketch.sketchsymbolname = tsketch.sketchfile.getName();
tsketch.bSymbolType = true;
}
tsketch.SetupSK();
// default to first value
if (subsetstyleindex != -1)
tsketch.SetSubsetAttrStyle(((SubsetAttrStyle)sketchdisplay.subsetpanel.jcbsubsetstyles.getItemAt(subsetstyleindex)), null);
tsketch.bsketchfilechanged = true;
// load into the structure and view it.
assert tsketch.bsketchfileloaded;
GetActiveTunnelSketches().add(tsketch);
tunnelfilelist.RemakeTFList();
tunnelfilelist.tflist.setSelectedIndex(tunnelfilelist.isketche - 1);
tunnelfilelist.UpdateSelect(true); // doubleclicks it.
}
/////////////////////////////////////////////
OneSketch FindSketchFrame(List tsketches, FileAbstraction fasketch)
{
System.out.println("finding sketchframes " + tsketches.size() + " " + fasketch.getPath());
// account for which sketches have actually been loaded
for (OneSketch ltsketch : tsketches)
{
if (fasketch.equals(ltsketch.sketchfile))
{
if (ltsketch.bsketchfileloaded)
return ltsketch;
else
{
tunnelloader.LoadSketchFile(ltsketch, true);
tunnelfilelist.tflist.repaint();
return ltsketch;
}
}
}
fasketch.xfiletype = fasketch.GetFileType(); // part of the constructor?
OneSketch tsketch = new OneSketch(fasketch);
if (GetActiveTunnelSketches() == vgsymbolstsketches)
{
tsketch.sketchsymbolname = tsketch.sketchfile.getName();
tsketch.bSymbolType = true;
}
tunnelloader.LoadSketchFile(tsketch, true);
// if fails return null
GetActiveTunnelSketches().add(tsketch);
tunnelfilelist.tflist.repaint();
tunnelfilelist.RemakeTFList();
return tsketch;
}
/////////////////////////////////////////////
void UpdateSketchFrames(OneSketch tsketch, int iProper)
{
List framesketchesseen = (iProper != SketchGraphics.SC_UPDATE_NONE ? new ArrayList() : null);
for (OneSArea osa : tsketch.vsareas)
{
if ((osa.iareapressig == SketchLineStyle.ASE_SKETCHFRAME) && (osa.opsketchframedefs != null))
{
for (OnePath op : osa.opsketchframedefs)
{
SketchFrameDef sketchframedef = op.plabedl.sketchframedef;
if (!op.bpathvisiblesubset)
{
System.out.println("skipping outofsubset sketchframe");
continue;
}
sketchframedef.SetSketchFrameFiller(this, tsketch.realposterpaperscale, tsketch.sketchLocOffset, tsketch.sketchfile);
OneSketch lpframesketch = sketchframedef.pframesketch;
if ((iProper != SketchGraphics.SC_UPDATE_NONE) && (lpframesketch != null))
{
// got to consider setting the sket
SubsetAttrStyle sksas = sketchdisplay.sketchlinestyle.subsetattrstylesmap.get(sketchframedef.sfstyle);
if ((sksas == null) && (sketchframedef.pframesketch.sksascurrent == null))
sksas = sketchdisplay.subsetpanel.sascurrent;
if ((sksas != null) && (sksas != sketchframedef.pframesketch.sksascurrent) && !framesketchesseen.contains(lpframesketch))
{
TN.emitMessage("Setting sketchstyle to " + sksas.stylename + " (maybe should relay the symbols)");
int scchangetyp = sketchframedef.pframesketch.SetSubsetAttrStyle(sksas, sketchdisplay.sketchlinestyle.pthstyleareasigtab.sketchframedefCopied);
SketchGraphics.SketchChangedStatic(scchangetyp, lpframesketch, null);
}
// SketchGraphics.SC_UPDATE_ALL_BUT_SYMBOLS or SketchGraphics.SC_UPDATE_ALL
lpframesketch.UpdateSomething(iProper, false);
SketchGraphics.SketchChangedStatic(iProper, lpframesketch, null);
}
if ((framesketchesseen != null) && !framesketchesseen.contains(lpframesketch))
framesketchesseen.add(lpframesketch);
}
}
}
}
/////////////////////////////////////////////
/////////////////////////////////////////////
/////////////////////////////////////////////
public MainBox() // the main construction is done in init()
{
TN.mainbox = this;
textareaerrors.setBackground(new Color(1.0F, 0.8F, 0.8F));
textareaerrors.setRows(4);
// hide for AppletConversion
setTitle("TunnelX - " + TN.tunnelversion);
setLocation(new Point(100, 100));
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent event) { MainExit(); } } );
}
// need to load the fontcolours.xml which will then call in a bunch of symbols that need to be loaded
// into vgsymbolss.
// each of these resources comes in as a name
//
// LoadSymbols
public void init()
{
FileAbstraction.InitFA();
if (FileAbstraction.helpFile != null)
instanthelp = new InstantHelp(this);
sketchdisplay = new SketchDisplay(this);
tunnelloader = new TunnelLoader(false, sketchdisplay.sketchlinestyle);
tunnelfilelist = new TunnelFileList(this);
symbollayoutprocess = new SymbolLayoutProcess(this);
JMenuItem miOpenXMLDir = new JMenuItem("Open Sketches Directory...");
miOpenXMLDir.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { MainOpen(null, SvxFileDialog.FT_DIRECTORY); } } );
JMenuItem miOpen = new JMenuItem("Open Sketch...");
miOpen.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { MainOpen(null, SvxFileDialog.FT_XMLSKETCH); } } );
JMenuItem miOpenSVX = new JMenuItem("Open Survex/Topo...");
miOpenSVX.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { MainOpen(null, SvxFileDialog.FT_SVX); } } );
JMenuItem miSaveAll = new JMenuItem("Save All");
miSaveAll.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { MainSaveAll(); } } );
JMenuItem miRefresh = new JMenuItem("Refreshhh");
miRefresh.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { MainRefresh(); } } );
miNetConnection = new JCheckBoxMenuItem("Net Connection", false);
miNetConnection.setEnabled(false);
JMenuItem miExit = new JMenuItem("Exit");
miExit.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { MainExit(); } } );
JMenuItem miSketch = new JMenuItem("View Sketch");
miSketch.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { ViewSketch((tunnelfilelist.activesketchindex != -1 ? GetActiveTunnelSketches().get(tunnelfilelist.activesketchindex) : null)); } } );
miViewSymbolsList = new JCheckBoxMenuItem("Symbols List", false);
miViewSymbolsList.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { tunnelfilelist.RemakeTFList(); } } );
JMenuItem miNewEmptySketch = new JMenuItem("New Empty Sketch");
miNewEmptySketch.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event) { NewSketch(TN.currentDirectory, "sketch", -1); } } );
// build the layout of the menu bar
JMenuBar menubar = new JMenuBar();
JMenu menufile = new JMenu("File");
if (!FileAbstraction.bIsApplet) // or use disable function on them to grey them out.
{
menufile.add(miOpen);
menufile.add(miOpenSVX);
menufile.add(miOpenXMLDir);
}
menufile.add(miNewEmptySketch);
menufile.add(miRefresh);
if (!FileAbstraction.bIsApplet)
{
menufile.add(miSaveAll);
menufile.add(miNetConnection);
menufile.add(miExit);
}
menubar.add(menufile);
JMenu menutunnel = new JMenu("Tunnel");
menutunnel.add(miViewSymbolsList);
menutunnel.add(miSketch);
menubar.add(menutunnel);
if (instanthelp != null)
{
JMenu menuHelp = new JMenu("Help");
for (JMenuItem mihelp : instanthelp.mihelpsmain)
menuHelp.add(mihelp);
menubar.add(menuHelp);
}
setJMenuBar(menubar);
tunnelfilelist.setPreferredSize(new Dimension(600, 300));
JSplitPane vsplitpane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
vsplitpane.setLeftComponent(tunnelfilelist);
vsplitpane.setRightComponent(new JScrollPane(textareaerrors));
getContentPane().add(vsplitpane);
pack(); //hide for AppletConversion
tunnelfilelist.jsp.setDividerLocation(0.3);
vsplitpane.setDividerLocation(0.8);
setVisible(true);
// load the symbols from the current working directory.
// byproduct is it will load the stoke colours too
LoadSymbols(FileAbstraction.currentSymbols);
sketchdisplay.miUseSurvex.setSelected(FileAbstraction.SurvexExists());
if (sketchdisplay.sketchlinestyle.bsubsetattributesneedupdating) // false is no subsetattributes ever got loaded (ie wasn't such a file in symbols directory)
sketchdisplay.sketchlinestyle.UpdateSymbols(true);
if (SketchLineStyle.strokew == -1.0F)
{
SketchLineStyle.SetStrokeWidths(0.625F, sketchdisplay.miNotDotted.isSelected());
if (sketchdisplay.todenodepanel != null)
sketchdisplay.todenodepanel.BuildSpirals();
}
}
/////////////////////////////////////////////
// we should soon be loading these files from the same place as the svx as well as this general directory
void LoadSymbols(FileAbstraction fasymbols)
{
TN.emitWarning("Loading symbols dir: " + fasymbols.getAbsolutePath());
// do the tunnel loading thing
TunnelLoader symbtunnelloader = new TunnelLoader(true, sketchdisplay.sketchlinestyle);
try
{
vgsymbolsdirectory = fasymbols;
int nfl = allfontcolours.size();
fasymbols.FindFilesOfDirectory(vgsymbolstsketches, allfontcolours);
for (int i = nfl; i < allfontcolours.size(); i++)
symbtunnelloader.LoadFontcolour(allfontcolours.get(i));
// load up sketches
for (OneSketch tsketch : vgsymbolstsketches)
symbtunnelloader.LoadSketchFile(tsketch, false);
}
catch (IOException ie)
{
TN.emitWarning(ie.toString());
ie.printStackTrace();
}
catch (NullPointerException e)
{
TN.emitWarning(e.toString());
e.printStackTrace();
};
}
/////////////////////////////////////////////
List GetActiveTunnelSketches()
{
return (miViewSymbolsList.isSelected() ? vgsymbolstsketches : ftsketches);
}
/////////////////////////////////////////////
// startup the program
public static void main(String args[])
{
//System.out.println("Content-Type: text/plain\n");
//System.out.println("Hi there");
//System.exit(0);
String fstart = null;
// produce a default
//fstart = "http://seagrass.goatchurch.org.uk/~expo/tunneldata/";
String snetconnection = null;
boolean bmakeimages = false;
boolean btwotone = false;
for (int i = 0; i < args.length; i++)
{
if (!args[i].substring(0, 2).equals("--"))
fstart = args[i];
else if (args[i].equals("--verbose"))
TN.bVerbose = true;
else if (args[i].equals("--quiet"))
TN.bVerbose = false;
else if (args[i].equals("--todenode"))
TN.bTodeNode = true;
else if (args[i].equals("--netconnection"))
snetconnection = "http://localhost:8000/run/tunnelx_receiver/";
else if (args[i].equals("--makeimages"))
bmakeimages = true;
else if (args[i].startsWith("--printdir="))
TN.currprintdir = FileAbstraction.MakeDirectoryFileAbstraction(args[i].substring(11));
else if (args[i].equals("--twotone"))
btwotone = true;
else
TN.emitWarning("Unknown arg: " + args[i]);
}
// start-up
FileAbstraction.bIsApplet = false;
TN.currentDirectory = FileAbstraction.MakeCurrentUserDirectory();
TN.currentDirectoryIMG = FileAbstraction.MakeCurrentUserDirectory();
MainBox mainbox = new MainBox();
mainbox.init(); // the init gets called
if (btwotone)
mainbox.sketchdisplay.printingpanel.cbBitmaptype.setSelectedIndex(2);
// do the filename
if (fstart != null)
{
FileAbstraction fastart = FileAbstraction.MakeOpenableFileAbstraction(fstart);
fastart = FileAbstraction.MakeCanonical(fastart);
if (fastart.localurl == null)
TN.currentDirectory = fastart;
fastart.xfiletype = fastart.GetFileType();
int ftype = (fastart.isDirectory() ? SvxFileDialog.FT_DIRECTORY : (fastart.xfiletype == FileAbstraction.FA_FILE_XML_SKETCH ? SvxFileDialog.FT_XMLSKETCH : SvxFileDialog.FT_SVX));
mainbox.MainOpen(fastart, ftype);
}
// the command line to generate bitmaps directly from all the frame sketches
if (bmakeimages)
{
if ((fstart != null) && (mainbox.sketchdisplay.sketchgraphicspanel.tsketch != null))
mainbox.sketchdisplay.MakeImages();
else
TN.emitError("Must specify a sketch on the command line to do makeimages");
}
if (snetconnection != null)
mainbox.netconnection.ncstart(snetconnection);
}
/////////////////////////////////////////////
boolean bFileLoaded = false;
public void start()
{
assert FileAbstraction.bIsApplet;
if (bFileLoaded)
return;
ClassLoader cl = MainBox.class.getClassLoader();
TN.currentDirectory = new FileAbstraction();
TN.currentDirectoryIMG = new FileAbstraction();
// uncomment for AppletConversion
// TN.currentDirectory.localurl = cl.getResource(getParameter("cavedir"));
// TN.currentDirectory.bIsDirType = true;
// System.out.println("inputdir: " + getParameter("cavedir"));
// System.out.println("currentdir: " + TN.currentDirectory.localurl);
// MainOpen(true, SvxFileDialog.FT_DIRECTORY);
//LoadTunnelDirectoryTree("cavecave", TN.currentDirectory);
MainRefresh();
bFileLoaded = true;
}
/////////////////////////////////////////////
public void stop()
{
}
/////////////////////////////////////////////
public void destroy()
{
}
/////////////////////////////////////////////
public String getAppletInfo()
{
return "tunnelx applet. Protected by the GPL";
}
}
tunnelx-20190701/src/NetConnection.java 0000664 0001750 0001750 00000036020 13531571147 017302 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2011 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.util.List;
import java.util.ArrayList;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.net.URLClassLoader;
import java.net.URL;
import java.net.URLConnection;
import java.net.MalformedURLException;
import java.net.ConnectException;
import java.util.Collections;
/////////////////////////////////////////////
class PthChange
{
String uuid;
String action;
String val = "";
String sketchuuid;
PthChange(OnePath op, String laction, String lsketchuuid)
{
uuid = op.uuid;
action = laction;
sketchuuid = lsketchuuid;
if (action.equals("add"))
{
LineOutputStream los = new LineOutputStream();
try {
op.WriteXMLpath(los, -1, -1, 0); }
catch (IOException ie) {;}
val = los.sb.toString();
}
}
}
////////////////////////////////////////////////////////////////////////////////
class NetConnection implements Runnable
{
URL urlnetconnection = null;
Thread ncthread = null;
List pthchanges = Collections.synchronizedList(new ArrayList());
MainBox mainbox;
NetConnection(MainBox lmainbox)
{
mainbox = lmainbox;
}
/////////////////////////////////////////////
public void run()
{
try
{
while (true)
{
Thread.sleep(500);
if (!pthchanges.isEmpty())
PostPathChangeBatch();
}
}
catch (InterruptedException ie)
{;}
ncthread = null;
}
/////////////////////////////////////////////
void PostPathChangeBatch()
{
List args = new ArrayList();
int ipthchanges = 0;
String lsketchuuid = null;
for ( ; ipthchanges < 10; ipthchanges++)
{
if (ipthchanges >= pthchanges.size())
break;
if (ipthchanges == 0)
lsketchuuid = pthchanges.get(ipthchanges).sketchuuid;
else if (!pthchanges.get(ipthchanges).sketchuuid.equals(lsketchuuid))
break;
PthChange pthchange = pthchanges.get(ipthchanges);
args.add("uuid_"+ipthchanges);
args.add(pthchange.uuid);
args.add("action_"+ipthchanges);
args.add(pthchange.action);
args.add("val_"+ipthchanges);
args.add(pthchange.val);
}
if (ipthchanges == 0)
return;
args.add("npthchanges");
args.add(String.valueOf(ipthchanges));
args.add("sketchuuid");
args.add(lsketchuuid);
try
{
String res = SimplePost(urlnetconnection, args);
System.out.println(res);
}
catch (ConnectException ce)
{
TN.emitWarning("Connection refused, turning off");
mainbox.miNetConnection.setState(false);
return;
}
catch (IOException ie) { System.out.println(ie); }
while (ipthchanges > 0)
pthchanges.remove(--ipthchanges);
}
/////////////////////////////////////////////
void netcommitpathchange(OnePath op, String action, OneSketch tsketch)
{
if (mainbox.miNetConnection.getState())
pthchanges.add(new PthChange(op, action, tsketch.sketchfile.getPath()));
}
/////////////////////////////////////////////
void ncstart(String snetconnection)
{
try
{
urlnetconnection = new URL(snetconnection);
}
catch (MalformedURLException e)
{ TN.emitWarning("yyy"); return; }
ncthread = new Thread(this);
ncthread.start();
mainbox.miNetConnection.setState(true);
try
{
List args = new ArrayList();
args.add("connectionmade");
args.add(TN.tunnelversion);
String d = SimplePost(urlnetconnection, args);
System.out.println("Response:"+d);
}
catch (ConnectException ce)
{
TN.emitWarning("Connection refused, turning off");
mainbox.miNetConnection.setState(false);
}
catch (IOException ie) {;}
}
/////////////////////////////////////////////
/////////////////////////////////////////////
static String boundry = "-----xxxxxxxBOUNDERxxxxdsx"; // something that is unlikely to appear in the text
public static void writeField(DataOutputStream out, String name, String value) throws java.io.IOException
{
out.writeBytes("--");
out.writeBytes(boundry);
out.writeBytes("\r\n");
out.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"");
out.writeBytes("\r\n");
out.writeBytes("\r\n");
out.writeBytes(value);
out.writeBytes("\r\n");
out.flush();
//TN.emitMessage("WriteField: " + name + "=" + value);
}
/////////////////////////////////////////////
static void writeTileImageFile(DataOutputStream out, String fieldname, String filename, BufferedImage bi) throws java.io.IOException
{
out.writeBytes("--");
out.writeBytes(boundry);
out.writeBytes("\r\n");
out.writeBytes("Content-Disposition: form-data; name=\"" + fieldname + "\"; filename=\"" + filename + "\"");
out.writeBytes("\r\n");
out.writeBytes("Content-Type: image/png");
out.writeBytes("\r\n");
out.writeBytes("\r\n");
ImageIO.write(bi, "png", out);
out.writeBytes("\r\n");
}
/////////////////////////////////////////////
static void writeSketchFile(DataOutputStream out, String name, String fileName, OneSketch tsketch) throws java.io.IOException
{
out.writeBytes("--");
out.writeBytes(boundry);
out.writeBytes("\r\n");
out.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + fileName + "\"");
out.writeBytes("\r\n");
out.writeBytes("Content-Type: text/plain");
out.writeBytes("\r\n");
out.writeBytes("\r\n");
LineOutputStream los = new LineOutputStream(out);
tsketch.SaveSketchLos(los);
out.writeBytes("\r\n");
}
/////////////////////////////////////////////
/////////////////////////////////////////////
// returns the URL of the image that has been uploaded
// should be a member function
public static FileAbstraction uploadFile(FileAbstraction target, String fieldname, String filename, BufferedImage bi, OneSketch tsketch)
{
String fres = "";
try
{
assert target.localurl != null;
String response = "";
URL url = target.localurl;
// append a command onto the end of the url to say what we're doing
if (url.toString().endsWith(".xml"))
url = new URL(url.toString() + "/upload");
TN.emitMessage("About to post\nURL: " + url.toString());
URLConnection conn = url.openConnection();
// Set connection parameters.
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
// Make server believe we are form data
conn.setRequestProperty("Content-Type",
"multipart/related; boundary=" + boundry);
// connection.setRequestProperty("MIME-version", "1.0");
DataOutputStream out = new DataOutputStream (conn.getOutputStream());
// out.write(("--" + boundry + " ").getBytes());
// write some fields
writeField(out, "tunneluser", TN.tunneluser);
writeField(out, "tunnelpassword", TN.tunnelpassword);
writeField(out, "tunnelproject", TN.tunnelproject);
writeField(out, "tunnelversion", TN.tunnelversion);
// Write out the bytes of the content string to the stream.
assert ((bi == null) != (tsketch == null));
if (bi != null)
writeTileImageFile(out, fieldname, filename, bi);
else
writeSketchFile(out, fieldname, filename, tsketch);
out.writeBytes("--");
out.writeBytes(boundry);
out.writeBytes("--");
out.writeBytes("\r\n");
out.flush();
out.close();
// Read response from the input stream (should detect the file name).
// directly from fileupload.html in the django template
String suploadedfile = "UPLOADEDFILE: ";
String smessage = "MESSAGE: ";
//Pattern pattuploadedfile = Pattern.compile("
UPLOADEDFILE: \"(.*?)\"");
//Pattern pattmessage = Pattern.compile("MESSAGE: (.*?)");
BufferedReader fin = new BufferedReader(new InputStreamReader(conn.getInputStream ()));
String fline;
System.out.println("Server response:");
while ((fline = fin.readLine()) != null)
{
System.out.println(":" + fline);
int iuploadedfile = fline.indexOf(suploadedfile);
if (iuploadedfile != -1)
{
fres = fline.substring(iuploadedfile + suploadedfile.length());
System.out.println("FIFIF:" + fres + ":::");
}
}
fin.close();
}
catch (MalformedURLException e)
{ TN.emitWarning("yyy"); return null;}
catch (IOException e)
{ TN.emitWarning("eee " + e.toString()); return null;}
return FileAbstraction.MakeOpenableFileAbstraction(fres);
}
/////////////////////////////////////////////
// see: http://seagrass.goatchurch.org.uk/~mjg/cgi-bin/addsurvey.py
//
//
//
//
public static void upmjgirebyoverlay(BufferedImage bi, String name, double dpmetrereal, double cornercoordX, double cornercoordY, String spatial_reference_system)
{
try
{
String target = "http://seagrass.goatchurch.org.uk/caves/image/upload_and_locate_image";
TN.emitMessage("About to post\nURL: " + target);
System.out.println(" fname=" + name + " ----dots per metre " + dpmetrereal + " XX " + cornercoordX + " YY " + cornercoordY + " spatial_system " + spatial_reference_system);
String response = "";
URL url = new URL(target);
URLConnection conn = url.openConnection();
// Set connection parameters.
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
// Make server believe we are form data
conn.setRequestProperty("Content-Type",
"multipart/related; boundary=" + boundry);
// connection.setRequestProperty("MIME-version", "1.0");
DataOutputStream out = new DataOutputStream(conn.getOutputStream());
// out.write(("--" + boundry + " ").getBytes());
// write some fields
// name=surveyname, acknowledgment=tunnelupload, copyright=left
writeField(out, "name-name", name);
writeField(out, "acknowledgment", "tunnelupload");
writeField(out, "copyright", "left");
writeField(out, "tunnelversion", TN.tunnelversion);
//writeField(out, "spatial_reference_system", "WGS84-UTM30");
int srsid = 31285; // MGI / M31
//if (spatial_reference_system.equals("OS Grid SD"))
// srsid = 13000;
double cavealtitude = 1800.0;
writeField(out, "at-srsid", String.valueOf(srsid));
// we want to get these all coming in from the change things
// the GPS signals are 50 apart.
// GPS from the Ireby is *fix 001 66668.00 78303.00 319.00 ;GPS Added 09/01/05 N.P
double gpx = cornercoordX;
double gpy = cornercoordY;
//double gpx = 532601 + (cornercoordX - 66668.00);
//double gpy = 6004830 + (cornercoordY - 78303.00);
double d100 = dpmetrereal * 100;
String sd100 = String.valueOf(d100);
String sdYbot = String.valueOf(bi.getHeight());
String sdYbotup100 = String.valueOf(bi.getHeight() - d100);
writeField(out, "p1-worldX", String.valueOf(gpx));
writeField(out, "p1-worldY", String.valueOf(gpy - 100));
writeField(out, "p1-imageX", "0");
writeField(out, "p1-imageY", sdYbotup100);
writeField(out, "p2-worldX", String.valueOf(gpx + 100));
writeField(out, "p2-worldY", String.valueOf(gpy - 100));
writeField(out, "p2-imageX", sd100);
writeField(out, "p2-imageY", sdYbotup100);
writeField(out, "p3-worldX", String.valueOf(gpx));
writeField(out, "p3-worldY", String.valueOf(gpy));
writeField(out, "p3-imageX", "0");
writeField(out, "p3-imageY", sdYbot);
writeField(out, "at-average_image_altitude", String.valueOf(cavealtitude));
// Write out the bytes of the content string to the stream.
writeTileImageFile(out, "name-image", name + ".png", bi);
out.writeBytes("--");
out.writeBytes(boundry);
out.writeBytes("--");
out.writeBytes("\r\n");
out.flush();
out.close();
BufferedReader fin = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String fline;
System.out.println("Server response:");
while ((fline = fin.readLine()) != null)
System.out.println(":" + fline);
fin.close();
}
catch (MalformedURLException e)
{ TN.emitWarning("yyy");}
catch (IOException e)
{ TN.emitWarning("eee " + e.toString());};
}
public static String SimplePost(URL url, List args) throws IOException
{
URLConnection conn = url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestProperty("Content-Type", "multipart/related; boundary=" + boundry);
DataOutputStream out = new DataOutputStream(conn.getOutputStream());
for (int i = 1; i < args.size(); i += 2)
writeField(out, args.get(i-1), args.get(i));
out.writeBytes("--");
out.writeBytes(boundry);
out.writeBytes("--");
out.writeBytes("\r\n");
out.flush();
out.close();
BufferedReader fin = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuffer response = new StringBuffer();
String fline;
while ((fline = fin.readLine()) != null)
{ response.append(fline); response.append(TN.nl); }
fin.close();
return response.toString();
}
}
tunnelx-20190701/src/TunnelTopParser.java 0000664 0001750 0001750 00000045601 13531571147 017646 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2011 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// FoUndation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
// See TopParser/readtop.py for the source code
import java.awt.geom.Line2D;
import java.util.List;
import java.util.ArrayList;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.awt.Font;
import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Rectangle2D.Float;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.FileReader;
import java.io.StreamTokenizer;
import java.io.InputStreamReader;
class TOPxsection
{
int x;
int y;
String stn;
float direction;
TOPxsection(InputStream inp) throws IOException
{
x = TunnelTopParser.ReadInt4(inp);
y = TunnelTopParser.ReadInt4(inp);
stn = TunnelTopParser.ReadStn(inp);
int idirection = TunnelTopParser.ReadInt4(inp);
if (idirection != -1)
direction = TunnelTopParser.adegrees(idirection);
else
direction = -1.0f;
System.out.println("Xsection "+ x +" "+y+" "+stn+" "+direction);
}
}
class TOPpolygon
{
int[] poly;
int col;
TOPpolygon(InputStream inp) throws IOException
{
//System.out.println("Polygon");
int a = TunnelTopParser.ReadInt4(inp);
poly = new int[a*2];
for (int i = 0; i 340.0));
double sumdist = 0.0;
double suminclination = 0.0;
double sumazimuth = 0.0;
String sumcomment = "";
for (TOPleg ntopleg = this; ntopleg != null; ntopleg = ntopleg.topleglink)
{
sumdist += ntopleg.dist;
suminclination += ntopleg.inclination;
sumazimuth += ntopleg.azimuth + (bazimuthnearzero && (ntopleg.azimuth < 180.0) ? 360.0 : 0.0);
if (!ntopleg.comment.equals(""))
sumcomment += ntopleg.comment+" ";
nduplicates++;
}
double avgdist = sumdist / nduplicates;
double avginclination = suminclination / nduplicates;
double avgazimuth = sumazimuth / nduplicates;
double extdist = 0.0;
double extinclination = 0.0;
double extazimuth = 0.0;
for (TOPleg ntopleg = this; ntopleg != null; ntopleg = ntopleg.topleglink)
{
extdist = Math.max(extdist, Math.abs(avgdist - ntopleg.dist));
extinclination = Math.max(extinclination, Math.abs(avginclination - ntopleg.inclination));
extazimuth = Math.max(extazimuth, Math.abs(avgazimuth - (ntopleg.azimuth + (bazimuthnearzero && (ntopleg.azimuth < 180.0) ? 360.0 : 0.0))));
}
String exts = "";
if ((extdist > 0.05) || (extinclination > 0.5) || (extazimuth > 0.5))
exts = String.format(" ext:%.1f,%.1f,%.1f ", extdist, extinclination, extazimuth);
if (avgazimuth >= 360.0)
avgazimuth -= 360.0;
String sflip = (bflip ? " " + TN.flipCLINEsignal : "");
return String.format("%s\t%s\t%.3f\t%.1f\t%.1f%s%s%s%s", fromstn, tostn, avgdist, avgazimuth, avginclination, sflip, exts, sumcomment, TN.nl);
}
}
/////////////////////////////////////////////
class TunnelTopParser
{
int version;
List planxsections = new ArrayList();
List elevxsections = new ArrayList();
StringBuilder sbsvx = new StringBuilder();
StringBuilder sbsvxsplay = new StringBuilder();
// look in LoadTopoSketch() in PocketTopoLoader.java
List vpathsplan = new ArrayList();
List vpathselev = new ArrayList();
static float TOPFILE_SCALE = 0.001F; // it's in milimetres
/////////////////////////////////////////////
static float adegrees(int bangle)
{
return 360*(float)bangle / 65536;
}
/////////////////////////////////////////////
static int ReadInt2(InputStream inp) throws IOException
{
int b0 = inp.read();
int b1 = inp.read();
int res = b0 + (b1 << 8);
//System.out.println("eee "+b0+" "+b1+" "+res);
return res;
}
/////////////////////////////////////////////
static int ReadInt4(InputStream inp) throws IOException
{
int b0 = inp.read();
int b1 = inp.read();
int b2 = inp.read();
int b3 = inp.read();
int res = b0 + (b1 << 8) + (b2 << 16) + (b3 << 24);
//System.out.println("eee "+b0+" "+b1+" "+b2+" "+b3+" "+res);
return res;
}
long ReadInt8(InputStream inp) throws IOException
{
long b0 = inp.read();
long b1 = inp.read();
long b2 = inp.read();
long b3 = inp.read();
long b4 = inp.read();
long b5 = inp.read();
long b6 = inp.read();
long b7 = inp.read();
long res = b0 + (b1 << 8) + (b2 << 16) + (b3 << 24) + (b4 << 32) + (b5 << 40) + (b6 << 48) + (b7 << 56);
//System.out.println("eee "+b0+" "+b1+" "+b2+" "+b3+" "+res);
return res;
}
/////////////////////////////////////////////
Date ReadDate(InputStream inp) throws IOException
{
long i1 = ReadInt4(inp);
long i2 = ReadInt4(inp);
long si = i1 + (i2<<32);
long sit = (si - 621355968000000000L) / 10000;
Date date = new Date(sit);
System.out.println(date);
return date;
// ticks = struct.unpack(' stationnodes) throws IOException
{
//System.out.println("Polygon");
int a = TunnelTopParser.ReadInt4(inp);
//System.out.println(col);
float xdisplace = 0.0F;
int x0 = TunnelTopParser.ReadInt4(inp);
int y0 = TunnelTopParser.ReadInt4(inp);
OnePathNode lpnstart = FindStationNode(null, x0, y0, stationnodes, xdisplace);
OnePath op = new OnePath(lpnstart);
for (int i = 1; i xsections, List toppaths, InputStream inp, List stationnodes) throws IOException
{
Rectangle2D res = null;
mapping(inp);
while (true)
{
int element = inp.read();
if (element == -1)
break; // end of file!
if (element == 0)
break;
if (element == 1)
{
OnePath topop = readTOPpolygon(inp, stationnodes);
if (res == null)
res = topop.getBounds(null).getBounds2D();
else
res.add(topop.getBounds(null));
toppaths.add(topop);
}
else if (element == 3)
xsections.add(new TOPxsection(inp));
else
TN.emitError("TOP Element number ["+element+"] not defined");
}
return res;
}
/////////////////////////////////////////////
void mapping(InputStream inp) throws IOException
{
//Gets the centre point of screen and scale of different views
int X = ReadInt4(inp);
int Y = ReadInt4(inp);
int scale = ReadInt4(inp);
System.out.println(X +" "+ Y +" "+ scale);
}
/////////////////////////////////////////////
static OnePathNode FindStationNode(String stn, int x, int y, List stationnodes, float xdisplace)
{
for (OnePathNode opn : stationnodes)
{
if (stn.equals(opn.pnstationlabel))
return opn;
}
// make new node in case of the sketch
OnePathNode opn = new OnePathNode(x * TOPFILE_SCALE * TN.CENTRELINE_MAGNIFICATION + xdisplace, y * TOPFILE_SCALE * TN.CENTRELINE_MAGNIFICATION, 0.0F);
opn.pnstationlabel = stn;
return opn;
}
/////////////////////////////////////////////
String GetSVX()
{
return sbsvx.toString();
}
boolean bsingledashsplays = false;
/////////////////////////////////////////////
boolean ParseTOPFile(FileAbstraction tfile)
{ try {
InputStream inp = tfile.GetInputStream();
byte[] htop = new byte[3];
inp.read(htop, 0, 3);
System.out.println(new String(htop));
assert "Top".equals(new String(htop));
version = inp.read();
int ntrips = ReadInt4(inp);
TN.emitWarning("We have a top file version " + version + " containing "+ntrips+" trips");
int lntrips = Math.max(ntrips, 1); // avoid array out of bounds exception when ntrips=0.
Date[] dates = new Date[lntrips];
String[] comments = new String[lntrips];
float[] declination = new float[lntrips];
for (int i = 0; i < ntrips; i++)
{
dates[i] = ReadDate(inp);
comments[i] = ReadComments(inp);
declination[i] = adegrees(ReadInt2(inp));
}
//legs/shots
int tripcount = 0;
sbsvx.append("*begin "+ tfile.getSketchName() + TN.nl);
sbsvx.append(";*require 1.????"+ TN.nl+ TN.nl);
tripcomments(sbsvx, comments[tripcount], dates[tripcount], declination[tripcount]);
int currenttrip = -1;
int currentdirection = -1;
sbsvx.append("*data normal from to tape compass clino ignoreall"+ TN.nl);
int nshots = ReadInt4(inp);
//sbsvx.append((r'\n',r'\n;',comments[tripcount]) + TN.nl);
List toplegs = new ArrayList();
for (int i = 0; i < nshots; i++)
{
//Station
String fromstn = ReadStn(inp);
String tostn = ReadStn(inp);
int dist = ReadInt4(inp);
float azimuth = adegrees(ReadInt2(inp));
float inclination = adegrees(ReadInt2(inp));
if (inclination > 180.0F)
inclination = inclination - 360.0F;
int flags = inp.read();
int roll = inp.read();
int tripindex = ReadInt2(inp);
String comment = "";
//bit 1 of flags is flip (left or right)
//bit 2 of flags indicates a comment
boolean bflip = ((flags & 1) == 1);
if ((flags & 2) == 2)
comment = ReadComments(inp);
// this accounts for the missing flips
// load into pockettopo to see if we can account for it!!!
//if (fromstn.equals("1-0") || fromstn.equals("1-1") || fromstn.equals("1-2") || fromstn.equals("5-3"))
// bflip = true;
//System.out.println("Flipflags="+flags+" on "+fromstn+" "+tostn);
// not sure what this bit is about, but have cleaned it up [maybe to do with survex extended elevations]
if (i == 0)
{
currenttrip = tripindex;
currentdirection = (flags & 1);
//assert(tostn.equals("-"));
//sbsvx.append((currentdirection == 1 ? "*eleft " : "*eright ") + fromstn +TN.nl);
}
else
{
if (currenttrip != tripindex);
{
//tripcomments(sbsvx, comments[tripcount], dates[tripcount], declination[tripcount]);
tripcount++;
currenttrip = tripindex;
}
}
TOPleg ntopleg = new TOPleg(fromstn, tostn, dist/1000.0, azimuth, inclination, 360*roll/256.0, tripindex, bflip, comment);
if ((toplegs.size() == 0) || !toplegs.get(toplegs.size() - 1).MergeDuplicate(ntopleg))
toplegs.add(ntopleg);
}
// very annoying *fix in here because you need to delete it to make the file work
// the first station to appear in the file sets the origin. problem is when it is connected
// to a series of anonymous stations and then you backsight to it
if (toplegs.size() != 0)
sbsvx.append(";; *fix "+toplegs.get(0).fromstn+" 0 0 0 ; default top fix for first station to appear"+TN.nl+TN.nl);
for (TOPleg topleg : toplegs)
//if (!topleg.tostn.equals("-")) // we can leave these anonymous legs in now
sbsvx.append(topleg.toString());
sbsvx.append(TN.nl);
/*sbsvx.append(";;;;;;;;;;;;"+TN.nl);
sbsvx.append("*flags splay"+TN.nl);
int nsplaycount = 1;
for (TOPleg topleg : toplegs)
{
if (topleg.tostn.equals("-"))
{
// this -n- format then can also be stripped out by FileAbstraction.RunSurvex
if (!bsingledashsplays)
topleg.tostn = "-"+nsplaycount+"-";
sbsvx.append(topleg.toString());
nsplaycount++;
}
}*/
sbsvx.append("*end "+ tfile.getSketchName());
sbsvx.append(TN.nl);
//System.out.println(tfile.getSketchName());
//Reference stations
int nrefstn = ReadInt4(inp);
System.out.println("Stn NS EW "+nrefstn);
for (int i = 0; i < nrefstn; i++)
{
String stn = ReadStn(inp);
long east = ReadInt8(inp);
long west = ReadInt8(inp);
int altitute = ReadInt2(inp);
String comment = ReadComments(inp);
}
//Overview Mapping information (not needed by import)
mapping(inp);
List stationnodes = new ArrayList();
Rectangle2D planrect = ReadDrawing(planxsections, vpathsplan, inp, stationnodes);
Rectangle2D elevrect = ReadDrawing(elevxsections, vpathselev, inp, stationnodes);
TN.emitMessage(" planrect "+planrect);
TN.emitMessage(" elevrect "+elevrect);
inp.close();
// example single path intop the file
// look in LoadTopoSketch() in PocketTopoLoader.java for more information (and how to do centrelines)
}
catch (IOException e)
{
TN.emitWarning(e.toString());
}
return false;
}
}
/*
def station(F):
#id's split into major.decimal(minor)
idd = struct.unpack(''
if (flags[0] & 0b00000010) == 0b000000010:
thline['comment'] = comments(F)
return thline
*/
tunnelx-20190701/src/MatchSketchCentrelines.java 0000664 0001750 0001750 00000041647 13531571147 021141 0 ustar wookey wookey ////////////////////////////////////////////////////////////////////////////////
// TunnelX -- Cave Drawing Program
// Copyright (C) 2008 Julian Todd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////////////
package Tunnel;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.Stack;
import java.util.Collections;
import java.util.Collection;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
//
//
// MatchSketchCentrelines
//
//
/////////////////////////////////////////////
class PrefixLeg
{
OnePath op;
String pnlabtail;
String pnlabhead;
float vx;
float vy;
// the begin-blocks for the tail and head labels
String pnlabblocktail;
String pnlabblockhead;
String pnlabstationtail;
String pnlabstationhead;
// matching destination
PrefixLeg pltmember = null;
/////////////////////////////////////////////
String desc()
{
return "Prefixleg "+pnlabtail+" "+pnlabhead+" "+vx+","+vy;
}
/////////////////////////////////////////////
PrefixLeg(OnePath lop)
{
op = lop;
pnlabtail = op.plabedl.centrelinetail.replaceAll("[|^]", ".");
pnlabhead = op.plabedl.centrelinehead.replaceAll("[|^]", ".");
int dotpnlabtail = pnlabtail.lastIndexOf(".");
pnlabblocktail = (dotpnlabtail != -1 ? pnlabtail.substring(0, dotpnlabtail) : "");
pnlabstationtail = (dotpnlabtail != -1 ? pnlabtail.substring(dotpnlabtail + 1) : pnlabtail);
int dotpnlabhead = pnlabhead.lastIndexOf(".");
pnlabblockhead = (dotpnlabhead != -1 ? pnlabhead.substring(0, dotpnlabhead) : "");
pnlabstationhead = (dotpnlabhead != -1 ? pnlabhead.substring(dotpnlabhead + 1) : pnlabhead);
vx = (float)(op.pnend.pn.getX() - op.pnstart.pn.getX());
vy = (float)(op.pnend.pn.getY() - op.pnstart.pn.getY());
}
/////////////////////////////////////////////
String FindCommonPrefix(PrefixLeg pl)
{
if (pnlabtail.endsWith(pl.pnlabtail) && pnlabhead.endsWith(pl.pnlabhead))
{
int lpt = pl.pnlabtail.length();
int lph = pl.pnlabhead.length();
int lt = pnlabtail.length();
int lh = pnlabhead.length();
if ((lpt == lt) && (lph == lh))
return "";
int ldt = lt - lpt - 1;
int ldh = lh - lph - 1;
if ((ldt >= 0) && (pnlabtail.charAt(ldt) == '.') && (ldh >= 0) && (pnlabhead.charAt(ldh) == '.'))
{
String prefixt = pnlabtail.substring(0, ldt + 1); // include the dot
String prefixh = pnlabhead.substring(0, ldh + 1);
if (prefixt.equals(prefixh))
return prefixt;
}
}
return null;
}
/////////////////////////////////////////////
float CompareDirection(PrefixLeg pl)
{
float lsq = vx * vx + vy * vy;
float losq = pl.vx * pl.vx + pl.vy * pl.vy;
float dot = vx * pl.vx + vy * pl.vy;
if (dot == 0.0F)
return 0.0F;
return Math.max(0.0F, dot / Math.max(lsq, losq));
}
}
/////////////////////////////////////////////
class PrefixCount implements Comparable
{
String prefixfrom;
String prefix;
float score = 0.0F;
int nscore = 0;
int nlegsfrom = 0;
int nlegsto = 0;
int i; // used when we are sorting by best for each prefix
PrefixCount(String lprefixfrom, String lprefix, int li, int lnlegsfrom, int lnlegsto)
{
prefixfrom = lprefixfrom;
prefix = lprefix;
i = li;
nlegsfrom = lnlegsfrom;
nlegsto = lnlegsto;
}
float avgscore()
{
float pres = score / Math.max(1, nscore);
if (prefixfrom.equals(prefix))
pres = (3 + pres) / 4;
// -2 attempt to mask mismatch on low numbers (eg 7 legs) where the end points are equated to something else and count against
float fac = 1.0F * nscore / Math.max(Math.max(nlegsfrom-2, nlegsto), 1);
return fac * pres;
}
String desc()
{
return "avgscore="+avgscore() + " prefix="+prefix + " prefixfrom="+prefixfrom + " score="+score+ " nscore="+nscore+ " nlegsfrom="+ nlegsfrom + " nlegsto=" + nlegsto;
}
public int compareTo(PrefixCount opc)
{
return (int)Math.signum(opc.avgscore() - avgscore());
}
}
/////////////////////////////////////////////
/////////////////////////////////////////////
class MatchSketchCentrelines
{
List blocknamesfrom = new ArrayList();
List blocknamesto = new ArrayList();
List prefixlegsfrom = new ArrayList();
List prefixlegsto = new ArrayList();
List prefixlegsfromunmatched = new ArrayList();
Map nodemapping = new HashMap();
/////////////////////////////////////////////
Map GetBlockMapping()
{
// make the lists of blocknames
Map > mblocknamesto = new HashMap >();
for (PrefixLeg plt : prefixlegsto)
{
if (!mblocknamesto.containsKey(plt.pnlabblocktail))
mblocknamesto.put(plt.pnlabblocktail, new ArrayList());
if (!mblocknamesto.containsKey(plt.pnlabblockhead))
mblocknamesto.put(plt.pnlabblockhead, new ArrayList());
if (plt.pnlabblocktail.equals(plt.pnlabblockhead))
mblocknamesto.get(plt.pnlabblocktail).add(plt);
}
blocknamesto.addAll(mblocknamesto.keySet());
Map > mblocknamesfrom = new HashMap >();
for (PrefixLeg plf : prefixlegsfrom)
{
if (!mblocknamesfrom.containsKey(plf.pnlabblocktail))
mblocknamesfrom.put(plf.pnlabblocktail, new ArrayList());
if (!mblocknamesfrom.containsKey(plf.pnlabblockhead))
mblocknamesfrom.put(plf.pnlabblockhead, new ArrayList());
if (plf.pnlabblocktail.equals(plf.pnlabblockhead))
mblocknamesfrom.get(plf.pnlabblocktail).add(plf);
}
blocknamesfrom.addAll(mblocknamesfrom.keySet());
// make the arrays of prefixcounts from-to
List< List > blockcorresp = new ArrayList< List >();
for (int i = 0; i < blocknamesfrom.size(); i++)
{
List pclist = new ArrayList();
for (int j = 0; j < blocknamesto.size(); j++)
{
String blocknamefrom = blocknamesfrom.get(i);
String blocknameto = blocknamesto.get(j);
/*System.out.println("\n\nblocknamefrom="+blocknamefrom);
for (PrefixLeg p : mblocknamesfrom.get(blocknamefrom))
System.out.println(p.desc());
System.out.println("blocknameto="+blocknameto);
for (PrefixLeg p : mblocknamesto.get(blocknameto))
System.out.println(p.desc()); */
pclist.add(new PrefixCount(blocknamefrom, blocknameto, i, mblocknamesfrom.get(blocknamefrom).size(), mblocknamesto.get(blocknameto).size()));
}
blockcorresp.add(pclist);
}
// insert all the possible corresponding edges according to each blockname and station names
for (PrefixLeg plf : prefixlegsfrom)
{
if (!plf.pnlabblocktail.equals(plf.pnlabblockhead))
continue;
for (PrefixLeg plt : prefixlegsto)
{
if (!plt.pnlabblocktail.equals(plt.pnlabblockhead))
continue;
if (plf.pnlabstationtail.equals(plt.pnlabstationtail) && plf.pnlabstationhead.equals(plt.pnlabstationhead))
{
int i = blocknamesfrom.indexOf(plf.pnlabblocktail);
int j = blocknamesto.indexOf(plt.pnlabblocktail);
PrefixCount pc = blockcorresp.get(i).get(j);
pc.score += plt.CompareDirection(plf);
pc.nscore++;
}
}
}
// print out the likely correspondences
List bestcorresp = new ArrayList();
for (int i = 0; i < blocknamesfrom.size(); i++)
{
Collections.sort(blockcorresp.get(i));
PrefixCount pc = blockcorresp.get(i).get(0);
bestcorresp.add(pc); // pc.i helps find it again
}
Collections.sort(bestcorresp);
// the map of blocknames to blocknames; connect first match to first match
Map blockmapping = new HashMap();
for (PrefixCount pc : bestcorresp)
{
for (PrefixCount tpc : blockcorresp.get(pc.i))
{
if (blockmapping.values().contains(tpc.prefix) || (tpc.nscore == 0))
continue;
TN.emitMessage("MM: " + tpc.desc());
if (true || (tpc.avgscore() > 0.5))
blockmapping.put(blocknamesfrom.get(pc.i), tpc.prefix);
else
TN.emitWarning("Rejecting map: "+tpc.desc()+" not enough agreement/overlap.\n\nPerhaps take out excess unmatched centrelines from source sketch");
break;
}
}
return blockmapping;
/*
// not very smart n^2 algorithm
Map prefixcounts = new HashMap();
for (PrefixLeg plf : prefixlegsfrom)
{
for (PrefixLeg plt : prefixlegsto) // the n^2 loop thing
{
String prefix = plt.FindCommonPrefix(plf);
if (prefix != null)
{
PrefixCount prefixcount = prefixcounts.get(prefix);
if (prefixcount == null)
{
prefixcount = new PrefixCount(prefix, -1);
prefixcounts.put(prefix, prefixcount);
}
prefixcount.score += plt.CompareDirection(plf);
}
}
}
List prefixcountlist = new ArrayList();
prefixcountlist.addAll(prefixcounts.values());
Collections.sort(prefixcountlist);
for (PrefixCount prefixcount : prefixcountlist)
System.out.println("Probable prefix: '" + prefixcount.prefix + "' score: " + prefixcount.score);
return (!prefixcountlist.isEmpty() ? prefixcountlist.get(0).prefix : null);
*/
}
/////////////////////////////////////////////
PrefixLeg IncreCorresp(PrefixLeg plf)
{
OnePathNode mpnstart = nodemapping.get(plf.op.pnstart);
OnePathNode mpnend = nodemapping.get(plf.op.pnend);
if ((mpnstart == null) && (mpnend == null))
return null;
// find the destination line that best shares the direction
PrefixLeg pltbest = null;
float pltbestcompare = 0.0F;
for (PrefixLeg plt : prefixlegsto)
{
if (((mpnstart == null) || (mpnstart == plt.op.pnstart)) && ((mpnend == null) || (mpnend == plt.op.pnend)))
{
float pltcompare = plf.CompareDirection(plt);
if ((pltbest == null) || (pltcompare > pltbestcompare))
{
pltbest = plt;
pltbestcompare = pltcompare;
}
}
}
return pltbest;
}
/////////////////////////////////////////////
boolean NodeMappingPut(OnePathNode opnf, OnePathNode opnt)
{
OnePathNode lopnt = nodemapping.get(opnf);
if (lopnt == null)
nodemapping.put(opnf, opnt);
else if (lopnt != opnt) // returns false
return !TN.emitWarning("NodeMappingPut mismatch:" + opnt.pnstationlabel + " " + lopnt.pnstationlabel);
return true;
}
/////////////////////////////////////////////
// need to find a mapping from centrelines in one to the other.
boolean CorrespMatching(List vpathsfrom, List vpathsto)
{
// add the paths into the prefixlegs structures
for (OnePath opt : vpathsto)
{
if ((opt.linestyle == SketchLineStyle.SLS_CENTRELINE) && (opt.plabedl != null) && opt.plabedl.IsCentrelineType())
prefixlegsto.add(new PrefixLeg(opt));
}
for (OnePath opf : vpathsfrom)
{
if ((opf.linestyle == SketchLineStyle.SLS_CENTRELINE) && (opf.plabedl != null) && opf.plabedl.IsCentrelineType())
prefixlegsfrom.add(new PrefixLeg(opf));
}
// make the likely mapping of blocks
Map