Most cases of premature ejaculation do not have a clear cause. With sexual experience and age, men often learn to delay orgasm. Premature ejaculation may occur with a new partner, only in certain sexual situations, or if it has been a long time since the last ejaculation. Psychological factors such as anxiety, guilt, or depression can cause premature ejaculation. In some cases, premature ejaculation may be related to a medical cause such as hormonal problems, injury, or a side effect of certain medicines. Quick flash to our customers: order cialis online uk no rx if you need generic cialis and get fast delivery to wales. Worrying that you won't be able to perform in bed can make it harder for you to do just that. Anxiety from other parts of your life can also spill over into the bedroom. Full information about Kamagra product line by Adjanta - buy kamagra online in uk.

Fastidious Python Shrub

July 31st, 2009

This shrub code features pains-takingly accurate collision-detection using closestIntersection nodes, and a UI featuring a progress bar.

It is very slow. Perhaps a tad obsessive in its detection. These 500 cones took about 10 minutes.

Code follows:

Maya Python code

### start: fastidious python shrub

from pymel import *
import pymel.core.datatypes as dt
import maya.OpenMaya as om
import random, time


# convert transform longName to OpenMaya dag node
def nameToDag( name ):
  selectionList = om.MSelectionList()
  selectionList.add( name )
  node = om.MDagPath()
  selectionList.getDagPath( 0, node )
  return node

# test whichEdge for intersection with whichMesh
def edgeIntersect(whichEdge, whichMesh):
  verts = whichEdge.connectedVertices()
  startVtx = verts[0].getPosition(space="world")
  endVtx = verts[1].getPosition(space="world")
  # normalize vector
  vectBtwPnts = (startVtx - endVtx) * -1
  vectorToFinish = om.MFloatVector(vectBtwPnts)
  # get length
  vectDistance = length(vectorToFinish)

  # convert longName to OpenMaya dag node
  dag = nameToDag( whichMesh.longName() )
  # create a MFnMesh object
  meshFn = om.MFnMesh()
  meshFn.setObject( dag )

  raySource = om.MFloatPoint(startVtx[0],startVtx[1],startVtx[2])
  rayDirection = vectorToFinish
  rayDirection = rayDirection.normal()

  hitFacePtr = om.MScriptUtil().asIntPtr()
  hitPoint   = om.MFloatPoint()

  idsSorted    = False
  testBothDirections = False
  faceIds      = None
  triIds       = None
  accelParams  = None
  hitRayParam  = None
  hitTriangle  = None
  hitBary1     = None
  hitBary2     = None

  maxParamPtr      = 99999999
  worldSpace = om.MSpace.kWorld

  hit = meshFn.closestIntersection(raySource,

  if hit:

    # make sure it's on the test edge, and not past the end vertex
    if length(startVtx - hitPoint) > vectDistance:
      return 0 # false alarm

      faceNumber = om.MScriptUtil(hitFacePtr).asInt()

      # make sure the intersection's on a face, not a vertex
      # get positions of all face's vertices
      verts = whichMesh.faces[faceNumber].getPoints(space="world")
      hitPointVector = [hitPoint[0], hitPoint[1], hitPoint[2]]

      # check each vertex - are any very close to the hitPoint?
      distances = []      
      for v in verts:
        # check distance between points
        # see if the hit is at a corner
        dist = distanceBetween(hitPointVector, v)
        if (dist < .001):
          return 0 # false alarm
      # still here? check to see if it's on an edge by
      # comparing combined distance to the two nearest vertices
      # to the length of an edge
      smallestTwo = [distances[0], distances[1]]
      i = 2
      while i<len(distances):
        if (distances[i] < smallestTwo[0]):
          smallestTwo[0] = distances[i]
        elif (distances[i] < smallestTwo[1]):
          smallestTwo[1] = distances[i]
        i += 1
      diff = (smallestTwo[0]+smallestTwo[1]) - 1.732051
      if (diff < .001):
        return 0 # false alarm
      # still here? valid hit, report it
      vector = om.MVector()
      NormalFn = om.MFnMesh(dag)
      NormalFn.getPolygonNormal(faceNumber, vector, worldSpace)
      return hitPoint

  else: return 0

def meshIntersection(mesh1, mesh2):
  for x in mesh1.edges:
    if edgeIntersect(x, mesh2):
      return 1
  for x in mesh2.edges:
    if edgeIntersect(x, mesh1):
      return 1
  else: return 0

# find the center of a face - aka the "centroid"
def centerOfFace(face):
  # get locations of all the face's vertices
  pos = face.getPoints(space="world")
  returnVec = [0, 0, 0]
  # add them all together
  for vec in pos:
    returnVec += vec
  # divide by # of vectors for average
  returnVec /= len(pos)
  return returnVec

# distange between two vectors
def distanceBetween(a, b):
  a = dt.Vector(a)
  b = dt.Vector(b)
  return length(a-b)

def getNormal(someFace):
  fc = centerOfFace(someFace)
  # returns normal relative to face at origin
  norm = someFace.getNormal(space='world')
  returnVec = [fc[0]+norm[0], fc[1]+norm[1], fc[2]+norm[2]]
  return returnVec

# get angle between two vectors
def getVectorAngle(aLoc, bLoc, orig):
  aLoc = dt.Vector(aLoc)
  bLoc = dt.Vector(bLoc)
  orig = dt.Vector(orig)
  cLoc = aLoc-bLoc
  cLocFloor = round(cLoc, 4)
  if (cLocFloor[0]==0 and cLocFloor[1]==0 and cLocFloor[2]==0):
    return 0
    # normalize locations to the face center
    aNorm = aLoc-orig
    bNorm = bLoc-orig
    returnAngle = degrees(angle(aNorm, bNorm))
    # round answer down to two decimal places
    returnAngle = round(returnAngle, 2)
    return returnAngle

# get angle between two vertices with respect to a third point
def getVertexAngle(aVert, bVert, orig):
  aVec = dt.Vector(pointPosition(aVert))
  bVec = dt.Vector(pointPosition(bVert))
  return getVectorAngle(aVec, bVec, orig)
# find the centroid of a cone
# 1/4 of the way from the base to the peak
def centerOfCone(cone):
  coneLoc = cone.t.get()
  coneLoc = datatypes.Vector(coneLoc)
  topLoc = pointPosition(cone.vtx[3]) # 3 = peak
  topLoc = datatypes.Vector(topLoc)
  center = ((topLoc-coneLoc)/4)+coneLoc
  return center

# find nearby cones
def checkProximity(conePos):
  ids = []
  global coneList
  global coneLocs
  for i in range(len(coneList)):
    iDist = distanceBetween(coneLocs[i], conePos)
    # detection radius: 2r = 2
    if (iDist < 0.70710678118654752440084436210485):
      # definite intersection
      return "fail"
    elif (iDist < 2.1213203435596425732025330863145):
      # possible intersection, add index to list of suspects
  return ids

def alignPyramids(pyrA, pyrB, fc):
  # pick a vertex on each pyramid
  newVertex = pyrA+".vtx[0]" # 0 is on the base
  oldVertex = pyrB+".vtx[3]" # 3 is the tip
  # get angle between two vertices
  angle = getVertexAngle(newVertex, oldVertex, fc)
  # if not already aligned
  if (angle > 0):
    # rotate new to align the corners
    xform(pyrA, r=1, os=1, ro=[0, angle, 0])
    # check the result
    angle2 = getVertexAngle(newVertex, oldVertex, fc)
    # if still not aligned, go the other way twice
    if (angle2 > 0):
      angle3 = angle * -2
      xform(pyrA, r=1, os=1, ro=[0, angle3, 0])

def copyCone(old):
  # make a list of faces on old that aren't the base
  faces = [1, 2, 3]
  new = ''
  while (len(faces) > 0):
    # pick a random face
    r = random.choice(faces)
    # strike face off the list
    selectedFace = old.f[r]
    fc = centerOfFace(selectedFace)
    # copy cone and move to selected face
    dupe = duplicate(old)
    new = dupe[0]
    xform(new, a=1, t=[fc[0], fc[1], fc[2]])
    # aim new at face with a temporary normal constraint
    tmpConst = normalConstraint(selectedFace, new, aim=(0, 1, 0))
    alignPyramids(new, old, fc)

    # collision detection - is area in new occupied?
    # reference coneList
    global coneList
    # check for other cones in search radius
    conePos = centerOfCone(new)
    if (len(coneList) > 1):
      suspects = checkProximity(conePos)
      if (suspects == "fail"):
        delete(new) # start over
        new = "fail"
        # remove parent cone from suspects
        for i in suspects:
          if (meshIntersection(new, i) != 0):
            # intersection found, try another face
            new = "fail"
        # no intersections? copy is good, clear facelist
        if (new == 'fail'):
        else: faces = []
    else: faces = []
  # facelist empty?
  return new

def promptNumber():
  result = cmds.promptDialog(
      title='Grow Shrub',
      message='Number of Cones:',
      button=['OK', 'Cancel'],

  if result == 'OK':
    return int(cmds.promptDialog(query=True, text=True))
  else: return 0;
def doit(totalCones):
  # make a tetrahedron
  new = polyCone(r=1, h=1.414214, sx=3)[0]
  # move its pivot point to the bottom face
  xform(piv=(0, -0.707107, 0))
  # move to origin and freeze xforms
  xform(t=(0, 0.707107, 0))
  makeIdentity(apply=True, t=1)

  # initialize cone list
  global coneList
  global coneLocs
  coneList = [new]
  coneLocs = [centerOfCone(new)]
  growList = [new]

  # progress bar, enabling "Esc"
  gMainProgressBar = mel.eval('$tmp = $gMainProgressBar');
  cmds.progressBar( gMainProgressBar,
  # main creation loop
  for i in range(totalCones-1):
    if cmds.progressBar(gMainProgressBar, query=True, isCancelled=True ) :
    while True:
      # pick a random cone in growList
      growCone = random.choice(growList)
      # attempt to grow a new cone
      new = copyCone(growCone)
      # if no growth spaces open on that cone
      if (new == "fail"):
        # remove it from the coneList
        # success! add new cone to list
        cmds.progressBar(gMainProgressBar, edit=True, step=1)
  cmds.progressBar(gMainProgressBar, edit=True, beginProgress=True)

  # delete all bottom faces to lighten the load
  for i in range(len(coneList)-1):
    cmds.progressBar(gMainProgressBar, edit=True, step=1)
    i += 1
    c = coneList[i]
    # animate cone growth
    setKeyframe(c, attribute = "visibility", v = 0, t = 0)
    setKeyframe(c, attribute = "visibility", v = 1, t = i/2)
    setKeyframe(c, attribute = "scaleY", v = 0, t = i/2)
    setKeyframe(c, attribute = "scaleY", v = 1, t = i/2+10)
    keyTangent(c, t = (i/2+10,i/2+10), itt = "flat")
  del coneList
  del growList
  cmds.progressBar(gMainProgressBar, edit=True, endProgress=True)

number = promptNumber()
if (number > 0): doit(number)
totalTime = timerX(startTime=startTime)
print("Total Time: %s"%totalTime)

### end
« previously: Fenrir | Home | next: Arduino to Maya Mocap II »

2 Responses to “Fastidious Python Shrub”

  1. Kiaran Says:

    That is some wild procedural animation.

  2. Michael Says:

    Almost 6 years later, this helped me figure out exactly how to use MFnMesh.closestIntersection(). Thank you!

Leave a Reply