Commit 6877051e authored by Rick Gruber-Riemer's avatar Rick Gruber-Riemer

Clean-up of texture code and removal of -A option in osm2city

parent 591325b9
This diff is collapsed.
......@@ -21,6 +21,23 @@ Therefore before running ``osm2city`` related programs please either:
$ cd /home/pingu/fg_customscenery/projects
.. _chapter-create-texture-atlas:
==========================
Creating the Texture Atlas
==========================
In order to consume the textures linked as described in chapter :ref:`Creating Soft Links to Texture Data <chapter-texture_data-label>` a texture atlas needs to be created. As this is a bit of a time consuming task, re-creating a texture atlas should only be done if the contained textures change. That is rarely the case. Also remember that if the texture atlas changes, then also the content has to be copied separately (see :ref:`chapter-copy-textures-label`).
In most situations it is enough to call the following command once and then only if the textures have changed:
::
/usr/bin/python2.7 /home/pingu/develop_vcs/osm2city/textures/manager.py -f LSZS/params.ini -a
Alternatively `osm2city.py` can be called with the ``-a`` option.
====================
Overview of Programs
====================
......@@ -53,7 +70,7 @@ In most situations you may want to at least provide command line parameter ``-f`
::
/usr/bin/python2.7 /home/pingu/develop_vcs/osm2city/osm2city.py -f LSZS/params.ini -l DEBUG -a
/usr/bin/python2.7 /home/pingu/develop_vcs/osm2city/osm2city.py -f LSZS/params.ini -l DEBUG
Remember that the paths are relative to the ``WORKING_DIRECTORY``. Alternatively provide the full path to your ``params.ini`` [#]_ file.
......
......@@ -56,6 +56,8 @@ Do the following:
.. _Git: http://www.git-scm.com/
.. _chapter-texture_data-label:
-----------------------------------
Creating Soft Links to Texture Data
-----------------------------------
......@@ -76,3 +78,4 @@ On a Windows computer do the following (path may differ):
> mklink /J C:\development\osm2city\tex.src C:\development\osm2city-data\tex.src
> mklink /J C:\development\osm2city\tex C:\development\osm2city-data\tex
You might as well check your installation and :ref:`create a texture atlas <chapter-create-texture-atlas>` — doing so makes sure your installation works and you do not run into the problem of having an empty texture atlas.
No preview for this file type
......@@ -635,8 +635,6 @@ if __name__ == "__main__":
, help="skip elevation interpolation", required=False)
parser.add_argument("-c", dest="c", action="store_true"
, help="do not check for overlapping with static objects", required=False)
parser.add_argument("-A", "--create-atlas-only", action="store_true"
, help="create texture atlas and exit", required=False)
parser.add_argument("-a", "--create-atlas", action="store_true"
, help="create texture atlas", required=False)
parser.add_argument("-u", dest="uninstall", action="store_true"
......@@ -662,9 +660,6 @@ if __name__ == "__main__":
parameters.NO_ELEV = True
parameters.OVERLAP_CHECK = False
if args.create_atlas or args.create_atlas_only:
parameters.CREATE_ATLAS = True
parameters.show()
......@@ -676,10 +671,7 @@ if __name__ == "__main__":
tools.init(coordinates.Transformation(center, hdg=0))
tex.manager.init(tools.get_osm2city_directory(), create_atlas=parameters.CREATE_ATLAS)
if args.create_atlas_only:
sys.exit(0)
tex.manager.init(tools.get_osm2city_directory(), args.create_atlas)
logging.info("reading elevation data")
elev = tools.get_interpolator(fake=parameters.NO_ELEV)
......
......@@ -79,7 +79,6 @@ TELNET_PORT = 5501 # The port FlightGear listens to. Needed for ELEV_MODE = "Te
# PARAMETERS RELATED TO BUILDINGS IN osm2city
#=============================================================================
CREATE_ATLAS = True # -- create texture atlas on osm2city startup
ATLAS_SUFFIX_DATE = False # -- add timestamp to file name
# -- check for overlap with static models. The scenery folder must contain an "Objects" folder
......
......@@ -12,8 +12,6 @@ It is likely to contain some old, unsused stuff.
"""
PROG="texGUI.py"
import pdb
import wx
import sys
import os
......@@ -28,11 +26,12 @@ import shutil
static_msg = ""
def importName(modulename):
""" Import a named object from a module in the context of this function.
"""
# -- from "Importing from a Module Whose Name Is Determined at Runtime"
# Credit: Jrgen Hermann
# Credit: Jørgen Hermann
print modulename
modulename = string.split(modulename, '.')[0]
print modulename
......@@ -44,6 +43,7 @@ def importName(modulename):
return module
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
......@@ -395,7 +395,7 @@ if __name__ == "__main__":
(options, args) = parser.parse_args()
if len(sys.argv) < 2:
print "usage:", PROG, "image"
print "usage:", "texGUI.py", "image"
sys.exit(1)
app = wx.PySimpleApp(0)
......
#!/usr/bin/env python2
#
#
"""generate texture atlas"""
"""Atlas of textures, where a couple of textures are put into one file including thier attributes"""
import PIL.Image as Image
import logging
class Region(object):
"""Also used as a container for a single image"""
def __init__(self, x, y, width, height):
......@@ -13,18 +14,17 @@ class Region(object):
self.y = y
self.width_px = width
self.height_px = height
logging.verbose(" New Region " + str(self))# @UndefinedVariable
logging.debug(" New Region " + str(self)) # @UndefinedVariable
def __str__(self):
return "(%i x %i + %i + %i)" % (self.width_px, self.height_px,
self.x, self.y)
return "(%i x %i + %i + %i)" % (self.width_px, self.height_px, self.x, self.y)
class Atlas(Region):
def __init__(self, x, y, width, height, name):
super(Atlas, self).__init__(x, y, width, height)
self.regions = [Region(x, y, width, height)]
self._textures = []
self._textures = [] # Type atlas.Texture
self.min_width = 1
self.min_height = 1
self.name = name
......@@ -36,7 +36,7 @@ class Atlas(Region):
def set_height(self, height):
self.height_px = height
self._compute_nondim_tex_coords()
def write(self, filename, format, image_var):
"""Allocate memory for the actual atlas image, paste images, write to disk.
image_var is the name (string) of the class variable that stores the image;
......@@ -46,137 +46,92 @@ class Atlas(Region):
for the_texture in self._textures:
the_image = getattr(the_texture, image_var)
try:
atlas.paste(the_image, (the_texture._x, the_texture._y))
atlas.paste(the_image, (the_texture.ax, the_texture.ay))
except ValueError:
logging.debug("%s : %s: Skipping an empty texture" % (self.name, the_texture.filename))
atlas.save(filename, optimize=True)
def pack(self, the_texture):
logging.debug("packing %s (%i %i)" %
(the_texture.filename, the_texture.width_px, the_texture.height_px))
(the_texture.filename, the_texture.width_px, the_texture.height_px))
for the_region in self.regions:
if self._pack(the_texture, the_region):
self._textures.append(the_texture)
logging.verbose(" packed at %i %i" % (the_texture._x, the_texture._y))# @UndefinedVariable
logging.verbose("now have %i regions" % len(self.regions))# @UndefinedVariable
logging.debug(" packed at %i %i" % (the_texture.ax, the_texture.ay))
logging.debug("now have %i regions" % len(self.regions))
for the_region in self.regions:
logging.verbose(" - " + str(the_region))# @UndefinedVariable
logging.debug(" - " + str(the_region))
return True
return False
def pack_at(self, the_texture, x, y):
logging.debug("packing %s (%i %i) at (%i %i)" %
(the_texture.filename, the_texture.width_px, the_texture.height_px, x, y))
the_texture._x = x
the_texture._y = y
(the_texture.filename, the_texture.width_px, the_texture.height_px, x, y))
the_texture.ax = x
the_texture.ay = y
self._textures.append(the_texture)
def _compute_nondim_tex_coords(self):
def _compute_nondim_tex_coords(self):
"""compute non-dim texture coords"""
for t in self._textures:
t.x0 = float(t._x) / self.width_px
t.x1 = float(t._x + t.width_px) / self.width_px
t.y1 = 1 - float(t._y) / self.height_px
t.y0 = 1 - float(t._y + t.height_px) / self.height_px
t.x0 = float(t.ax) / self.width_px
t.x1 = float(t.ax + t.width_px) / self.width_px
t.y1 = 1 - float(t.ay) / self.height_px
t.y0 = 1 - float(t.ay + t.height_px) / self.height_px
t.sx = float(t.width_px) / self.width_px
t.sy = float(t.height_px) / self.height_px
def check_regions(self):
def _check_regions(self):
for region1 in self.regions:
if region1.width_px < self.min_width or region1.height_px < self.min_height:
self.regions.remove(region1)
for region2 in self.regions:
if region2 == region1: continue
if region2 == region1:
continue
# -- check if we can join two regions
if region1.x == region2.x and region1.width_px == region2.width_px \
and region1.y + region1.height_px == region2.y:
region1.height_px += region2.height_px
self.regions.remove(region2)
def _pack(self, the_texture, the_region):
assert(the_texture.height_px > 0)
assert(the_texture.width_px > 0)
if the_texture.height_px == the_region.height_px:
if the_texture.width_px == the_region.width_px:
logging.verbose("H split exact fit")# @UndefinedVariable
the_texture._x = the_region.x
the_texture._y = the_region.y
logging.debug("H split exact fit")
the_texture.ax = the_region.x
the_texture.ay = the_region.y
self.regions.remove(the_region)
return True
elif the_texture.width_px < the_region.width_px:
logging.verbose("H split")# @UndefinedVariable
# split horiz
the_texture._x = the_region.x
the_texture._y = the_region.y
logging.debug("H split")
# split horizontally
the_texture.ax = the_region.x
the_texture.ay = the_region.y
the_region.x += the_texture.width_px
the_region.width_px -= the_texture.width_px
self.check_regions()
self._check_regions()
return True
else:
logging.verbose("H too small (%i < %i), trying next" % (the_region.width_px, the_texture.width_px))# @UndefinedVariable
logging.debug("H too small (%i < %i), trying next" % (the_region.width_px, the_texture.width_px))
return False
elif the_texture.height_px > the_region.height_px:
logging.verbose("V too small, trying next")# @UndefinedVariable
logging.debug("V too small, trying next")
return False
else:
# check if it fits width
if the_texture.width_px > the_region.width_px:
return False
logging.verbose("V split")# @UndefinedVariable
logging.debug("V split")
# vertical split
the_texture._x = the_region.x
the_texture._y = the_region.y
new_region = Region(the_region.x, the_region.y + the_texture.height_px, the_region.width_px, the_region.height_px - the_texture.height_px)
the_texture.ax = the_region.x
the_texture.ay = the_region.y
new_region = Region(the_region.x, the_region.y + the_texture.height_px,
the_region.width_px, the_region.height_px - the_texture.height_px)
the_region.x += the_texture.width_px
the_region.width_px -= the_texture.width_px
the_region.height_px = the_texture.height_px
self.regions.insert(self.regions.index(the_region) + 1, new_region)
self.check_regions()
self._check_regions()
return True
class Texture(object):
"""A collection of one or more frames."""
def __init__(self, filename):
self.filename = filename
self.im = Image.open(filename)
self.width_px, self.height_px = self.im.size
@property
def name(self):
return self._name
def mk_atlas(filenames_list):
import glob
textures = []
filenames_list = glob.glob("textureatlas/textureatlas-master/samples/*.jpg")
atlas = Atlas(0, 0, 256, 14000)
for filename in filenames_list:
# Add frames to texture object list
textures.append(Texture(filename))
# Sort textures by perimeter size in non-increasing order
textures = sorted(textures, key=lambda i:i.height_px, reverse=True)
for the_texture in textures:
if atlas.pack(the_texture):
atlas.write("atlas.png", "RGBA")
raw_input("Press Enter to continue...")
pass
else:
logging.debug("no")
atlas.write("atlast.png", "RGBA")
def main():
mk_atlas(1)
if __name__ == '__main__':
main()
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
......@@ -3,7 +3,6 @@ from PIL import Image
import logging
class Texture(object):
"""
possible texture types:
......@@ -33,11 +32,11 @@ class Texture(object):
"""
def __init__(self, filename,
h_size_meters=None, h_cuts=[], h_can_repeat=False, \
v_size_meters=None, v_cuts=[], v_can_repeat=False, \
height_min = 0, height_max = 9999, \
v_align_bottom = False, \
provides = [], requires = [], levels=None):
h_size_meters=None, h_cuts=list(), h_can_repeat=False,
v_size_meters=None, v_cuts=list(), v_can_repeat=False,
height_min=0, height_max=9999,
v_align_bottom=False,
provides=list(), requires=list(), levels=None):
self.filename = filename
self.x0 = self.x1 = self.y0 = self.y1 = 0
self.sy = self.sx = 0
......@@ -51,13 +50,12 @@ class Texture(object):
self.v_align_bottom = v_align_bottom
h_cuts.sort()
v_cuts.sort()
# roof type, color
# self.v_min = v_min
# self.v_max = v_max
self.ax = 0 # coordinate in atlas (int)
self.ay = 0
try:
self.im = Image.open(self.filename)
except:
except IOError:
logging.warning("Skipping non-existing texture %s" % self.filename)
return
self.width_px, self.height_px = self.im.size
......@@ -66,40 +64,38 @@ class Texture(object):
if v_size_meters:
if levels:
logging.warning("Ignoring levels=%g because v_size_meters=%g is given for texture %s."
% (levels, v_size_meters, filename))
% (levels, v_size_meters, filename))
self.v_size_meters = v_size_meters
else:
if not levels:
logging.warning("Ignoring texture %s because neither v_size_meters nor levels is given"
% filename)
% filename)
# Set filename to "" to make TextureManger reject us. Bad style, but raising
# an exception instead would prohobit the nice, simple structure of catalog.py
# an exception instead would prohibit the nice, simple structure of catalog.py
self.filename = ""
return
else:
self.v_size_meters = levels * 3.3
self.v_size_meters = levels * 3.3 # FIXME: this should be configurable
if h_size_meters:
self.h_size_meters = h_size_meters
else:
self.h_size_meters = self.v_size_meters / image_aspect
logging.debug("No hsize, using image aspect %i x %i = %g. h_size = %g v_size = %g" % \
(self.width_px, self.height_px, image_aspect, self.h_size_meters, self.v_size_meters))
logging.debug("No hsize, using image aspect %i x %i = %g. h_size = %g v_size = %g" %
(self.width_px, self.height_px, image_aspect, self.h_size_meters, self.v_size_meters))
# aspect = v / h
if v_cuts == []:
v_cuts = [1,2,3,4,5,6,7,8,9,10]
if len(v_cuts) == 0:
v_cuts = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
if v_cuts != None:
v_cuts.insert(0,0)
if v_cuts is not None:
v_cuts.insert(0, 0)
self.v_cuts = np.array(v_cuts, dtype=np.float)
if len(self.v_cuts) > 1:
# FIXME test for not type list
# FIXME: test for not type list
self.v_cuts /= self.v_cuts[-1]
# print self.v_cuts
# -- Gimp origin is upper left, convert to OpenGL lower left
self.v_cuts = (1. - self.v_cuts)[::-1]
# print self.v_cuts
else:
self.v_cuts = 1.
self.v_cuts_meters = self.v_cuts * self.v_size_meters
......@@ -110,14 +106,12 @@ class Texture(object):
self.height_min = self.v_cuts_meters[0]
self.height_max = self.v_size_meters
if h_cuts == []:
h_cuts = [1,2,3,4,5,6,7,8,9,10]
if len(h_cuts) == 0:
h_cuts = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
self.h_cuts = np.array(h_cuts, dtype=np.float)
#print "h1", self.h_cuts
#print "h2", h_cuts
if h_cuts == None:
if h_cuts is None:
self.h_cuts = np.array([1.])
elif len(self.h_cuts) > 1:
self.h_cuts /= self.h_cuts[-1]
......@@ -129,8 +123,8 @@ class Texture(object):
self.width_max = self.h_size_meters
if self.h_can_repeat + self.v_can_repeat > 1:
raise ValueError('%s: Textures can repeat in one direction only. '\
'Please set either h_can_repeat or v_can_repeat to False.' % self.filename)
raise ValueError('%s: Textures can repeat in one direction only. \
Please set either h_can_repeat or v_can_repeat to False.' % self.filename)
def x(self, x):
"""given non-dimensional texture coord, return position in atlas"""
......@@ -142,15 +136,13 @@ class Texture(object):
def y(self, y):
"""given non-dimensional texture coord, return position in atlas"""
if self.rotated:
# print "Yr self.x0 + y * self.sx %g + (%s) * %g:", (self.x0, str(y), self.sx)
return self.x0 + y * self.sx
else:
# print "YY self.y0 + y * self.sy : %g + (%s) * %g" % (self.y0, str(y), self.sy)
return self.y0 + y * self.sy
def __str__(self):
return "<%s> x0,1 %4.2f %4.2f y0,1 %4.2f %4.2f sh,v %4.2fm %4.2fm" % \
(self.filename, self.x0, self.x1, self.y0, self.y1, \
(self.filename, self.x0, self.x1, self.y0, self.y1,
self.h_size_meters, self.v_size_meters)
# self.type = type
# commercial-
......@@ -161,7 +153,6 @@ class Texture(object):
# - old
# - modern
# european, north_american, south_american, mediterreanian, african, asian
def closest_h_match(self, frac):
return self.h_cuts[np.abs(self.h_cuts - frac).argmin()]
#self.h_cuts[np.abs(self.h_cuts - frac).argmin()]
#bla
......@@ -50,6 +50,15 @@ def get_osm2city_directory():
return my_dir
def assert_trailing_slash(path):
"""Takes a path and makes sure it has an os_specific trailing slash unless the path is empty."""
my_path = path
if len(my_path) > 0:
if not my_path.endswith(os.sep):
my_path += os.sep
return my_path
class Interpolator(object):
"""load elevation data from file, interpolate"""
def __init__(self, filename, fake=False, clamp=False):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment