Exemplo n.º 1
0
def gen_U(info, layerNum, objID):
    """For a given layerNum and objID, compute the quantity:
    ```latex
    U_{n,i}(t) = (\cup_{m<n;j} G_{m,j}) \cup (\cup_{k} A_k),
    ```
    where the inner union terms are not included if their intersection
    with B_i is empty.
    """
    layers = info.lithoDict["layers"]
    B = layers[layerNum]["objIDs"][objID]["B"]  # B prism for this layer & objID
    GList = []
    for m in layers.keys():
        if m < layerNum:  # then this is a lower layer
            for j in layers[m].keys():
                if "G" not in layers[layerNum]["objIDs"][objID]:
                    gen_G(info, m, j)
                G = layers[layerNum]["objIDs"][objID]["G"]
                if checkOverlap([B, G]):
                    GList.append(G)
    AList = []
    for A in info.lithoDict["substrate"][()]:
        if checkOverlap([B, A]):
            AList.append(A)
    unionList = GList + AList
    unionObj = genUnion(unionList, consumeInputs=False)
    return unionObj
Exemplo n.º 2
0
def screened_A_UnionList(info, opts, obj, t, ti, offsetTuple, checkOffsetTuple):
    """Form the screened union list of obj with the substrate A that has
    been offset according to offsetTuple.
    """
    logging.debug(">>> %s (%s)", obj.Name, obj.Label)
    # First, we need to see if we have built the objects before:
    if checkOffsetTuple not in info.lithoDict["substrate"]:
        info.lithoDict["substrate"][checkOffsetTuple] = []
        for A in info.lithoDict["substrate"][()]:
            AObj = gen_offset(opts, A, t)
            info.trash.append(AObj)
            info.lithoDict["substrate"][checkOffsetTuple].append(AObj)
    if offsetTuple not in info.lithoDict["substrate"]:
        info.lithoDict["substrate"][offsetTuple] = []
        for A in info.lithoDict["substrate"][()]:
            AObj = gen_offset(opts, A, t + ti)
            info.trash.append(AObj)
            info.lithoDict["substrate"][offsetTuple].append(AObj)

    returnList = []
    for i, ACheck in enumerate(info.lithoDict["substrate"][checkOffsetTuple]):
        if checkOverlap([obj, ACheck]):
            returnList.append(info.lithoDict["substrate"][offsetTuple][i])

    logging.debug("<<< %s", [o.Name + " (" + o.Label + ")" for o in returnList])
    return returnList
Exemplo n.º 3
0
def screened_H_union_list(info, opts, obj, m, j, offsetTuple,
                          checkOffsetTuple):
    """Foremd the "screened union list" of obj with the layer m, objID j H object that has
    been offset according to offsetTuple. The screened union list is defined by checking
    first whether the object intersects with the components of the checkOffset version
    of the H object. Then, for each component that would intersect, we return the a list
    of the offsetTuple version of the object.
    """
    # First, we need to check to see if we need to compute either of the
    # underlying H obj lists:
    HDict = info.lithoDict['layers'][m]['objIDs'][j]['HDict']
    # HDict stores a collection of H object component lists for each (layerNum,objID)
    # pair. The index of this dictionary is a tuple: () indicates no
    # offset, while other indices indicate an offset by summing the thicknesses
    # from corresponding layers.
    if checkOffsetTuple not in HDict:  # If we haven't computed this yet
        HDict[checkOffsetTuple] = H_offset(
            info, opts, m, j, tList=list(checkOffsetTuple))  # list of H parts
        info.trash += HDict[checkOffsetTuple]
    if offsetTuple not in HDict:  # If we haven't computed this yet
        HDict[offsetTuple] = H_offset(
            info, opts, m, j, tList=list(offsetTuple))  # list of H parts
        info.trash += HDict[offsetTuple]
    HObjCheckList = HDict[checkOffsetTuple]
    HObjList = HDict[offsetTuple]
    returnList = []
    for i, HObjPart in enumerate(HObjCheckList):
        if checkOverlap([obj, HObjPart]):  # if we need to include an overlap
            returnList.append(HObjList[i])
    return returnList
Exemplo n.º 4
0
def screened_H_union_list(info, opts, obj, m, j, offsetTuple, checkOffsetTuple):
    """Form the screened union list of obj with the layer m, objID j H object that has
    been offset according to offsetTuple. The screened union list is defined by checking
    first whether the object intersects with the components of the checkOffset version
    of the H object. Then, for each component that would intersect, we return the a list
    of the offsetTuple version of the object.
    """
    logging.debug(">>> %s (%s)", obj.Name, obj.Label)
    # First, we need to check to see if we need to compute either of the
    # underlying H obj lists:
    HDict = info.lithoDict["layers"][m]["objIDs"][j]["HDict"]
    # HDict stores a collection of H object component lists for each (layerNum,objID)
    # pair. The index of this dictionary is a tuple: () indicates no
    # offset, while other indices indicate an offset by summing the thicknesses
    # from corresponding layers.
    if checkOffsetTuple not in HDict:  # If we haven't computed this yet
        HDict[checkOffsetTuple] = H_offset(
            info, opts, m, j, tList=list(checkOffsetTuple)
        )  # list of H parts
        info.trash += HDict[checkOffsetTuple]
    if offsetTuple not in HDict:  # If we haven't computed this yet
        HDict[offsetTuple] = H_offset(
            info, opts, m, j, tList=list(offsetTuple)
        )  # list of H parts
        info.trash += HDict[offsetTuple]
    HObjCheckList = HDict[checkOffsetTuple]
    HObjList = HDict[offsetTuple]

    returnList = []
    for i, HObjPart in enumerate(HObjCheckList):
        if checkOverlap([obj, HObjPart]):  # if we need to include an overlap
            returnList.append(HObjList[i])

    # fix for multilayer intersections: make sure we really check all overlaps
    for i, HObjPart in enumerate(HObjList):
        if checkOverlap([obj, HObjPart]):  # if we need to include an overlap
            returnList.append(HObjList[i])

    logging.debug("<<< %s", [o.Name + " (" + o.Label + ")" for o in returnList])
    return returnList
Exemplo n.º 5
0
def test_overlapping_parts(datadir):
    """
    This tests that two parts that were generated from lithography over a wire register as intersecting. Due to
    an OCC bug, FC 0.18 at one point would claim that these didn't intersect, resulting in geometry and meshing errors.
    """
    path = os.path.join(datadir, "intersection_test.FCStd")
    doc = FreeCAD.newDocument("instance")
    FreeCAD.setActiveDocument("instance")
    doc.load(path)
    shape_1 = doc.Objects[0]
    shape_2 = doc.Objects[1]
    assert checkOverlap([shape_1, shape_2])
    FreeCAD.closeDocument(doc.Name)
Exemplo n.º 6
0
def screened_A_UnionList(info, opts, obj, t, ti, offsetTuple,
                         checkOffsetTuple):
    """Form the screened union list of obj with the substrate A that has
    been offset according to offsetTuple.

    Parameters
    ----------
    info :

    opts : dict
        Options dict in the QMT Geometry3D.__init__ input format.

    obj : FreeCAD.App.Document
        A FreeCAD object.
    t :

    ti :

    offsetTuple :

    checkOffsetTuple :


    Returns
    -------


    """
    logging.debug(">>> %s (%s)", obj.Name, obj.Label)
    # First, we need to see if we have built the objects before:
    if checkOffsetTuple not in info.lithoDict["substrate"]:
        info.lithoDict["substrate"][checkOffsetTuple] = []
        for A in info.lithoDict["substrate"][()]:
            AObj = gen_offset(opts, A, t)
            info.trash.append(AObj)
            info.lithoDict["substrate"][checkOffsetTuple].append(AObj)
    if offsetTuple not in info.lithoDict["substrate"]:
        info.lithoDict["substrate"][offsetTuple] = []
        for A in info.lithoDict["substrate"][()]:
            AObj = gen_offset(opts, A, t + ti)
            info.trash.append(AObj)
            info.lithoDict["substrate"][offsetTuple].append(AObj)

    returnList = []
    for i, ACheck in enumerate(info.lithoDict["substrate"][checkOffsetTuple]):
        if checkOverlap([obj, ACheck]):
            returnList.append(info.lithoDict["substrate"][offsetTuple][i])

    logging.debug("<<< %s", [f"{o.Name} ({o.Label})" for o in returnList])
    return returnList
Exemplo n.º 7
0
def screened_A_UnionList(info, opts, obj, t, ti, offsetTuple,
                         checkOffsetTuple):
    """Foremd the "screened union list" of obj with the substrate A that has
    been offset according to offsetTuple.
    """
    # First, we need to see if we have built the objects before:
    if checkOffsetTuple not in info.lithoDict['substrate']:
        info.lithoDict['substrate'][checkOffsetTuple] = []
        for A in info.lithoDict['substrate'][()]:
            AObj = gen_offset(opts, A, t)
            info.trash.append(AObj)
            info.lithoDict['substrate'][checkOffsetTuple].append(AObj)
    if offsetTuple not in info.lithoDict['substrate']:
        info.lithoDict['substrate'][offsetTuple] = []
        for A in info.lithoDict['substrate'][()]:
            AObj = gen_offset(opts, A, t + ti)
            info.trash.append(AObj)
            info.lithoDict['substrate'][offsetTuple].append(AObj)

    returnList = []
    for i, ACheck in enumerate(info.lithoDict['substrate'][checkOffsetTuple]):
        if checkOverlap([obj, ACheck]):
            returnList.append(info.lithoDict['substrate'][offsetTuple][i])
    return returnList
Exemplo n.º 8
0
def build(opts):
    """Build the 3D geometry in FreeCAD.

    Parameters
    ----------
    opts : dict
        Options dict in the QMT Geometry3D.__init__ input format.
        Options dict in the QMT Geometry3D.__init__ input format.

    Returns
    -------
    Geo3DData object.

    """
    doc = FreeCAD.ActiveDocument
    geo = Geo3DData(opts.get("lunit", None))

    # Schedule for deletion all objects not explicitly selected by the user
    input_parts_names = []
    for part in opts["input_parts"]:
        if part.fc_name is None:
            obj_list = doc.getObjectsByLabel(part.label)
            if len(obj_list) != 1:
                msg = f"Part labeled {part.label} returned object list {obj_list}"
                raise KeyError(msg)
            fc_name = obj_list[0].Name
            part.fc_name = fc_name
        else:
            fc_name = part.fc_name
        input_parts_names += [fc_name]

    blacklist = []
    for obj in doc.Objects:
        if (obj.Name not in input_parts_names) and (obj.TypeId !=
                                                    "Spreadsheet::Sheet"):
            blacklist.append(obj)

    # Update the model parameters
    if "params" in opts:
        # Extend params dictionary to original parts schema
        fcdict = {
            key: (value, "freeCAD")
            for (key, value) in opts["params"].items()
        }
        set_params(doc, fcdict)

    doc.recompute(
    )  # recompute here to update any sketches that change due to parameters

    if "built_part_names" not in opts:
        opts["built_part_names"] = {}
    if "serial_stp_parts" not in opts:
        opts["serial_stp_parts"] = {}

    # Build the parts
    info_holder = DummyInfo()  # temporary workaround to support old litho code
    built_parts = []
    for input_part in opts["input_parts"]:

        if isinstance(input_part, part_3d.ExtrudePart):
            part = build_extrude(input_part)
        elif isinstance(input_part, part_3d.SAGPart):
            part = build_sag(input_part)
        elif isinstance(input_part, part_3d.WirePart):
            part = build_wire(input_part)
        elif isinstance(input_part, part_3d.WireShellPart):
            part = build_wire_shell(input_part)
        elif isinstance(input_part, part_3d.LithographyPart):
            part = build_lithography(input_part, opts, info_holder)
        elif isinstance(input_part, part_3d.Geo3DPart):
            part = build_pass(input_part)
        else:
            raise ValueError(
                f"{input_part} is not a recognized Geo3DPart type")

        assert part is not None
        doc.recompute()
        built_parts.append(part)
        # needed for litho steps
        opts["built_part_names"][input_part.label] = part.Name

    # Cleanup
    if not DBG_OUT:
        collect_garbage(info_holder)
        for obj in blacklist:
            delete(obj)
        doc.recompute()

    # Subtraction (removes the need for subtractlists)
    for i, (input_part,
            part) in enumerate(zip(opts["input_parts"], built_parts)):
        if input_part.virtual:
            continue
        for other_input_part, other_part in zip(opts["input_parts"][0:i],
                                                built_parts[0:i]):
            if other_input_part.virtual:
                continue
            if checkOverlap([part, other_part]):
                cut = subtract(
                    part,
                    copy_move(other_part),
                    consumeInputs=True if not DBG_OUT else False,
                )
                simple_copy = doc.addObject("Part::Feature", "simple_copy")
                # no solid, just its shape (can be disjoint)
                simple_copy.Shape = cut.Shape
                delete(cut)
                part = simple_copy
                built_parts[i] = simple_copy

    # Update names and store the built parts
    built_parts_dict = {}  # dict for cross sections
    for input_part, built_part in zip(opts["input_parts"], built_parts):
        built_part.Label = input_part.label  # here it's collision free
        output_part = deepcopy(input_part)
        output_part.serial_stp = store_serial([built_part], exportCAD, "stp")
        output_part.serial_stl = store_serial([built_part], exportMeshed,
                                              "stl")
        output_part.built_fc_name = built_part.Name
        geo.add_part(output_part.label, output_part)
        # dict for cross sections
        built_parts_dict[input_part.label] = built_part

    # Build cross sections:
    for xsec_name in opts["xsec_dict"]:
        axis = opts["xsec_dict"][xsec_name]["axis"]
        distance = opts["xsec_dict"][xsec_name]["distance"]
        polygons = buildCrossSection(xsec_name, axis, distance,
                                     built_parts_dict)
        geo.add_xsec(xsec_name, polygons, axis=axis, distance=distance)

    # Store the FreeCAD document
    geo.set_data(doc)

    return geo
Exemplo n.º 9
0
def build(opts):
    '''Build the 3D geometry in FreeCAD.

    :param dict opts:   Options dict in the QMT Geometry3D.__init__ input format.
    :return geo:        Geo3DData object with the built objects.
    '''
    doc = FreeCAD.ActiveDocument
    geo = Geo3DData()

    # Schedule for deletion all objects not explicitly selected by the user
    input_parts_names = [part.fc_name for part in opts['input_parts']]
    blacklist = []
    for obj in doc.Objects:
        if (obj.Name not in input_parts_names) and (obj.TypeId !=
                                                    'Spreadsheet::Sheet'):
            blacklist.append(obj)

    # Update the model parameters
    if 'params' in opts:
        # Extend params dictionary to original parts schema
        fcdict = {
            key: (value, 'freeCAD')
            for (key, value) in opts['params'].items()
        }
        set_params(doc, fcdict)

    if 'built_part_names' not in opts:
        opts['built_part_names'] = {}
    if 'serial_stp_parts' not in opts:
        opts['serial_stp_parts'] = {}

    # Build the parts
    info_holder = DummyInfo()  # temporary workaround to support old litho code
    built_parts = []
    for input_part in opts['input_parts']:

        if input_part.directive == 'extrude':
            part = build_extrude(input_part)
        elif input_part.directive == 'SAG':
            part = build_sag(input_part)
        elif input_part.directive == 'wire':
            part = build_wire(input_part)
        elif input_part.directive == 'wire_shell':
            part = build_wire_shell(input_part)
        elif input_part.directive == 'lithography':
            part = build_lithography(input_part, opts, info_holder)
        elif input_part.directive == '3d_shape':
            part = build_pass(input_part)
        else:
            raise ValueError('Directive ' + input_part.directive +
                             ' is not a recognized directive type.')

        assert part is not None
        doc.recompute()
        built_parts.append(part)
        opts['built_part_names'][
            input_part.label] = part.Name  # needed for litho steps

    # Cleanup
    collect_garbage(info_holder)
    for obj in blacklist:
        delete(obj)
    doc.recompute()

    # Subtraction (removes the need for subtractlists)
    for i, part in enumerate(built_parts):
        for other_part in built_parts[0:i]:
            if checkOverlap([part, other_part]):
                cut = subtract(part, copy_move(other_part), consumeInputs=True)
                simple_copy = doc.addObject('Part::Feature', "simple_copy")
                simple_copy.Shape = cut.Shape  # no solid, just its shape (can be disjoint)
                delete(cut)
                part = simple_copy
                built_parts[i] = simple_copy

    # Update names and store the built parts
    for input_part, built_part in zip(opts['input_parts'], built_parts):
        built_part.Label = input_part.label  # here it's collision free
        input_part.serial_stp = store_serial([built_part], exportCAD, 'stp')
        input_part.built_fc_name = built_part.Name
        geo.add_part(input_part.label, input_part)

    # Store the FreeCAD document
    geo.set_data('fcdoc', doc)

    return geo