RobRotation.RobRotationProxy Class Reference

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

Public Member Functions

def printt (self)
 
def __init__ (self, fp)
 Initialization method for RobRotationProxy. More...
 
def onChanged (self, fp, prop)
 Method called after DocumentObjectGroupPython RobRotation was changed. More...
 
def execute (self, fp)
 Method called when recomputing a DocumentObjectGroupPython. More...
 
def onDocumentRestored (self, fp)
 Method called when document is restored to make sure everything is as it was. More...
 
def setProperties (self, fp)
 Method to set properties during initialization or document restoration. More...
 
def change_joint_sequence (self, joint_sequence)
 Method used to change a RobRotation's joint variable sequence. More...
 
def is_rotation_property (self, prop)
 Method to check that a property describes a rotation. More...
 
def is_ValidRotation (self, timestamps=[], thetas=[], rotation=None)
 Method to check if a rotation is valid. More...
 
def find_timestamp_indices_and_weights (self, fp)
 Method to find weighted timestamps indices corresponding to a given time. More...
 
def __getstate__ (self)
 Necessary method to avoid errors when trying to save unserializable objects. More...
 
def __setstate__ (self, state)
 Necessary method to avoid errors when trying to restore unserializable objects. More...
 

Public Attributes

 updated
 
 fp
 A DocumentObjectGroupPython associated with the proxy. More...
 

Static Public Attributes

bool updated = False
 A bool - True if a property was changed by a class and not user. More...
 

Detailed Description

Proxy class for a DocumentObjectGroupPython RobRotation instance.

A RobRotationProxy instance adds properties to a DocumentObjectGroupPython RobRotation instance and responds to their changes. It provides a RobotPanel to be able to see an object in a rotation range.

To connect this Proxy object to a DocumentObjectGroupPython RobRotation do:

a = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroupPython",
"RobRotation")
RobRotationProxy(a)

Definition at line 71 of file RobRotation.py.

Constructor & Destructor Documentation

◆ __init__()

def RobRotation.RobRotationProxy.__init__ (   self,
  fp 
)

Initialization method for RobRotationProxy.

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

Parameters
fpA DocumentObjectGroupPython RobRotation object to be extended.

Definition at line 94 of file RobRotation.py.

94  def __init__(self, fp):
95  # Add (and preset) properties
96  self.setProperties(fp)
97  fp.Proxy = self
98 

Member Function Documentation

◆ __getstate__()

def RobRotation.RobRotationProxy.__getstate__ (   self)

Necessary method to avoid errors when trying to save unserializable objects.

This method is used by JSON to serialize unserializable objects during autosave. Without this an Error would rise when JSON would try to do that itself.

We need this for unserializable fp attribute, but we don't serialize it, because it's enough to reset it when object is restored.

Returns
None, because we don't serialize anything.

Definition at line 556 of file RobRotation.py.

556  def __getstate__(self):
557  return None
558 

◆ __setstate__()

def RobRotation.RobRotationProxy.__setstate__ (   self,
  state 
)

Necessary method to avoid errors when trying to restore unserializable objects.

This method is used during a document restoration. We need this for unserializable fp attribute, but we do not restore it, because it's enough to reset them from saved parameters.

Returns
None, because we don't restore anything.

Definition at line 569 of file RobRotation.py.

569  def __setstate__(self, state):
570  return None
571 
572 

◆ change_joint_sequence()

def RobRotation.RobRotationProxy.change_joint_sequence (   self,
  joint_sequence 
)

Method used to change a RobRotation's joint variable sequence.

A joint_sequence dictionary containing a rotation is tested for validity and then assigned to a RobRotation DocumentObjectGroupPython.

Parameters
joint_sequenceA dictionary describing a rotation.

Definition at line 420 of file RobRotation.py.

420  def change_joint_sequence(self, joint_sequence):
421  # Check that RobRotation has a correct format and load it
422  if self.is_ValidRotation(rotation=joint_sequence):
423  self.fp.Timestamps = joint_sequence["Timestamps"]
424  self.fp.thetaSequence = joint_sequence["thetaSequence"]
425  else:
426  FreeCAD.Console.PrintError("Invalid joint sequence!")
427 

◆ execute()

def RobRotation.RobRotationProxy.execute (   self,
  fp 
)

Method called when recomputing a DocumentObjectGroupPython.

New placement is computed, if a RobotPanel is active or it is not active, but rotation is valid. The current pose in a parent coordinate frame is computed using DH parameters. At last ObjectPlacement and Placement are updated accordingly.

Parameters
fpA DocumentObjectGroupPython RobRotation object.

Definition at line 167 of file RobRotation.py.

167  def execute(self, fp):
168  # Check that joint is not controlled by a RobotPanel
169  if not fp.RobotPanelActive:
170  # Check that current rotation has valid format
171  if not fp.ValidRotation:
172  FreeCAD.Console.PrintWarning(fp.Name +
173  ".execute(): Rotation " +
174  "is not in a valid format.\n")
175  return
176 
177  # Update theta according to current time and rotation
178  indices, weights = self.find_timestamp_indices_and_weights(fp)
179 
180  fp.theta = fp.thetaOffset \
181  + (weights[0]*fp.thetaSequence[indices[0]]
182  + weights[1]*fp.thetaSequence[indices[1]])
183 
184  # DH transformation
185  T_theta = FreeCAD.Placement(FreeCAD.Vector(0, 0, 0),
186  FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1),
187  fp.theta))
188  T_d = FreeCAD.Placement(FreeCAD.Vector(0, 0, fp.d),
189  FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0))
190  T_a = FreeCAD.Placement(FreeCAD.Vector(fp.a, 0, 0),
191  FreeCAD.Rotation(FreeCAD.Vector(1, 0, 0), 0))
192  T_alpha = FreeCAD.Placement(FreeCAD.Vector(0, 0, 0),
193  FreeCAD.Rotation(FreeCAD.Vector(1, 0, 0),
194  fp.alpha))
195 
196  fp.ObjectPlacement = T_theta.multiply(T_d.multiply(
197  T_a.multiply(T_alpha)))
198 
199  # Placement update
200  fp.Placement = fp.ParentFramePlacement.multiply(fp.ObjectPlacement)
201 

◆ find_timestamp_indices_and_weights()

def RobRotation.RobRotationProxy.find_timestamp_indices_and_weights (   self,
  fp 
)

Method to find weighted timestamps indices corresponding to a given time.

If a time is smaller than the first timestamp, the returned indices are [0,0] with weights [1,0] as that's the closest value. Similarly, if the time is greater than the last timestamp, the returned indices are [-1,-1] pointing to the last element of a timestamps list with weights [1,0]. If the time value is between the first and last timestamp, the indices belong to the closest higher and lower time. At the same time, if interpolation is off, the weights are 0 and 1, where one is given to the index closest to the time. Otherwise, the weights, whose sum equals to 1, are computed to show inverse relative distance i.e. an index with a greater weight is the closer.

Parameters
fpA DocumentObjectGroupPython RobRotation object.
Returns
indices A list of two integers between -1 and and length of Timestamps.
weights A list of two floats between 0 and 1 showing relative closeness.

Definition at line 513 of file RobRotation.py.

513  def find_timestamp_indices_and_weights(self, fp):
514  # Retrieve indices corresponding to current time
515  # If the time is before the first Timestamp use the first Timestamp
516  if fp.Time <= fp.Timestamps[0]:
517  indices = [0, 0]
518  weights = [1, 0]
519 
520  # If the time is after the last Timpestamp use the last Timestamp
521  elif fp.Time >= fp.Timestamps[-1]:
522  indices = [-1, -1]
523  weights = [1, 0]
524 
525  # If time is in the range of Timesteps
526  else:
527  # Find the index of the closest higher value
528  indices = [bisect(fp.Timestamps, fp.Time)]
529  # Add the previous index
530  indices.insert(0, indices[0]-1)
531  weights = [fp.Timestamps[indices[1]] - fp.Time,
532  fp.Time - fp.Timestamps[indices[0]]]
533  if not fp.Interpolate:
534  if weights[0] > weights[1]:
535  weights = [1, 0]
536  else:
537  weights = [0, 1]
538  else:
539  weights = [weights[0]/sum(weights), weights[1]/sum(weights)]
540 
541  return indices, weights
542 

◆ is_rotation_property()

def RobRotation.RobRotationProxy.is_rotation_property (   self,
  prop 
)

Method to check that a property describes a rotation.

It's checked whether prop is Timestamps or thetaSequence.

Parameters
propA str name of a changed property.
Returns
True if prop describes a rotation and False otherwise.

Definition at line 439 of file RobRotation.py.

439  def is_rotation_property(self, prop):
440  return prop in ["Timestamps", "thetaSequence"]
441 

◆ is_ValidRotation()

def RobRotation.RobRotationProxy.is_ValidRotation (   self,
  timestamps = [],
  thetas = [],
  rotation = None 
)

Method to check if a rotation is valid.

This method needs either a rotation dictionary argument or all the other lists of floats. A valid rotation needs to have all the necessary lists. All the lists must have same length. A timestamps list must consist of a sequence of strictly increasing floats. A rotation angle cannot exceed joint limits.

Parameters
timestampsA list of floats marking timestamps.
thetasA list of floats signifying rotation angles about Z axis.
rotationA dict containing all lists above.
Returns
True if rotation is valid and False otherwise.

Definition at line 459 of file RobRotation.py.

459  def is_ValidRotation(self, timestamps=[], thetas=[], rotation=None):
460  # Check all keys are included and record lengths of their lists
461  if rotation is not None and isinstance(rotation, dict):
462  for key in ["Timestamps", "thetaSequence"]:
463  if key not in rotation.keys():
464  FreeCAD.Console.PrintWarning("Rotation misses key " +
465  key + ".\n")
466  return False
467  timestamps = rotation["Timestamps"]
468  thetas = rotation["thetaSequence"]
469 
470  # Check that all lists have the same length
471  if len(timestamps) == 0 or \
472  (len(timestamps) != 0 and len(timestamps) != len(thetas)):
473  FreeCAD.Console.PrintWarning("Rotation has lists with "
474  + "inconsistent or zero "
475  + "lengths.\n")
476  return False
477 
478  # Check timestamps correspond to list of increasing values
479  if any([timestamps[i] >= timestamps[i+1]
480  for i in range(len(timestamps)-1)]):
481  FreeCAD.Console.PrintWarning("Rotation 'Timestamps' is not "
482  + "list of increasing values.\n")
483  return False
484 
485  if not all([self.fp.thetaMinimum <= th <= self.fp.thetaMaximum
486  for th in thetas]):
487  FreeCAD.Console.PrintWarning("Rotation 'thetaSequence' elements"
488  + " are out of theta range.\n")
489  return False
490 
491  return True
492 

◆ onChanged()

def RobRotation.RobRotationProxy.onChanged (   self,
  fp,
  prop 
)

Method called after DocumentObjectGroupPython RobRotation was changed.

A rotation is checked for its validity. If the Placement property is changed, then ParentFramePlacement property of a RobRotation children is set to equal the new Placement. If the ParentFramePlacement is changed, then the Placement property is changed.

Parameters
fpA DocumentObjectGroupPython RobRotation object.
propA str name of a changed property.

Definition at line 111 of file RobRotation.py.

111  def onChanged(self, fp, prop):
112  # Ignore updates to ranges
113  if self.updated:
114  self.updated = False
115  return
116 
117  # Control allowed theta range limits
118  elif prop == "thetaMinimum" and hasattr(fp, "thetaMaximum"):
119  self.updated = True
120  fp.thetaMaximum = (fp.thetaMaximum, fp.thetaMinimum,
121  float("inf"), 1)
122  elif prop == "thetaMaximum" and hasattr(fp, "thetaMinimum"):
123  self.updated = True
124  fp.thetaMinimum = (fp.thetaMinimum, -float("inf"),
125  fp.thetaMaximum, 1)
126 
127  # Check that the rotation has valid format
128  elif self.is_rotation_property(prop) and \
129  hasattr(fp, "thetaMaximum") and \
130  hasattr(fp, "thetaMinimum") and \
131  hasattr(self, "fp"):
132  traj_valid = self.is_ValidRotation(
133  fp.Timestamps, fp.thetaSequence)
134  if traj_valid != fp.ValidRotation:
135  fp.ValidRotation = traj_valid
136 
137  elif prop == "Placement":
138  # Propagate the Placement updates down the chain
139  if hasattr(fp, "Group") and len(fp.Group) != 0:
140  for child in fp.Group:
141  child.ParentFramePlacement = fp.Placement
142  child.purgeTouched()
143 
144  # Display animated objects in a pose specified by the rotation
145  # and current time
146  if hasattr(fp, "AnimatedObjects") and len(fp.AnimatedObjects) != 0:
147  for o in fp.AnimatedObjects:
148  o.Placement = fp.Placement
149  o.purgeTouched()
150 
151  elif prop == "ParentFramePlacement":
152  # If parent frame changed, recompute placement
153  fp.Placement = fp.ParentFramePlacement.multiply(
154  fp.ObjectPlacement)
155 

◆ onDocumentRestored()

def RobRotation.RobRotationProxy.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 RobRotation object.

Definition at line 212 of file RobRotation.py.

212  def onDocumentRestored(self, fp):
213  fp.ViewObject.Proxy.setProperties(fp.ViewObject)
214  self.setProperties(fp)
215 

◆ setProperties()

def RobRotation.RobRotationProxy.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 DocumentObjectGroupPython RobRotation object.

Definition at line 226 of file RobRotation.py.

226  def setProperties(self, fp):
227  # Add (and preset) properties
228  # Animation properties
229  if not hasattr(fp, "ValidRotation"):
230  fp.addProperty("App::PropertyBool", "ValidRotation", "General",
231  "This property records if rotation was changed."
232  ).ValidRotation = False
233  if not hasattr(fp, "RobotPanelActive"):
234  fp.addProperty("App::PropertyBool", "RobotPanelActive", "General",
235  "This property records if robot panel is active."
236  ).RobotPanelActive = False
237  if not hasattr(fp, "AnimatedObjects"):
238  fp.addProperty("App::PropertyLinkListGlobal", "AnimatedObjects",
239  "General", "Objects that will be animated.")
240  if not hasattr(fp, "Interpolate"):
241  fp.addProperty("App::PropertyBool", "Interpolate", "General",
242  "Interpolate RobRotation between timestamps."
243  ).Interpolate = True
244  if not hasattr(fp, "AllowServer"):
245  fp.addProperty("App::PropertyBool", "AllowServer", "General",
246  "Should this object allow a Server object to "
247  + "change it.").AllowServer = True
248  if not hasattr(fp, "AllowControl"):
249  fp.addProperty("App::PropertyBool", "AllowControl", "General",
250  "Should this object allow a Control object "
251  + " to change it."
252  ).AllowControl = True
253  if not hasattr(fp, "Time"):
254  fp.addProperty("App::PropertyFloat", "Time", "General",
255  "Animation time in seconds.").Time = 0
256  if not hasattr(fp, "ParentFramePlacement"):
257  fp.addProperty("App::PropertyPlacement", "ParentFramePlacement",
258  "General", "Current placement of a Parent Frame.")
259  if not hasattr(fp, "ObjectPlacement"):
260  fp.addProperty("App::PropertyPlacement", "ObjectPlacement",
261  "General",
262  "Current Object placement in a Parent Frame.")
263 
264  # DH parameters
265  if not hasattr(fp, "d"):
266  fp.addProperty("App::PropertyFloat", "d", "d-hParameters",
267  "Displacement along Z axis.").d = 0
268  if not hasattr(fp, "a"):
269  fp.addProperty("App::PropertyFloat", "a", "d-hParameters",
270  "Displacement along X axis.").a = 0
271  if not hasattr(fp, "alpha"):
272  fp.addProperty("App::PropertyFloat", "alpha", "d-hParameters",
273  "Rotation angle about X axis in degrees.").alpha = 0
274  if not hasattr(fp, "theta"):
275  fp.addProperty("App::PropertyFloat", "theta", "d-hParameters",
276  "Rotation angle about X axis in degrees.").theta = 0
277  if not hasattr(fp, "thetaMaximum"):
278  fp.addProperty("App::PropertyFloatConstraint", "thetaMaximum",
279  "d-hParameters", "Upper limit of rotation angle"
280  + " about Z axis in degrees."
281  ).thetaMaximum = (360, 0, float("inf"), 1)
282  elif hasattr(fp, "thetaMinimum"):
283  fp.thetaMaximum = (fp.thetaMaximum, fp.thetaMinimum,
284  float("inf"), 1)
285  if not hasattr(fp, "thetaMinimum"):
286  fp.addProperty("App::PropertyFloatConstraint", "thetaMinimum",
287  "d-hParameters", "Lower limit of rotation angle"
288  + " about Z axis in degrees."
289  ).thetaMinimum = (0, -float("inf"), 360, 1)
290  elif hasattr(fp, "thetaMaximum"):
291  fp.thetaMinimum = (fp.thetaMinimum, -float("inf"),
292  fp.thetaMaximum, 1)
293  if not hasattr(fp, "thetaOffset"):
294  fp.addProperty("App::PropertyFloat", "thetaOffset",
295  "d-hParameters", "Offset of rotation angle"
296  + " about Z axis in degrees.").thetaOffset = 0
297 
298  # Frame properties
299  if not hasattr(fp, "ShowFrame"):
300  fp.addProperty("App::PropertyBool", "ShowFrame", "Frame",
301  "Show a frame for current pose."
302  ).ShowFrame = True
303  if not hasattr(fp, "FrameTransparency"):
304  fp.addProperty("App::PropertyPercent", "FrameTransparency",
305  "Frame", "Transparency of the frame in percents."
306  ).FrameTransparency = 0
307  if not hasattr(fp, "ShowFrameArrowheads"):
308  fp.addProperty("App::PropertyBool", "ShowFrameArrowheads", "Frame",
309  "Show arrowheads for frame axis arrow's."
310  ).ShowFrameArrowheads = True
311  if not hasattr(fp, "FrameArrowheadLength"):
312  fp.addProperty("App::PropertyFloatConstraint",
313  "FrameArrowheadLength", "Frame",
314  "Frame axis arrow's arrowhead length.\n"
315  + "Range is < 1.0 | 1e6 >."
316  ).FrameArrowheadLength = (10, 1.0, 1e6, 1)
317  else:
318  fp.FrameArrowheadLength = (fp.FrameArrowheadLength, 1.0, 1e6, 1)
319  if not hasattr(fp, "FrameArrowheadRadius"):
320  fp.addProperty("App::PropertyFloatConstraint",
321  "FrameArrowheadRadius", "Frame",
322  "Frame axis arrow's arrowhead bottom radius.\n"
323  + "Range is < 0.5 | 1e6 >."
324  ).FrameArrowheadRadius = (5, 0.5, 1e6, 0.5)
325  else:
326  fp.FrameArrowheadRadius = (fp.FrameArrowheadRadius, 0.5, 1e6, 0.5)
327  if not hasattr(fp, "ShaftLength"):
328  fp.addProperty("App::PropertyFloatConstraint", "ShaftLength",
329  "Frame", "Frame axis arrow's shaft length.\n"
330  + "Range is < 1.0 | 1e6 >."
331  ).ShaftLength = (20, 1.0, 1e6, 1)
332  else:
333  fp.ShaftLength = (fp.ShaftLength, 1.0, 1e6, 1)
334  if not hasattr(fp, "ShaftWidth"):
335  fp.addProperty("App::PropertyFloatConstraint", "ShaftWidth",
336  "Frame", "Frame axis arrow's shaft width.\n"
337  + "Range is < 1.0 | 64 >."
338  ).ShaftWidth = (4, 1.0, 64, 1)
339  else:
340  fp.ShaftWidth = (fp.ShaftWidth, 1.0, 64, 1)
341  if not hasattr(fp, "ShowFrameLabels"):
342  fp.addProperty("App::PropertyBool", "ShowFrameLabels",
343  "Frame", "Show label for frame axes."
344  ).ShowFrameLabels = True
345 
346  # Label properties
347  if not hasattr(fp, "FontSize"):
348  fp.addProperty("App::PropertyIntegerConstraint", "FontSize",
349  "Labels", "Label font size.\n"
350  + "Range is < 1 | 100 >."
351  ).FontSize = (10, 1, 100, 1)
352  else:
353  fp.FontSize = (fp.FontSize, 1, 100, 1)
354  if not hasattr(fp, "DistanceToAxis"):
355  fp.addProperty("App::PropertyFloatConstraint", "DistanceToAxis",
356  "Labels", "Distance from label to its axis.\n"
357  + "Range is < 0.5 | 1e6 >."
358  ).DistanceToAxis = (5, 0.5, 1e6, 0.5)
359  else:
360  fp.DistanceToAxis = (fp.DistanceToAxis, 0.5, 1e6, 0.5)
361  if not hasattr(fp, "Subscription"):
362  fp.addProperty("App::PropertyString", "Subscription", "Labels",
363  "Subscription added to an axis name."
364  ).Subscription = ""
365  if not hasattr(fp, "Superscription"):
366  fp.addProperty("App::PropertyString", "Superscription", "Labels",
367  "Superscription added to an axis name."
368  ).Superscription = ""
369  if not hasattr(fp, "FontFamily"):
370  fp.addProperty("App::PropertyEnumeration", "FontFamily",
371  "Labels", "Label font family."
372  ).FontFamily = ["SERIF", "SANS", "TYPEWRITER"]
373  if not hasattr(fp, "FontStyle"):
374  fp.addProperty("App::PropertyEnumeration", "FontStyle",
375  "Labels", "Label font style."
376  ).FontStyle = ["NONE", "BOLD", "ITALIC",
377  "BOLD ITALIC"]
378 
379  # Placement properties
380  if not hasattr(fp, "Placement"):
381  fp.addProperty("App::PropertyPlacement", "Placement", "Base",
382  "Current placement for animated objects in "
383  + "world frame.")
384 
385  # Rotation properties
386  if not hasattr(fp, "Timestamps"):
387  fp.addProperty("App::PropertyFloatList", "Timestamps",
388  "Rotation", "Timestamps at which we define\n"
389  + "translation and rotation.")
390  if not hasattr(fp, "thetaSequence"):
391  fp.addProperty("App::PropertyFloatList", "thetaSequence",
392  "Rotation", "Rotation angles about Z axis in"
393  + " degrees.")
394 
395  # Add feature python
396  self.fp = fp
397 
398  # Make some properties read-only
399  fp.setEditorMode("ObjectPlacement", 1)
400  fp.setEditorMode("ParentFramePlacement", 1)
401  fp.setEditorMode("theta", 1)
402 
403  # Hide some properties
404  fp.setEditorMode("Placement", 2)
405  fp.setEditorMode("ValidRotation", 2)
406  fp.setEditorMode("RobotPanelActive", 2)
407 
408  import AnimateDocumentObserver
410 
def addObserver()
Adds an AnimateDocumentObserver between FreeCAD's document observers safely.

Member Data Documentation

◆ fp

RobRotation.RobRotationProxy.fp

A DocumentObjectGroupPython associated with the proxy.

Definition at line 396 of file RobRotation.py.

◆ updated

RobRotation.RobRotationProxy.updated = False
static

A bool - True if a property was changed by a class and not user.

Definition at line 79 of file RobRotation.py.


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