Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Problems with c4d.utils.CalculateVisiblePoints()

    Scheduled Pinned Locked Moved PYTHON Development
    5 Posts 0 Posters 713 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H Offline
      Helper
      last edited by

      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

      1 Reply Last reply Reply Quote 0
      • H Offline
        Helper
        last edited by

        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://developers.maxon.net/forum/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 !

        1 Reply Last reply Reply Quote 0
        • H Offline
          Helper
          last edited by

          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

          1 Reply Last reply Reply Quote 0
          • H Offline
            Helper
            last edited by

            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().

            1 Reply Last reply Reply Quote 0
            • H Offline
              Helper
              last edited by

              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

              1 Reply Last reply Reply Quote 0
              • First post
                Last post