def group_planes_by_axis(shape):
    """[summary]
    Extract all planes from shape, and group them according to their normal
    vector.

    Arguments:
        shape {TopoDS_Shape} -- [description]

    Returns:
        {dict} -- key: normal vector as string)
                  value: list of TopoDS_Shape(Plane)
    """
    if shape is None:
        logging.warn("Input shape is None")
        pln_dict = None
    else:
        planeList = RecognizeTopo(shape).planes()
        pln_dict = {}
        for pln in planeList:
            gp_pln = BRepAdaptor_Surface(pln).Plane()
            normal = gp_pln.Axis().Direction()
            key = '%.6f,%.6f,%.6f' % (round(normal.X(), 6), round(
                normal.Y(), 6), round(normal.Z(), 6))
            key = tuple([float(i) for i in key.split(',')])
            if key not in pln_dict.keys():
                pln_dict[key] = [pln]
            else:
                pln_dict[key].append(pln)
    return pln_dict
def match_singleHole(solid_add, solid_base):

    cyls_sel_base, cyls_sel_add, projPln = selectCylinderFromClosestPln(
        solid_add, solid_base)
    pntList_base = []
    for i in cyls_sel_base:
        loc = BRepAdaptor_Surface(i).Cylinder().Location()
        pnt = gp_Pnt(loc.X(), loc.Y(), loc.Z())
        pntList_base.append(pnt)

    pntList_add = []
    for i in cyls_sel_add:
        loc = BRepAdaptor_Surface(i).Cylinder().Location()
        pnt = gp_Pnt(loc.X(), loc.Y(), loc.Z())
        pntList_add.append(pnt)

    pntList_base_proj = [
        ais_ProjectPointOnPlane(pnt, projPln) for pnt in pntList_base
    ]
    pntList_add_proj = [
        ais_ProjectPointOnPlane(pnt, projPln) for pnt in pntList_add
    ]

    mvVec = get_shortest_vec(pntList_add_proj, pntList_base_proj)
    trsf = gp_Trsf()
    trsf.SetTranslation(mvVec)
    solid_add.Move(TopLoc_Location(trsf))
def filter_cylinder_by_position(cylList_from_solidAdd, projPln, dist_tol=0.3):
    """Project all points of cylinders' axis into the projPln, and return the projected point on the projPln

    Arguments:
        cylList_from_solidAdd {[type]} -- [description]
        projPln {[type]} -- [description]

    Keyword Arguments:
        dist_tol {float} -- [description] (default: {0.3})

    Returns:
        [type] -- [description]
    """
    # project the first cylinder to get the point. Which is needed for the later distance calculation
    initPnt = ais_ProjectPointOnPlane(
        BRepAdaptor_Surface(cylList_from_solidAdd[0],
                            True).Cylinder().Location(), projPln)
    projPntList = [initPnt]
    for cyl in cylList_from_solidAdd:
        newPnt = ais_ProjectPointOnPlane(
            BRepAdaptor_Surface(cyl, True).Cylinder().Location(), projPln)
        isNewPnt = True
        # check whehter the projected point overlaps other points
        for pnt in projPntList:
            if newPnt.Distance(pnt) < dist_tol:
                isNewPnt = False
        if isNewPnt:
            projPntList.append(newPnt)
    return projPntList
Exemple #4
0
def recognize_face(a_face):
    """ Takes a TopoDS shape and tries to identify its nature
    whether it is a plane a cylinder a torus etc.
    if a plane, returns the normal
    if a cylinder, returns the radius
    """
    surf = BRepAdaptor_Surface(a_face, True)
    surf_type = surf.GetType()
    if  surf_type == GeomAbs_Plane:
        print("--> plane")
        # look for the properties of the plane
        # first get the related gp_Pln
        gp_pln = surf.Plane()
        location = gp_pln.Location()  # a point of the plane
        normal = gp_pln.Axis().Direction()  # the plane normal
        # then export location and normal to the console output
        print("--> Location (global coordinates)", location.X(), location.Y(), location.Z())
        print("--> Normal (global coordinates)", normal.X(), normal.Y(), normal.Z())
    elif surf_type == GeomAbs_Cylinder:
        print("--> cylinder")
        # look for the properties of the cylinder
        # first get the related gp_Cyl
        gp_cyl = surf.Cylinder()
        location = gp_cyl.Location()  # a point of the axis
        axis = gp_cyl.Axis().Direction()  # the cylinder axis
        # then export location and normal to the console output
        print("--> Location (global coordinates)", location.X(), location.Y(), location.Z())
        print("--> Axis (global coordinates)", axis.X(), axis.Y(), axis.Z())
    else:
        # TODO there are plenty other type that can be checked
        # see documentation for the BRepAdaptor class
        # https://www.opencascade.com/doc/occt-6.9.1/refman/html/class_b_rep_adaptor___surface.html
        print("not implemented")
Exemple #5
0
    def Shape(self):
        ball_vecs = []
        for i in self.balls:
            ball_vecs.append(gp_Vec(i.getPnt().XYZ()))
        v_ball_to_ball = ball_vecs[1] - ball_vecs[0]
        ax = gp_Ax2(gp_Pnt(ball_vecs[0].XYZ()), gp_Dir(v_ball_to_ball.XYZ()))
        mcyl = BRepPrimAPI_MakeCylinder(ax, self.d_o / 2.0,
                                        v_ball_to_ball.Magnitude())
        cyl = mcyl.Shape()
        mch = BRepFilletAPI_MakeChamfer(cyl)

        endFaces = []
        for face in Topo(cyl).faces():
            adaptor = BRepAdaptor_Surface(face)
            if adaptor.GetType() == GeomAbs_Plane:
                endFaces.append(face)
                for edge in Topo(face).edges():
                    mch.Add(self.chamfer_distance, edge, face)
        try:
            chamferedCyl = mch.Shape()
        except:
            chamferedCyl = cyl
            print("chamfer on ForceTransferCylinder failed!")
        mc = BRepAlgoAPI_Cut(chamferedCyl, self.balls[0].Shape())
        mc = BRepAlgoAPI_Cut(mc.Shape(), self.balls[1].Shape())
        return mc.Shape()
Exemple #6
0
def pipe_segment_to_edge(compound, uid=None):
    """ if it is two circles with linear face segments,
        the end sections will have N - 2 edges"""
    the_topo = Topo(compound)
    faces = [Face(f) for f in the_topo.faces()]
    faces.sort(reverse=True, key=lambda x: len(x.edges()))
    areas = []
    verts = []
    for f1 in faces[:2]:
        surf = BRepAdaptor_Surface(f1, True)
        surf_type = surf.GetType()
        areas.append(f1.area)

        uv, pnt = f1.mid_point()

        if surf_type == GeomAbs_Plane:
            gp_pln = surf.Plane()
            normal = f1.normal

            gppln2 = gp_Pln(pnt, normal)
            v = MEPConnector(gppln2)
            verts.append(v)

    radius = math.sqrt(sum(areas)) / (2 * math.pi)
    edge = MEPCurve(*verts)
    return MEPSegment(edge, radius, uid=uid)
def get_neighbor_vector(hole_cyl, cylList, projPln):
    vecList = []
    pnt_hole = BRepAdaptor_Surface(hole_cyl, True).Cylinder().Location()
    pnt_start = ais_ProjectPointOnPlane(pnt_hole, projPln)
    for cyl in cylList:
        pnt_cyl = BRepAdaptor_Surface(cyl, True).Cylinder().Location()
        pnt_end = ais_ProjectPointOnPlane(pnt_cyl, projPln)
        vecList.append(gp_Vec(pnt_start, pnt_end))
    return vecList
 def __init__(self, topods_shp, proj_pln=None):
     self.shp = topods_shp
     adaptor = BRepAdaptor_Surface(self.shp)
     if adaptor.GetType() == GeomAbs_Cylinder:
         self.cyl = adaptor.Cylinder()
         self.axis = self.cyl.Axis()
         self.direction = self.axis.Direction()
         self.location = self.cyl.Location()
         self.neighborIsSet = False
     else:
         logging.warning('Wrong shape type, input should be cylinder')
     if proj_pln is not None:
         self.setProjPln(proj_pln)
def group_cylinders_byAxisDir(cylinders,
                              anglTolDeg=5,
                              roundDigit=6,
                              groupParallelAx=True):
    logging.debug('Entering group_cylinders_byAxisDir')
    cyl_ax = {}
    for cylinder in cylinders:
        cyl = BRepAdaptor_Surface(cylinder, True).Cylinder()
        axis = cyl.Axis()
        key = (round(axis.Direction().X(),
                     roundDigit), round(axis.Direction().Y(), roundDigit),
               round(axis.Direction().Z(), roundDigit))
        if key in cyl_ax.keys():
            cyl_ax[key].append(cylinder)
        else:
            cyl_ax[key] = [cylinder]
    for key in cyl_ax.keys():
        listOflist = list(find_full_cylinder(cyl_ax[key]).values())
        cyl_ax[key] = [k for i in listOflist for k in i]

    if groupParallelAx:
        axisKeyList = list(cyl_ax.keys())
        combineList = []
        j = 0
        while len(axisKeyList) >= 1:
            ax1 = axisKeyList.pop(0)
            grp = [ax1]
            dir1 = gp_Dir(ax1[0], ax1[1], ax1[2])
            while j < len(axisKeyList):
                ax2 = axisKeyList[j]
                dir2 = gp_Dir(ax2[0], ax2[1], ax2[2])
                j += 1
                if dir1.IsParallel(dir2, radians(anglTolDeg)):
                    grp.append(ax2)
                    j -= 1
                    axisKeyList.pop(j)
            combineList.append(grp)
            j = 0
        cyl_grpByAx = {}
        for i in combineList:
            cyl_grpByAx[i[0]] = []
            for j in i:
                cyl_grpByAx[i[0]] += cyl_ax[j]
    else:
        cyl_grpByAx = cyl_ax

    return cyl_grpByAx
Exemple #10
0
    def setPreselection(self, doc, obj, sub):

        sel = FreeCADGui.Selection.getSelectionEx()
        v = FreeCADGui.ActiveDocument.ActiveView
        d = FreeCADGui.ActiveDocument

        so = FreeCAD.ActiveDocument.getObject(obj)
        if not hasattr(so, "Shape"): return

        faces = so.Shape.Faces
        typ = sub[0:4]

        if not typ == "Face": return

        idx = int(sub[4:])
        face = faces[idx - 1]

        txt = ""

        occface = Part.__toPythonOCC__(face)
        #surf =  occface.Surface()

        ts = _TopoDS_face(occface)

        face_adaptor = BRepAdaptor_Surface(ts)
        face_type = face_adaptor.GetType()
        surf_txt = self.getSurfType(face_type)

        txt = self.getSurfEqua(surf_txt, face_adaptor)

        #t = GeomAdaptor_Surface(TopoDS_Shape(occface)).GetType()
        #FreeCAD.Console.PrintMessage("%s\n" % (str(t)))
        #if (str(face.Surface) == "<Plane object>"):
        #txt = "Plane"
        #elif (str(face.Surface) == "<Cylinder object>"):
        #txt = "Cylinder"
        #elif (str(face.Surface) == "<Toriod object>"):
        #txt = "Torus"

        pnt = v.getPoint(v.getCursorPos())
        #FreeCAD.Console.PrintMessage("X %f Y %f Z %f\n" % (pnt.x, pnt.y, pnt.z))
        adoc = FreeCAD.ActiveDocument
        objlist = adoc.findObjects("App::Annotation", "SurfInfo")

        if (objlist):
            objlist[0].LabelText = txt
            objlist[0].Position = (pnt.x, pnt.y, pnt.z)
Exemple #11
0
 def adaptor(self):
     if self._adaptor is not None and not self.is_dirty:
         pass
     else:
         self._adaptor = BRepAdaptor_Surface(self)
         self._adaptor_handle = BRepAdaptor_HSurface()
         self._adaptor_handle.Set(self._adaptor)
     return self._adaptor
Exemple #12
0
 def adaptor(self):
     if self._adaptor is not None and not self.is_dirty:
         pass
     else:
         from OCC.BRepAdaptor import BRepAdaptor_Surface, BRepAdaptor_HSurface
         self._adaptor = BRepAdaptor_Surface(self.topo)
         self._adaptor_handle = BRepAdaptor_HSurface()
         self._adaptor_handle.Set(self._adaptor)
     return self._adaptor
Exemple #13
0
    def identifySurf(self):

        occface = Part.__toPythonOCC__(self.__faceObj)
        ts = _TopoDS_face(occface)
        face_adaptor = BRepAdaptor_Surface(ts)
        face_type = face_adaptor.GetType()

        if (face_type == GeomAbs_Plane):
            self.__surfType = "Plane"
        elif (face_type == GeomAbs_Cylinder):
            self.__surfType = "Cylinder"
        elif (face_type == GeomAbs_Sphere):
            self.__surfType = "Sphere"
        elif (face_type == GeomAbs_Cone):
            self.__surfType = "Cone"
        elif (face_type == GeomAbs_Torus):
            self.__surfType = "Toroid"
        elif (face_type == GeomAbs_SurfaceOfRevolution):
            self.__surfType = "Revolution"
        else:
            self.__surfType = "Spline"
def __cylinder_group_radius(cyl_ax_grp, tol=0.1):
    logging.debug('Entering group_radius')

    keyList = list(cyl_ax_grp.keys())
    cyl_rad_grp = {}
    for k in keyList:
        cylinders = cyl_ax_grp[k]
        skipList = []
        for i in range(0, len(cylinders)):
            if i in skipList:
                continue
            cyl1 = BRepAdaptor_Surface(cylinders[i], True).Cylinder()
            radius1 = cyl1.Radius()
            key = '%s,r=%.3f' % (k, radius1)

            if key not in cyl_rad_grp:
                cyl_rad_grp[key] = [cylinders[i]]
            else:
                logging.warning('Error !!! Please check the logic again !')

            for j in range(i + 1, len(cylinders)):
                # logging.debug('i = %d, j = %d' % (i, j))
                if j in skipList:
                    continue
                cyl2 = BRepAdaptor_Surface(cylinders[j], True).Cylinder()
                radius2 = cyl2.Radius()
                if abs(radius1 - radius2) <= tol:
                    # logging.debug('Same radius found')
                    cyl_rad_grp[key].append(cylinders[j])
                    skipList.append(j)
    return cyl_rad_grp
def __group_coaxial_cylinders(cylinders,
                              tol_ang=0.5,
                              tol_lin=0.1,
                              roundDigit=6):
    """According to cylinders' axis, categorize a list of cylinders into a dictionary by using its axis as a key.

    Arguments:
        cylinders {[TopoDS_Face,...]} -- list of TopoDS_Face
        tol_ang {float} -- [Unit - degree] the angle between these two axis below this value will be recognize as two parallel axis
        tol_lin

    Returns:
        {'string': [TopoDS_Face,...]} -- returns a dictionary, key is string of axis and location vector, value is list of TopoDS_Shape
    """
    logging.debug('Entering group_coaxial')
    tol_rad = radians(tol_ang)
    skipList = []
    cyl_ax_grp = {}
    for i in range(0, len(cylinders)):
        if i in skipList:
            continue

        cyl1 = BRepAdaptor_Surface(cylinders[i], True).Cylinder()
        axis1 = cyl1.Axis()
        location1 = cyl1.Location()
        axisDir1 = (round(axis1.Direction().X(), roundDigit),
                    round(axis1.Direction().Y(),
                          roundDigit), round(axis1.Direction().Z(),
                                             roundDigit))
        cylLoc1 = (round(location1.X(),
                         roundDigit), round(location1.Y(), roundDigit),
                   round(location1.Z(), roundDigit))
        key = (axisDir1, cylLoc1)

        if key not in cyl_ax_grp.keys():
            cyl_ax_grp[key] = [cylinders[i]]
        else:
            logging.warning('Error !!! Please check the logic again !')

        for j in range(i + 1, len(cylinders)):
            # logging.debug('i = %d, j = %d' % (i, j))

            if j in skipList:
                # logging.debug('skip !!')
                continue
            cyl2 = BRepAdaptor_Surface(cylinders[j]).Cylinder()
            axis2 = cyl2.Axis()
            if axis1.IsCoaxial(axis2, tol_rad, tol_lin) or axis1.IsCoaxial(
                    axis2.Reversed(), tol_rad, tol_lin):
                # logging.debug('Coaxial !!')
                cyl_ax_grp[key].append(cylinders[j])
                skipList.append(j)
    return cyl_ax_grp
def select_cyl_by_axisDir(full_cylinders, gpDir, ang_tol=0.5):
    """[summary]

    Arguments:
        full_cylinders {dictionary} -- {'string': List of TopoDS_Shape; GeomType in item of list:Cylinder}
        gpDir {gp_Dir} -- target axis direction
        ang_tol {float} -- angular tolerance expressed in Degrees. The angle between cylinder's axis and target axis dirction in this tol, will be consider parallel

    Returns:
        selected_cyl_List {list} -- List of TopoDS_Shape(cylinders)
    """
    selected_cyl_List = []
    for cylList in full_cylinders.values():
        for cyl in cylList:
            axis = BRepAdaptor_Surface(cyl, True).Cylinder().Axis().Direction()
            if gpDir.IsParallel(axis, radians(0.5)):
                selected_cyl_List.append(cyl)
    return selected_cyl_List
def get_closest_parallel_planePair(solid_add,
                                   solid_base=None,
                                   init_min_dist=1000.0,
                                   xyplane_z_inMM=1215.0):
    """
    Arguments:
        solid_add {TopoDS_Solid} -- The solid going to be added

    Keyword Arguments:
        solid_base {TopoDS_Solid} -- By default, solid_base will be xy-plane (default: {None})
        init_min_dist {float} -- [description] (default: {10.0})

    Returns:
        {dict} -- keyValues: miniDist, topoPair, geomPair, mvVec
    """
    min_dist = init_min_dist
    ang_list = find_closest_normal_pair(solid_add, solid_base)
    if solid_base is None:
        solid_base = gen_boxSolidAsTable(height=xyplane_z_inMM)
    axisGrp1 = group_planes_by_axis(solid_base)
    axisGrp2 = group_planes_by_axis(solid_add)
    axisPair = ang_list['minAxisKeyPair']
    for axKeyPair in axisPair:
        for topoPln1 in axisGrp1[axKeyPair[0]]:
            surf1 = BRepAdaptor_Surface(topoPln1, True)
            pln1 = surf1.Plane()
            # [ToDo] A better distance evaluation, how to select a correct point which is inside the wire or centerofmass of plane
            plnpnt1 = pln1.Location()
            for topoPln2 in axisGrp2[axKeyPair[1]]:
                surf2 = BRepAdaptor_Surface(topoPln2, True)
                pln2 = surf2.Plane()
                # rospy.logdebug('Distance:', pln2.Distance(plnpnt1))
                dist = pln2.Distance(plnpnt1)
                if dist < min_dist:
                    min_dist = dist
                    minDistTopoPair = [topoPln1, topoPln2]
                    minDistGeomPair = [pln1, pln2]
    p = gp_Pnt(0, 0, 0)
    p1 = ais_ProjectPointOnPlane(p, minDistGeomPair[0])
    p2 = ais_ProjectPointOnPlane(p, minDistGeomPair[1])
    # in order to remove small digits
    projPln = minDistGeomPair[0]
    mvVec = gp_Vec(p2, p1)
    projPlnNormal = gp_Vec(projPln.Axis().Direction())
    mag = np.sign(mvVec.Dot(projPlnNormal)) * mvVec.Magnitude()
    mvVec = projPlnNormal.Normalized().Multiplied(mag)
    return {
        'minDist': dist,
        'topoPair': minDistTopoPair,
        'geomPair': minDistGeomPair,
        'mvVec': mvVec
    }
def group_cyl_byPln(solid, distTol=0.5, angTolDeg=5.0):
    cylinders = RecognizeTopo(solid).cylinders()
    cyl_dirGrp = group_cylinders_byAxisDir(cylinders,
                                           anglTolDeg=angTolDeg,
                                           groupParallelAx=True)
    cyl_dirGrpKeys = list(cyl_dirGrp.keys())

    # group cylinders by plane
    CylinderGrpsFromDiffPln = {}
    j = 0
    for dirKey in cyl_dirGrpKeys:
        CylinderGrpsFromDiffPln[dirKey] = []
        parallel_cyl_grps = cyl_dirGrp[dirKey].copy()
        grp_cylinderOnSamePln = {}
        while len(parallel_cyl_grps) >= 1:
            # take out the first element for creating plane, and search the other cylinders on the same plane
            firstCylinder = parallel_cyl_grps.pop(0)
            # fitting a geomety surface to TopoDS_Surface
            brepCylinder = BRepAdaptor_Surface(firstCylinder).Cylinder()
            dir1 = brepCylinder.Axis().Direction()
            # location of cylinder is usually the location of local coordinate system, which is on the axis of cylinder
            loc1 = brepCylinder.Location()
            # create gp_Pln
            pln = gp_Pln(loc1, dir1)
            grp_cylinderOnSamePln[pln] = [firstCylinder]
            # Search the cylinders on the same pln, if yes, extract from parallel_cyl_grps
            # loop all elements in parallel_cyl_grps
            while j < len(parallel_cyl_grps):
                brepCylinder2 = BRepAdaptor_Surface(
                    parallel_cyl_grps[j]).Cylinder()
                loc2 = brepCylinder2.Location()
                if pln.Distance(gp_Pnt(loc2.X(), loc2.Y(),
                                       loc2.Z())) < distTol:
                    grp_cylinderOnSamePln[pln].append(parallel_cyl_grps[j])
                    parallel_cyl_grps.pop(j)
                else:
                    j += 1
            j = 0
        CylinderGrpsFromDiffPln[dirKey] = grp_cylinderOnSamePln
    return CylinderGrpsFromDiffPln