Skip to content
This repository has been archived by the owner on Mar 21, 2023. It is now read-only.

Commit

Permalink
visual enhancements
Browse files Browse the repository at this point in the history
  • Loading branch information
Gliptal committed Feb 24, 2017
1 parent b5eb1cb commit 4abdd2f
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 124 deletions.
13 changes: 12 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
# python
__pycache__
*.xml

# generated
*.xml

#build
*.ico
*.spec
verpatch.exe

#privacy
ranges.yaml
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,12 @@
+ code refactoring
+ coordinates shifter
+ leeway parameters

#### 0.6.0-beta1

+ usage documentation
+ minor bugfixes
+ heading fix
+ heading flag
+ conventional ranges data
+ better rendering
64 changes: 60 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,76 @@
TASER
======

TAcview SlEds Renderer: generate `.xml` files to visually render SLED attack profiles in the Tacview 3D environment.
**TA**cview **S**l**E**ds **R**enderer: dynamically generate `.xml` files to visually render SLED attack profiles in the Tacview 3D environment. This tool will generate the attack wire, and track, release, abort, and floor altitude blocks relative to a specific target in a specific NTTR conventional range.

FRAMEWORK
Place `taser.exe` inside Tacview's `Data/Static Objects` folder:

![folder](http://i.imgur.com/UoaYtNk.jpg)

Open an elevated (administrator) cmd window in the folder:

![admin](http://i.imgur.com/WdNJzux.jpg)

Execute the application by typing `taser.exe` and passing all required and any optional parameters:

![cmd](http://i.imgur.com/lK5lKhR.jpg)

If no errors occur the application will generate an `.xml` and exit:

![result](http://i.imgur.com/DPDaZKN.jpg)

Analyze your attack runs with Tacview:

![tacview](http://i.imgur.com/B4emnDk.jpg)

USAGE
======

The development framework is powered by [python](https://www.python.org/), and the software packaged in an `.exe` by [py2exe](https://pypi.python.org/pypi/py2exe/).
`taser.py [-h] [-o file] [-l ft] [-e °] -b nm -r ft -t ft -p ft -a ft -f ft range target`

`range` is the short name of the range containing the target (e.g. "64C")
`target` is the name of the target, with dashes "-" replacing spaces " " (e.g. "West-Bomb-Circle")

| required | flag | shorthand | purpose | unit | default |
| :---: | :---: | :---: | --- | :---: | :---: |
| YES | --base | -b | SLED's *base* distance | nm | |
| YES | --roll | -r | SLED's *roll-in* MSL altitude | ft | |
| YES | --track | -t | SLED's *track* MSL altitude | ft | |
| YES | --pickle | -p | SLED's *release* MSL altitude | ft | |
| YES | --abort | -a | SLED's *abort* MSL altitude | ft | |
| YES | --floor | -f | SLED's *mimimum* MSL altitude | ft | |
| | --out | -o | name of the generated `.xml` file | | "sled" |
| | --leeway | -l | available +/- leeway for the SLED's *roll-in*, *release*, and *track* altitudes | ft | 200ft |
| | --entry | -e | available +/- leeway for the range's attack heading at the SLED's *roll-in* altitude | ° | 10° |

PLUGINS
Help is also available from the CLI itself by providing the `-h` (`--help`) flag.

FRAMEWORK
======

Development framework powered by [python](https://www.python.org/) and the following non-embedded plugins:

- [colorclass](https://pypi.python.org/pypi/colorclass)
- [dicttoxml](https://pypi.python.org/pypi/dicttoxml)
- [geopy](https://github.com/geopy/geopy)
- [PyYAML](http://pyyaml.org/)

BUILD
======

`.exe` packaging powered by [PyInstaller](http://www.pyinstaller.org/):

`pyinstaller --clean --workpath="../build" --distpath="../dist" --specpath="../dist" --add-data="../source/data;data" --onefile --icon="../dist/icon.ico" taser.py`

`.exe` versioning powered by [Simple Version Resource Tool](https://www.codeproject.com/articles/37133/simple-version-resource-tool-for-windows):

`verpatch.exe taser.exe /va /langid 0x0809 /high 0.6.0-beta1 /s desc "Generate Tacview .xml files to render SLED profiles." /s product "TAcview SlEds Renderer" /s (c) "CC Attribution-ShareAlike 4.0" /pv "0.6.0.0"`

DATA
======

The full targets data is not available in this public repository. Contact the [476th vFG](http://www.476vfightergroup.com/content.php) for further information.

CHANGELOG
======

Expand Down
Binary file added dist/taser.exe
Binary file not shown.
50 changes: 38 additions & 12 deletions source/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
FILE = None
LEEWAY = None
ENTRY = None
DIRECTION = None
BASE = None
ROLL = None
TRACK = None
Expand All @@ -23,26 +24,33 @@ def parse():
global FILE
global LEEWAY
global ENTRY
global DIRECTION
global BASE
global ROLL
global TRACK
global PICKLE
global ABORT
global FLOOR

parser = argparse.ArgumentParser(description="generate .xml files to visually render SLED attack profiles in the Tacview 3D environment")
parser = argparse.ArgumentParser(description="generate .xml files to visually render SLED attack profiles in the Tacview 3D environment version: 0.6.0-beta1")
parser.add_argument("-v", "--version", action="version", version="0.6.0-beta1")

parser.add_argument("range", type=str, help="the range containing the attacked target")
parser.add_argument("target", type=str, help="the attacked target")
parser.add_argument("-o", "--out", type=str, help="name of the generated .xml file", metavar="file", default="sled")
parser.add_argument("-l", "--leeway", type=_positive_int, help="available +/- leeway for roll-in, track, and release altitudes (in feet): default 200ft", metavar="ft", default=200)
parser.add_argument("-e", "--entry", type=_positive_int, help="available +/- leeway for the attack heading at roll-in (in degrees): defaulr 3°", metavar="°", default=3)
required_options = parser.add_argument_group("required SLED options")

optional_options = parser.add_argument_group("optional other parameters")
optional_options.add_argument("-o", "--out", type=str, help="name of the generated .xml file: default \"sled\"", metavar="file", default="sled")
optional_options.add_argument("-l", "--leeway", type=_positive_int, help="available +/- leeway for the SLED's roll-in, release, and track altitudes (in feet) [default: 200ft]", metavar="ft", default=200)
optional_options.add_argument("-e", "--entry", type=_angle, help="available +/- leeway for the range's attack heading at the SLED's roll-in altitude (in degrees) [default: 10°]", metavar="°", default=10)
optional_options.add_argument("-d", "--direction", type=_heading, help="required attack heading, overrides the range's default (in degrees)", metavar="°", default=None)

required_options = parser.add_argument_group("required SLED parametes")
required_options.add_argument("-b", "--base", type=_positive_int, help="base distance (in nautical miles)", metavar="nm", required=True)
required_options.add_argument("-r", "--roll", type=_positive_float, help="roll-in altitude (in feet)", metavar="ft", required=True)
required_options.add_argument("-t", "--track", type=_positive_float, help="track altitude (in feet)", metavar="ft", required=True)
required_options.add_argument("-p", "--pickle", type=_positive_float, help="release altitude (in feet)", metavar="ft", required=True)
required_options.add_argument("-a", "--abort", type=_positive_float, help="abort altitude (in feet)", metavar="ft", required=True)
required_options.add_argument("-f", "--floor", type=_positive_float, help="minimum altitude (in feet)", metavar="ft", required=True)
required_options.add_argument("-r", "--roll", type=_positive_float, help="roll-in altitude (in feet MSL)", metavar="ft", required=True)
required_options.add_argument("-t", "--track", type=_positive_float, help="track altitude (in feet MSL)", metavar="ft", required=True)
required_options.add_argument("-p", "--pickle", type=_positive_float, help="release altitude (in feet MSL)", metavar="ft", required=True)
required_options.add_argument("-a", "--abort", type=_positive_float, help="abort altitude (in feet MSL)", metavar="ft", required=True)
required_options.add_argument("-f", "--floor", type=_positive_float, help="minimum altitude (in feet MSL)", metavar="ft", required=True)

args = parser.parse_args()

Expand All @@ -51,6 +59,7 @@ def parse():
FILE = args.out
LEEWAY = args.leeway
ENTRY = args.entry
DIRECTION = args.direction
BASE = args.base
ROLL = args.roll
TRACK = args.track
Expand All @@ -71,7 +80,7 @@ def check_range():
break

if not found:
log.fail("no such range "+RANGE)
log.fail("no such range \""+RANGE+"\"")
raise Exception

def check_target():
Expand All @@ -87,11 +96,12 @@ def check_target():
break

if not found:
log.fail("no such target "+TARGET+" in range "+RANGE["name"])
log.fail("no such target \""+TARGET+"\" in range \""+RANGE["name"]+"\"")
raise Exception

def convert():
global LEEWAY
global DIRECTION
global BASE
global ROLL
global TRACK
Expand All @@ -100,6 +110,8 @@ def convert():
global FLOOR

LEEWAY = calc.ft_to_m(LEEWAY)
if DIRECTION is not None:
DIRECTION = calc.thdg_to_mhdg(DIRECTION)
BASE = calc.ft_to_m(BASE)
ROLL = calc.ft_to_m(ROLL)
TRACK = calc.ft_to_m(TRACK)
Expand All @@ -120,3 +132,17 @@ def _positive_float(value):
raise argparse.ArgumentTypeError("number must be positive")

return number

def _heading(value):
number = int(value)
if number < 0 or number > 359:
raise argparse.ArgumentTypeError("heading must be between 0° and 359°")

return number

def _angle(value):
number = int(value)
if number < 0 or number > 45:
raise argparse.ArgumentTypeError("entry leeway must be between 0° and 45°")

return number
26 changes: 14 additions & 12 deletions source/calc.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
import geopy
from geopy.distance import distance, VincentyDistance
import math
import re

def ft_to_m(ft):
return ft*0.3048

def thdg_to_mhdg(thdg):
return thdg

def reverse_heading(hdg):
return (hdg+180) % 360

def hypotenuse_from_catheti(h, l):
return math.sqrt((l**2)+(h**2))

def angle_from_catheti(h, l):
return math.degrees(math.atan(h/l))

def cathetus_from_angle(l, a):
def sin_cathetus_from_angle(l, a):
return l*math.tan(math.radians(a))

def reverse_heading(hdg):
return (hdg+180) % 360
def cos_cathetus_from_angle(h, a):
return h/math.tan(math.radians(a))

def shift_coords(coords, dist, hdg):
lat = _dms_to_dd(coords["latitude"])
lon = _dms_to_dd(coords["longitude"])

x = dist*math.cos(math.radians(hdg))
y = dist*math.sin(math.radians(hdg))

Dlat = x/6378137
Dlon = y/(6378137*math.cos(math.radians(lat)))

lat0 = lat+math.degrees(Dlat)
lon0 = lon+math.degrees(Dlon)
origin = geopy.Point(lat, lon)
destination = geopy.distance.VincentyDistance(kilometers=dist/1000).destination(origin, hdg)

return _dd_to_dms(lat0), _dd_to_dms(lon0)
return _dd_to_dms(destination.latitude)+"N", _dd_to_dms(destination.longitude)+"W"

def _dms_to_dd(dms):
parts = re.split('[°\'"]+', dms.replace("Â", ""))
Expand Down
13 changes: 12 additions & 1 deletion source/data.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import os
import sys

import yaml

import log


def load(path):
try:
file = open(path)
file = open(resource_path(path))
data = yaml.safe_load(file)
file.close()
except IOError:
log.fail("missing data file")
else:
return data

def resource_path(relative_path):
try:
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")

return os.path.join(base_path, relative_path)
62 changes: 0 additions & 62 deletions source/data/ranges.yaml

This file was deleted.

Loading

0 comments on commit 4abdd2f

Please sign in to comment.