def calculateModeVolume(arguments):
    # .. todo:: Finish this
    # NOTE: Add way to specify snapshots, epsilon/frequency snapshot pairs

    # read in mesh
    if arguments.meshfile is None:
        print('ERROR: No meshfile specified.', file=sys.stderr)
        sys.exit(-1)
    sim_mesh = bfdtd.readBristolFDTD(arguments.meshfile, arguments.verbosity)

    # read in snapshot files from the various input files
    if len(arguments.infile) <= 0:
        print('ERROR: No infile(s) specified.', file=sys.stderr)
        sys.exit(-1)
    sim_in = bfdtd.BFDTDobject()
    sim_in.verbosity = arguments.verbosity
    for infile in arguments.infile:
        sim_in.readBristolFDTD(infile)

    # .. todo:: add path of file based on where it was read from
    # .. todo:: read in .prn files
    # calculate mode volume

    snaplist = sim_in.getFrequencySnapshots()
    for numID in range(len(snaplist)):
        snapshot = snaplist[numID]
        #print(['x','y','z'][snapshot.plane-1])
        #print(sim_in.flag.id_string)
        fsnap_filename, alphaID, pair = brisFDTD_ID_info.numID_to_alphaID_FrequencySnapshot(
            numID + 1, ['x', 'y', 'z'][snapshot.plane - 1],
            sim_in.flag.id_string.strip('"'),
            snap_time_number=1)
        print(fsnap_filename)
        esnap_filename, alphaID, pair = brisFDTD_ID_info.numID_to_alphaID_EpsilonSnapshot(
            numID + 1, ['x', 'y', 'z'][snapshot.plane - 1],
            sim_in.flag.id_string.strip('"'),
            snap_time_number=1)
        print(esnap_filename)

    #if arguments.fsnapfiles is None:
    #arguments.fsnapfiles = sim_in.getFrequencySnapshots():
    #if arguments.esnapfiles is None:
    #arguments.esnapfiles = sim_in.getEpsilonSnapshots()

    #if len(arguments.fsnapfiles) != len(arguments.esnapfiles):
    #print('ERROR: number of frequency snapshots and epsilon snapshots do not match', file=sys.stderr)
    #sys.exit(-1)
    #else:
    #print('OK')

    #print(arguments.fsnapfiles)
    #print(arguments.esnapfiles)

    return
def calculateModeVolume(arguments):
    # TODO: Finish this
    # NOTE: Add way to specify snapshots, epsilon/frequency snapshot pairs

    # read in mesh
    if arguments.meshfile is None:
        print("ERROR: No meshfile specified.", file=sys.stderr)
        sys.exit(-1)
    sim_mesh = bfdtd.readBristolFDTD(arguments.meshfile, arguments.verbosity)

    # read in snapshot files from the various input files
    if len(arguments.infile) <= 0:
        print("ERROR: No infile(s) specified.", file=sys.stderr)
        sys.exit(-1)
    sim_in = bfdtd.BFDTDobject()
    sim_in.verbosity = arguments.verbosity
    for infile in arguments.infile:
        sim_in.readBristolFDTD(infile)

    # TODO: add path of file based on where it was read from
    # TODO: read in .prn files
    # calculate mode volume

    snaplist = sim_in.getFrequencySnapshots()
    for numID in range(len(snaplist)):
        snapshot = snaplist[numID]
        # print(['x','y','z'][snapshot.plane-1])
        # print(sim_in.flag.id_string)
        fsnap_filename, alphaID, pair = brisFDTD_ID_info.numID_to_alphaID_FrequencySnapshot(
            numID + 1, ["x", "y", "z"][snapshot.plane - 1], sim_in.flag.id_string.strip('"'), snap_time_number=1
        )
        print(fsnap_filename)
        esnap_filename, alphaID, pair = brisFDTD_ID_info.numID_to_alphaID_EpsilonSnapshot(
            numID + 1, ["x", "y", "z"][snapshot.plane - 1], sim_in.flag.id_string.strip('"'), snap_time_number=1
        )
        print(esnap_filename)

    # if arguments.fsnapfiles is None:
    # arguments.fsnapfiles = sim_in.getFrequencySnapshots():
    # if arguments.esnapfiles is None:
    # arguments.esnapfiles = sim_in.getEpsilonSnapshots()

    # if len(arguments.fsnapfiles) != len(arguments.esnapfiles):
    # print('ERROR: number of frequency snapshots and epsilon snapshots do not match', file=sys.stderr)
    # sys.exit(-1)
    # else:
    # print('OK')

    # print(arguments.fsnapfiles)
    # print(arguments.esnapfiles)

    return
def importBristolFDTD(filename):
    ''' import BristolFDTD geometry from .in,.geo or .inp and create corresponding structure in Blender '''
    print('----->Importing bristol FDTD geometry: ' + filename)
    #Blender.Window.WaitCursor(1);

    # save import path
    # Blender.Set('tempdir',os.path.dirname(filename));
    #FILE = open(, 'w');
    #pickle.dump(, FILE);
    #FILE.close();

    with open(cfgfile, 'wb') as f:
        # Pickle the 'data' dictionary using the highest protocol available.
        pickle.dump(filename, f, pickle.HIGHEST_PROTOCOL)

    # create structured_entries
    structured_entries = readBristolFDTD(filename)

    ##################
    # GROUP SETUP
    ##################
    # create group corresponding to this file
    # deselect all
    bpy.ops.object.select_all(action='DESELECT')
    # Truncated to 63 characters because that seems to be the maximum string length Blender accepts for group names.
    # (allows keeping part of the path for better identification if multiple files use the same basename)
    group_name = filename[-63:]
    bpy.ops.group.create(name=group_name)

    if not 'meshes' in bpy.data.groups: bpy.ops.group.create(name='meshes')
    if not 'boxes' in bpy.data.groups: bpy.ops.group.create(name='boxes')
    if not 'excitations' in bpy.data.groups:
        bpy.ops.group.create(name='excitations')
    if not 'frequencySnapshots' in bpy.data.groups:
        bpy.ops.group.create(name='frequencySnapshots')
    if not 'timeSnapshots' in bpy.data.groups:
        bpy.ops.group.create(name='timeSnapshots')
    if not 'epsilonSnapshots' in bpy.data.groups:
        bpy.ops.group.create(name='epsilonSnapshots')
    if not 'spheres' in bpy.data.groups: bpy.ops.group.create(name='spheres')
    if not 'distorted' in bpy.data.groups:
        bpy.ops.group.create(name='distorted')
    if not 'blocks' in bpy.data.groups: bpy.ops.group.create(name='blocks')
    if not 'cylinders' in bpy.data.groups:
        bpy.ops.group.create(name='cylinders')
    if not 'probes' in bpy.data.groups: bpy.ops.group.create(name='probes')
    ##################

    FDTDGeometryObjects_obj = FDTDGeometryObjects()

    # Blender.Window.RedrawAll(); # This must be called before any SetActiveLayer calls!

    layerManager = LayerManagerObjects()

    # Box
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('box'));
    obj = FDTDGeometryObjects_obj.GEObox(structured_entries.box.name,
                                         Vector(structured_entries.box.lower),
                                         Vector(structured_entries.box.upper))
    bpy.context.scene.objects.active = obj
    bpy.ops.object.group_link(group=group_name)
    bpy.ops.object.group_link(group='boxes')

    # mesh
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('mesh'));
    #FDTDGeometryObjects_obj.GEOmesh('mesh', False, structured_entries.delta_X_vector,structured_entries.delta_Y_vector,structured_entries.delta_Z_vector);
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('mesh'));
    obj = FDTDGeometryObjects_obj.GEOmesh(
        'mesh', False, structured_entries.mesh.getXmeshDelta(),
        structured_entries.mesh.getYmeshDelta(),
        structured_entries.mesh.getZmeshDelta())
    bpy.context.scene.objects.active = obj
    bpy.ops.object.group_link(group=group_name)
    bpy.ops.object.group_link(group='meshes')

    # Time_snapshot (time or EPS)
    Ntsnaps = 0
    for time_snapshot in structured_entries.time_snapshot_list:

        Ntsnaps += 1
        snap_plane = ['x', 'y', 'z'][time_snapshot.plane - 1]
        probe_ident = structured_entries.flag.id_string.replace('\"', '')
        snap_time_number = 1
        TimeSnapshotFileName, alphaID, pair = brisFDTD_ID_info.numID_to_alphaID_EpsilonSnapshot(
            Ntsnaps, snap_plane, probe_ident, snap_time_number)

        if time_snapshot.eps == 0:
            #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('time_snapshots_'+planeNumberName(time_snapshot.plane)[1]))
            obj = FDTDGeometryObjects_obj.GEOtime_snapshot(
                time_snapshot.name, time_snapshot.plane, time_snapshot.P1,
                time_snapshot.P2)
            bpy.context.scene.objects.active = obj
            bpy.ops.object.group_link(group=group_name)
            bpy.ops.object.group_link(group='timeSnapshots')
        else:
            #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('eps_snapshots_'+planeNumberName(time_snapshot.plane)[1]))

            obj = FDTDGeometryObjects_obj.GEOeps_snapshot(
                TimeSnapshotFileName, time_snapshot.plane, time_snapshot.P1,
                time_snapshot.P2)
            #obj = FDTDGeometryObjects_obj.GEOeps_snapshot(time_snapshot.name, time_snapshot.plane, time_snapshot.P1, time_snapshot.P2)

            bpy.context.scene.objects.active = obj
            bpy.ops.object.group_link(group=group_name)
            bpy.ops.object.group_link(group='epsilonSnapshots')

    # Frequency_snapshot
    # TODO: Finally get a correct system for filenames/comment names/etc implemented. getfilename() or something...
    Nfsnaps = 0
    for frequency_snapshot in structured_entries.frequency_snapshot_list:
        #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('frequency_snapshots_'+planeNumberName(frequency_snapshot.plane)[1]));

        Nfsnaps += 1
        snap_plane = ['x', 'y', 'z'][frequency_snapshot.plane - 1]
        probe_ident = structured_entries.flag.id_string.replace('\"', '')
        snap_time_number = 0
        FrequencySnapshotFileName, alphaID, pair = brisFDTD_ID_info.numID_to_alphaID_FrequencySnapshot(
            Nfsnaps, snap_plane, probe_ident, snap_time_number)

        obj = FDTDGeometryObjects_obj.GEOfrequency_snapshot(
            FrequencySnapshotFileName, frequency_snapshot.plane,
            frequency_snapshot.P1, frequency_snapshot.P2)
        #obj = FDTDGeometryObjects_obj.GEOfrequency_snapshot(frequency_snapshot.name, frequency_snapshot.plane, frequency_snapshot.P1, frequency_snapshot.P2)

        bpy.context.scene.objects.active = obj
        bpy.ops.object.group_link(group=group_name)
        bpy.ops.object.group_link(group='frequencySnapshots')

    # Excitation
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('excitations'));
    for excitation in structured_entries.excitation_list:
        #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('excitations'));
        #print(Blender.Window.GetActiveLayer())
        #print(excitation)
        obj = FDTDGeometryObjects_obj.GEOexcitation(excitation)
        bpy.context.scene.objects.active = obj
        bpy.ops.object.group_link(group=group_name)
        bpy.ops.object.group_link(group='excitations')
        #FDTDGeometryObjects_obj.GEOexcitation(excitation.name, Vector(excitation.P1), Vector(excitation.P2));
    # Probe
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('probes'));
    Nprobes = 0
    for probe in structured_entries.probe_list:
        # print('probe = ',Vector(probe.position))
        Nprobes += 1
        ProbeFileName = 'p' + str(Nprobes).zfill(
            2) + structured_entries.flag.id_string.replace('\"', '') + '.prn'
        #FDTDGeometryObjects_obj.GEOprobe(probe.name+' ('+ProbeFileName+')', Vector(probe.position));
        obj = FDTDGeometryObjects_obj.GEOprobe(ProbeFileName,
                                               Vector(probe.position))
        bpy.context.scene.objects.active = obj
        bpy.ops.object.group_link(group=group_name)
        bpy.ops.object.group_link(group='probes')

    # Sphere
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('spheres'));
    for sphere in structured_entries.sphere_list:
        # variables
        centre = Vector(sphere.centre)

        # initialise rotation_matrix
        rotation_matrix = Matrix()
        rotation_matrix.identity()

        # scale object
        #Sx=Blender.Mathutils.ScaleMatrix(abs(2*sphere.outer_radius),4,Blender.Mathutils.Vector(1,0,0))
        #Sy=Blender.Mathutils.ScaleMatrix(abs(2*sphere.outer_radius),4,Blender.Mathutils.Vector(0,1,0))
        #Sz=Blender.Mathutils.ScaleMatrix(abs(2*sphere.outer_radius),4,Blender.Mathutils.Vector(0,0,1))
        #rotation_matrix *= Sx*Sy*Sz;

        # position object
        #T = Blender.Mathutils.TranslationMatrix(centre)
        #rotation_matrix *= T;

        # add rotations
        #for r in sphere.rotation_list:
        #rotation_matrix *= rotationMatrix(r.axis_point, r.axis_direction, r.angle_degrees);

        # create object
        obj = FDTDGeometryObjects_obj.GEOsphere(sphere.name, sphere.centre,
                                                sphere.outer_radius,
                                                sphere.inner_radius,
                                                sphere.permittivity,
                                                sphere.conductivity)
        #FDTDGeometryObjects_obj.GEOsphere_matrix(sphere.name, rotation_matrix, sphere.outer_radius, sphere.inner_radius, sphere.permittivity, sphere.conductivity);
        #FDTDGeometryObjects_obj.GEOblock_matrix(sphere.name, rotation_matrix, sphere.permittivity, sphere.conductivity);
        bpy.context.scene.objects.active = obj
        bpy.ops.object.group_link(group=group_name)
        bpy.ops.object.group_link(group='spheres')

    # Block
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('blocks'))
    for block in structured_entries.block_list:
        # variables
        lower = Vector(block.lower)
        upper = Vector(block.upper)
        pos = 0.5 * (lower + upper)
        diag = 0.5 * (upper - lower)

        # initialise rotation_matrix
        rotation_matrix = Matrix()
        rotation_matrix.identity()

        # add rotations
        for r in block.rotation_list:
            rotation_matrix = rotationMatrix(r.axis_point, r.axis_direction,
                                             r.angle_degrees) * rotation_matrix

        # position object
        T = Matrix.Translation(pos)
        rotation_matrix *= T

        ## scale object
        Sx = Matrix.Scale(abs(diag[0]), 4, Vector((1, 0, 0)))
        Sy = Matrix.Scale(abs(diag[1]), 4, Vector((0, 1, 0)))
        Sz = Matrix.Scale(abs(diag[2]), 4, Vector((0, 0, 1)))
        rotation_matrix *= Sx * Sy * Sz

        # create object
        obj = FDTDGeometryObjects_obj.GEOblock_matrix(block.name,
                                                      rotation_matrix,
                                                      block.permittivity,
                                                      block.conductivity)
        #FDTDGeometryObjects_obj.GEOblock(block.name, block.lower, block.upper, block.permittivity, block.conductivity)
        bpy.context.scene.objects.active = obj
        bpy.ops.object.group_link(group=group_name)
        bpy.ops.object.group_link(group='blocks')

    # Distorted
    for distorted in structured_entries.distorted_list:
        # create object
        #print(distorted)
        obj = FDTDGeometryObjects_obj.GEOdistorted(distorted.name,
                                                   distorted.vertices,
                                                   distorted.permittivity,
                                                   distorted.conductivity)
        bpy.context.scene.objects.active = obj
        bpy.ops.object.group_link(group=group_name)
        bpy.ops.object.group_link(group='distorted')

    # Cylinder
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('cylinders'));
    for cylinder in structured_entries.cylinder_list:

        # initialise rotation_matrix
        rotation_matrix = Matrix()
        rotation_matrix.identity()

        # add rotations
        for r in cylinder.rotation_list:
            rotation_matrix = rotationMatrix(r.axis_point, r.axis_direction,
                                             r.angle_degrees) * rotation_matrix

        # position object
        T = Matrix.Translation(
            Vector(
                [cylinder.centre[0], cylinder.centre[1], cylinder.centre[2]]))
        rotation_matrix *= T

        # because FDTD cylinders are aligned with the Y axis by default
        rotation_matrix *= rotationMatrix(Vector([0, 0, 0]), Vector([1, 0, 0]),
                                          -90)

        # create object
        obj = FDTDGeometryObjects_obj.GEOcylinder_matrix(
            cylinder.name, rotation_matrix, cylinder.inner_radius,
            cylinder.outer_radius, cylinder.height, cylinder.permittivity,
            cylinder.conductivity)
        bpy.context.scene.objects.active = obj
        bpy.ops.object.group_link(group=group_name)
        bpy.ops.object.group_link(group='cylinders')

        #angle_X = numpy.deg2rad(-90)
        #angle_X = -0.5*numpy.pi
        #angle_Y = 0
        #angle_Z = 0
        #FDTDGeometryObjects_obj.GEOcylinder(cylinder.name, cylinder.centre, cylinder.inner_radius, cylinder.outer_radius, cylinder.height, cylinder.permittivity, cylinder.conductivity, angle_X, angle_Y, angle_Z)

    #########################
    # Not yet implemented:
    # Flag
    # structured_entries.flag;
    # Boundaries
    # structured_entries.boundaries;
    #########################

    # TODO: Save the layer settings somewhere for reuse
    #scene = Blender.Scene.GetCurrent()
    scene = bpy.context.scene

    layersOn = [
        layerManager.DefaultLayers.index('spheres') + 1,
        layerManager.DefaultLayers.index('blocks') + 1,
        layerManager.DefaultLayers.index('cylinders') + 1
    ]
    print(layersOn)
    #layersOn = [1,2,3]
    #print layersOn
    #Blender.Scene.GetCurrent().setLayers(layersOn)

    #scene.update(0);
    #Blender.Window.RedrawAll();
    #Blender.Window.WaitCursor(0);
    #Blender.Scene.GetCurrent().setLayers([1,3,4,5,6,7,8,9,10]);
    print('...done')
    def importBristolFDTD_single_file(self,
                                      filename,
                                      filename_idx=None,
                                      prefix_zfill=0):
        '''
      Import BristolFDTD geometry from .in,.geo or .inp and create corresponding structure in Blender.
      
      This function imports a single file.
      To import multiple files, use :py:func:`importBristolFDTD`
      '''

        start_time = time.time()

        print('----->Importing bristol FDTD geometry: ' + filename)
        print(self.PrintSelf('\t'))

        #Blender.Window.WaitCursor(1);

        # save import path
        # Blender.Set('tempdir',os.path.dirname(filename));
        #FILE = open(, 'w');
        #pickle.dump(, FILE);
        #FILE.close();

        with open(cfgfile, 'wb') as f:
            # Pickle the 'data' dictionary using the highest protocol available.
            pickle.dump(filename, f, pickle.HIGHEST_PROTOCOL)

        # create structured_entries
        structured_entries = readBristolFDTD(filename)

        ##################
        # GROUP SETUP
        ##################
        # create group corresponding to this file
        # deselect all
        bpy.ops.object.select_all(action='DESELECT')

        # Truncated to 63 characters because that seems to be the maximum string length Blender accepts for group names.
        # (allows keeping part of the path for better identification if multiple files use the same basename)
        if filename_idx is None:
            group_name = filename[-63:]
        else:
            group_name_prefix = str(filename_idx).zfill(prefix_zfill) + '-'
            group_name = group_name_prefix + filename[-(
                63 - len(group_name_prefix)):]

        #if group_name in bpy.data.groups:
        #raise Exception('group already exists: {}\n{}'.format(group_name, bpy.data.groups))

        # older version
        #bpy.ops.group.create(name=group_name)
        # This version ensures that a new group name is created if necessary and stores the new group in *current_group*.
        # current_group = bpy.data.groups.new(name=group_name) # blender<2.8
        # group_name = current_group.name # blender<2.8
        collection_current_file = blender_utilities.make_collection(
            group_name)  # blender>=2.8

        collection_meshes = blender_utilities.make_collection('meshes')
        collection_boxes = blender_utilities.make_collection('boxes')
        collection_excitations = blender_utilities.make_collection(
            'excitations')
        collection_frequencySnapshots = blender_utilities.make_collection(
            'frequencySnapshots')
        collection_timeSnapshots = blender_utilities.make_collection(
            'timeSnapshots')
        collection_epsilonSnapshots = blender_utilities.make_collection(
            'epsilonSnapshots')
        collection_spheres = blender_utilities.make_collection('spheres')
        collection_distorted = blender_utilities.make_collection('distorted')
        collection_blocks = blender_utilities.make_collection('blocks')
        collection_cylinders = blender_utilities.make_collection('cylinders')
        collection_probes = blender_utilities.make_collection('probes')
        ##################

        # we create an instance of the FDTDGeometryObjects class, which allows adding objects to the scene with shared materials (TODO: maybe find a better system?)
        FDTDGeometryObjects_obj = FDTDGeometryObjects()

        # Blender.Window.RedrawAll(); # This must be called before any SetActiveLayer calls!

        layerManager = LayerManagerObjects()

        # Box
        #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('box'));
        obj = FDTDGeometryObjects_obj.GEObox(
            structured_entries.box.name, Vector(structured_entries.box.lower),
            Vector(structured_entries.box.upper))
        blender_utilities.setActiveObject(obj)
        # if bpy.app.version >= (2, 8, 0):
        # bpy.context.view_layer.objects.active = obj
        # else:
        # bpy.context.scene.objects.active = obj

        # if bpy.app.version >= (2, 8, 0):
        blender_utilities.addToCollection(obj,
                                          group_name,
                                          removeFromOthers=False)
        blender_utilities.addToCollection(obj, 'boxes', removeFromOthers=False)

        # blender_utilities.addToCollection(obj, 'cylinders', removeFromOthers=False)
        # blender_utilities.addToCollection(obj, 'cylinders', removeFromOthers=False)
        # blender_utilities.addToCollection(obj, 'probes', removeFromOthers=False)
        # blender_utilities.addToCollection(obj, collection_probes, removeFromOthers=False)
        # blender_utilities.addToCollection(obj, collection_spheres, removeFromOthers=True)
        # else:
        # bpy.ops.object.group_link(group=group_name)
        # bpy.ops.object.group_link(group='boxes')

        # mesh
        #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('mesh'));
        #FDTDGeometryObjects_obj.GEOmesh('mesh', False, structured_entries.delta_X_vector,structured_entries.delta_Y_vector,structured_entries.delta_Z_vector);
        #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('mesh'));
        obj = FDTDGeometryObjects_obj.GEOmesh(
            'mesh', False, structured_entries.mesh.getXmeshDelta(),
            structured_entries.mesh.getYmeshDelta(),
            structured_entries.mesh.getZmeshDelta())
        blender_utilities.setActiveObject(obj, context=bpy.context)

        blender_utilities.addToCollection(obj,
                                          group_name,
                                          removeFromOthers=False)
        blender_utilities.addToCollection(obj,
                                          'meshes',
                                          removeFromOthers=False)

        # Time_snapshot (time or EPS)
        Ntsnaps = 0
        for time_snapshot in structured_entries.time_snapshot_list:

            Ntsnaps += 1
            snap_plane = time_snapshot.getPlaneLetter()
            probe_ident = structured_entries.flag.id_string.replace('\"', '')
            snap_time_number = 1
            TimeSnapshotFileName, alphaID, pair = brisFDTD_ID_info.numID_to_alphaID_TimeSnapshot(
                Ntsnaps, snap_plane, probe_ident, snap_time_number)

            if time_snapshot.eps == 0:
                #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('time_snapshots_'+planeNumberName(time_snapshot.plane)[1]))
                obj = FDTDGeometryObjects_obj.GEOtime_snapshot(
                    time_snapshot.name, time_snapshot.getPlaneLetter(),
                    time_snapshot.P1, time_snapshot.P2)
                blender_utilities.setActiveObject(obj, context=bpy.context)
                blender_utilities.addToCollection(obj,
                                                  group_name,
                                                  removeFromOthers=False)
                blender_utilities.addToCollection(obj,
                                                  'timeSnapshots',
                                                  removeFromOthers=False)
            else:
                #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('eps_snapshots_'+planeNumberName(time_snapshot.plane)[1]))

                obj = FDTDGeometryObjects_obj.GEOeps_snapshot(
                    TimeSnapshotFileName, time_snapshot.getPlaneLetter(),
                    time_snapshot.P1, time_snapshot.P2)
                #obj = FDTDGeometryObjects_obj.GEOeps_snapshot(time_snapshot.name, time_snapshot.plane, time_snapshot.P1, time_snapshot.P2)

                blender_utilities.setActiveObject(obj, context=bpy.context)
                blender_utilities.addToCollection(obj,
                                                  group_name,
                                                  removeFromOthers=False)
                blender_utilities.addToCollection(obj,
                                                  'epsilonSnapshots',
                                                  removeFromOthers=False)

        # Frequency_snapshot
        # TODO: Finally get a correct system for filenames/comment names/etc implemented. getfilename() or something...
        Nfsnaps = 0
        for frequency_snapshot in structured_entries.frequency_snapshot_list:
            #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('frequency_snapshots_'+planeNumberName(frequency_snapshot.plane)[1]));

            Nfsnaps += 1
            snap_plane = frequency_snapshot.getPlaneLetter()
            probe_ident = structured_entries.flag.id_string.replace('\"', '')
            snap_time_number = 0
            FrequencySnapshotFileName, alphaID, pair = brisFDTD_ID_info.numID_to_alphaID_FrequencySnapshot(
                Nfsnaps,
                snap_plane,
                probe_ident,
                snap_time_number,
                pre_2008_BFDTD_version=self.pre_2008_BFDTD_version)

            obj = FDTDGeometryObjects_obj.GEOfrequency_snapshot(
                FrequencySnapshotFileName, frequency_snapshot.getPlaneLetter(),
                frequency_snapshot.P1, frequency_snapshot.P2)
            #obj = FDTDGeometryObjects_obj.GEOfrequency_snapshot(frequency_snapshot.name, frequency_snapshot.plane, frequency_snapshot.P1, frequency_snapshot.P2)

            blender_utilities.setActiveObject(obj, context=bpy.context)
            blender_utilities.addToCollection(obj,
                                              group_name,
                                              removeFromOthers=False)
            blender_utilities.addToCollection(obj,
                                              'frequencySnapshots',
                                              removeFromOthers=False)

        # Excitation
        #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('excitations'));
        for excitation in structured_entries.excitation_list:
            #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('excitations'));
            #print(Blender.Window.GetActiveLayer())
            #print(excitation)
            obj = FDTDGeometryObjects_obj.GEOexcitation(excitation)
            blender_utilities.setActiveObject(obj, context=bpy.context)
            blender_utilities.addToCollection(obj,
                                              group_name,
                                              removeFromOthers=False)
            blender_utilities.addToCollection(obj,
                                              'excitations',
                                              removeFromOthers=False)
            #FDTDGeometryObjects_obj.GEOexcitation(excitation.name, Vector(excitation.P1), Vector(excitation.P2));
        # Probe
        #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('probes'));
        Nprobes = 0
        for probe in structured_entries.probe_list:
            # print('probe = ',Vector(probe.position))
            Nprobes += 1
            ProbeFileName = 'p' + str(
                Nprobes).zfill(2) + structured_entries.flag.id_string.replace(
                    '\"', '') + '.prn'
            #FDTDGeometryObjects_obj.GEOprobe(probe.name+' ('+ProbeFileName+')', Vector(probe.position));
            obj = FDTDGeometryObjects_obj.GEOprobe(ProbeFileName,
                                                   Vector(probe.position))
            blender_utilities.setActiveObject(obj, context=bpy.context)
            blender_utilities.addToCollection(obj,
                                              group_name,
                                              removeFromOthers=False)
            blender_utilities.addToCollection(obj,
                                              'probes',
                                              removeFromOthers=False)

        ##################################################################
        ### geometry loading

        if not self.no_geometry:

            if self.create_vertex_mesh:

                # just create a mesh of vertices representing object locations
                # .. todo:: just as with the lines for cylinders, this should be an option for spheres (i.e. different placeholders for each type of object) (also create different vertex mesh for each "material"/.geo file)

                L = structured_entries.getGeometryObjects()
                N = len(L)
                print('N(objects) = {}'.format(N))

                verts = N * [Vector((0, 0, 0))]

                for idx, obj in enumerate(L):
                    verts[idx] = Vector(obj.getLocation())

                edges = []
                faces = []

                mesh = bpy.data.meshes.new(name="Object positions")
                mesh.from_pydata(verts, edges, faces)
                #object_data_add(bpy.context, mesh, operator=self)
                object_data_add(bpy.context, mesh)

            else:
                # Sphere
                #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('spheres'));
                for sphere in structured_entries.sphere_list:
                    # variables
                    centro = Vector(sphere.getLocation())

                    # initialise rotation_matrix
                    rotation_matrix = Matrix()
                    rotation_matrix.identity()

                    # scale object
                    #Sx=Blender.Mathutils.ScaleMatrix(abs(2*sphere.outer_radius),4,Blender.Mathutils.Vector(1,0,0))
                    #Sy=Blender.Mathutils.ScaleMatrix(abs(2*sphere.outer_radius),4,Blender.Mathutils.Vector(0,1,0))
                    #Sz=Blender.Mathutils.ScaleMatrix(abs(2*sphere.outer_radius),4,Blender.Mathutils.Vector(0,0,1))
                    #rotation_matrix *= Sx*Sy*Sz;

                    # position object
                    #T = Blender.Mathutils.TranslationMatrix(centro)
                    #rotation_matrix *= T;

                    # add rotations
                    #for r in sphere.rotation_list:
                    #rotation_matrix *= rotationMatrix(r.axis_point, r.axis_direction, r.angle_degrees);

                    # create object
                    obj = FDTDGeometryObjects_obj.GEOsphere(
                        sphere.name, sphere.getLocation(), sphere.outer_radius,
                        sphere.inner_radius, sphere.permittivity,
                        sphere.conductivity)
                    #FDTDGeometryObjects_obj.GEOsphere_matrix(sphere.name, rotation_matrix, sphere.outer_radius, sphere.inner_radius, sphere.permittivity, sphere.conductivity);
                    #FDTDGeometryObjects_obj.GEOblock_matrix(sphere.name, rotation_matrix, sphere.permittivity, sphere.conductivity);
                    blender_utilities.setActiveObject(obj, context=bpy.context)
                    blender_utilities.addToCollection(obj,
                                                      group_name,
                                                      removeFromOthers=False)
                    blender_utilities.addToCollection(obj,
                                                      'spheres',
                                                      removeFromOthers=False)

                if self.import_blocks:
                    # Block
                    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('blocks'))
                    for block in structured_entries.block_list:
                        # variables
                        lower = Vector(block.getLowerAbsolute())
                        upper = Vector(block.getUpperAbsolute())
                        pos = 0.5 * (lower + upper)
                        diag = 0.5 * (upper - lower)

                        # initialise rotation_matrix
                        rotation_matrix = Matrix()
                        rotation_matrix.identity()

                        # add rotations
                        for r in block.rotation_list:
                            rotation_matrix = rotationMatrix(
                                r.axis_point, r.axis_direction,
                                r.angle_degrees) * rotation_matrix

                        # position object
                        T = Matrix.Translation(pos)
                        if bpy.app.version >= (2, 8, 0):
                            rotation_matrix @= T
                        else:
                            rotation_matrix *= T

                        ## scale object
                        Sx = Matrix.Scale(abs(diag[0]), 4, Vector((1, 0, 0)))
                        Sy = Matrix.Scale(abs(diag[1]), 4, Vector((0, 1, 0)))
                        Sz = Matrix.Scale(abs(diag[2]), 4, Vector((0, 0, 1)))
                        if bpy.app.version >= (2, 8, 0):
                            rotation_matrix @= Sx @ Sy @ Sz
                        else:
                            rotation_matrix *= Sx * Sy * Sz

                        # create object
                        obj = FDTDGeometryObjects_obj.GEOblock_matrix(
                            block.name, rotation_matrix, block.permittivity,
                            block.conductivity)
                        #FDTDGeometryObjects_obj.GEOblock(block.name, block.lower, block.upper, block.permittivity, block.conductivity)
                        blender_utilities.setActiveObject(obj,
                                                          context=bpy.context)
                        blender_utilities.addToCollection(
                            obj, group_name, removeFromOthers=False)
                        blender_utilities.addToCollection(
                            obj, 'blocks', removeFromOthers=False)

                # Distorted
                for distorted in structured_entries.distorted_list:
                    # create object
                    #print(distorted)
                    obj = FDTDGeometryObjects_obj.GEOdistorted(distorted)
                    blender_utilities.setActiveObject(obj, context=bpy.context)
                    blender_utilities.addToCollection(obj,
                                                      group_name,
                                                      removeFromOthers=False)
                    #bpy.ops.object.group_link(group=type(distorted).__name__)
                    blender_utilities.addToCollection(obj,
                                                      'distorted',
                                                      removeFromOthers=False)

                #########################
                # Cylinders

                if self.import_cylinders:

                    if self.cylinder_to_line_mesh:
                        createLineMeshFromCylinders(structured_entries)
                    else:
                        ## progress indicator does not work when running from CLI
                        if self.GUI_loaded:
                            bpy.context.window_manager.progress_begin(0, 100)

                        #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('cylinders'));

                        if self.restrict_import_volume:
                            if self.volume_specification_style == 'relative':
                                import_volume_xmin = self.xmin * structured_entries.getSize(
                                )[0]
                                import_volume_xmax = self.xmax * structured_entries.getSize(
                                )[0]
                                import_volume_ymin = self.ymin * structured_entries.getSize(
                                )[1]
                                import_volume_ymax = self.ymax * structured_entries.getSize(
                                )[1]
                                import_volume_zmin = self.zmin * structured_entries.getSize(
                                )[2]
                                import_volume_zmax = self.zmax * structured_entries.getSize(
                                )[2]
                            else:
                                import_volume_xmin = self.xmin
                                import_volume_xmax = self.xmax
                                import_volume_ymin = self.ymin
                                import_volume_ymax = self.ymax
                                import_volume_zmin = self.zmin
                                import_volume_zmax = self.zmax

                            truncated_cylinder_list = truncateGeoList(
                                structured_entries.cylinder_list,
                                import_volume_xmin, import_volume_xmax,
                                import_volume_ymin, import_volume_ymax,
                                import_volume_zmin, import_volume_zmax)
                            if self.verbosity > 0:
                                print(self)
                                print(
                                    'len(structured_entries.cylinder_list) = {}'
                                    .format(
                                        len(structured_entries.cylinder_list)))
                                print(
                                    'len(truncated_cylinder_list) = {}'.format(
                                        len(truncated_cylinder_list)))
                        else:
                            truncated_cylinder_list = structured_entries.cylinder_list

                        if self.use_Nmax_objects:
                            truncated_cylinder_list = truncated_cylinder_list[:
                                                                              self
                                                                              .
                                                                              Nmax_objects]

                        # hack to create a lot of objects quickly using duplication.
                        # .. todo:: replace/improve + implement for other objects
                        # .. todo:: one mesh per material & .geo file, rather than multiple objects, while respecting appearance order, i.e. group sequences of same material objects into a single mesh.
                        # cf:
                        #   https://blender.stackexchange.com/questions/7358/python-performance-with-blender-operators
                        #   https://blender.stackexchange.com/questions/39721/how-can-i-create-many-objects-quickly

                        N = len(truncated_cylinder_list)
                        if self.verbosity > 0:
                            print(
                                'len(truncated_cylinder_list) = {}'.format(N))
                        if N > 0:
                            N_added_max = 500
                            N_added = min(N_added_max, N)
                            N_duplications = (N // N_added) - 1
                            N_remainder = N % N_added

                            print('N', N)
                            print('N_added_max', N_added_max)
                            print('N_added', N_added)
                            print('N_duplications', N_duplications)
                            print('N_remainder', N_remainder)
                            print('total = ' +
                                  str(N_added + N_duplications * N_added +
                                      N_remainder))

                            Nfill = len(str(N))

                            cyl_list = N * [0]

                            # add all cylinders
                            print('Adding all ' + str(N) + ' cylinders...')

                            # normal add
                            if self.GUI_loaded:
                                bpy.context.window_manager.progress_update(0)
                            for i in range(N_added + N_remainder):
                                bpy.ops.mesh.primitive_cylinder_add(
                                    location=Vector([0, 0, 0]),
                                    rotation=(radians(-90), 0, 0))
                                bpy.ops.object.transform_apply(
                                    rotation=True
                                )  # aligning cylinder to Y axis directly and applying rotation, to follow BFDTD standard cylinder orientation.
                                cyl_list[i] = bpy.context.object
                                if self.GUI_loaded:
                                    bpy.context.window_manager.progress_update(
                                        i / (N_added + N_remainder))

                            ## select items to duplicate
                            selectObjects(cyl_list[0:N_added])

                            ## duplicate
                            if self.GUI_loaded:
                                bpy.context.window_manager.progress_update(0)
                            for i in range(N_duplications):
                                #'cyl.''{:0>-{Nfill}}'.format(i,Nfill=Nfill)
                                bpy.ops.object.duplicate_move_linked()
                                start_idx = N_added + N_remainder + i * N_added
                                end_idx = start_idx + N_added
                                print((start_idx, end_idx))
                                cyl_list[
                                    start_idx:
                                    end_idx] = bpy.context.selected_objects
                                if self.GUI_loaded:
                                    bpy.context.window_manager.progress_update(
                                        i / N_duplications)

                            # set location/rotation/scale of cylinders
                            print('Setting location/rotation/scale of all ' +
                                  str(N) + ' cylinders...')
                            #for i, cylinder in enumerate(truncated_cylinder_list):
                            #obj = cyl_list[i]

                            if self.GUI_loaded:
                                bpy.context.window_manager.progress_update(0)
                            for i, cylinder in enumerate(
                                    truncated_cylinder_list):
                                #for cylinder in truncated_cylinder_list:

                                # initialise rotation_matrix
                                rotation_matrix = Matrix()
                                rotation_matrix.identity()

                                scale = [
                                    cylinder.outer_radius,
                                    cylinder.outer_radius,
                                    0.5 * cylinder.height
                                ]

                                Sx = Matrix.Scale(scale[0], 4, [1, 0, 0])
                                Sy = Matrix.Scale(scale[1], 4, [0, 1, 0])
                                Sz = Matrix.Scale(scale[2], 4, [0, 0, 1])

                                #rotation_matrix *= Sx*Sy*Sz;

                                # add rotations
                                # TODO: Check it works correctly...
                                for r in cylinder.rotation_list:
                                    rotation_matrix *= rotationMatrix(
                                        r.axis_point, r.axis_direction,
                                        r.angle_degrees) * rotation_matrix

                                #r = cylinder.rotation_list[0]

                                # position object
                                T = Matrix.Translation(
                                    Vector([
                                        cylinder.location[0],
                                        cylinder.location[1],
                                        cylinder.location[2]
                                    ]))
                                rotation_matrix *= T

                                # because FDTD cylinders are aligned with the Y axis by default
                                #rotation_matrix *= rotationMatrix(Vector([0,0,0]), Vector([1,0,0]), -90)

                                # create object
                                #obj = FDTDGeometryObjects_obj.GEOcylinder_matrix(cylinder.name, rotation_matrix, cylinder.inner_radius, cylinder.outer_radius, cylinder.height, cylinder.permittivity, cylinder.conductivity)
                                #obj = cyl_list[i]
                                #GEOcylinder_matrix2(self, obj, name, rotation_matrix, inner_radius, outer_radius, height, permittivity, conductivity)
                                obj = FDTDGeometryObjects_obj.GEOcylinder_matrix2(
                                    cyl_list[i], cylinder.name,
                                    rotation_matrix, cylinder.inner_radius,
                                    cylinder.outer_radius, cylinder.height,
                                    cylinder.permittivity,
                                    cylinder.conductivity)
                                #obj = FDTDGeometryObjects_obj.GEOcylinder_matrix(cylinder.name, rotation_matrix, cylinder.inner_radius, cylinder.outer_radius, cylinder.height, cylinder.permittivity, cylinder.conductivity)
                                #obj = FDTDGeometryObjects_obj.GEOcylinder_passedObj(cyl_list[i], cylinder.name, r.axis_point, r.axis_direction, r.angle_degrees, inner_radius, outer_radius, height, permittivity, conductivity)

                                blender_utilities.setActiveObject(
                                    obj, context=bpy.context)
                                blender_utilities.addToCollection(
                                    obj, group_name, removeFromOthers=False)
                                blender_utilities.addToCollection(
                                    obj, 'cylinders', removeFromOthers=False)

                                #angle_X = numpy.deg2rad(-90)
                                #angle_X = -0.5*numpy.pi
                                #angle_Y = 0
                                #angle_Z = 0
                                #FDTDGeometryObjects_obj.GEOcylinder(cylinder.name, cylinder.centro, cylinder.inner_radius, cylinder.outer_radius, cylinder.height, cylinder.permittivity, cylinder.conductivity, angle_X, angle_Y, angle_Z)

                                if self.GUI_loaded:
                                    bpy.context.window_manager.progress_update(
                                        i / N)
                                else:
                                    print('progress = {}'.format(i / N))

                            if self.GUI_loaded:
                                bpy.context.window_manager.progress_end()
                    ######################### if N > 0: end
        ##################################################################

        #########################
        # Not yet implemented:
        # Flag
        # structured_entries.flag;
        # Boundaries
        # structured_entries.boundaries;
        #########################

        # TODO: Save the layer settings somewhere for reuse
        #scene = Blender.Scene.GetCurrent()
        scene = bpy.context.scene

        layersOn = [
            layerManager.DefaultLayers.index('spheres') + 1,
            layerManager.DefaultLayers.index('blocks') + 1,
            layerManager.DefaultLayers.index('cylinders') + 1
        ]
        print(layersOn)
        #layersOn = [1,2,3]
        #print layersOn
        #Blender.Scene.GetCurrent().setLayers(layersOn)

        #scene.update(0);
        #Blender.Window.RedrawAll();
        #Blender.Window.WaitCursor(0);
        #Blender.Scene.GetCurrent().setLayers([1,3,4,5,6,7,8,9,10]);
        print('...done')
        #print Blender.Get('scriptsdir')
        #Blender.Run(Blender.Get('scriptsdir')+'/layer_manager.py')
        #layer_manager_objects = layer_manager.LayerManagerObjects()
        #Draw.Register(layer_manager_objects.gui, layer_manager_objects.event, layer_manager_objects.button_event)

        #print '=========================='
        #print Blender.Window.GetScreens()
        #print Blender.Window.GetAreaID()
        #print Blender.Window.GetAreaSize()
        #print Blender.Text.Get()
        #print '=========================='
        #~ Blender.Window.FileSelector(algosomething, "Import Bristol FDTD file...");
        #~ Blender.Run('~/.blender/scripts/bfdtd_import.py')

        print('Elapsed time: ', round(time.time() - start_time, 4), 'seconds')
def processFiles(arguments):

    src = arguments.files

    # add .prn files in specified directories recursively
    if arguments.directory:
        for directory in arguments.directory:
            matches = []
            for root, dirnames, filenames in os.walk(directory):
                for filename in fnmatch.filter(filenames, '*.prn'):
                    matches.append(os.path.join(root, filename))

            src.extend(matches)

    dst = len(src) * [0]

    for i in range(len(src)):
        #print(src[i])
        numID, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type = brisFDTD_ID_info.alphaID_to_numID(
            src[i], arguments.expected_object_type, arguments.probe_ident)
        #print(numID, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type)
        if fixed_filename is not None:
            (directory, basename) = os.path.split(fixed_filename)

            # temporary quick hack (TODO: generalize use of offset and implement actual format specifier)
            if arguments.output_format and object_type == 'fsnap':
                #print(snap_time_number)
                basename, alphaID, pair = brisFDTD_ID_info.numID_to_alphaID_FrequencySnapshot(
                    numID + arguments.offset, snap_plane, probe_ident,
                    snap_time_number)

            if arguments.output_directory:
                directory = arguments.output_directory

            if basename is None:
                continue

            fixed_filename = os.path.join(directory, basename)

            dst[i] = fixed_filename
            if dst[i]:
                if arguments.verbose:
                    print(arguments.action + ' ' + src[i] + ' -> ' + dst[i])
                if os.path.isfile(src[i]):
                    if (not os.path.isfile(dst[i])) or arguments.force:
                        if (not arguments.no_act):
                            if arguments.action == 'move':
                                os.rename(src[i], dst[i])
                            elif arguments.action == 'copy':
                                shutil.copy(src[i], dst[i])
                            elif arguments.action == 'copyfile':
                                shutil.copyfile(
                                    src[i], dst[i]
                                )  # when the filesystem does not support chmod permissions (i.e. Windows)
                            elif arguments.action == 'hardlink':
                                os.link(src[i], dst[i])
                            elif arguments.action == 'symlink':
                                os.symlink(src[i], dst[i])
                            else:
                                print('action not recognized : action = ' +
                                      arguments.action,
                                      file=sys.stderr)
                                sys.exit(-1)
                    else:
                        print('WARNING: Skipping ' + src[i] + ' -> ' + dst[i] +
                              ' : destination file exists',
                              file=sys.stderr)
                else:
                    print('WARNING: Skipping ' + src[i] + ' -> ' + dst[i] +
                          ' : source file does not exist',
                          file=sys.stderr)
            else:
                print('WARNING: ' + src[i] + ' could not be converted',
                      file=sys.stderr)

    # left in for reference
    #for filename in fnmatch.filter(filenames, '*:*.prn'):
    #dst.append(os.path.join(root, string.replace(filename,':','10')))
    #for filename in fnmatch.filter(filenames, 'p??id.prn'):
    #dst.append(os.path.join(root, string.replace(filename,'p','p0',1)))
    return
def importBristolFDTD(filename):
    ''' import BristolFDTD geometry from .in,.geo or .inp and create corresponding structure in Blender '''
    print('----->Importing bristol FDTD geometry: '+filename)
    #Blender.Window.WaitCursor(1);

    # save import path
    # Blender.Set('tempdir',os.path.dirname(filename));
    #FILE = open(, 'w');
    #pickle.dump(, FILE);
    #FILE.close();
    
    with open(cfgfile, 'wb') as f:
      # Pickle the 'data' dictionary using the highest protocol available.
      pickle.dump(filename, f, pickle.HIGHEST_PROTOCOL)
    
    # create structured_entries
    structured_entries = readBristolFDTD(filename);
    
    ##################
    # GROUP SETUP
    ##################
    # create group corresponding to this file
    # deselect all
    bpy.ops.object.select_all(action='DESELECT')
    # Truncated to 63 characters because that seems to be the maximum string length Blender accepts for group names.
    # (allows keeping part of the path for better identification if multiple files use the same basename)
    group_name = filename[-63:]
    bpy.ops.group.create(name=group_name)
    
    if not 'meshes' in bpy.data.groups: bpy.ops.group.create(name='meshes')
    if not 'boxes' in bpy.data.groups: bpy.ops.group.create(name='boxes')
    if not 'excitations' in bpy.data.groups: bpy.ops.group.create(name='excitations')
    if not 'frequencySnapshots' in bpy.data.groups: bpy.ops.group.create(name='frequencySnapshots')
    if not 'timeSnapshots' in bpy.data.groups: bpy.ops.group.create(name='timeSnapshots')
    if not 'epsilonSnapshots' in bpy.data.groups: bpy.ops.group.create(name='epsilonSnapshots')
    if not 'spheres' in bpy.data.groups: bpy.ops.group.create(name='spheres')
    if not 'distorted' in bpy.data.groups: bpy.ops.group.create(name='distorted')
    if not 'blocks' in bpy.data.groups: bpy.ops.group.create(name='blocks')
    if not 'cylinders' in bpy.data.groups: bpy.ops.group.create(name='cylinders')
    if not 'probes' in bpy.data.groups: bpy.ops.group.create(name='probes')
    ##################

    FDTDGeometryObjects_obj = FDTDGeometryObjects()
    
    # Blender.Window.RedrawAll(); # This must be called before any SetActiveLayer calls!
    
    layerManager = LayerManagerObjects()
    
    # Box
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('box'));
    obj = FDTDGeometryObjects_obj.GEObox(structured_entries.box.name, Vector(structured_entries.box.lower), Vector(structured_entries.box.upper));
    bpy.context.scene.objects.active = obj
    bpy.ops.object.group_link(group=group_name)
    bpy.ops.object.group_link(group='boxes')
    
    # mesh
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('mesh'));
    #FDTDGeometryObjects_obj.GEOmesh('mesh', False, structured_entries.delta_X_vector,structured_entries.delta_Y_vector,structured_entries.delta_Z_vector);
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('mesh'));
    obj = FDTDGeometryObjects_obj.GEOmesh('mesh', False, structured_entries.mesh.getXmeshDelta(),structured_entries.mesh.getYmeshDelta(),structured_entries.mesh.getZmeshDelta());
    bpy.context.scene.objects.active = obj
    bpy.ops.object.group_link(group=group_name)
    bpy.ops.object.group_link(group='meshes')

    # Time_snapshot (time or EPS)
    Ntsnaps = 0
    for time_snapshot in structured_entries.time_snapshot_list:

      Ntsnaps += 1
      snap_plane = ['x','y','z'][time_snapshot.plane - 1]
      probe_ident = structured_entries.flag.id_string.replace('\"','')
      snap_time_number = 1
      TimeSnapshotFileName, alphaID, pair = brisFDTD_ID_info.numID_to_alphaID_EpsilonSnapshot(Ntsnaps, snap_plane, probe_ident, snap_time_number)

      if time_snapshot.eps == 0:
        #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('time_snapshots_'+planeNumberName(time_snapshot.plane)[1]))
        obj = FDTDGeometryObjects_obj.GEOtime_snapshot(time_snapshot.name, time_snapshot.plane, time_snapshot.P1, time_snapshot.P2)
        bpy.context.scene.objects.active = obj
        bpy.ops.object.group_link(group=group_name)
        bpy.ops.object.group_link(group='timeSnapshots')
      else:
        #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('eps_snapshots_'+planeNumberName(time_snapshot.plane)[1]))

        obj = FDTDGeometryObjects_obj.GEOeps_snapshot(TimeSnapshotFileName, time_snapshot.plane, time_snapshot.P1, time_snapshot.P2)
        #obj = FDTDGeometryObjects_obj.GEOeps_snapshot(time_snapshot.name, time_snapshot.plane, time_snapshot.P1, time_snapshot.P2)

        bpy.context.scene.objects.active = obj
        bpy.ops.object.group_link(group=group_name)
        bpy.ops.object.group_link(group='epsilonSnapshots')

    # Frequency_snapshot
    # TODO: Finally get a correct system for filenames/comment names/etc implemented. getfilename() or something...
    Nfsnaps = 0
    for frequency_snapshot in structured_entries.frequency_snapshot_list:
      #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('frequency_snapshots_'+planeNumberName(frequency_snapshot.plane)[1]));

      Nfsnaps += 1
      snap_plane = ['x','y','z'][frequency_snapshot.plane - 1]
      probe_ident = structured_entries.flag.id_string.replace('\"','')
      snap_time_number = 0
      FrequencySnapshotFileName, alphaID, pair = brisFDTD_ID_info.numID_to_alphaID_FrequencySnapshot(Nfsnaps, snap_plane, probe_ident, snap_time_number)

      obj = FDTDGeometryObjects_obj.GEOfrequency_snapshot(FrequencySnapshotFileName, frequency_snapshot.plane, frequency_snapshot.P1, frequency_snapshot.P2)
      #obj = FDTDGeometryObjects_obj.GEOfrequency_snapshot(frequency_snapshot.name, frequency_snapshot.plane, frequency_snapshot.P1, frequency_snapshot.P2)

      bpy.context.scene.objects.active = obj
      bpy.ops.object.group_link(group=group_name)
      bpy.ops.object.group_link(group='frequencySnapshots')

    # Excitation
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('excitations'));
    for excitation in structured_entries.excitation_list:
        #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('excitations'));
        #print(Blender.Window.GetActiveLayer())
        #print(excitation)
        obj = FDTDGeometryObjects_obj.GEOexcitation(excitation);
        bpy.context.scene.objects.active = obj
        bpy.ops.object.group_link(group=group_name)
        bpy.ops.object.group_link(group='excitations')
        #FDTDGeometryObjects_obj.GEOexcitation(excitation.name, Vector(excitation.P1), Vector(excitation.P2));
    # Probe
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('probes'));
    Nprobes = 0
    for probe in structured_entries.probe_list:
        # print('probe = ',Vector(probe.position))
        Nprobes += 1
        ProbeFileName = 'p' + str(Nprobes).zfill(2) + structured_entries.flag.id_string.replace('\"','') + '.prn'
        #FDTDGeometryObjects_obj.GEOprobe(probe.name+' ('+ProbeFileName+')', Vector(probe.position));
        obj = FDTDGeometryObjects_obj.GEOprobe(ProbeFileName, Vector(probe.position));
        bpy.context.scene.objects.active = obj
        bpy.ops.object.group_link(group=group_name)
        bpy.ops.object.group_link(group='probes')
    
    # Sphere
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('spheres'));
    for sphere in structured_entries.sphere_list:
        # variables
        centre = Vector(sphere.centre)

        # initialise rotation_matrix
        rotation_matrix = Matrix()
        rotation_matrix.identity();

        # scale object
        #Sx=Blender.Mathutils.ScaleMatrix(abs(2*sphere.outer_radius),4,Blender.Mathutils.Vector(1,0,0))
        #Sy=Blender.Mathutils.ScaleMatrix(abs(2*sphere.outer_radius),4,Blender.Mathutils.Vector(0,1,0))
        #Sz=Blender.Mathutils.ScaleMatrix(abs(2*sphere.outer_radius),4,Blender.Mathutils.Vector(0,0,1))
        #rotation_matrix *= Sx*Sy*Sz;

        # position object
        #T = Blender.Mathutils.TranslationMatrix(centre)
        #rotation_matrix *= T;
        
        # add rotations
        #for r in sphere.rotation_list:
          #rotation_matrix *= rotationMatrix(r.axis_point, r.axis_direction, r.angle_degrees);
          
        # create object
        obj = FDTDGeometryObjects_obj.GEOsphere(sphere.name, sphere.centre, sphere.outer_radius, sphere.inner_radius, sphere.permittivity, sphere.conductivity)
        #FDTDGeometryObjects_obj.GEOsphere_matrix(sphere.name, rotation_matrix, sphere.outer_radius, sphere.inner_radius, sphere.permittivity, sphere.conductivity);
        #FDTDGeometryObjects_obj.GEOblock_matrix(sphere.name, rotation_matrix, sphere.permittivity, sphere.conductivity);
        bpy.context.scene.objects.active = obj
        bpy.ops.object.group_link(group=group_name)
        bpy.ops.object.group_link(group='spheres')
        
    # Block
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('blocks'))
    for block in structured_entries.block_list:
        # variables
        lower = Vector(block.lower)
        upper = Vector(block.upper)
        pos = 0.5*(lower+upper)
        diag = 0.5*(upper-lower)

        # initialise rotation_matrix
        rotation_matrix = Matrix()
        rotation_matrix.identity()
        
        # add rotations
        for r in block.rotation_list:
          rotation_matrix = rotationMatrix(r.axis_point, r.axis_direction, r.angle_degrees)*rotation_matrix

        # position object
        T = Matrix.Translation(pos)
        rotation_matrix *= T

        ## scale object
        Sx = Matrix.Scale(abs(diag[0]), 4, Vector((1,0,0)) )
        Sy = Matrix.Scale(abs(diag[1]), 4, Vector((0,1,0)) )
        Sz = Matrix.Scale(abs(diag[2]), 4, Vector((0,0,1)) )
        rotation_matrix *= Sx*Sy*Sz;

        # create object
        obj = FDTDGeometryObjects_obj.GEOblock_matrix(block.name, rotation_matrix, block.permittivity, block.conductivity)
        #FDTDGeometryObjects_obj.GEOblock(block.name, block.lower, block.upper, block.permittivity, block.conductivity)
        bpy.context.scene.objects.active = obj
        bpy.ops.object.group_link(group=group_name)
        bpy.ops.object.group_link(group='blocks')

    # Distorted
    for distorted in structured_entries.distorted_list:
        # create object
        #print(distorted)
        obj = FDTDGeometryObjects_obj.GEOdistorted(distorted.name, distorted.vertices, distorted.permittivity, distorted.conductivity);
        bpy.context.scene.objects.active = obj
        bpy.ops.object.group_link(group=group_name)
        bpy.ops.object.group_link(group='distorted')
        
    # Cylinder
    #Blender.Window.SetActiveLayer(1<<layerManager.DefaultLayers.index('cylinders'));
    for cylinder in structured_entries.cylinder_list:
      
        # initialise rotation_matrix
        rotation_matrix = Matrix()
        rotation_matrix.identity()

        # add rotations
        for r in cylinder.rotation_list:
          rotation_matrix = rotationMatrix(r.axis_point, r.axis_direction, r.angle_degrees)*rotation_matrix

        # position object
        T = Matrix.Translation(Vector([cylinder.centre[0],cylinder.centre[1],cylinder.centre[2]]))
        rotation_matrix *= T;

        # because FDTD cylinders are aligned with the Y axis by default
        rotation_matrix *= rotationMatrix(Vector([0,0,0]), Vector([1,0,0]), -90)

        # create object
        obj = FDTDGeometryObjects_obj.GEOcylinder_matrix(cylinder.name, rotation_matrix, cylinder.inner_radius, cylinder.outer_radius, cylinder.height, cylinder.permittivity, cylinder.conductivity)
        bpy.context.scene.objects.active = obj
        bpy.ops.object.group_link(group=group_name)
        bpy.ops.object.group_link(group='cylinders')
        
        #angle_X = numpy.deg2rad(-90)
        #angle_X = -0.5*numpy.pi
        #angle_Y = 0
        #angle_Z = 0
        #FDTDGeometryObjects_obj.GEOcylinder(cylinder.name, cylinder.centre, cylinder.inner_radius, cylinder.outer_radius, cylinder.height, cylinder.permittivity, cylinder.conductivity, angle_X, angle_Y, angle_Z)

    #########################
    # Not yet implemented:
    # Flag
    # structured_entries.flag;
    # Boundaries
    # structured_entries.boundaries;
    #########################

    # TODO: Save the layer settings somewhere for reuse
    #scene = Blender.Scene.GetCurrent()
    scene = bpy.context.scene
    
    layersOn = [layerManager.DefaultLayers.index('spheres')+1,layerManager.DefaultLayers.index('blocks')+1,layerManager.DefaultLayers.index('cylinders')+1]
    print(layersOn)
    #layersOn = [1,2,3]
    #print layersOn
    #Blender.Scene.GetCurrent().setLayers(layersOn)
    
    #scene.update(0);
    #Blender.Window.RedrawAll();
    #Blender.Window.WaitCursor(0);
    #Blender.Scene.GetCurrent().setLayers([1,3,4,5,6,7,8,9,10]);
    print('...done')
def processFiles(arguments):

  src = arguments.files

  # add .prn files in specified directories recursively
  if arguments.directory:
    for directory in arguments.directory:
      matches = []
      for root, dirnames, filenames in os.walk(directory):
        for filename in fnmatch.filter(filenames, '*.prn'):
          matches.append(os.path.join(root, filename))
      
      src.extend(matches)
  
  dst = len(src)*[0]
  
  for i in range(len(src)):
    #print(src[i])
    numID, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type = brisFDTD_ID_info.alphaID_to_numID(src[i], arguments.expected_object_type, arguments.probe_ident)
    #print(numID, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type)
    if fixed_filename is not None:
      (directory, basename) = os.path.split(fixed_filename)

      # temporary quick hack (TODO: generalize use of offset and implement actual format specifier)
      if arguments.output_format and object_type=='fsnap':
        #print(snap_time_number)
        basename, alphaID, pair = brisFDTD_ID_info.numID_to_alphaID_FrequencySnapshot(numID + arguments.offset, snap_plane, probe_ident, snap_time_number)

      if arguments.output_directory:
        directory = arguments.output_directory
      
      if basename is None:
        continue
        
      fixed_filename = os.path.join(directory, basename)

      dst[i] = fixed_filename
      if dst[i]:
        if arguments.verbose:
          print( arguments.action + ' ' + src[i] + ' -> ' + dst[i] )
        if os.path.isfile(src[i]):
          if (not os.path.isfile(dst[i])) or arguments.force:
            if (not arguments.no_act):
              if arguments.action == 'move':
                os.rename(src[i], dst[i])
              elif arguments.action == 'copy':
                shutil.copy(src[i], dst[i])
              elif arguments.action == 'copyfile':
                shutil.copyfile(src[i], dst[i]) # when the filesystem does not support chmod permissions (i.e. Windows)
              elif arguments.action == 'hardlink':
                os.link(src[i], dst[i])
              elif arguments.action == 'symlink':
                os.symlink(src[i], dst[i])
              else:
                print('action not recognized : action = ' + arguments.action,file=sys.stderr)
                sys.exit(-1)
          else:
            print('WARNING: Skipping '+src[i]+' -> '+dst[i]+' : destination file exists', file=sys.stderr)
        else:
          print('WARNING: Skipping '+src[i]+' -> '+dst[i]+' : source file does not exist', file=sys.stderr)
      else:
        print('WARNING: ' + src[i] + ' could not be converted', file=sys.stderr)

  # left in for reference
  #for filename in fnmatch.filter(filenames, '*:*.prn'):
    #dst.append(os.path.join(root, string.replace(filename,':','10')))
  #for filename in fnmatch.filter(filenames, 'p??id.prn'):
    #dst.append(os.path.join(root, string.replace(filename,'p','p0',1)))
  return