CollisionDetector.CollisionDetectorProxy Class Reference

Proxy class for a DocumentObjectGroupPython CollisionDetector instance. More...

Inheritance diagram for CollisionDetector.CollisionDetectorProxy:

Public Member Functions

def __init__ (self, fp)
 Initialization method for CollsionDetectorProxy. More...
 
def onDocumentRestored (self, fp)
 Method called when document is restored to make sure everything is as it was. More...
 
def onBeforeChange (self, fp, prop)
 Method called before DocumentObjectGroupPython CollisionDetector is changed. More...
 
def onChanged (self, fp, prop)
 Method called after DocumentObjectGroupPython CollisionDetector was changed. More...
 
def resetObject (self, object_)
 Method that resets style of an object_ to what it was before. More...
 
def loadObjects (self, objects, save_style=True)
 Adds shape info and loads object to restore them during reset. More...
 
def execute (self, fp)
 Method called when recomputing a DocumentObjectGroupPython CollisionDetector. More...
 
def setProperties (self, fp)
 Method to set properties during initialization or document restoration. More...
 
def checkCollisions (self)
 Method which checks for collisions among observed objects. More...
 
def exploreGroup (self, group)
 Method to explore a group for all objects and shapes inside. More...
 
def intersection (self, obj1, obj2)
 Method to check intersection between obj1 and obj2. More...
 
def makeCollisionObject (self, shape, cause1, cause2, color)
 Method to make a collision object and add it to the CollisionDetector. More...
 
def visualize (self, ok, in_collision)
 Method to visualize which object are in-collision and which have collided. More...
 
def reset (self)
 Method to reset CollisionDetector. More...
 
def setChecking (self, value)
 Method necessary to be able to set checking attribute with delayed execution. More...
 
def setResetting (self, value)
 Method necessary for setting resetting attribute with delayed execution. More...
 
def executeLater (self, var, command, args)
 Method to postpone execution after coin is finished (and avoid crashing coin). More...
 
def executeCommandQueue (self)
 Method to execute queue of postponed commands so that coin does not crash. More...
 
def __getstate__ (self)
 Necessary method to save unserializable objects. More...
 
def __setstate__ (self, data)
 Necessary method to restore unserializable objects when loading document. More...
 

Public Attributes

 observed_objects_before
 An ObservedObjects property before change. More...
 
 in_collision
 A set of objects which are in-collision together. More...
 
 collided
 A set of objects which have collided since the last reset. More...
 
 original_styles
 A dict of objects and their style original style. More...
 
 shape_info
 A dict of objects, Part objects inside them and fused shapes. More...
 
 fp
 A DocumentObjectGroupPython associated with the proxy. More...
 
 checking
 A flag to signal collision checking is in progress. More...
 
 resetting
 A flag to signal resetting objects to previous state. More...
 
 command_queue
 

Static Public Attributes

list command_queue = []
 A list of commands interfering with Coin3D to execute later. More...
 

Detailed Description

Proxy class for a DocumentObjectGroupPython CollisionDetector instance.

A CollisionDetectorProxy instance adds properties to a DocumentObjectGroupPython CollisionDetector instance and responds to theirs changes. It detects collisions among ObservedObjects.

To connect this Proxy object to a DocumentObjectGroupPython CollisionDetector do:

a = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroupPython",
"CollisionDetector")
CollisionDetectorProxy(a)

Definition at line 67 of file CollisionDetector.py.

Constructor & Destructor Documentation

◆ __init__()

def CollisionDetector.CollisionDetectorProxy.__init__ (   self,
  fp 
)

Initialization method for CollsionDetectorProxy.

A class instance is created and made a Proxy for a generic DocumentObjectGroupPython CollisionDetector object. During initialization number of properties are specified and preset.

Parameters
fpA barebone CollisionDetector object to be extended.

Definition at line 107 of file CollisionDetector.py.

107  def __init__(self, fp):
108  self.setProperties(fp)
109  fp.Proxy = self
110 

Member Function Documentation

◆ __getstate__()

def CollisionDetector.CollisionDetectorProxy.__getstate__ (   self)

Necessary method to save unserializable objects.

We use this to save original_styles dictionary, collided and in_collision sets.

Returns
data A JSON string representation of a Python data structure.

Definition at line 740 of file CollisionDetector.py.

740  def __getstate__(self):
741  state = {"original_styles": self.original_styles,
742  "collided": [obj.Name for obj in self.collided],
743  "in_collision": [obj.Name for obj in self.in_collision]}
744  data = json.JSONEncoder().encode(state)
745  return data
746 

◆ __setstate__()

def CollisionDetector.CollisionDetectorProxy.__setstate__ (   self,
  data 
)

Necessary method to restore unserializable objects when loading document.

We use this to restore original_styles dictionary, collided and in_collision sets.

Parameters
dataA JSON string representation of a Python data structure.

Definition at line 756 of file CollisionDetector.py.

756  def __setstate__(self, data):
757  state = json.JSONDecoder().decode(data)
758  self.original_styles = state["original_styles"]
759  self.collided = {FreeCAD.ActiveDocument.getObject(name)
760  for name in state["collided"]}
761  self.in_collision = {FreeCAD.ActiveDocument.getObject(name)
762  for name in state["in_collision"]}
763 
764 

◆ checkCollisions()

def CollisionDetector.CollisionDetectorProxy.checkCollisions (   self)

Method which checks for collisions among observed objects.

If observed objects are valid and checking is not already in progress, the collision checking is started.

Definition at line 384 of file CollisionDetector.py.

384  def checkCollisions(self):
385  # Don't check if there are invalid objects
386  if not self.fp.ValidObservedObjects:
387  QMessageBox.warning(
388  None,
389  'Error while checking collisions',
390  "One or more objects to check for collisions "
391  + "don't have shapes attached, or are empty groups.")
392  return
393 
394  # Don't check if resetting
395  if self.resetting:
396  FreeCAD.Console.PrintWarning("Can't check, Resetting!")
397  return
398 
399  # Don't check if already checking
400  if self.checking:
401  FreeCAD.Console.PrintWarning("Already Checking!")
402  return
403  else:
404  self.checking = True
405 
406  # Prepare sets for objects in-collision and not-in-collision(ok)
407  in_collision = set()
408  ok = set()
409 
410  # Remove previously detected collisions
411  self.executeLater(None, self.fp.removeObjectsFromDocument, None)
412 
413  # No observed object present
414  if len(self.fp.ObservedObjects) == 0:
415  FreeCAD.Console.PrintWarning(
416  "CollisionDetector observes no objects.\n")
417  self.checking = False
418  return
419 
420  # Only 1 observed object
421  elif len(self.fp.ObservedObjects) == 1:
422  FreeCAD.Console.PrintWarning(
423  "CollisionDetector observes only 1 object.\n")
424  ok.add(self.fp.ObservedObjects[0])
425  self.visualize(ok, in_collision)
426  self.checking = False
427  return
428 
429  # Go through observed objects and update their placement
430  for obj in self.fp.ObservedObjects:
431  if len(self.shape_info[obj]["objects"]) >= 2:
432  self.shape_info[obj]["shape"] = \
433  self.shape_info[obj]["objects"][0].Shape.fuse(
434  [o.Shape for o in self.shape_info[obj]["objects"][1:]])
435  if hasattr(obj, "Placement"):
436  self.shape_info[obj]["shape"].Placement.Base = \
437  obj.Placement.Base
438  self.shape_info[obj]["shape"].Placement.Rotation = \
439  obj.Placement.Rotation
440 
441  elif hasattr(obj, "Placement"):
442  self.shape_info[obj]["shape"] = obj.Shape
443 
444  # Go through observed objects and check for intersections
445  for i in range(len(self.fp.ObservedObjects) - 1):
446  for j in range(i+1, len(self.fp.ObservedObjects)):
447  if self.intersection(self.fp.ObservedObjects[i],
448  self.fp.ObservedObjects[j]):
449  in_collision.add(self.fp.ObservedObjects[i])
450  in_collision.add(self.fp.ObservedObjects[j])
451  else:
452  ok.add(self.fp.ObservedObjects[i])
453  ok.add(self.fp.ObservedObjects[j])
454 
455  # make ok and in-collision disjoint
456  ok.difference_update(in_collision)
457  # visualize which objects are ok/in-collision/collided
458  self.visualize(ok, in_collision)
459  # set checking to false after all objects are truly removed and added
460  self.executeLater(None, self.setChecking, False)
461 

◆ execute()

def CollisionDetector.CollisionDetectorProxy.execute (   self,
  fp 
)

Method called when recomputing a DocumentObjectGroupPython CollisionDetector.

Collisions are checked upon recompute.

Parameters
fpA DocumentObjectGroupPython CollisionDetector object.

Definition at line 249 of file CollisionDetector.py.

249  def execute(self, fp):
250  self.checkCollisions()
251 

◆ executeCommandQueue()

def CollisionDetector.CollisionDetectorProxy.executeCommandQueue (   self)

Method to execute queue of postponed commands so that coin does not crash.

Call this method using a singleshot timer. For the fastest execution set time to 0.

Usage example: PySide2.QtCore.QTimer.singleShot(0, self.executeCommandQueue)

Definition at line 713 of file CollisionDetector.py.

713  def executeCommandQueue(self):
714  try:
715  for var, cmd, args in self.command_queue:
716  try:
717  if var is not None:
718  cmd(*args)
719  else:
720  var = cmd(*args)
721  except Exception as e:
722  FreeCAD.Console.PrintWarning(
723  "CollisionDetector: Executing a command in the "
724  + "command_queue.\n")
725  FreeCAD.Console.PrintWarning(str(e) + "\n")
726  except ReferenceError as e:
727  FreeCAD.Console.PrintLog(
728  "CollisionDetector: Deleted object in the command_queue.\n")
729  self.command_queue = []
730 

◆ executeLater()

def CollisionDetector.CollisionDetectorProxy.executeLater (   self,
  var,
  command,
  args 
)

Method to postpone execution after coin is finished (and avoid crashing coin).

Removing objects is necessary to do using this method, otherwise coin will crash. When using with variable or arguments, its crutial that they stay available and unchanged until the command is executed.

Usage example: self.executeLater(None, self.fp.removeObjectsFromDocument, None)

Parameters
varA variable to be assigned return value from a command or None.
commandA command to be executed.
argsA tuple or arguments to used in a command, an argument or None.

Definition at line 694 of file CollisionDetector.py.

694  def executeLater(self, var, command, args):
695  if isinstance(args, tuple):
696  self.command_queue.append((var, command, args))
697  elif args is None:
698  self.command_queue.append((var, command, ()))
699  else:
700  self.command_queue.append((var, command, (args,)))
701  QTimer.singleShot(0, self.executeCommandQueue)
702 

◆ exploreGroup()

def CollisionDetector.CollisionDetectorProxy.exploreGroup (   self,
  group 
)

Method to explore a group for all objects and shapes inside.

All object in the group are added to a groupobjects list and their shapes are fused into a groupshape.

Parameters
groupA group object.
Returns
groupobjects A list of objects in the group.
groupshape A shape fused from the shapes of groupobjects or None.

Definition at line 475 of file CollisionDetector.py.

475  def exploreGroup(self, group):
476  # Shapes of objects in the group
477  shapes = []
478  # Objects and groups to go through
479  objects = group.Group
480  i = 0
481  while i < len(objects):
482  # Object has a shape attached
483  if hasattr(objects[i], "Shape"):
484  shapes.append(objects[i].Shape)
485 
486  # Object has a group attached
487  if hasattr(objects[i], "Group"):
488  # Remove regular groups as their content is already between
489  # objects
490  if objects[i].__class__.__name__ == "DocumentObjectGroup":
491  objects.pop(i)
492 
493  # Go through content of other groups and add it
494  else:
495  groupobjects, groupshape = self.exploreGroup(
496  objects.pop(i))
497  if groupshape is not None:
498  shapes.append(groupshape)
499  objects = objects[:i] + groupobjects + objects[i:]
500  i += len(groupobjects) - 1
501  i += 1
502 
503  # There are shapes present in the group
504  if len(shapes) != 0:
505  # There are more than 2 shapes in the group
506  if len(shapes) >= 2:
507  shape = shapes[0].fuse(shapes[1:])
508  else:
509  shape = shapes[0]
510 
511  # Group has a placement property
512  if hasattr(group, "Placement"):
513  shape.Placement = group.Placement
514  return objects, shape
515 
516  # No shapes in the group
517  else:
518  return objects, None
519 

◆ intersection()

def CollisionDetector.CollisionDetectorProxy.intersection (   self,
  obj1,
  obj2 
)

Method to check intersection between obj1 and obj2.

Based on selected checking level this method checks for collisions and makes an intersection object if required.

Parameters
obj1An object to check for a mutual intersection.
obj2Another object to check for a mutual intersection.
Returns
groupobjects A list of objects in the group.
groupshape A shape fused from the shapes of groupobjects or None.

Definition at line 534 of file CollisionDetector.py.

534  def intersection(self, obj1, obj2):
535  # Check Bounding box is intersecting (the fastest and crudest)
536  if not self.shape_info[obj1]["shape"].BoundBox.intersect(
537  self.shape_info[obj2]["shape"].BoundBox):
538  return False
539 
540  # Check the shortest distance between the shapes is 0
541  if self.fp.CheckingLevel == "Shape distance" and \
542  self.shape_info[obj1]["shape"].distToShape(
543  self.shape_info[obj2]["shape"])[0] > 0:
544  return False
545 
546  # If requested, check intersection volume, and show intersection
547  if self.fp.CheckingLevel == "Intersection volume" or \
548  self.fp.CheckingLevel == "Intersection volume visualizations":
549  # Compute common volume to both objects
550  intersection = self.shape_info[obj1]["shape"].common(
551  self.shape_info[obj2]["shape"])
552 
553  # Test common volume is not 0 i.e. objects are not just touching
554  if intersection.Volume == 0:
555  return False
556 
557  # Make an Collision object to show the intersection if asked for
558  if self.fp.CheckingLevel == "Intersection volume visualizations":
559  self.executeLater(None, self.makeCollisionObject,
560  (intersection, obj1, obj2,
561  self.fp.IntersectionColor))
562  return True
563 

◆ loadObjects()

def CollisionDetector.CollisionDetectorProxy.loadObjects (   self,
  objects,
  save_style = True 
)

Adds shape info and loads object to restore them during reset.

Groups and GroupExtensions are explored and shapes inside are added to the shape_info dictionary. Their styles are recorded.

Parameters
objectsA list or set of added objects.

Definition at line 196 of file CollisionDetector.py.

196  def loadObjects(self, objects, save_style=True):
197  # Go through objects
198  for obj in objects:
199  # Invalid object - No shape nor group
200  if not hasattr(obj, "Shape") and not hasattr(obj, "Group"):
201  QMessageBox.warning(
202  None,
203  'Error while checking collisions',
204  "Object " + obj.Label + " does not have a shape assigned."
205  + "\nNeither does it group objects which do.\n"
206  + "It is not possible to check its collisions.\n"
207  + "Remove it from the observed objects.")
208  # Group object
209  elif not hasattr(obj, "Shape") and hasattr(obj, "Group"):
210  # Explore it
211  groupobjects, groupshape = self.exploreGroup(obj)
212  if groupshape is not None:
213  self.shape_info[obj] = {"objects": groupobjects,
214  "shape": groupshape}
215  if save_style:
216  for obj in groupobjects:
217  self.original_styles[obj.Name] = {
218  "Transparency": obj.ViewObject.Transparency,
219  "ShapeColor": obj.ViewObject.ShapeColor,
220  "LineColor": obj.ViewObject.LineColor,
221  "LineWidth": obj.ViewObject.LineWidth}
222  else:
223  QMessageBox.warning(
224  None,
225  'Error while checking collisions',
226  "Group " + obj.Label + " does not contain\n"
227  + "any objects with shapes assigned.\n"
228  + "It is not possible to check its collisions.\n"
229  + "Remove it from the observed objects.")
230  # Regular object
231  else:
232  self.shape_info[obj] = {"objects": [obj],
233  "shape": obj.Shape}
234  if save_style:
235  self.original_styles[obj.Name] = {
236  "Transparency": obj.ViewObject.Transparency,
237  "ShapeColor": obj.ViewObject.ShapeColor,
238  "LineColor": obj.ViewObject.LineColor,
239  "LineWidth": obj.ViewObject.LineWidth}
240 

◆ makeCollisionObject()

def CollisionDetector.CollisionDetectorProxy.makeCollisionObject (   self,
  shape,
  cause1,
  cause2,
  color 
)

Method to make a collision object and add it to the CollisionDetector.

Parameters
shapeA shape of a common volume between objects cause1 and cause2.
cause1An intersecting object.
cause2An intersecting object.
colorA color assigned to the collision object.

Definition at line 573 of file CollisionDetector.py.

573  def makeCollisionObject(self, shape, cause1, cause2, color):
574  # Add new object to the CollisionDetector
575  collision = self.fp.newObject("Part::FeaturePython", "Collision")
576  # Attach a Proxy to it and it's ViewObject, then purge its touched flag
577  CollisionProxy(collision, shape, cause1, cause2)
578  ViewProviderCollisionProxy(collision.ViewObject, color)
579  collision.purgeTouched()
580 

◆ onBeforeChange()

def CollisionDetector.CollisionDetectorProxy.onBeforeChange (   self,
  fp,
  prop 
)

Method called before DocumentObjectGroupPython CollisionDetector is changed.

A list of ObservedObjects is loaded to check which objects were added or removed so that their style can be changed appropriately.

Parameters
fpA DocumentObjectGroupPython CollisionDetector object.
propA str of a property about to change.

Definition at line 135 of file CollisionDetector.py.

135  def onBeforeChange(self, fp, prop):
136  if prop == "ObservedObjects":
137  self.observed_objects_before = fp.ObservedObjects
138 

◆ onChanged()

def CollisionDetector.CollisionDetectorProxy.onChanged (   self,
  fp,
  prop 
)

Method called after DocumentObjectGroupPython CollisionDetector was changed.

A list of ObservedObjects is loaded and checked for added or removed objects so that their style can be changed appropriately.

Parameters
fpA DocumentObjectGroupPython CollisionDetector object.
propA str of a changed property.

Definition at line 149 of file CollisionDetector.py.

149  def onChanged(self, fp, prop):
150  # Check if an object was deleted/added from the ObservedObjects
151  # and reset it to the original style/remember its style
152  if prop == "ObservedObjects":
153  removed_objects = set(self.observed_objects_before)\
154  - set(fp.ObservedObjects)
155  for obj in removed_objects:
156  self.resetObject(obj)
157  added_objects = set(fp.ObservedObjects) \
158  - set(self.shape_info.keys())
159  self.loadObjects(added_objects)
160  # remember if all observed objects are valid
161  fp.ValidObservedObjects = (set(self.shape_info.keys())
162  == set(fp.ObservedObjects))
163 

◆ onDocumentRestored()

def CollisionDetector.CollisionDetectorProxy.onDocumentRestored (   self,
  fp 
)

Method called when document is restored to make sure everything is as it was.

Reinitialization it creates properties and sets them to default, if they were not restored automatically. Properties of connected ViewObject are also recreated and reset if necessary.

Parameters
fpA restored DocumentObjectGroupPython CollisionDetector object.

Definition at line 121 of file CollisionDetector.py.

121  def onDocumentRestored(self, fp):
122  fp.ViewObject.Proxy.setProperties(fp.ViewObject)
123  self.setProperties(fp)
124 

◆ reset()

def CollisionDetector.CollisionDetectorProxy.reset (   self)

Method to reset CollisionDetector.

Deletes CollisionObjects and returns all ObservedObjects to their original style.

Definition at line 635 of file CollisionDetector.py.

635  def reset(self):
636  if self.checking:
637  FreeCAD.Console.PrintWarning("Can't reset, Checking!")
638  return
639  else:
640  self.resetting = True
641  self.executeLater(None, self.fp.removeObjectsFromDocument, None)
642  for obj_name, style in self.original_styles.items():
643  obj = FreeCAD.ActiveDocument.getObject(obj_name)
644  obj.ViewObject.Transparency = style["Transparency"]
645  obj.ViewObject.ShapeColor = tuple(style["ShapeColor"])
646  obj.ViewObject.LineColor = tuple(style["LineColor"])
647  obj.ViewObject.LineWidth = style["LineWidth"]
648  self.in_collision = set()
649  self.collided = set()
650  # set resetting to false after all objects are truly removed
651  self.executeLater(None, self.setResetting, False)
652 

◆ resetObject()

def CollisionDetector.CollisionDetectorProxy.resetObject (   self,
  object_ 
)

Method that resets style of an object_ to what it was before.

The object can be a Part::PartFeature, a group object or a Part object. Its Transparency, ShapeColor, LineColor and LineWidth are restored to previous values.

Parameters
object_An observed object.

Definition at line 174 of file CollisionDetector.py.

174  def resetObject(self, object_):
175  # Check that object to be reset has shape info recorded.
176  if object_ in self.shape_info.keys():
177  # Go through all 'Part objects' inside
178  for obj in self.shape_info.pop(object_)["objects"]:
179  # Reset styles
180  if obj.Name in self.original_styles.keys():
181  style = self.original_styles.pop(obj.Name)
182  obj.ViewObject.Transparency = style["Transparency"]
183  obj.ViewObject.ShapeColor = tuple(style["ShapeColor"])
184  obj.ViewObject.LineColor = tuple(style["LineColor"])
185  obj.ViewObject.LineWidth = style["LineWidth"]
186 

◆ setChecking()

def CollisionDetector.CollisionDetectorProxy.setChecking (   self,
  value 
)

Method necessary to be able to set checking attribute with delayed execution.

In order to be able to check when a Collision is deleted/moved by user instead of a CollisionDetector instance owning it, it's necessary to set checking attribute to False after all collisions are removed.

Parameters
valueA bool flagging that CollisionDetector is checking for Collisions.

Definition at line 663 of file CollisionDetector.py.

663  def setChecking(self, value):
664  self.checking = value
665 

◆ setProperties()

def CollisionDetector.CollisionDetectorProxy.setProperties (   self,
  fp 
)

Method to set properties during initialization or document restoration.

The properties are set if they are not already present and an AnimateDocumentObserver is recreated.

Parameters
fpA restored or barebone CollisionDetector object.

Definition at line 261 of file CollisionDetector.py.

261  def setProperties(self, fp):
262  if not hasattr(fp, "ValidObservedObjects"):
263  fp.addProperty(
264  "App::PropertyBool", "ValidObservedObjects", "General",
265  "All objects are valid for collision detection"
266  ).ValidObservedObjects = False
267  # Add (and preset) properties
268  if not hasattr(fp, "ObservedObjects"):
269  fp.addProperty(
270  "App::PropertyLinkListGlobal", "ObservedObjects", "General",
271  "Objects that will be checked for intersections.")
272  if not hasattr(fp, "RememberCollisions"):
273  fp.addProperty(
274  "App::PropertyBool", "RememberCollisions", "General",
275  "Remember which objects collided and show them."
276  ).RememberCollisions = True
277  if not hasattr(fp, "CheckingLevel"):
278  fp.addProperty("App::PropertyEnumeration", "CheckingLevel",
279  "General", "Levels of checking from coarse and\n"
280  + "fast (Bounding box) to slow but precise\n"
281  + "(Intersection volume). To see intersected area\n"
282  + "select 'Intersection volume visualizations'")
283  fp.CheckingLevel = ["Bounding box",
284  "Shape distance",
285  "Intersection volume",
286  "Intersection volume visualizations"]
287  # Intersection style
288  if not hasattr(fp, "IntersectionColor"):
289  fp.addProperty(
290  "App::PropertyColor", "IntersectionColor", "IntersectionStyle",
291  "Color for highlighting intersections."
292  ).IntersectionColor = (1.0, 0.0, 0.0)
293 
294  # Style of objects in collision
295  if not hasattr(fp, "InCollisionTransparency"):
296  fp.addProperty(
297  "App::PropertyPercent", "InCollisionTransparency",
298  "In-CollisionStyle",
299  "Transparency set to objects in collision."
300  ).InCollisionTransparency = 50
301  if not hasattr(fp, "InCollisionShapeColor"):
302  fp.addProperty(
303  "App::PropertyColor", "InCollisionShapeColor",
304  "In-CollisionStyle",
305  "Shape color for highlighting objects in collision."
306  ).InCollisionShapeColor = (1.0, 0.667, 0.333)
307  if not hasattr(fp, "InCollisionLineColor"):
308  fp.addProperty(
309  "App::PropertyColor", "InCollisionLineColor",
310  "In-CollisionStyle",
311  "Line color for highlighting objects in collision."
312  ).InCollisionLineColor = (1.0, 0.667, 0.0)
313  if not hasattr(fp, "InCollisionLineWidth"):
314  fp.addProperty(
315  "App::PropertyFloatConstraint", "InCollisionLineWidth",
316  "In-CollisionStyle",
317  "Line width for highlighting objects\n"
318  + "in collision. Range is < 1 | 64 >."
319  ).InCollisionLineWidth = (2, 1, 64, 1)
320  else:
321  fp.InCollisionLineWidth = (fp.InCollisionLineWidth, 2, 64, 1)
322 
323  # Style of collided objects
324  if not hasattr(fp, "CollidedTransparency"):
325  fp.addProperty(
326  "App::PropertyPercent", "CollidedTransparency",
327  "CollidedStyle", "Transparency set to collided objects."
328  ).CollidedTransparency = 50
329  if not hasattr(fp, "CollidedShapeColor"):
330  fp.addProperty(
331  "App::PropertyColor", "CollidedShapeColor", "CollidedStyle",
332  "Color for highlighting objects which collided."
333  ).CollidedShapeColor = (0.667, 0.333, 1.0)
334  if not hasattr(fp, "CollidedLineColor"):
335  fp.addProperty(
336  "App::PropertyColor", "CollidedLineColor",
337  "CollidedStyle",
338  "Line color for highlighting objects in collision."
339  ).CollidedLineColor = (0.667, 0.0, 1.0)
340  if not hasattr(fp, "CollidedLineWidth"):
341  fp.addProperty(
342  "App::PropertyFloatConstraint",
343  "CollidedLineWidth", "CollidedStyle",
344  "Line width for highlighting objects"
345  + "in collision. Range is < 1 | 64 >."
346  ).CollidedLineWidth = (2, 1, 64, 1)
347  else:
348  fp.CollidedLineWidth = (fp.CollidedLineWidth, 2, 64, 1)
349 
350  if not hasattr(self, "in_collision") or \
351  (hasattr(self, "in_collision") and self.in_collision is None):
352  self.in_collision = set()
353  if not hasattr(self, "collided") or \
354  (hasattr(self, "collided") and self.collided is None):
355  self.collided = set()
356  if not hasattr(self, "original_styles") or \
357  (hasattr(self, "original_styles") and
358  self.original_styles is None):
359  self.original_styles = dict()
360  if not hasattr(self, "shape_info") or \
361  (hasattr(self, "shape_info") and
362  self.shape_info is None):
363  self.shape_info = dict()
364  self.loadObjects(fp.ObservedObjects, save_style=False)
365 
366  self.fp = fp
367  self.checking = False
368  self.resetting = False
369 
370  fp.setEditorMode("Group", 1)
371  fp.setEditorMode("ValidObservedObjects", 2)
372  fp.ValidObservedObjects = (set(self.shape_info.keys())
373  == set(fp.ObservedObjects))
374 
375  import AnimateDocumentObserver
377 
def addObserver()
Adds an AnimateDocumentObserver between FreeCAD's document observers safely.

◆ setResetting()

def CollisionDetector.CollisionDetectorProxy.setResetting (   self,
  value 
)

Method necessary for setting resetting attribute with delayed execution.

In order to be able to check when a Collision is deleted/moved by user instead of a CollisionDetector instance owning it, it's necessary to set resetting attribute to False after all collisions are removed.

Parameters
valueA bool flagging that CollisionDetector is resetting Collisions.

Definition at line 676 of file CollisionDetector.py.

676  def setResetting(self, value):
677  self.resetting = value
678 

◆ visualize()

def CollisionDetector.CollisionDetectorProxy.visualize (   self,
  ok,
  in_collision 
)

Method to visualize which object are in-collision and which have collided.

Sets of collided and in-collision objects are kept up to date in this method. Then these sets are highlighted using style properties (Transparency, Shape Color, Line Color, Line Width).

Parameters
okA set of objects that are not in-collision.
in_collisionA set of objects that are in-collision.

Definition at line 592 of file CollisionDetector.py.

592  def visualize(self, ok, in_collision):
593  # Compute which objects are no longer in collision
594  collided = self.in_collision.intersection(ok)
595  # Add them to a set of objects which have collided
596  self.collided = self.collided.union(collided)
597  # Remove objects which no longer collide from a set for such objects
598  self.in_collision.difference_update(collided)
599  # Add new object which are in-collision to the set
600  self.in_collision = self.in_collision.union(in_collision)
601 
602  # If collided objects shall be shown
603  if self.fp.RememberCollisions:
604  # show them
605  for obj in collided:
606  for o in self.shape_info[obj]["objects"]:
607  o.ViewObject.Transparency = self.fp.CollidedTransparency
608  o.ViewObject.ShapeColor = self.fp.CollidedShapeColor
609  o.ViewObject.LineColor = self.fp.CollidedLineColor
610  o.ViewObject.LineWidth = self.fp.CollidedLineWidth
611  else:
612  # otherwise reset them
613  for obj in collided:
614  for o in self.shape_info[obj]["objects"]:
615  style = self.original_styles[obj.Name]
616  o.ViewObject.Transparency = style["Transparency"]
617  o.ViewObject.ShapeColor = style["ShapeColor"]
618  o.ViewObject.LineColor = style["LineColor"]
619  o.ViewObject.LineWidth = style["LineWidth"]
620 
621  # Show objects in-collision
622  for obj in in_collision:
623  for o in self.shape_info[obj]["objects"]:
624  o.ViewObject.Transparency = self.fp.InCollisionTransparency
625  o.ViewObject.ShapeColor = self.fp.InCollisionShapeColor
626  o.ViewObject.LineColor = self.fp.InCollisionLineColor
627  o.ViewObject.LineWidth = self.fp.InCollisionLineWidth
628 

Member Data Documentation

◆ checking

CollisionDetector.CollisionDetectorProxy.checking

A flag to signal collision checking is in progress.

Definition at line 367 of file CollisionDetector.py.

◆ collided

CollisionDetector.CollisionDetectorProxy.collided

A set of objects which have collided since the last reset.

Definition at line 355 of file CollisionDetector.py.

◆ command_queue

CollisionDetector.CollisionDetectorProxy.command_queue = []
static

A list of commands interfering with Coin3D to execute later.

Definition at line 95 of file CollisionDetector.py.

◆ fp

CollisionDetector.CollisionDetectorProxy.fp

A DocumentObjectGroupPython associated with the proxy.

Definition at line 366 of file CollisionDetector.py.

◆ in_collision

CollisionDetector.CollisionDetectorProxy.in_collision

A set of objects which are in-collision together.

Definition at line 352 of file CollisionDetector.py.

◆ observed_objects_before

CollisionDetector.CollisionDetectorProxy.observed_objects_before

An ObservedObjects property before change.

Definition at line 137 of file CollisionDetector.py.

◆ original_styles

CollisionDetector.CollisionDetectorProxy.original_styles

A dict of objects and their style original style.

Definition at line 359 of file CollisionDetector.py.

◆ resetting

CollisionDetector.CollisionDetectorProxy.resetting

A flag to signal resetting objects to previous state.

Definition at line 368 of file CollisionDetector.py.

◆ shape_info

CollisionDetector.CollisionDetectorProxy.shape_info

A dict of objects, Part objects inside them and fused shapes.

Definition at line 363 of file CollisionDetector.py.


The documentation for this class was generated from the following file: