orthographic/xp_dsfgen.py

216 lines
9.1 KiB
Python
Raw Normal View History

# -------------------------------------------------------------------
# ORTHOGRAPHIC
# Your personal aerial satellite. Always on. At any altitude.*
# Developed by MarStrMind
# License: Open Software License 3.0
# Up to date version always on marstr.online
# -------------------------------------------------------------------
# xp_dsfgen.py
# This class is coming into play at the very end of the tile
# generation process, and builds the DSF (Distributable Scenery
# Format) file for X-Plane.
#
# For this, you will need DSFTool which I cannot re-distribute.
#
# You can download it for free from X-Plane's website.
# Place them somewhere convenient, and point to them in the
# xp_ variables in defines.py
# -------------------------------------------------------------------
import os
import glob
import math
from random import randrange
from log import *
class mstr_xp_dsfgen:
# Instantiate with Lat/Lng, as usual
def __init__(self, lat, lng, mlat, mlng, vstep):
self._latitude = lat
self._longitude = lng
self._maxlat = mlat
self._maxlng = mlng
self._tmpdsf = mstr_datafolder + "_cache/tiledsf.txt"
self._vstep = vstep
self._dsfstring = ""
mstr_msg("xp_dsfgen", "[X-Plane] DSFgen initialized")
self.build_header()
# Construct header of DSF txt
def build_header(self):
self._dsfstring = self._dsfstring + "PROPERTY sim/west " + str(int(self._longitude)) + "\n"
self._dsfstring = self._dsfstring + "PROPERTY sim/east " + str(int(self._longitude + 1)) + "\n"
self._dsfstring = self._dsfstring + "PROPERTY sim/south " + str(int(self._latitude)) + "\n"
self._dsfstring = self._dsfstring + "PROPERTY sim/north " + str(int(self._latitude+1)) + "\n"
self._dsfstring = self._dsfstring + "PROPERTY sim/planet earth\n"
self._dsfstring = self._dsfstring + "PROPERTY sim/creation_agent Orthographic\n"
self._dsfstring = self._dsfstring + "PROPERTY sim/overlay 1\n" # <- DO NOT REMOVE THIS!!
self._dsfstring = self._dsfstring + "PROPERTY sim/require_facade 6/0\n"
mstr_msg("xp_dsfgen", "[X-Plane] DSF header built")
# Write the text file
def write_dsf_txt(self):
mstr_msg("xp_dsfgen", "[X-Plane] Writing DSF txt file")
with open(self._tmpdsf, 'w') as textfile:
textfile.write(self._dsfstring)
# Convert the DSF into actual, usable data for X-Plane
def convert_dsf_text(self):
mstr_msg("xp_dsfgen", "[X-Plane] Converting DSF information into X-Plane DSF file")
# Find separator
sep = ""
if os.name == "nt":
sep = "\\"
if os.name == "posix":
sep = "/"
datafolder = mstr_datafolder.replace("/", sep)
# First, create the Earth nav data folder should it not exist
end_base = datafolder + "Tiles/z_orthographic_" + self.xplane_latlng_folder([self._latitude, self._longitude]) + sep + "Earth nav data"
# Create the appropriate rounded folder
end_round = self.xplane_latlng_folder(self.find_earthnavdata_number())
if not os.path.exists(end_base):
os.makedirs(end_base)
if not os.path.exists(end_base + sep + end_round):
os.makedirs(end_base + sep + end_round)
# Get the file name for the DSF
end_latlng = self.xplane_latlng_folder([self._latitude, self._longitude])
# Perform conversion
os.system(mstr_xp_dsftool + " --text2dsf " + datafolder + "_cache" + sep + "tiledsf.txt \"" + end_base + sep + end_round + sep + end_latlng + ".dsf\"")
mstr_msg("xp_dsfgen", "[X-Plane] DSF conversion complete")
# Find the next "by-ten" numbers for the current latitude and longitude
def find_earthnavdata_number(self):
earthnavdata = []
lat = abs(int(self._latitude / 10) * 10)
lng = abs(int(self._longitude / 10) * 10)
earthnavdata.append(lat)
earthnavdata.append(lng)
return earthnavdata
# Find with of a longitude (needed for DSF and .pol files)
def _findWidthOfLongitude(self, lat):
dm = math.cos(math.radians(lat)) * 111.321 # <- 1 deg width at equator in km
return round(dm * 1000, 3)
# Find diameter of an ortho
def find_ortho_diameter(self, side):
sq = side * side
sqsum = sq + sq
dm = math.sqrt(sqsum)
# Construct an X-Plane compatible folder name for latitude and longitude
def xplane_latlng_folder(self, numbers):
fstr = ""
if numbers[0] >= 0: fstr = "+"
if numbers[0] < 0: fstr = "-"
if abs(numbers[0]) < 10: fstr = fstr + "0" + str(numbers[0])
if abs(numbers[0]) >= 10 and numbers[0] <= 90: fstr = fstr + str(numbers[0])
if numbers[1] >= 0: fstr = fstr + "+"
if numbers[1] < 0: fstr = fstr + "-"
if abs(numbers[1]) < 10: fstr = fstr + "00" + str(numbers[1])
if abs(numbers[1]) >= 10 and numbers[0] <= 99: fstr = fstr + "0" + str(numbers[1])
if abs(numbers[1]) >= 100 : fstr = fstr + str(numbers[1])
return fstr
# Build the complete DSF.
# This is the main function to call.
def build_dsf_for_tile(self):
mstr_msg("xp_dsfgen", "[X-Plane] Building DSF file")
# Add the polygon definition file entries
for v in range(1, self._maxlat+1):
for h in range(1, self._maxlng+1):
self._dsfstring = self._dsfstring + "POLYGON_DEF terrain/"+str(v)+"_"+str(h)+".pol\n"
# Add the definitions for each ortho tile
curpol = 0
cur_lat = self._latitude
cur_lng = self._longitude
for v in range(1, self._maxlat+1):
for h in range(1, self._maxlng+1):
bbox = [ cur_lat, cur_lng, cur_lat+self._vstep-0.00001, cur_lng + mstr_zl_18-0.00001 ]
self._dsfstring = self._dsfstring + "BEGIN_POLYGON "+str(curpol)+" 65535 4\n"
self._dsfstring = self._dsfstring + "BEGIN_WINDING\n"
self._dsfstring = self._dsfstring + "POLYGON_POINT " + str(bbox[1]) + " " + str(bbox[0]) + " 0.000000000 0.000000000\n"
self._dsfstring = self._dsfstring + "POLYGON_POINT " + str(bbox[3]) + " " + str(bbox[0]) + " 1.000000000 0.000000000\n"
self._dsfstring = self._dsfstring + "POLYGON_POINT " + str(bbox[3]) + " " + str(bbox[2]) + " 1.000000000 1.000000000\n"
self._dsfstring = self._dsfstring + "POLYGON_POINT " + str(bbox[1]) + " " + str(bbox[2]) + " 0.000000000 1.000000000\n"
self._dsfstring = self._dsfstring + "END_WINDING\n"
self._dsfstring = self._dsfstring + "END_POLYGON\n"
# Adjust forward
cur_lng = cur_lng + mstr_zl_18
curpol = curpol + 1
# Adjust up, reset longitude
cur_lng = self._longitude
cur_lat = cur_lat + self._vstep
# OK... we can now save this
self.write_dsf_txt()
# Generate the single .pol files now
mstr_msg("xp_dsfgen", "[X-Plane] Beginning generation of terrain/*.pol files")
cur_lat = self._latitude
cur_lng = self._longitude
lclat = cur_lat + (self._vstep/2)
lclng = cur_lng + (mstr_zl_18/2)
for v in range(1, self._maxlat+1):
for h in range(1, self._maxlng+1):
dm = self._findWidthOfLongitude(cur_lng) * mstr_zl_18
dg = self.find_ortho_diameter(dm)
polstr = ""
polstr = polstr + "A\n"
polstr = polstr + "850\n"
polstr = polstr + "DRAPED_POLYGON\n"
polstr = polstr + "\n"
polstr = polstr + "TEXTURE_NOWRAP ../orthos/"+str(v)+"_"+str(h)+".dds\n"
# Check for existence of a normal map
# If there is one, we will add that too
end_latlng = self.xplane_latlng_folder([self._latitude, self._longitude])
if os.path.isfile(mstr_datafolder + "Tiles/z_orthographic_"+end_latlng+"/normals/" + str(v) + "_" + str(h) + ".png") == True:
polstr = polstr + "TEXTURE_NORMAL 1 ../normals/"+str(v)+"_"+str(h)+".png\n"
polstr = polstr + "SCALE "+str(dm)+" "+str(dm)+"\n"
polstr = polstr + "LOAD_CENTER "+str(lclat)+" " +str(lclng)+" " +str(dg)+ " " +str(mstr_photores)+"\n"
polstr = polstr + "LAYER_GROUP TERRAIN 1\n"
# Save this content
with open(mstr_datafolder + "Tiles/z_orthographic_"+end_latlng+"/terrain/"+str(v)+"_"+str(h)+".pol", 'w') as textfile:
textfile.write(polstr)
# Adjust forward
cur_lng = cur_lng + mstr_zl_18
lclng = cur_lng + (mstr_zl_18/2)
cur_lng = self._longitude
lclng = cur_lng + (mstr_zl_18/2)
cur_lat = cur_lat + self._vstep
lclat = cur_lat + (self._vstep/2)
mstr_msg("xp_dsfgen", "[X-Plane] Converting DSF txt")
self.convert_dsf_text()
mstr_msg("xp_dsfgen", "[X-Plane] DSF for tile completed")
# Testing
dsf = mstr_xp_dsfgen(51, 7, 101, 63, 0.01010)
dsf.build_dsf_for_tile()