Python API 2.0 Reference
python/api1/py1TorusField.py
1 from __future__ import division
2 #-
3 # ==========================================================================
4 # Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All
5 # rights reserved.
6 #
7 # The coded instructions, statements, computer programs, and/or related
8 # material (collectively the "Data") in these files contain unpublished
9 # information proprietary to Autodesk, Inc. ("Autodesk") and/or its
10 # licensors, which is protected by U.S. and Canadian federal copyright
11 # law and by international treaties.
12 #
13 # The Data is provided for use exclusively by You. You have the right
14 # to use, modify, and incorporate this Data into other products for
15 # purposes authorized by the Autodesk software license agreement,
16 # without fee.
17 #
18 # The copyright notices in the Software and this entire statement,
19 # including the above license grant, this restriction and the
20 # following disclaimer, must be included in all copies of the
21 # Software, in whole or in part, and all derivative works of
22 # the Software, unless such copies or derivative works are solely
23 # in the form of machine-executable object code generated by a
24 # source language processor.
25 #
26 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
27 # AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED
28 # WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF
29 # NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
30 # PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR
31 # TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS
32 # BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL,
33 # DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK
34 # AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY
35 # OR PROBABILITY OF SUCH DAMAGES.
36 #
37 # ==========================================================================
38 #+
39 
40 #
41 # Creation Date: 3 October 2006
42 #
43 
44 ########################################################################
45 # DESCRIPTION:
46 #
47 # Produces the dependency graph node "spTorusField".
48 #
49 # The spTorusField node implements an attraction-and-repel field.
50 #
51 # The field repels all objects between itself and repelDistance attribute
52 # and attracts objects greater than attractDistance attribute from itself.
53 # This will eventually result in the objects clustering in a torus shape
54 # around the field.
55 #
56 # See the torusFieldTest.py script for an example on using this node.
57 # The example creates a new field node and a particle object, and connects them together.
58 #
59 ########################################################################
60 
61 from builtins import range
62 import math, sys
63 import maya.OpenMaya as OpenMaya
64 import maya.OpenMayaUI as OpenMayaUI
65 import maya.OpenMayaMPx as OpenMayaMPx
66 import maya.OpenMayaRender as OpenMayaRender
67 
68 kPluginName = "spTorusField"
69 kPluginNodeId = OpenMaya.MTypeId(0x0008004f)
70 
71 glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer()
72 glFT = glRenderer.glFunctionTable()
73 
74 def statusError(msg):
75  sys.stderr.write("%s\n" % message)
76  raise # called from exception handlers only, reraise exception
77 
78 
79 # Node definition
80 class TorusField(OpenMayaMPx.MPxFieldNode):
81  # Attributes
82  # minimum distance from field at which repel is applied
83  #
84  aMinDistance = OpenMaya.MObject()
85 
86  # min distance from field at which the force attracts
87  #
88  aAttractDistance = OpenMaya.MObject()
89 
90  # max distance from field at which the force repels.
91  #
92  aRepelDistance = OpenMaya.MObject()
93 
94  # drag exerted on the attractRepel force.
95  #
96  aDrag = OpenMaya.MObject()
97 
98  # amplitude/magnitude of the swarm force.
99  #
100  aSwarmAmplitude = OpenMaya.MObject()
101 
102  # frequency of the swarm force.
103  #
104  aSwarmFrequency = OpenMaya.MObject()
105 
106  # phase of the swarm force.
107  #
108  aSwarmPhase = OpenMaya.MObject()
109 
110 
111  def __init__(self):
112  OpenMayaMPx.MPxFieldNode.__init__(self)
113 
114 
115  def compute(self, plug, block):
116  """
117  Compute output force.
118  """
119  outputForce = OpenMayaMPx.cvar.MPxFieldNode_mOutputForce
120  if not (plug == outputForce):
121  return
122 
123  # get the logical index of the element this plug refers to.
124  #
125  try:
126  multiIndex = plug.logicalIndex()
127  except:
128  statusError("ERROR in plug.logicalIndex.")
129 
130  # Get input data handle, use outputArrayValue since we do not
131  # want to evaluate both inputs, only the one related to the
132  # requested multiIndex. Evaluating both inputs at once would cause
133  # a dependency graph loop.
134  #
135  inputData = OpenMayaMPx.cvar.MPxFieldNode_mInputData
136  try:
137  hInputArray = block.outputArrayValue(inputData)
138  except:
139  statusError("ERROR in hInputArray = block.outputArrayValue().")
140 
141  try:
142  hInputArray.jumpToElement(multiIndex)
143  except:
144  statusError("ERROR: hInputArray.jumpToElement failed.")
145 
146  # get children of aInputData.
147  #
148  try:
149  hCompond = hInputArray.inputValue()
150  except:
151  statusError("ERROR in hCompond=hInputArray.inputValue")
152 
153  inputPositions = OpenMayaMPx.cvar.MPxFieldNode_mInputPositions
154  hPosition = hCompond.child(inputPositions)
155  dPosition = hPosition.data()
156  fnPosition = OpenMaya.MFnVectorArrayData(dPosition)
157  try:
158  points = fnPosition.array()
159  except:
160  statusError("ERROR in fnPosition.array(), not find points.")
161 
162  inputVelocities = OpenMayaMPx.cvar.MPxFieldNode_mInputVelocities
163  hVelocity = hCompond.child(inputVelocities)
164  dVelocity = hVelocity.data()
165  fnVelocity = OpenMaya.MFnVectorArrayData(dVelocity)
166  try:
167  velocities = fnVelocity.array()
168  except:
169  statusError("ERROR in fnVelocity.array(), not find velocities.")
170 
171  inputMass = OpenMayaMPx.cvar.MPxFieldNode_mInputMass
172  hMass = hCompond.child(inputMass)
173  dMass = hMass.data()
174  fnMass = OpenMaya.MFnDoubleArrayData(dMass)
175  try:
176  masses = fnMass.array()
177  except:
178  statusError("ERROR in fnMass.array(), not find masses.")
179 
180  # Compute the output force.
181  #
182  forceArray = OpenMaya.MVectorArray()
183  useMaxDistSet = self.__useMaxDistanceValue(block)
184  if useMaxDistSet:
185  self.__applyMaxDist(block, points, velocities, masses, forceArray)
186  else:
187  self.__applyNoMaxDist(block, points, velocities, masses, forceArray)
188 
189  # get output data handle
190  #
191  try:
192  hOutArray = block.outputArrayValue(outputForce)
193  except:
194  statusError("ERROR in hOutArray = block.outputArrayValue.")
195  try:
196  bOutArray = hOutArray.builder()
197  except:
198  statusError("ERROR in bOutArray = hOutArray.builder.")
199 
200  # get output force array from block.
201  #
202  try:
203  hOut = bOutArray.addElement(multiIndex)
204  except:
205  statusError("ERROR in hOut = bOutArray.addElement.")
206 
207  fnOutputForce = OpenMaya.MFnVectorArrayData()
208  try:
209  dOutputForce = fnOutputForce.create(forceArray)
210  except:
211  statusError("ERROR in dOutputForce = fnOutputForce.create")
212 
213  # update data block with new output force data.
214  #
215  hOut.setMObject(dOutputForce)
216  block.setClean(plug)
217 
218 
219  def draw (self, view, path, style, status):
220  """
221  Draw a set of rings to symbolie the field. This does not override default icon, you can do that by implementing the iconBitmap() function
222  """
223  TORUS_PI = 3.14159265
224  TORUS_2PI = 2.0 * TORUS_PI
225  EDGES = 30
226  SEGMENTS = 20
227 
228  view.beginGL()
229  for j in range(SEGMENTS):
230  glFT.glPushMatrix()
231  glFT.glRotatef(360.0 * j / SEGMENTS, 0.0, 1.0, 0.0)
232  glFT.glTranslatef(1.5, 0.0, 0.0)
233  for i in range(EDGES):
234  glFT.glBegin(OpenMayaRender.MGL_LINE_STRIP)
235  p0 = TORUS_2PI * i / EDGES
236  p1 = TORUS_2PI * (i+1) / EDGES
237  glFT.glVertex2f(math.cos(p0), math.sin(p0))
238  glFT.glVertex2f(math.cos(p1), math.sin(p1))
239  glFT.glEnd()
240  glFT.glPopMatrix()
241  view.endGL()
242 
243 
244  def getForceAtPoint(self, points, velocities, masses, forceArray, deltaTime):
245  """
246  This method is not required to be overridden, it is only necessary
247  for compatibility with the MFnField function set.
248  """
249  block = forceCache()
250  useMaxDistSet = self.__useMaxDistanceValue(block)
251  if useMaxDistSet:
252  self.__applyMaxDist(block, points, velocities, masses, forceArray)
253  else:
254  self.__applyNoMaxDist(block, points, velocities, masses, forceArray)
255 
256 
257  def iconSizeAndOrigin(self, width, height, xbo, ybo):
258  OpenMaya.MScriptUtil.setUint( width, 32 )
259  OpenMaya.MScriptUtil.setUint( height, 32 )
260  OpenMaya.MScriptUtil.setUint( xbo, 4 )
261  OpenMaya.MScriptUtil.setUint( ybo, 4 )
262 
263 
264  def iconBitmap(self, bitmap):
265  OpenMaya.MScriptUtil.setUcharArray( bitmap, 0, 0x18 )
266  OpenMaya.MScriptUtil.setUcharArray( bitmap, 4, 0x66 )
267  OpenMaya.MScriptUtil.setUcharArray( bitmap, 8, 0xC3 )
268  OpenMaya.MScriptUtil.setUcharArray( bitmap, 12, 0x81 )
269  OpenMaya.MScriptUtil.setUcharArray( bitmap, 16, 0x81 )
270  OpenMaya.MScriptUtil.setUcharArray( bitmap, 20, 0xC3 )
271  OpenMaya.MScriptUtil.setUcharArray( bitmap, 24, 0x66 )
272  OpenMaya.MScriptUtil.setUcharArray( bitmap, 28, 0x18 )
273 
274 
275  # methods to compute output force.
276  #
277  def __applyNoMaxDist(self, block, points, velocities, masses, outputForce):
278  """
279  Compute output force in the case that the useMaxDistance is not set.
280  """
281  # points and velocities should have the same length. If not return.
282  #
283  if points.length() != velocities.length():
284  return
285 
286  # clear the output force array
287  #
288  outputForce.clear()
289 
290  # get field parameters.
291  #
292  magValue = self.__magnitudeValue(block)
293  minDist = self.__minDistanceValue(block)
294  attractDist = self.__attractDistanceValue(block)
295  repelDist = self.__repelDistanceValue(block)
296  dragMag = self.__dragValue(block)
297  swarmAmp = self.__swarmAmplitudeValue(block)
298 
299  # get owner's data. posArray may have only one point which is the centroid
300  # (if this has owner) or field position(if without owner). Or it may have
301  # a list of points if with owner and applyPerVertex.
302  #
303  posArray = self.__ownerPosition(block)
304 
305  fieldPosCount = posArray.length()
306  receptorSize = points.length()
307 
308  # With this model,if max distance isn't set then we
309  # also don't attenuate, because 1 - dist/maxDist isn't
310  # meaningful. No max distance and no attenuation.
311  #
312  for ptIndex in range(receptorSize):
313  forceV = OpenMaya.MVector(0.0,0.0,0.0)
314  receptorPoint = points[ptIndex]
315 
316  # Apply from every field position to every receptor position.
317  #
318  distance = 0.0
319  for i in range(fieldPosCount-1, -1, -1):
320  difference = receptorPoint - posArray[i]
321  distance = difference.length()
322 
323  if distance < minDist:
324  continue
325 
326  if distance <= repelDist:
327  forceV += difference * magValue
328  elif distance >= attractDist:
329  forceV += -difference * magValue
330 
331  # Apply drag/swarm only if the object is inside the zone
332  # the repulsion-attraction is pushing the object to.
333  #
334  if distance >= repelDist and distance <= attractDist:
335  if dragMag > 0:
336  if fieldPosCount > 0:
337  dragForceV = velocities[ptIndex] * (-dragMag) * fieldPosCount
338  forceV += dragForceV
339 
340  if swarmAmp > 0:
341  frequency = self.__swarmFrequencyValue(block)
342  phase = OpenMaya.MVector(0.0, 0.0, frequency)
343 
344  # Add swarm in here
345  #
346  for i in range(fieldPosCount-1, -1, -1):
347  difference = receptorPoint - posArray[i]
348  difference = (difference + phase) * frequency
349 
350  noiseEffect = [ difference[i] for i in range(3) ]
351  if( (noiseEffect[0] < -2147483647.0) or
352  (noiseEffect[0] > 2147483647.0) or
353  (noiseEffect[1] < -2147483647.0) or
354  (noiseEffect[1] > 2147483647.0) or
355  (noiseEffect[2] < -2147483647.0) or
356  (noiseEffect[2] > 2147483647.0) ):
357  continue
358 
359  noiseOut = self.__noiseFunction(noiseEffect)
360  swarmForce = OpenMaya.MVector(noiseOut[0] * swarmAmp,
361  noiseOut[1] * swarmAmp,
362  noiseOut[2] * swarmAmp)
363  forceV += swarmForce
364 
365  outputForce.append(forceV)
366 
367 
368  def __applyMaxDist(self, block, points, velocities, masses, outputForce):
369  """
370  Compute output force in the case that the useMaxDistance is set.
371  """
372  # points and velocities should have the same length. If not return.
373  #
374  if points.length() != velocities.length():
375  return
376 
377  # clear the output force array.
378  #
379  outputForce.clear()
380 
381  # get field parameters.
382  #
383  magValue = self.__magnitudeValue(block)
384  attenValue = self.__attenuationValue(block)
385  maxDist = self.__maxDistanceValue(block)
386  minDist = self.__minDistanceValue(block)
387  attractDist = self.__attractDistanceValue(block)
388  repelDist = self.__repelDistanceValue(block)
389  dragMag = self.__dragValue(block)
390  swarmAmp = self.__swarmAmplitudeValue(block)
391 
392  # get owner's data. posArray may have only one point which is the centroid
393  # (if this has owner) or field position(if without owner). Or it may have
394  # a list of points if with owner and applyPerVertex.
395  #
396  posArray = self.__ownerPosition(block)
397 
398  fieldPosCount = posArray.length()
399  receptorSize = points.length()
400 
401  for ptIndex in range(receptorSize):
402  receptorPoint = points[ptIndex]
403 
404  # Apply from every field position to every receptor position.
405  #
406  forceV = OpenMaya.MVector(0,0,0)
407  sumForceV = OpenMaya.MVector(0,0,0)
408  for i in range(fieldPosCount-1, -1, -1):
409  difference = receptorPoint-posArray[i]
410  distance = difference.length()
411 
412  if (distance < minDist or distance > maxDist):
413  continue
414 
415  if attenValue > 0.0:
416  force = magValue * (math.pow((1.0-(distance/maxDist)),attenValue))
417  forceV = difference * force
418  elif (distance <= repelDist):
419  forceV = difference * magValue
420  elif (distance >= attractDist):
421  forceV = -difference * magValue
422 
423  # Apply drag and swarm if the object is inside
424  # the zone the repulsion-attraction is pushing the
425  # object to, and if they are set.
426  #
427  if distance >= repelDist and distance <= attractDist:
428  if dragMag > 0:
429  if fieldPosCount > 0:
430  dragForceV = velocities[ptIndex] * (-dragMag) * fieldPosCount
431  forceV += dragForceV
432 
433  if swarmAmp > 0:
434  frequency = self.__swarmFrequencyValue(block)
435  phase = OpenMaya.MVector(0.0, 0.0, frequency)
436 
437  # Add swarm in here
438  #
439  for i in range(fieldPosCount-1, -1, -1):
440  difference = receptorPoint - posArray[i]
441  difference = (difference + phase) * frequency
442 
443  noiseEffect = [ difference[i] for i in range(3) ]
444  if( (noiseEffect[0] < -2147483647.0) or
445  (noiseEffect[0] > 2147483647.0) or
446  (noiseEffect[1] < -2147483647.0) or
447  (noiseEffect[1] > 2147483647.0) or
448  (noiseEffect[2] < -2147483647.0) or
449  (noiseEffect[2] > 2147483647.0) ):
450  continue
451 
452  noiseOut = self.__noiseFunction(noiseEffect)
453  swarmForce = OpenMaya.MVector(noiseOut[0] * swarmAmp,
454  noiseOut[1] * swarmAmp,
455  noiseOut[2] * swarmAmp)
456  forceV += swarmForce
457 
458  if (maxDist > 0.0):
459  forceV *= self.falloffCurve(distance/maxDist)
460  sumForceV += forceV
461 
462  outputForce.append(sumForceV)
463 
464 
465  def __ownerPosition(self, block):
466  """
467  If this field has an owner, get the owner's position array or
468  centroid, then assign it to the ownerPosArray.
469  If it does not have owner, get the field position in the world
470  space, and assign it to the given array, ownerPosArray.
471  """
472  ownerPosArray = OpenMaya.MVectorArray()
473  if self.__applyPerVertexValue(block):
474  ownerPos = OpenMayaMPx.cvar.MPxFieldNode_mOwnerPosData
475  try:
476  hOwnerPos = block.inputValue(ownerPos)
477  except:
478  # get the field position in the world space
479  # and add it into ownerPosArray.
480  #
481  worldPos = self.__getWorldPosition()
482  ownerPosArray.append(worldPos)
483  else:
484  dOwnerPos = hOwnerPos.data()
485  fnOwnerPos = OpenMaya.MFnVectorArrayData(dOwnerPos)
486  try:
487  posArray = fnOwnerPos.array()
488  except:
489  worldPos = self.__getWorldPosition()
490  ownerPosArray.append(worldPos)
491  else:
492  # assign vectors from block to ownerPosArray.
493  #
494  for i in range(posArray.length()):
495  ownerPosArray.append(posArray[i])
496  else:
497  try:
498  centroidV = self.__ownerCentroidValue(block)
499  except:
500  # get the field position in the world space.
501  #
502  worldPos = self.__getWorldPosition()
503  ownerPosArray.append(worldPos)
504  else:
505  ownerPosArray.append(centroidV)
506 
507  return ownerPosArray
508 
509 
510  def __getWorldPosition(self):
511  thisNode = self.thisMObject()
512  fnThisNode = OpenMaya.MFnDependencyNode(thisNode)
513 
514  # get worldMatrix attribute.
515  #
516  worldMatrixAttr = fnThisNode.attribute("worldMatrix")
517 
518  # build worldMatrix plug, and specify which element the plug refers to.
519  # We use the first element(the first dagPath of this field).
520  #
521  matrixPlug = OpenMaya.MPlug(thisNode, worldMatrixAttr)
522  matrixPlug = matrixPlug.elementByLogicalIndex(0)
523 
524  # Get the value of the 'worldMatrix' attribute
525  #
526  try:
527  matrixObject = matrixPlug.asMObject(matrixObject)
528  except:
529  statusError("TorusField.__getWorldPosition: get matrixObject")
530 
531  try:
532  worldMatrixData = OpenMaya.MFnMatrixData(matrixObject)
533  except:
534  statusError("TorusField.__getWorldPosition: get worldMatrixData")
535 
536  try:
537  worldMatrix = worldMatrixData.matrix()
538  except:
539  statusError("TorusField.__getWorldPosition: get worldMatrix")
540 
541  # assign the translate to the given vector.
542  #
543  return OpenMaya.MVector(worldMatrix(3, 0), worldMatrix(3, 1), worldMatrix(3, 2))
544 
545 
546  def __noiseFunction(self, inNoise):
547  """
548  A noise function
549  """
550  # Shared data for noise computation
551  #
552  xlim = [ [0,0], [0,0], [0,0] ] # integer bound for point
553  xarg = [0.0, 0.0, 0.0 ] # fractional part
554 
555  # Helper functions to compute noise
556  #
557  rand3a = lambda x,y,z: frand(67*(x)+59*(y)+71*(z))
558  rand3b = lambda x,y,z: frand(73*(x)+79*(y)+83*(z))
559  rand3c = lambda x,y,z: frand(89*(x)+97*(y)+101*(z))
560  rand3d = lambda x,y,z: frand(103*(x)+107*(y)+109*(z))
561 
562  def frand(s):
563  seed = s << 13^s
564  return (1.0 - ((s*(s*s*15731+789221)+1376312589) & 0x7fffffff)/1073741824.0)
565 
566  def hermite(p0, p1, r0, r1, t):
567  t2 = t * t
568  t3 = t2 * t
569  _3t2 = 3.0 * t2
570  _2t3 = 2.0 * t3
571 
572  return (p0*(_2t3-_3t2+1) + p1*(-_2t3+_3t2) + r0*(t3-2.0*t2+t) + r1*(t3-t2))
573 
574  def interpolate(i, n):
575  f = [ 0.0, 0.0, 0.0, 0.0 ]
576  if n == 0: # at 0, return lattice value
577  f[0] = rand3a( xlim[0][i&1], xlim[1][i>>1&1], xlim[2][i>>2] )
578  f[1] = rand3b( xlim[0][i&1], xlim[1][i>>1&1], xlim[2][i>>2] )
579  f[2] = rand3c( xlim[0][i&1], xlim[1][i>>1&1], xlim[2][i>>2] )
580  f[3] = rand3d( xlim[0][i&1], xlim[1][i>>1&1], xlim[2][i>>2] )
581  else:
582  n -= 1
583  f0 = interpolate(i, n) # compute first half
584  f1 = interpolate(i | 1<<n, n) # compute second half
585 
586  # use linear interpolation for slopes
587  f[0] = (1.0 - xarg[n]) * f0[0] + xarg[n] * f1[0]
588  f[1] = (1.0 - xarg[n]) * f0[1] + xarg[n] * f1[1]
589  f[2] = (1.0 - xarg[n]) * f0[2] + xarg[n] * f1[2]
590 
591  # use hermite interpolation for values
592  f[3] = hermite(f0[3], f1[3], f0[n], f1[n], xarg[n])
593 
594  return f
595 
596  xlim[0][0] = int(math.floor(inNoise[0]))
597  xlim[0][1] = xlim[0][0] + 1
598  xlim[1][0] = int(math.floor(inNoise[1]))
599  xlim[1][1] = xlim[1][0] + 1
600  xlim[2][0] = int(math.floor(inNoise[2]))
601  xlim[2][1] = xlim[2][0] + 1
602 
603  xarg[0] = inNoise[0] - xlim[0][0]
604  xarg[1] = inNoise[1] - xlim[1][0]
605  xarg[2] = inNoise[2] - xlim[2][0]
606 
607  return interpolate(0, 3)
608 
609 
610  # methods to get attribute value.
611  #
612  def __magnitudeValue(self, block):
613  magnitude = OpenMayaMPx.cvar.MPxFieldNode_mMagnitude
614  hValue = block.inputValue(magnitude)
615  return hValue.asDouble()
616 
617 
618  def __attenuationValue(self, block):
619  attenuation = OpenMayaMPx.cvar.MPxFieldNode_mAttenuation
620  hValue = block.inputValue(attenuation)
621  return hValue.asDouble()
622 
623 
624  def __maxDistanceValue(self, block):
625  maxDistance = OpenMayaMPx.cvar.MPxFieldNode_mMaxDistance
626  hValue = block.inputValue(maxDistance)
627  return hValue.asDouble()
628 
629 
630  def __useMaxDistanceValue(self, block):
631  useMaxDistance = OpenMayaMPx.cvar.MPxFieldNode_mUseMaxDistance
632  hValue = block.inputValue(useMaxDistance)
633  return hValue.asBool()
634 
635 
636  def __applyPerVertexValue(self, block):
637  applyPerVertex = OpenMayaMPx.cvar.MPxFieldNode_mApplyPerVertex
638  hValue = block.inputValue(applyPerVertex)
639  return hValue.asBool()
640 
641 
642  # methods to get attribute value of local attributes.
643  #
644  def __minDistanceValue(self, block):
645  hValue = block.inputValue(TorusField.aMinDistance)
646  return hValue.asDouble()
647 
648 
649  def __attractDistanceValue(self, block):
650  hValue = block.inputValue(TorusField.aAttractDistance)
651  return hValue.asDouble()
652 
653 
654  def __repelDistanceValue(self, block):
655  hValue = block.inputValue(TorusField.aRepelDistance)
656  return hValue.asDouble()
657 
658 
659  def __dragValue(self, block):
660  hValue = block.inputValue(TorusField.aDrag)
661  return hValue.asDouble()
662 
663 
664  def __swarmAmplitudeValue(self, block):
665  hValue = block.inputValue(TorusField.aSwarmAmplitude)
666  return hValue.asDouble()
667 
668 
669  def __swarmFrequencyValue(self, block):
670  hValue = block.inputValue(TorusField.aSwarmFrequency)
671  return hValue.asDouble()
672 
673 
674  def __swarmPhaseValue(self, block):
675  hValue = block.inputValue(TorusField.aSwarmPhase)
676  return hValue.asDouble()
677 
678 
679  def __ownerCentroidValue(self, block):
680  ownerCentroidX = OpenMayaMPx.cvar.MPxFieldNode_mOwnerCentroidX
681  ownerCentroidY = OpenMayaMPx.cvar.MPxFieldNode_mOwnerCentroidY
682  ownerCentroidZ = OpenMayaMPx.cvar.MPxFieldNode_mOwnerCentroidZ
683  hValueX = block.inputValue(ownerCentroidX)
684  hValueY = block.inputValue(ownerCentroidY)
685  hValueZ = block.inputValue(ownerCentroidZ)
686  return OpenMaya.MVector(hValueX.asDouble(),
687  hValueY.asDouble(),
688  hValueZ.asDouble())
689 
690 
691 ############################################################################
692 
693 
694 # creator
695 def nodeCreator():
696  return OpenMayaMPx.asMPxPtr(TorusField())
697 
698 
699 # initializer
700 def nodeInitializer():
701  numAttr = OpenMaya.MFnNumericAttribute()
702 
703  # create the field basic attributes.
704  #
705  TorusField.aMinDistance = numAttr.create("minDistance", "mnd", OpenMaya.MFnNumericData.kDouble, 0.0)
706  numAttr.setKeyable(True)
707  try:
708  TorusField.addAttribute(TorusField.aMinDistance)
709  except:
710  statusError("ERROR adding aMinDistance attribute.")
711 
712  TorusField.aAttractDistance = numAttr.create("attractDistance", "ad", OpenMaya.MFnNumericData.kDouble, 20.0)
713  numAttr.setKeyable(True)
714  try:
715  TorusField.addAttribute(TorusField.aAttractDistance)
716  except:
717  statusError("ERROR adding aAttractDistance attribute.")
718 
719  TorusField.aRepelDistance = numAttr.create("repelDistance", "rd", OpenMaya.MFnNumericData.kDouble, 10.0)
720  numAttr.setKeyable(True)
721  try:
722  TorusField.addAttribute(TorusField.aRepelDistance)
723  except:
724  statusError("ERROR adding aRepelDistance attribute.")
725 
726  TorusField.aDrag = numAttr.create("drag", "d", OpenMaya.MFnNumericData.kDouble, 0.0)
727  numAttr.setKeyable(True)
728  try:
729  TorusField.addAttribute(TorusField.aDrag)
730  except:
731  statusError("ERROR adding aDrag attribute.")
732 
733  TorusField.aSwarmAmplitude = numAttr.create("swarmAmplitude", "samp", OpenMaya.MFnNumericData.kDouble, 0.0)
734  numAttr.setKeyable(True)
735  try:
736  TorusField.addAttribute(TorusField.aSwarmAmplitude)
737  except:
738  statusError("ERROR adding aSwarmAmplitude attribute.")
739 
740  TorusField.aSwarmFrequency = numAttr.create("swarmFrequency", "sfrq", OpenMaya.MFnNumericData.kDouble, 1.0)
741  numAttr.setKeyable(True)
742  try:
743  TorusField.addAttribute(TorusField.aSwarmFrequency)
744  except:
745  statusError("ERROR adding aSwarmFrequency attribute.")
746 
747  TorusField.aSwarmPhase = numAttr.create("swarmPhase", "sa", OpenMaya.MFnNumericData.kDouble, 0.0)
748  numAttr.setKeyable(True)
749  try:
750  TorusField.addAttribute(TorusField.aSwarmPhase)
751  except:
752  statusError("ERROR adding aSwarmPhase attribute.")
753 
754 
755 # initialize the script plug-in
756 def initializePlugin(mobject):
757  mplugin = OpenMayaMPx.MFnPlugin(mobject, "Autodesk", "1.0", "Any")
758  try:
759  mplugin.registerNode(kPluginName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kFieldNode)
760  except:
761  statusError("Failed to register node: %s" % kPluginName)
762 
763 
764 # uninitialize the script plug-in
765 def uninitializePlugin(mobject):
766  mplugin = OpenMayaMPx.MFnPlugin(mobject)
767  try:
768  mplugin.deregisterNode(kPluginNodeId)
769  except:
770  statusError("Failed to deregister node: %s" % kPluginName)