Esempio n. 1
0
def _bspline_restrict(solid, tol):
    """
    Attempt to re-fit OpenVSP surfaces with more continuity.
    """
    # Use dmax=1 because that was only way to get the tool actually refit the
    # surfaces other than another surface where the multiplicity equaled the
    # degree. Not sure why the tool operates this way.
    logger.info('\tApplying ShapeBSplineRestriction tool...')
    tool = ShapeBSplineRestriction(solid, dmax=1, tol3d=tol)
    if not tool.is_done:
        logger.info('Method unsuccessful. Using original solid.')
        return solid

    # Get new shape and solid
    new_solid = tool.modified_shape(solid)

    # Limit/fix tolerance
    FixShape.limit_tolerance(new_solid)
    tol = new_solid.tol_avg
    if not CheckShape(new_solid).is_valid:
        logger.info('Shape invalid. Using original solid.')
        return solid

    logger.info('\tMethod successful with surface error: {}'.format(
        tool.error_surface))
    logger.info('\tNew shape tolerance: {}'.format(tol))

    return new_solid
Esempio n. 2
0
    def __init__(self, group=None, precision=None, min_tol=None, max_tol=None):
        group = GroupAPI.get_group(group)
        if not isinstance(group, Group):
            raise TypeError('Could not find group.')

        parts = group.get_parts()
        compound = group.get_shape()

        fix = FixShape(compound, precision, min_tol, max_tol)

        for part in parts:
            new_shape = fix.apply(part.shape)
            part.set_shape(new_shape)
Esempio n. 3
0
    def fix(self,
            precision=None,
            min_tol=None,
            max_tol=None,
            context=None,
            include_subgroup=True):
        """
        Attempt to fix the shape of the part using :class:`.FixShape`.

        :param float precision: Basic precision value.
        :param float min_tol: Minimum tolerance.
        :param float max_tol: Maximum tolerance.
        :param context: The context shape or group.
        :type context: afem.topology.entities.Shape or
            afem.structure.entities.Group or str
        :param bool include_subgroup: Option to recursively include parts
            from any subgroups.

        :return: None.
        """
        if context is not None:
            if not isinstance(context, Shape):
                context = GroupAPI.get_shape(context, include_subgroup)

        new_shape = FixShape(self._shape, precision, min_tol, max_tol,
                             context).shape
        self.set_shape(new_shape)
Esempio n. 4
0
    def set_tolerance(group=None, tol=1.0e7):
        """
        Enforce tolerance on the given group.

        :param group: The group. If ``None`` then the active group is
            used.
        :type group: str or afem.structure.group.Group or None
        :param float tol: The tolerance.

        :return: None.

        :raise TypeError: If an :class:`.Group` instance is not found.
        """
        group = GroupAPI.get_group(group)
        if not isinstance(group, Group):
            raise TypeError('Could not find group.')

        shape = group.get_shape()
        return FixShape.set_tolerance(shape, tol)
Esempio n. 5
0
    def limit_tolerance(group=None, tol=1.0e-7):
        """
        Limit tolerances for the group shapes.

        :param group: The group. If ``None`` then the active group is
            used.
        :type group: str or afem.structure.group.Group or None
        :param float tol: Target tolerance.

        :return: *True* if at least one tolerance of a sub-shape was modified.
        :rtype: bool

        :raise TypeError: If an :class:`.Group` instance is not found.
        """
        group = GroupAPI.get_group(group)
        if not isinstance(group, Group):
            raise TypeError('Could not find group.')

        shape = group.get_shape()
        return FixShape.limit_tolerance(shape, tol)
Esempio n. 6
0
def _build_solid(compound, divide_closed):
    """
    Try to build a solid from the OpenVSP compound of faces.

    :param afem.topology.entities.Compound compound: The compound.
    :param bool divide_closed: Option to divide closed faces.

    :return: The solid.
    :rtype: afem.topology.entities.Solid
    """
    # Get all the faces in the compound. The surfaces must be split. Discard
    # any with zero area.
    faces = []
    for face in compound.faces:
        area = SurfaceProps(face).area
        if area > 1.0e-7:
            faces.append(face)

    # Replace any planar B-Spline surfaces with planes.
    non_planar_faces = []
    planar_faces = []
    for f in faces:
        srf = f.surface
        try:
            pln = srf.as_plane()
            if pln:
                w = f.outer_wire
                # Fix the wire because they are usually degenerate edges in
                # the planar end caps.
                builder = BRepBuilderAPI_MakeWire()
                for e in w.edges:
                    if LinearProps(e).length > 1.0e-7:
                        builder.Add(e.object)
                w = builder.Wire()
                fix = ShapeFix_Wire()
                fix.Load(w)
                fix.SetSurface(pln.object)
                fix.FixReorder()
                fix.FixConnected()
                fix.FixEdgeCurves()
                fix.FixDegenerated()
                w = Wire(fix.WireAPIMake())
                fnew = Face.by_wire(w)
                planar_faces.append(fnew)
            else:
                non_planar_faces.append(f)
        except RuntimeError:
            logger.info('Failed to check for planar face...')
            non_planar_faces.append(f)

    # Make a compound of the faces
    shape = Compound.by_shapes(non_planar_faces + planar_faces)

    # Split closed faces
    if divide_closed:
        shape = DivideClosedShape(shape).shape

    # Sew shape
    sewn_shape = SewShape(shape).sewed_shape
    if isinstance(sewn_shape, Face):
        sewn_shape = sewn_shape.to_shell()

    # Attempt to unify planar domains
    shell = UnifyShape(sewn_shape).shape

    # Make solid
    if not isinstance(shell, Shell):
        logger.info('\tA valid shell was not able to be generated.')
        check = CheckShape(shell)
        if not check.is_valid:
            logger.info('\tShape errors:')
            check.log_errors()
        return shell, check.invalid_shapes

    solid = Solid.by_shell(shell)

    # Limit tolerance
    FixShape.limit_tolerance(solid)

    # Check the solid and attempt to fix
    invalid = []
    check = CheckShape(solid)
    if not check.is_valid:
        logger.info('\tFixing the solid...')
        solid = FixShape(solid).shape
        check = CheckShape(solid)
        if not check.is_valid:
            logger.info('\t...solid could not be fixed.')
            logger.info('\tShape errors:')
            check.log_errors()
            failed = check.invalid_shapes
            invalid += failed
    else:
        tol = solid.tol_avg
        logger.info(
            '\tSuccessfully generated solid with tolerance={}'.format(tol))

    return solid, invalid