Problems with c4d.utils.CalculateVisiblePoints()
On 08/11/2017 at 13:04, xxxxxxxx wrote:
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?
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()
On 10/11/2017 at 06:54, xxxxxxxx wrote:
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:
thanks for the answer.
So switching to c4d.utils.GeRayCollider() was the right decision.