Problems with c4d.utils.CalculateVisiblePoints()



  • On 08/11/2017 at 13:04, xxxxxxxx wrote:

    Hi,

    i want to select all visible points from an polygon object.
    I think c4d.utils.CalculateVisiblePoints(bd, op) shoud be the easiest way.

    import c4d
      
    def main() :
        bd = doc.GetActiveBaseDraw()
        visarr = c4d.utils.CalculateVisiblePoints(bd, op)
        print visarr
               
      
    if __name__=='__main__':
        main()
    

    But the function returns always a list of '0'.
    What am I doing wrong?

    Thanks



  • On 08/11/2017 at 16:44, xxxxxxxx wrote:

    I also can't get CalculateVisiblePoints to work.

    But I come with tree ways for testing if a point is visible or not.

    Check if it's on the screen (didn't check if it's hide by other polygons)

    def main() :
        obj = op
        if not obj:
            return
        
        bd = doc.GetActiveBaseDraw()
        ptWithinScreen = list()
        mg = obj.GetMg()
      
        for pt in obj.GetAllPoints() :
            screenPt = bd.WS(pt*mg) # Get point in world space to screen space
            
            # Get if is in the screen
            ptWithinScreen.append(bd.TestPoint(screenPt.x, screenPt.y))
            
        #Ordered by ptID
        print ptWithinScreen
    

    Check if point is within the safe frame (didn't check if it's hide by others polygons)

    def main() :
        obj = op
        if not obj:
            return
        
        bd = doc.GetActiveBaseDraw()
        ptWithinScreen = list()
        mg = obj.GetMg()
        sf = bd.GetSafeFrame()
        
        for pt in obj.GetAllPoints() :
            screenPt = bd.WS(pt*mg) # Get point in world space to screen space
            
            # Get if is withing safe frame or not
            ptWithinSafeFrame.append(sf["cl"] <= screenPt.x <= sf["cr"] and sf["ct"] <= screenPt.y <= sf["cb"])
            
        #Ordered by ptID
        print ptWithinSafeFrame
    

    And finally check if a point is hidden by another polygon from the camera (actually only check for self, you may have to take a look at this thread https://plugincafe.maxon.net/topic/708/13870_geraycollider-intersection-test-with-whole-scene and of course you can combine to see if bounding box of another object is within the direction of the ray), and of course you can combine this method with the two previous one, in order to only test points within screen.

    def main() :
        obj = op
        if not obj:
            return
        
        bd = doc.GetActiveBaseDraw()
        ptVisibleFromCamera = list()
        mg = obj.GetMg()
      
        # Init our Ray outside of the loop for efficiency
        ray = c4d.utils.GeRayCollider()
        ray.Init(obj)
        
        for pt in obj.GetAllPoints() :        
            # Get if it's visible from camera
            start = pt*mg
            end = bd.GetMg().off
        
            angle = (end - start).GetNormalized()
            lenght = (end - start).GetLength()
            result = ray.Intersect(pt, angle, lenght)
            
            isVisible = True
            for rayId in range(0, ray.GetIntersectionCount()) :
                if ray.GetIntersection(rayId)["hitpos"] != pt:
                    isVisible = False
                    break
                
            ptVisibleFromCamera.append(isVisible)
            
        #Ordered by ptID
        print ptVisibleFromCamera
    

    Hope it's help !



  • On 09/11/2017 at 14:25, xxxxxxxx wrote:

    Thank you for your reply.
    My workaround was also the use of c4d.utils.GeRayCollider().
    With one little difference. I added a small offset vector to the start position. So i don't have to check the hit positions against the start position. In other word one can set the 'only_test' flag of the GeRayCollider.Intersect methode to 'True'. If the Intersect methode returns 'True' the point isn't visible. If it returns 'False' the point ist visible.

    import c4d
    from c4d import gui
      
      
    eps = 0.1
      
    def main() :
        
        if not op or not op.CheckType(c4d.Opoint) :
            return
        
        doc.StartUndo()
        bd = doc.GetActiveBaseDraw()
        if not bd: return
        
        mg_cam = bd.GetMg()
        projection = bd[c4d.BASEDRAW_DATA_PROJECTION]
        
        pointarr = op.GetAllPoints()
        mg_op = op.GetMg()
        
        rc = c4d.utils.GeRayCollider()
        rc.Init(op)
        
        bs = op.GetPointS()    
        bs.DeselectAll()    
        
        for i,p in enumerate(pointarr) :      
            if projection == 0: # Perspective
                ray_p = p
                ray = mg_cam.off - p*mg_op
                ray_dir = ~ray
                ray_length =   ray.GetLength()      
            elif projection > 0 and projection < 8: # Ortho views
                ray_p = p
                ray_dir = -(~mg_cam.v3)
                ray_length = op.GetRad().GetLength()*2.0
                
            if not rc.Intersect(ray_p + ray_dir*eps, ray_dir, ray_length, only_test = True) :
                doc.AddUndo(c4d.UNDOTYPE_CHANGE_SELECTION, op)
                bs.Select(i)
        
        doc.EndUndo()        
        c4d.EventAdd()
               
      
    if __name__=='__main__':
        main()
    

    By
    Peter



  • On 10/11/2017 at 06:54, xxxxxxxx wrote:

    Hi Peter,

    I'm afraid c4d.utils.CalculateVisiblePoints() is broken in the Python API and has to be fixed.
    Moreover it is not possible to pass  select_visibonly parameter  like the C++ API version of the function so this parameter has to be added in Python.

    As you already found, and gr4ph0s as well, the solution is to use c4d.utils.GeRayCollider().



  • On 12/11/2017 at 23:52, xxxxxxxx wrote:

    Hi Yannick,

    thanks for the answer.
    So switching to c4d.utils.GeRayCollider() was the right decision.

    By
    Peter


Log in to reply