Ejemplo n.º 1
0
def get_window_group(config: util.MradConfig) -> Tuple[dict, list]:
    window_groups = {}
    window_normals: List[radgeom.Vector] = []
    for wname, windowpath in config.windows.items():
        _window_primitives = radutil.unpack_primitives(windowpath)
        window_groups[wname] = _window_primitives
        _normal = radutil.parse_polygon(
            _window_primitives[0].real_arg).normal()
        window_normals.append(_normal)
    return window_groups, window_normals
Ejemplo n.º 2
0
def get_sender_grid(config: util.MradConfig) -> dict:
    """."""
    sender_grid = {}
    for name, surface_path in config.grid_surface_paths.items():
        surface_polygon = radutil.parse_polygon(
            radutil.unpack_primitives(surface_path)[0].real_arg)
        sensor_pts = radutil.gen_grid(surface_polygon,
                                      float(config.grid_height),
                                      float(config.grid_spacing))
        sender_grid[name] = radmtx.Sender.as_pts(pts_list=sensor_pts,
                                                 ray_cnt=int(config.ray_count))
    return sender_grid
Ejemplo n.º 3
0
def merge_windows(primitive_list: List[Primitive]):
    """Merge rectangles if coplanar."""
    polygons = [radutil.parse_polygon(p.real_arg) for p in primitive_list]
    normals = [p.normal() for p in polygons]
    if len(set(normals)) > 1:
        logger.warning("Windows Oriented Differently")
    points = [i for p in polygons for i in p.vertices]
    hull_polygon = rg.Convexhull(points, normals[0]).hull
    modifier = primitive_list[0].modifier
    identifier = primitive_list[0].identifier
    new_prim = radutil.polygon2prim(hull_polygon, modifier, identifier)
    return new_prim
Ejemplo n.º 4
0
def prepare_surface(*, prims, basis, left, offset, source, out) -> str:
    """Prepare the sender or receiver surface, adding appropriate tags.
    Args:
        prims(list): list of primitives
        basis(str): sampling basis
        left(bool): use instead the left-hand rule
        offset(float): offset surface in its normal direction
        source(str): surface light source for receiver
        out: output path
    Returns:
        The receiver as string
    """

    if basis is None:
        raise ValueError('Sampling basis cannot be None')
    upvector = str(radutil.up_vector(prims)).replace(' ', ',')
    upvector = "-" + upvector if left else upvector
    modifier_set = {p.modifier for p in prims}
    if len(modifier_set) != 1:
        logger.warning("Primitives don't share modifier")
    src_mod = f"rflx{prims[0].modifier}"
    header = f'#@rfluxmtx h={basis} u={upvector}\n'
    if out is not None:
        header += f"#@rfluxmtx o={out}\n\n"
    if source is not None:
        source_line = f"void {source} {src_mod}\n0\n0\n4 1 1 1 0\n\n"
        header += source_line
    modifiers = [p.modifier for p in prims]
    content = ''
    for prim in prims:
        if prim.identifier in modifiers:
            _identifier = 'discarded'
        else:
            _identifier = prim.identifier
        _modifier = src_mod
        if offset is not None:
            poly = radutil.parse_polygon(prim.real_arg)
            offset_vec = poly.normal().scale(offset)
            moved_pts = [pt + offset_vec for pt in poly.vertices]
            _real_args = radgeom.Polygon(moved_pts).to_real()
        else:
            _real_args = prim.real_arg
        new_prim = radutil.Primitive(_modifier, prim.ptype, _identifier,
                                     prim.str_arg, _real_args)
        content += str(new_prim) + '\n'
    return header + content
Ejemplo n.º 5
0
def get_port(win_polygon, win_norm, ncs_prims):
    """
    Generate ports polygons that encapsulate the window and NCP geometries.

    window and NCP geometries are rotated around +Z axis until
    the area projected onto XY plane is the smallest, thus the systems are facing
    orthogonal direction. A boundary box is then generated with a slight
    outward offset. This boundary box is then rotated back the same amount
    to encapsulate the original window and NCP geomteries.
    """
    ncs_polygon = [radutil.parse_polygon(p.real_arg)
                   for p in ncs_prims if p.ptype=='polygon']
    if 1 in [int(abs(i)) for i in win_norm.to_list()]:
        ncs_polygon.append(win_polygon)
        bbox = rg.getbbox(ncs_polygon, offset=0.00)
        bbox.remove([b for b in bbox if b.normal().reverse()==win_norm][0])
        return [b.move(win_norm.scale(-.1)) for b in bbox]
    xax = [1, 0, 0]
    _xax = [-1, 0, 0]
    yax = [0, 1, 0]
    _yax = [0, -1, 0]
    zaxis = rg.Vector(0, 0, 1)
    rm_pg = [xax, _yax, _xax, yax]
    area_list = []
    win_normals = []
    # Find axiel aligned rotation angle
    bboxes = []
    for deg in range(90):
        rad = math.radians(deg)
        win_polygon_r = win_polygon.rotate(zaxis, rad)
        win_normals.append(win_polygon_r.normal())
        ncs_polygon_r = [p.rotate(zaxis, rad) for p in ncs_polygon]
        ncs_polygon_r.append(win_polygon_r)
        _bbox = rg.getbbox(ncs_polygon_r, offset=0.001)
        bboxes.append(_bbox)
        area_list.append(_bbox[0].area())
    # Rotate to position
    deg = area_list.index(min(area_list))
    rrad = math.radians(deg)
    bbox = bboxes[deg]
    _win_normal = [round(i, 1) for i in win_normals[deg].to_list()]
    del bbox[rm_pg.index(_win_normal) + 2]
    rotate_back = [pg.rotate(zaxis, rrad * -1) for pg in bbox]
    return rotate_back
Ejemplo n.º 6
0
def genport(*, wpolys, npolys, depth, scale):
    """Generate the appropriate aperture for F matrix generation."""
    if len(wpolys) > 1:
        wpoly = merge_windows(wpolys)
    else:
        wpoly = wpolys[0]
    wpoly = radutil.parse_polygon(wpoly.real_arg)
    wnorm = wpoly.normal()
    if npolys is not None:
        all_ports = get_port(wpoly, wnorm, npolys)
    elif depth is None:
        raise ValueError('Need to specify (depth and scale) or ncp path')
    else:  # user direct input
        extrude_vector = wpoly.normal().reverse().scale(depth)
        scale_vector = rg.Vector(scale, scale, scale)
        scaled_window = wpoly.scale(scale_vector, wpoly.centroid())
        all_ports = scaled_window.extrude(extrude_vector)[1:]
    port_prims = []
    for pi in range(len(all_ports)):
        new_prim = radutil.polygon2prim(all_ports[pi], 'port',
                                     'portf%s' % str(pi + 1))
        logger.debug(str(new_prim))
        port_prims.append(new_prim)
    return port_prims
Ejemplo n.º 7
0
 def check_srf_normal(self, zone):
     """Check the surface normal in each zone."""
     polygons = [
         ru.parse_polygon(v.real_arg) for v in zone['Floor'].values()
     ]
     polygons.extend(
         [ru.parse_polygon(v.real_arg) for v in zone['Ceiling'].values()])
     polygons.extend(
         [ru.parse_polygon(v.real_arg) for v in zone['Wall'].values()])
     polygons.extend(
         [ru.parse_polygon(v.real_arg) for v in zone['Window'].values()])
     centroid = rg.polygon_center(*polygons)
     new_floor = {}
     for key, val in zone['Floor'].items():
         fpolygon = ru.parse_polygon(val.real_arg)
         angle2center = fpolygon.normal().angle_from(centroid -
                                                     fpolygon.centroid())
         if angle2center < PI / 4:
             new_prim = Primitive(val.modifier, val.ptype, val.identifier,
                                  '0',
                                  fpolygon.flip().to_real())
             new_floor[key] = new_prim
         else:
             new_floor[key] = val
     zone['Floor'] = new_floor
     new_window = {}
     for key, val in zone['Window'].items():
         wpolygon = ru.parse_polygon(val.real_arg)
         angle2center = wpolygon.normal().angle_from(centroid -
                                                     wpolygon.centroid())
         if angle2center > PI / 4:
             new_prim = Primitive(val.modifier, val.ptype, val.identifier,
                                  '0',
                                  wpolygon.flip().to_real())
             new_window[key] = new_prim
         else:
             new_window[key] = val
     zone['Window'] = new_window
     return zone
Ejemplo n.º 8
0
def main():
    parser = ArgumentParser()
    genfmtx_parser = genfmtx_args(parser)
    genfmtx_parser.add_argument('-v',
                                '--verbose',
                                action='count',
                                default=0,
                                help='verbose mode')
    args = genfmtx_parser.parse_args()
    logger = logging.getLogger('frads')
    formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    console_handler = logging.StreamHandler()
    _level = args.verbose * 10
    logger.setLevel(_level)
    console_handler.setLevel(_level)
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)
    raw_wndw_prims = radutil.unpack_primitives(args.window)
    ncp_prims = radutil.unpack_primitives(args.ncp)
    wndw_prims = [p for p in raw_wndw_prims if p.ptype == 'polygon']
    port_prims = fcd.genport(wpolys=wndw_prims,
                             npolys=ncp_prims,
                             depth=None,
                             scale=None)
    wndw_polygon = [
        radutil.parse_polygon(p.real_arg) for p in wndw_prims
        if p.ptype == 'polygon'
    ]
    args.env.append(args.ncp)
    all_prims = []
    for env in args.env:
        all_prims.extend(radutil.unpack_primitives(env))
    ncp_mod = [prim.modifier for prim in ncp_prims
               if prim.ptype == 'polygon'][0]
    ncp_mat: radutil.Primitive
    ncp_type: str = ''
    for prim in all_prims:
        if prim.identifier == ncp_mod:
            ncp_mat = prim
            ncp_type = prim.ptype
            break
    if ncp_type == '':
        raise ValueError("Unknown NCP material")
    wrap2xml = args.wrap
    dirname = os.path.dirname(args.o)
    dirname = '.' if dirname == '' else dirname
    if args.solar and ncp_type == 'BSDF':
        logger.info('Computing for solar and visible spectrum...')
        wrap2xml = False
        xmlpath = ncp_mat.str_arg.split()[2]
        td = tf.mkdtemp()
        with open(xmlpath) as rdr:
            raw = rdr.read()
        raw = raw.replace('<Wavelength unit="Integral">Visible</Wavelength>',
                          '<Wavelength unit="Integral">Visible2</Wavelength>')
        raw = raw.replace('<Wavelength unit="Integral">Solar</Wavelength>',
                          '<Wavelength unit="Integral">Visible</Wavelength>')
        raw = raw.replace('<Wavelength unit="Integral">Visible2</Wavelength>',
                          '<Wavelength unit="Integral">Solar</Wavelength>')
        solar_xml_path = os.path.join(td, 'solar.xml')
        with open(solar_xml_path, 'w') as wtr:
            wtr.write(raw)
        _strarg = ncp_mat.str_arg.split()
        _strarg[2] = solar_xml_path
        solar_ncp_mat = radutil.Primitive(ncp_mat.modifier, ncp_mat.ptype,
                                          ncp_mat.identifier + ".solar",
                                          ' '.join(_strarg), '0')

        _env_path = os.path.join(td, 'env_solar.rad')
        with open(_env_path, 'w') as wtr:
            for prim in all_prims:
                wtr.write(str(prim))
        outsolar = os.path.join(dirname, '_solar_' + util.basename(args.o))
        process_thread = Thread(target=fcd.Genfmtx,
                                kwargs={
                                    'win_polygons': wndw_polygon,
                                    'port_prim': port_prims,
                                    'out': outsolar,
                                    'env': [_env_path],
                                    'sbasis': args.ss,
                                    'rbasis': args.rs,
                                    'opt': args.opt,
                                    'refl': args.refl,
                                    'forw': args.forw,
                                    'wrap': wrap2xml
                                })
        process_thread.start()
        #fcd.Genfmtx(win_polygons=wndw_polygon, port_prim=port_prims, out=outsolar,
        #            env=[_env_path], sbasis=args['ss'], rbasis=args['rs'],
        #            opt=args['opt'], refl=args['refl'], forw=args['forw'], wrap=wrap2xml)

    fcd.Genfmtx(win_polygons=wndw_polygon,
                port_prim=port_prims,
                out=args.o,
                env=args.env,
                sbasis=args.ss,
                rbasis=args.rs,
                opt=args.opt,
                refl=args.refl,
                forw=args.forw,
                wrap=wrap2xml)
    if args.solar and ncp_type == 'BSDF':
        process_thread.join()
        vis_dict = {}
        sol_dict = {}
        oname = util.basename(args['o'])
        mtxs = [
            os.path.join(dirname, mtx) for mtx in os.listdir(dirname)
            if mtx.endswith('.mtx')
        ]
        for mtx in mtxs:
            _direc = util.basename(mtx).split('_')[-1][:2]
            mtxname = util.basename(mtx)
            if mtxname.startswith(oname):
                #vis_dict[_direc] = os.path.join(dirname, f"_vis_{_direc}")
                vis_dict[_direc] = os.path.join(td, f"vis_{_direc}")
                out2 = os.path.join(dirname, f"vis_{_direc}")
                klems_wrap(vis_dict[_direc], out2, mtx, args.ss)
            if mtxname.startswith('_solar_'):
                sol_dict[_direc] = os.path.join(td, f"sol_{_direc}")
                out2 = os.path.join(dirname, f"sol_{_direc}")
                klems_wrap(sol_dict[_direc], out2, mtx, args.ss)
        cmd = f"wrapBSDF -a {args.ss} -c -s Visible "
        cmd += ' '.join([f"-{key} {vis_dict[key]}" for key in vis_dict])
        cmd += ' -s Solar '
        cmd += ' '.join([f"-{key} {sol_dict[key]}" for key in sol_dict])
        cmd += f" > {os.path.join(dirname, oname)}.xml"
        os.system(cmd)
        shutil.rmtree(td)
        [os.remove(mtx) for mtx in mtxs]