Exemple #1
0
def associate_inner_boundaries(fc_boundaries, doc):
    """Associate parent boundary and inner boundaries"""
    to_delete = []
    for fc_boundary in fc_boundaries:
        if not fc_boundary.IsHosted or fc_boundary.ParentBoundary:
            continue
        host_boundaries = []
        for host_element in fc_boundary.RelatedBuildingElement.HostElements:
            host_boundaries.extend(host_element.ProvidesBoundaries)

        candidates = set(fc_boundaries).intersection(host_boundaries)

        try:
            host = get_host(fc_boundary, candidates)
        except InvalidBoundary as err:
            logger.exception(err)
            to_delete.append(fc_boundary)
            continue

        fc_boundary.ParentBoundary = host
        if host:
            utils.append(host, "InnerBoundaries", fc_boundary)

    # Remove invalid boundary and corresponding inner wire
    updated_boundaries = fc_boundaries[:]
    for boundary in to_delete:
        remove_invalid_inner_wire(boundary, updated_boundaries)
        updated_boundaries.remove(boundary)
        doc.removeObject(boundary.Name)
Exemple #2
0
def merge_boundaries(boundary1, boundary2) -> bool:
    """Try to merge 2 boundaries. Retrun True if successfully merged"""
    wire1 = utils.get_outer_wire(boundary1)
    wire2 = utils.get_outer_wire(boundary2)

    new_wire, extra_inner_wires = merged_wires(wire1, wire2)
    if not new_wire:
        return False

    # Update shape
    if boundary1.IsHosted:
        utils.remove_inner_wire(boundary1.ParentBoundary, wire1)
        utils.remove_inner_wire(boundary2.ParentBoundary, wire2)
        utils.append_inner_wire(boundary1.ParentBoundary, new_wire)
    else:
        for inner_boundary in boundary2.InnerBoundaries:
            utils.append(boundary1, "InnerBoundaries", inner_boundary)
            inner_boundary.ParentBoundary = boundary1
    inner_wires = utils.get_inner_wires(boundary1)[:]
    inner_wires.extend(utils.get_inner_wires(boundary2))
    inner_wires.extend(extra_inner_wires)

    try:
        utils.generate_boundary_compound(boundary1, new_wire, inner_wires)
    except RuntimeError as error:
        logger.exception(error)
        return False
    RelSpaceBoundary.recompute_areas(boundary1)

    return True
Exemple #3
0
def handle_curtain_walls(space, doc) -> None:
    """Add an hosted window with full area in curtain wall boundaries as they are not handled
    by BEM softwares"""
    for boundary in space.SecondLevel.Group:
        if getattr(boundary.RelatedBuildingElement, "IfcType",
                   "") != "IfcCurtainWall":
            continue
        # Prevent Revit issue which produce curtain wall with an hole inside but no inner boundary
        if not boundary.InnerBoundaries:
            if len(boundary.Shape.SubShapes) > 2:
                outer_wire = boundary.Shape.SubShapes[1]
                utils.generate_boundary_compound(boundary, outer_wire, ())
        boundary.LesoType = "Wall"
        fake_window = doc.copyObject(boundary)
        fake_window.IsHosted = True
        fake_window.LesoType = "Window"
        fake_window.ParentBoundary = boundary
        fake_window.GlobalId = ifcopenshell.guid.new()
        fake_window.Id = IfcId.new(doc)
        RelSpaceBoundary.set_label(fake_window)
        space.SecondLevel.addObject(fake_window)
        # Host cannot be an empty face so inner wire is scaled down a little
        inner_wire = utils.get_outer_wire(boundary).scale(0.999)
        inner_wire = utils.project_wire_to_plane(inner_wire,
                                                 utils.get_plane(boundary))
        utils.append_inner_wire(boundary, inner_wire)
        utils.append(boundary, "InnerBoundaries", fake_window)
        if FreeCAD.GuiUp:
            fake_window.ViewObject.ShapeColor = (0.0, 0.7, 1.0)
Exemple #4
0
def ensure_hosted_element_are(space, doc):
    for boundary in space.SecondLevel.Group:
        try:
            ifc_type = boundary.RelatedBuildingElement.IfcType
        except AttributeError:
            continue

        if not is_typically_hosted(ifc_type):
            continue

        if boundary.IsHosted and boundary.ParentBoundary:
            continue

        def valid_hosts(boundary):
            """Guess valid hosts"""
            for boundary2 in space.SecondLevel.Group:
                if boundary is boundary2 or is_typically_hosted(
                        boundary2.IfcType):
                    continue

                if not boundary2.Area.Value - boundary.Area.Value >= 0:
                    continue

                if not utils.are_parallel_boundaries(boundary, boundary2):
                    continue

                if utils.are_too_far(boundary, boundary2):
                    continue

                yield boundary2

        def find_host(boundary):
            fallback_solution = None
            for boundary2 in valid_hosts(boundary):

                fallback_solution = boundary2
                for inner_wire in utils.get_inner_wires(boundary2):
                    if (not abs(
                            Part.Face(inner_wire).Area - boundary.Area.Value) <
                            TOLERANCE):
                        continue

                    return boundary2
            if not fallback_solution:
                raise HostNotFound(
                    f"No host found for RelSpaceBoundary Id<{boundary.Id}>")
            logger.warning(
                f"Using fallback solution to resolve host of RelSpaceBoundary Id<{boundary.Id}>"
            )
            return fallback_solution

        try:
            host = find_host(boundary)
        except HostNotFound as err:
            host = create_fake_host(boundary, space, doc)
            logger.exception(err)
        boundary.IsHosted = True
        boundary.ParentBoundary = host
        utils.append(host, "InnerBoundaries", boundary)
Exemple #5
0
 def create_element_type(self, fc_element, ifc_entity_type):
     if not ifc_entity_type:
         return
     try:
         fc_element_type = self.element_types[ifc_entity_type.id()]
     except KeyError:
         fc_element_type = ElementType.create_from_ifc(
             ifc_entity_type, self)
         self.element_types[fc_element_type.Id] = fc_element_type
     fc_element.IsTypedBy = fc_element_type
     utils.append(fc_element_type, "ApplicableOccurrence", fc_element)
Exemple #6
0
 def assign_material(self, material_select):
     if material_select.is_a("IfcMaterial"):
         self.obj.Material = self.create_single(material_select)
     elif material_select.is_a("IfcMaterialLayerSet"):
         self.obj.Material = self.create_layer_set(material_select)
         utils.append(self.obj.Material, "AssociatedTo", self.obj)
     elif material_select.is_a("IfcMaterialConstituentSet"):
         self.obj.Material = self.create_constituent_set(material_select)
     elif material_select.is_a("IfcMaterialProfileSet"):
         self.obj.Material = self.create_profile_set(material_select)
     else:
         raise NotImplementedError(
             f"{material_select.is_a()} not handled yet")
Exemple #7
0
def associate_host_element(ifc_file, elements_group):
    # Associate Host / Hosted elements
    ifc_elements = (e for e in ifc_file.by_type("IfcElement")
                    if e.ProvidesBoundaries)
    for ifc_entity in ifc_elements:
        if ifc_entity.FillsVoids:
            try:
                host = utils.get_element_by_guid(
                    utils.get_host_guid(ifc_entity), elements_group)
            except LookupError as err:
                logger.exception(err)
                continue
            hosted = utils.get_element_by_guid(ifc_entity.GlobalId,
                                               elements_group)
            utils.append(host, "HostedElements", hosted)
            utils.append(hosted, "HostElements", host)
Exemple #8
0
def associate_parent_and_corresponding(ifc_file, doc):
    try:
        for boundary in ifc_file.by_type("IfcRelSpaceBoundary2ndLevel"):
            if boundary.ParentBoundary:
                fc_boundary = utils.get_object(boundary, doc)
                fc_parent = utils.get_object(boundary.ParentBoundary, doc)
                fc_boundary.ParentBoundary = fc_parent
                utils.append(fc_parent, "InnerBoundaries", fc_boundary)
            if boundary.CorrespondingBoundary:
                fc_boundary = utils.get_object(boundary, doc)
                if fc_boundary.CorrespondingBoundary:
                    continue
                fc_corresponding_boundary = utils.get_object(
                    boundary.CorrespondingBoundary, doc)
                fc_boundary.CorrespondingBoundary = fc_corresponding_boundary
                fc_corresponding_boundary.CorrespondingBoundary = fc_boundary
    except RuntimeError:
        # When entity do not exist in the schema
        pass
Exemple #9
0
def create_fake_host(boundary, space, doc):
    fake_host = doc.copyObject(boundary)
    fake_host.IsHosted = False
    fake_host.LesoType = "Wall"
    fake_host.GlobalId = ifcopenshell.guid.new()
    fake_host.Id = IfcId.new(doc)
    RelSpaceBoundary.set_label(fake_host)
    space.SecondLevel.addObject(fake_host)
    inner_wire = utils.get_outer_wire(boundary)
    outer_wire = inner_wire.scaled(1.001, inner_wire.CenterOfMass)
    plane = utils.get_plane(boundary)
    outer_wire = utils.project_wire_to_plane(outer_wire, plane)
    inner_wire = utils.project_wire_to_plane(inner_wire, plane)
    utils.generate_boundary_compound(fake_host, outer_wire, [inner_wire])
    boundary.ParentBoundary = fake_host
    fake_building_element = doc.copyObject(boundary.RelatedBuildingElement)
    fake_building_element.Id = IfcId.new(doc)
    fake_host.RelatedBuildingElement = fake_building_element
    utils.append(fake_host, "InnerBoundaries", boundary)
    if FreeCAD.GuiUp:
        fake_host.ViewObject.ShapeColor = (0.7, 0.3, 0.0)
    return fake_host