def face(self): """ Get the face the point is on. :return: The face. :rtype: afem.topology.entities.Face """ return Face(self._tool.Face())
def has_ancestor_face2(self, edge): """ Get the ancestor face on the intersection edge on the second shape if available. :param afem.topology.entities.Edge edge: The edge. :return: *True* and the face if available, *False* and *None* if not. :rtype: tuple(bool, afem.topology.entities.Face or None) """ f = TopoDS_Face() if self._bop.HasAncestorFaceOn2(edge.object, f): return True, Face(f) return False, None
def rebuild_wing_solid(srfs, divide_closed=True, reloft=False, tol=0.01): """ Rebuild a solid shape from the OpenVSP wing surface(s). If only one surface is provided then it is assumed that a single surface models the OML and it will be split and modified at the root, tip, and trailing edge. This single surface should have similar form and parametrization as the original OpenVSP surface. If more than once surface is provided then it is assumed that the surfaces were split during OpenVSP export and are simply sewn together to form the solid. :param srfs: The wing surface(s) used to rebuild the solid. :type srfs: collections.Sequence(afem.geometry.entities.Surface) :param bool divide_closed: Option to divide closed faces. :param bool reloft: For wings that are not split, this option will extract isocurves at each spanwise cross section, tessellate the curve using *tol*, and then approximate the section using a C1 continuous curve. These curves are then used to generate a new wing surface. This method is experimental. :param float tol: Tolerance for approximation if *bspline_restrict* or *reloft* is *True*. :return: The new solid. :rtype: afem.topology.entities.Solid :raise ValueError: If no surfaces are provided. """ faces = [Face.by_surface(s) for s in srfs] compound = Compound.by_shapes(faces) nsrfs = len(srfs) if nsrfs == 1: solid, _ = _process_unsplit_wing(compound, divide_closed, reloft, tol) return solid elif nsrfs > 1: solid, _ = _build_solid(compound, divide_closed) return solid else: raise ValueError('No surfaces provided.')
def __init__(self, face, v): v = CheckGeom.to_vector(v) builder = BRepPrimAPI_MakePrism(face.object, v) self._solid = Solid(builder.Shape()) self._f1 = Face(builder.FirstShape()) self._f2 = Face(builder.LastShape())
def __init__(self, edge, v): v = CheckGeom.to_vector(v) builder = BRepPrimAPI_MakePrism(edge.object, v) self._f = Face(builder.Shape()) self._e1 = Edge(builder.FirstShape()) self._e2 = Edge(builder.LastShape())
def __init__(self, wire): if isinstance(wire, Curve): wire = Wire.by_curve(wire) elif isinstance(wire, Edge): wire = Wire.by_edge(wire) self._f = Face(BRepBuilderAPI_MakeFace(wire.object, True).Face())
def __init__(self, pln, umin, umax, vmin, vmax): builder = BRepBuilderAPI_MakeFace(pln.gp_pln, umin, umax, vmin, vmax) self._f = Face(builder.Face())
def bottom_face(self): """ :return: The bottom face. :rtype: afem.topology.entities.Face """ return Face(self._builder.BottomFace())
def face(self): """ :return: The sphere as a face. :rtype: afem.topology.entities.Face """ return Face(self._builder.Face())
def face(self): """ :return: The lateral face of the cylinder :rtype: afem.topology.entities.Face """ return Face(self._builder.Face())
def top_face(self): """ :return: The top face. :rtype: afem.topology.entities.Face """ return Face(self._builder.TopFace())
def right_face(self): """ :return: The right face. :rtype: afem.topology.entities.Face """ return Face(self._builder.RightFace())
def left_face(self): """ :return: The left face. :rtype: afem.topology.entities.Face """ return Face(self._builder.LeftFace())
def front_face(self): """ :return: The front face. :rtype: afem.topology.entities.Face """ return Face(self._builder.FrontFace())
def back_face(self): """ :return: The back face. :rtype: afem.topology.entities.Face """ return Face(self._builder.BackFace())
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
def _process_unsplit_wing(compound, divide_closed, reloft, tol): # Process a wing that was generated without "Split Surfs" option. faces = compound.faces if len(faces) != 1: return None, None face = faces[0] # Get the surface. master_surf = face.surface # master_surf = NurbsSurface(master_surf.object) uknots, vknots = master_surf.uknots, master_surf.vknots vsplit = master_surf.local_to_global_param('v', 0.5) # Segment off the end caps and the trailing edges. u1, u2 = uknots[1], uknots[-2] v1, v2 = vknots[1], vknots[-2] s1 = master_surf.copy() s1.segment(u1, u2, v1, v2) # Reloft the surface by tessellating a curve at each spanwise knot. This # enforces C1 continuity but assumes linear spanwise wing which may not # support blending wing sections in newer versions of OpenVSP. Also, since # the tessellated curves may not match up to the wing end caps making # sewing unreliable, flat end caps are assumed. if reloft: s1 = _reloft_wing_surface(s1, tol) # Generate new flat end caps using isocurves at the root and tip of # this new surface c0 = s1.v_iso(s1.v1) c1 = s1.v_iso(s1.v2) e0 = Edge.by_curve(c0) e1 = Edge.by_curve(c1) w0 = Wire.by_edge(e0) w1 = Wire.by_edge(e1) f0 = Face.by_wire(w0) f1 = Face.by_wire(w1) # Make faces of surfaces f = Face.by_surface(s1) new_faces = [f, f0, f1] else: # Reparamterize knots in spanwise direction to be chord length instead # of uniform. Use isocurve at quarter-chord to determine knot values. # This only works as long as surfaces are linear. c0 = s1.u_iso(s1.u1) c0.segment(vsplit, c0.u2) qc_u = PointFromParameter(c0, vsplit, 0.25 * c0.length).parameter c = s1.v_iso(qc_u) pnts = [c.eval(u) for u in c.knots] new_uknots = geom_utils.chord_parameters(pnts, 0., 1.) s1.set_uknots(new_uknots) # Segment off end caps u1, u2 = uknots[0], uknots[1] v1, v2 = vknots[1], vsplit s2 = master_surf.copy() s2.segment(u1, u2, v1, v2) u1, u2 = uknots[0], uknots[1] v1, v2 = vsplit, vknots[-2] s3 = master_surf.copy() s3.segment(u1, u2, v1, v2) u1, u2 = uknots[-2], uknots[-1] v1, v2 = vknots[1], vsplit s4 = master_surf.copy() s4.segment(u1, u2, v1, v2) u1, u2 = uknots[-2], uknots[-1] v1, v2 = vsplit, vknots[-2] s5 = master_surf.copy() s5.segment(u1, u2, v1, v2) # Make faces of surfaces new_faces = [] for s in [s1, s2, s3, s4, s5]: f = Face.by_surface(s) new_faces.append(f) # Segment off TE. u1, u2 = uknots[0], uknots[-1] v1, v2 = vknots[0], vknots[1] s6 = master_surf.copy() s6.segment(u1, u2, v1, v2) u1, u2 = uknots[0], uknots[-1] v1, v2 = vknots[-2], vknots[-1] s7 = master_surf.copy() s7.segment(u1, u2, v1, v2) # Split the TE surface at each u-knot. usplits = occ_utils.to_tcolstd_hseq_real(uknots[1:-1]) split = ShapeUpgrade_SplitSurface() split.Init(s6.object) split.SetUSplitValues(usplits) split.Perform() comp_surf1 = split.ResSurfaces() split = ShapeUpgrade_SplitSurface() split.Init(s7.object) split.SetUSplitValues(usplits) split.Perform() comp_surf2 = split.ResSurfaces() # For each patch in the composite surfaces create a face. for i in range(1, comp_surf1.NbUPatches() + 1): for j in range(1, comp_surf1.NbVPatches() + 1): hpatch = comp_surf1.Patch(i, j) f = BRepBuilderAPI_MakeFace(hpatch, 0.).Face() new_faces.append(f) for i in range(1, comp_surf2.NbUPatches() + 1): for j in range(1, comp_surf2.NbVPatches() + 1): hpatch = comp_surf2.Patch(i, j) f = BRepBuilderAPI_MakeFace(hpatch, 0.).Face() new_faces.append(f) # Put all faces into a compound a generate solid. new_compound = Compound.by_shapes(new_faces) return _build_solid(new_compound, divide_closed)
def __init__(self, srf, tol=1.0e-7): self._f = Face(BRepBuilderAPI_MakeFace(srf.object, tol).Face())