# -*- coding: utf-8 -*-
# Copyright (c) 2020 Stephen Wasilewski, HSLU and EPFL
# =======================================================================
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# =======================================================================
"""factory functions for easy api access raytraverse."""
import os
import configparser
from clasp.click_ext import ConfigSectionMap
from raytools import io
from raytraverse.integrator import Integrator
from raytraverse.scene import Scene
from raytraverse.sky import SkyData
from raytraverse.mapper import PlanMapper
from raytraverse.lightfield import SunsPlaneKD, LightPlaneKD
from raytraverse.lightpoint import LightPointKD
[docs]
def get_config(config, com="raytraverse_"):
"""load a config file into a dict
Parameters
----------
config: str
path to .cfg file with sections raytarverse_*
com: str
basename of commands in .cfg file
Returns
-------
result: dict
"""
parser = configparser.ConfigParser(
interpolation=configparser.ExtendedInterpolation())
parser.read(config)
gargs = {}
for section in parser.keys():
subc = section.replace(com, "")
gargs[subc] = ConfigSectionMap(parser, section)
return gargs
[docs]
def auto_reload(scndir, area, areaname="plan", skydata="skydata", ptres=1.0,
rotation=0.0, zheight=None):
"""reload associated class instances from file paths
Parameters
----------
scndir: str
matches outdir argument of Scene()
area: str np.array
radiance scene geometry defining a plane to sample, tsv file of
points to generate bounding box, or np.array of points.
areaname: str, optional
matches name argument of PlanMapper()
skydata: str, optional
matches name argument of SkyData.write()
ptres: float, optional
resolution for considering points duplicates, border generation
(1/2) and add_grid(). updateable
rotation: float, optional
positive Z rotation for point grid alignment
zheight: float, optional
override calculated zheight
Returns
-------
Scene
PlanMapper
SkyData
"""
if not os.path.exists(scndir):
raise FileNotFoundError(f"auto_reload is only for reloading existing "
f"scenes. {scndir} does not exist")
scn = Scene(scndir)
if not os.path.isfile(f"{scndir}/{skydata}.npz"):
raise FileNotFoundError(f"auto_reload is only for reloading existing "
f"skydata. {scndir}/{skydata}.npz does not "
f"exist")
skd = SkyData(f"{scndir}/{skydata}.npz")
pm = PlanMapper(area, name=areaname, ptres=ptres, rotation=rotation,
zheight=zheight)
return scn, pm, skd
[docs]
def load_lp(path, hasparent=True):
"""load a lightpoint from a file
will try to get appropriate scene/zone information from file path but
reverts to a lightpoint without correct meta-data if it does not have the
appropriate nesting.
Parameters
----------
path: str
relative path to .rytpt file
hasparent: bool, optional
was sampled within a zone (typical), set to false in the case that
the lightpoint file is multiple folders deep from CWD but was not
sampled within a zone (meaning you used a samplerpt class, not typical).
Returns
-------
LightPointKD
"""
try:
if hasparent:
try:
ftree = path.rsplit("/", 3)
scndir = ftree[-4]
parent = ftree[-3]
except IndexError:
ftree = path.rsplit("/", 2)
scndir = ftree[-3]
parent = None
else:
ftree = path.rsplit("/", 2)
scndir = ftree[-3]
parent = None
except IndexError:
return LightPointKD(path)
else:
scn = Scene(scndir)
pidx = int(ftree[-1].split(".")[0])
try:
pts = io.load_txt(path.replace(f"/{ftree[-1]}", "_points.tsv"))
except FileNotFoundError:
pt = (0, 0, 0)
else:
try:
pt = pts[pidx, -3:]
except IndexError:
pt = pts[-3:]
return LightPointKD(scn, parent=parent, src=ftree[-2], posidx=pidx, pt=pt)
stypes = ('1comp', '2comp', '3comp', '1compdv', 'directview', 'directpatch',
'sunonly', 'sunpatch', 'skyonly')
stypedescriptions = {
'1comp': "standard DC method, sky patch only, full contribution depending "
"on skyengine settings",
'2comp': "sky patch for sky contribution, sun run for sun contribution, "
"depth of contributions depends on skyengine and sunengine "
"settings, no approximation for sun from sky patch",
'3comp': "2-phase DDS, sky handles sky+indirect sun, sun handles direct sun"
" requires directskyrun -ab 1 and sunrun -ab 0",
'1compdv': "standad DC method, but with direct view replacement of sun and"
" specular reflections",
'directview': "only evaluate srcviewpts (direct views to sun and specular "
"reflections",
'directpatch': "only evaluate results from dskyrun",
'sunonly': "only evaluate results from sunrun",
'sunpatch': "use skyrun results to evaluate sun contribution",
'skyonly': "use skyrun to evaluate sky contribution only"
}
stypedocstring = "\n".join([f" - {k}: {v}" for k,v in stypedescriptions.items()])
[docs]
def get_integrator(scn, pm, srcname="suns", simtype="2comp",
sunviewengine=None):
req_sun = ('2comp', '3comp', 'directview', 'sunonly')
req_sky = ('1comp', '2comp', '3comp', 'sunpatch', 'skyonly', '1compdv')
req_dsk = ('3comp', 'directpatch', '1compdv')
sunfile = f"{scn.outdir}/{pm.name}/{srcname}_sunpositions.tsv"
skpoints = f"{scn.outdir}/{pm.name}/sky_points.tsv"
dskpoints = f"{scn.outdir}/{pm.name}/skydcomp_points.tsv"
try:
sunplane = SunsPlaneKD(scn, sunfile, pm, f"{srcname}_sun")
except OSError:
if simtype in req_sun:
raise OSError(f"file: {sunfile} does not exist, make sure that a"
f" complete sun sampling exists")
sunplane = None
try:
skyplane = LightPlaneKD(scn, skpoints, pm, "sky")
except OSError:
if simtype in req_sky:
raise OSError(f"file: {skpoints} does not exist, make sure that a"
f" complete sky sampling exists")
skyplane = None
try:
dskplane = LightPlaneKD(scn, dskpoints, pm, "skydcomp")
except OSError:
if simtype in req_dsk:
raise OSError(f"file: {dskpoints} does not exist, make sure that a"
f" complete direct sky sampling exists")
dskplane = None
if simtype in ["1comp", "sunpatch", "skyonly"]:
return Integrator(skyplane, includesky=simtype != "sunpatch",
includesun=simtype != "skyonly", sunviewengine=sunviewengine)
if simtype == "2comp":
return Integrator(skyplane, sunplane, sunviewengine=sunviewengine)
if simtype == "3comp":
return Integrator(skyplane, dskplane, sunplane,
sunviewengine=sunviewengine, ds=True)
if simtype == "1compdv":
return Integrator(skyplane, dskplane, sunviewengine=sunviewengine,
dv=True)
if simtype in ["directview", "sunonly"]:
return Integrator(sunplane, includesky=False,
sunviewengine=sunviewengine)
if simtype == "directpatch":
return Integrator(dskplane, includesky=False,
sunviewengine=sunviewengine)
try:
srcpoints = f"{scn.outdir}/{pm.name}/{simtype}_points.tsv"
srcplane = LightPlaneKD(scn, srcpoints, pm, simtype)
except OSError:
raise ValueError(f"Error loading {simtype}")
else:
return Integrator(srcplane, sunviewengine=sunviewengine)