/******************************************************************************* * Breakout Cave Survey Visualizer * * Copyright (C) 2014 James Edwards * * jedwards8 at fastmail dot fm * * 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., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *******************************************************************************/ package org.breakout.model; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.PriorityQueue; import java.util.Set; import org.andork.math.misc.AngleUtils; import org.andork.math3d.Vecmath; public class Shot { private static class PriorityEntry implements Comparable<PriorityEntry> { public final Shot shot; public final double priority; public PriorityEntry(Shot shot, double priority) { super(); this.shot = shot; this.priority = priority; } @Override public int compareTo(PriorityEntry o) { return Double.compare(priority, o.priority); } } private static double angle(double a, double b) { double a1 = b - a; double a2 = b - a - Math.PI * 2.0; return Math.abs(a1) < Math.abs(a2) ? a1 : a2; } public static double averageAzm(double avgIncDegrees, double fsAzm, double bsAzm) { if (Math.abs(avgIncDegrees) == Math.toRadians(90.0)) { return 0.0; } if (Double.isInfinite(fsAzm) || Double.isInfinite(bsAzm)) { throw new IllegalArgumentException("fsAzm and bsAzm must be non-infinite"); } if (Double.isNaN(fsAzm)) { return bsAzm; } if (Double.isNaN(bsAzm)) { return fsAzm; } fsAzm %= Math.PI * 2.0; if (fsAzm < 0) { fsAzm += Math.PI * 2.0; } bsAzm %= Math.PI * 2.0; if (bsAzm < 0) { bsAzm += Math.PI * 2.0; } double bsAzm180 = (bsAzm + Math.PI) % Math.PI * 2.0; if (Math.abs(angle(fsAzm, bsAzm180)) < Math.abs(angle(fsAzm, bsAzm))) { bsAzm = bsAzm180; } return fsAzm + angle(fsAzm, bsAzm) * 0.5; } public static double averageInc(double fsInc, double bsInc) { if (Double.isNaN(fsInc)) { return bsInc; } else if (Double.isNaN(bsInc)) { return fsInc; } else { if (Math.signum(fsInc) != Math.signum(bsInc)) { double angle = Math.abs(fsInc) + Math.abs(bsInc); if (angle > Math.toRadians(4.0)) { bsInc = -bsInc; } } return (fsInc + bsInc) * 0.5; } } public static void computeConnected(Collection<Station> stations) { Set<Station> visited = new HashSet<Station>(); for (Station station : stations) { if (!Vecmath.hasNaNsOrInfinites(station.position)) { if (!visited.contains(station)) { computeConnected(station, visited); } } } } public static void computeConnected(Station start, Set<Station> visited) { if (Vecmath.hasNaNsOrInfinites(start.position)) { throw new IllegalArgumentException("start's position has NaN or infinite values"); } PriorityQueue<PriorityEntry> heap = new PriorityQueue<Shot.PriorityEntry>(10); for (Shot shot : start.shots) { if (Double.isNaN(shot.dist)) { if (Vecmath.hasNaNsOrInfinites(shot.otherStation(start).position)) { continue; } shot.dist = Vecmath.distance3(shot.from.position, shot.to.position); } shot.priorityEntry = new PriorityEntry(shot, shot.dist); heap.add(shot.priorityEntry); } visited.add(start); while (!heap.isEmpty()) { Station station = null; Shot shot = heap.poll().shot; if (visited.add(shot.from)) { try { shot.computeFrom(); } catch (Exception ex) { System.err.println("Can't caltulate: " + shot); } station = shot.from; } else if (visited.add(shot.to)) { try { shot.computeTo(); } catch (Exception ex) { System.err.println("Can't caltulate: " + shot); } station = shot.to; } if (station != null) { if (station.toString().equals("BH80")) { Station temp = station; while (temp != null) { System.out.println(temp); temp = temp.calcedFrom; } } for (Shot nextShot : station.shots) { if (nextShot == shot) { continue; } if (Double.isNaN(nextShot.dist)) { if (Vecmath.hasNaNsOrInfinites(nextShot.otherStation(station).position)) { continue; } nextShot.dist = Vecmath.distance3(nextShot.from.position, shot.to.position); } double dist = shot.priorityEntry.priority + nextShot.dist; if (nextShot.priorityEntry != null) { if (dist < nextShot.priorityEntry.priority) { heap.remove(nextShot.priorityEntry); nextShot.priorityEntry = new PriorityEntry(nextShot, dist); heap.add(nextShot.priorityEntry); } } else { nextShot.priorityEntry = new PriorityEntry(nextShot, dist); heap.add(nextShot.priorityEntry); } } } } } public static String getName(String fromName, String toName) { return String.valueOf(fromName) + " - " + String.valueOf(toName); } public int number = -1; public Station from; public Station to; public double dist = Double.NaN; public double azm = Double.NaN; public double inc = Double.NaN; public CrossSection fromXsection = new CrossSection(); public CrossSection toXsection = new CrossSection(); public float[][] fromSplayPoints; public float[][] fromSplayNormals; public float[][] toSplayPoints; public float[][] toSplayNormals; public Date date; PriorityEntry priorityEntry; public String desc; public double azimuthAt(Station station) { if (station == from) { return azm; } if (station == to) { return AngleUtils.oppositeAngle(azm); } else { throw new IllegalArgumentException("not one of this shot's stations"); } } public void computeFrom() { if (Vecmath.hasNaNsOrInfinites(to.position)) { throw new IllegalStateException("to.position has NaN or infinite values"); } if (!Vecmath.hasNaNsOrInfinites(from.position)) { deriveMeasurements(); } else { if (Double.isNaN(azm) || Double.isInfinite(azm)) { throw new IllegalStateException("azm is NaN or infinite"); } if (Double.isNaN(inc) || Double.isInfinite(inc)) { throw new IllegalStateException("inc is NaN or infinite"); } from.calcedFrom = to; from.position[0] = to.position[0] - Math.sin(azm) * Math.cos(inc) * dist; from.position[1] = to.position[1] - Math.sin(inc) * dist; from.position[2] = to.position[2] + Math.cos(azm) * Math.cos(inc) * dist; } } public void computeTo() { if (Vecmath.hasNaNsOrInfinites(from.position)) { throw new IllegalStateException("from.position has NaN or infinite values"); } if (!Vecmath.hasNaNsOrInfinites(to.position)) { deriveMeasurements(); } else { if (Double.isNaN(azm) || Double.isInfinite(azm)) { throw new IllegalStateException("azm is NaN or infinite"); } if (Double.isNaN(inc) || Double.isInfinite(inc)) { throw new IllegalStateException("inc is NaN or infinite"); } to.calcedFrom = from; to.position[0] = from.position[0] + Math.sin(azm) * Math.cos(inc) * dist; to.position[1] = from.position[1] + Math.sin(inc) * dist; to.position[2] = from.position[2] - Math.cos(azm) * Math.cos(inc) * dist; } } public CrossSection crossSectionAt(Station station) { if (station == from) { return fromXsection; } else if (station == to) { return toXsection; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } private void deriveMeasurements() { if (Double.isNaN(dist)) { dist = Vecmath.distance3(to.position, from.position); } double dx = to.position[0] - from.position[0]; double dy = to.position[1] - from.position[1]; double dz = to.position[2] - from.position[2]; double dxz = Math.sqrt(dx * dx + dz * dz); if (Double.isNaN(azm)) { azm = Math.atan2(dx, -dz); } if (Double.isNaN(inc)) { inc = Math.atan2(dy, dxz); } } public String getName() { return getName(from.name, to.name); } public double leftAt(Station station) { if (station == from) { if (fromXsection.type != CrossSectionType.LRUD) { throw new IllegalArgumentException("Invalid cross section type"); } return fromXsection.dist[0]; } else if (station == to) { if (toXsection.type != CrossSectionType.LRUD) { throw new IllegalArgumentException("Invalid cross section type"); } return toXsection.dist[1]; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } public float[] leftSplayNormalAt(Station station) { if (station == from) { return fromSplayNormals[0]; } else if (station == to) { return toSplayNormals[1]; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } public float[] leftSplayPointAt(Station station) { if (station == from) { return fromSplayPoints[0]; } else if (station == to) { return toSplayPoints[1]; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } public Station otherStation(Station station) { if (station == from) { return to; } else if (station == to) { return from; } else { throw new IllegalArgumentException("not one of this shot's stations"); } } public double rightAt(Station station) { if (station == from) { if (fromXsection.type != CrossSectionType.LRUD) { throw new IllegalArgumentException("Invalid cross section type"); } return fromXsection.dist[1]; } else if (station == to) { if (toXsection.type != CrossSectionType.LRUD) { throw new IllegalArgumentException("Invalid cross section type"); } return toXsection.dist[0]; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } public float[] rightSplayNormalAt(Station station) { if (station == from) { return fromSplayNormals[1]; } else if (station == to) { return toSplayNormals[0]; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } public float[] rightSplayPointAt(Station station) { if (station == from) { return fromSplayPoints[1]; } else if (station == to) { return toSplayPoints[0]; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } public void setCrossSectionAt(Station station, CrossSection xSection) { if (station == from) { fromXsection = xSection; } else if (station == to) { toXsection = xSection; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } public void setLeftSplayNormalAt(Station station, float[] splayNormal) { if (station == from) { fromSplayNormals[0] = splayNormal; } else if (station == to) { toSplayNormals[1] = splayNormal; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } public void setLeftSplayPointAt(Station station, float[] splayPoint) { if (station == from) { fromSplayPoints[0] = splayPoint; } else if (station == to) { toSplayPoints[1] = splayPoint; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } public void setRightSplayNormalAt(Station station, float[] splayNormal) { if (station == from) { fromSplayNormals[1] = splayNormal; } else if (station == to) { toSplayNormals[0] = splayNormal; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } public void setRightSplayPointAt(Station station, float[] splayPoint) { if (station == from) { fromSplayPoints[1] = splayPoint; } else if (station == to) { toSplayPoints[0] = splayPoint; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } public void setSplayNormalsAt(Station station, float[][] splayNormals) { if (station == from) { fromSplayNormals = splayNormals; } else if (station == to) { toSplayNormals = splayNormals; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } public void setSplayPointsAt(Station station, float[][] splayPoints) { if (station == from) { fromSplayPoints = splayPoints; } else if (station == to) { toSplayPoints = splayPoints; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } public float[][] splayNormalsAt(Station station) { if (station == from) { return fromSplayNormals; } else if (station == to) { return toSplayNormals; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } public float[][] splayPointsAt(Station station) { if (station == from) { return fromSplayPoints; } else if (station == to) { return toSplayPoints; } else { throw new IllegalArgumentException("the given station is not one of this shot's stations"); } } @Override public String toString() { return getName(); } }