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