Пример #1
0
def aim_atMidPoint(obj = None, targets = None, aimAxis = "z+", upAxis = "y+",mode='local',vectorUp = None):
    """
    Aim functionality.
    
    :parameters:
        obj(str): Object to modify
        target(str): object to copy from
        aimAxis(str): axis that is pointing forward
        upAxis(str): axis that is pointing up
        vectorUp(vector): Only relevent during vector mode
        mode(str): 
            'local'-- use standard maya aiming with local axis
            'world' -- use standard maya aiming with world axis
            'matrix' -- use Bokser's fancy method
            'vector' -- maya standard with vector up axis
    :returns
        success(bool)
    """  
    _str_func = 'aimAtMidpoint'
    
    _obj = VALID.objString(obj, noneValid=False, calledFrom = __name__ + _str_func + ">> validate obj")
    _targets = VALID.objStringList(targets, noneValid=False, calledFrom = __name__ + _str_func + ">> validate targets")

    targetPos = MATH.Vector3.zero()

    for t in _targets:
        targetPos += MATH.Vector3.Create(POS.get(t))

    targetPos /= len(_targets)

    aim_atPoint(_obj, MATH.Vector3.AsArray(targetPos), aimAxis, upAxis,mode = mode,vectorUp=vectorUp)
Пример #2
0
def createMeshSliceCurve(mesh, mi_obj,latheAxis = 'z',aimAxis = 'y+',
                         points = 12, curveDegree = 3, minRotate = None, maxRotate = None, rotateRange = None,
                         posOffset = None, vectorOffset = None, markHits = False,rotateBank = None, closedCurve = True, maxDistance = 1000,
                         initialRotate = 0, offsetMode = 'vector', midMeshCast = False,
                         l_specifiedRotates = None, closestInRange = True,
                         returnDict = False,axisToCheck = ['x','y'],**kws):
    """
    This function lathes an axis of an object, shoot rays out the aim axis at the provided mesh and returning hits. 
    it then uses this information to build a curve shape.

    :parameters:
        mesh(string) | Surface to cast at
    mi_obj(string/mObj) | our casting object
    latheAxis(str) | axis of the objec to lathe TODO: add validation
    aimAxis(str) | axis to shoot out of
    points(int) | how many points you want in the curve
    curveDegree(int) | specified degree
    minRotate(float) | let's you specify a valid range to shoot
    maxRotate(float) | let's you specify a valid range to shoot
    posOffset(vector) | transformational offset for the hit from a normalized locator at the hit. Oriented to the surface
    markHits(bool) | whether to keep the hit markers
    returnDict(bool) | whether you want all the infomation from the process.
    rotateBank (float) | let's you add a bank to the rotation object
    l_specifiedRotates(list of values) | specify where to shoot relative to an object. Ignores some other settings
    maxDistance(float) | max distance to cast rays
    closestInRange(bool) | True by default. If True, takes first hit. Else take the furthest away hit in range.

    :returns:
        Dict ------------------------------------------------------------------
    'source'(double3) |  point from which we cast
    'hit'(double3) | world space points | active during single return
    'hits'(list) | world space points | active during multi return
    'uv'(double2) | uv on surface of hit | only works for mesh surfaces

    :raises:
    Exception | if reached

    """       
    _str_func = 'createMeshSliceCurve'

    try:
        mi_obj = cgmMeta.validateObjArg(mi_obj,mType = 'cgmObject', noneValid = True)
        if not mi_obj:
            return False

        log.debug("mi_obj: {0}".format(mi_obj.mNode))

        mesh = VALID.objStringList(mesh,['mesh','nurbsSurface'], calledFrom = _str_func)
        #if len(mc.ls(mesh))>1:
            #log.error("{0}>>> More than one mesh named. Using first: {1}".format(_str_func,mesh))
        #mesh = mesh[0]
        log.debug("mesh: {0}".format(mesh))
        log.debug("points: {0}".format(points))

    except Exception,error:
        raise ValueError,"Validation fail | {0}".format(error) 
Пример #3
0
def createMeshSliceCurve(mesh, mi_obj,latheAxis = 'z',aimAxis = 'y+',
                         points = 12, curveDegree = 3, minRotate = None, maxRotate = None, rotateRange = None,
                         posOffset = 0, markHits = False,rotateBank = None, closedCurve = True, maxDistance = 1000,
                         initialRotate = 0, offsetMode = 'vector', midMeshCast = False,
                         l_specifiedRotates = None, closestInRange = True,
                         returnDict = False,axisToCheck = ['x','y'],**kws):
    """
    This function lathes an axis of an object, shoot rays out the aim axis at the provided mesh and returning hits. 
    it then uses this information to build a curve shape.
    
    :parameters:
        mesh(string) | Surface to cast at
	mi_obj(string/mObj) | our casting object
	latheAxis(str) | axis of the objec to lathe TODO: add validation
	aimAxis(str) | axis to shoot out of
	points(int) | how many points you want in the curve
	curveDegree(int) | specified degree
	minRotate(float) | let's you specify a valid range to shoot
	maxRotate(float) | let's you specify a valid range to shoot
	posOffset(vector) | transformational offset for the hit from a normalized locator at the hit. Oriented to the surface
	markHits(bool) | whether to keep the hit markers
	returnDict(bool) | whether you want all the infomation from the process.
	rotateBank (float) | let's you add a bank to the rotation object
	l_specifiedRotates(list of values) | specify where to shoot relative to an object. Ignores some other settings
	maxDistance(float) | max distance to cast rays
	closestInRange(bool) | True by default. If True, takes first hit. Else take the furthest away hit in range.

    :returns:
        Dict ------------------------------------------------------------------
	'source'(double3) |  point from which we cast
	'hit'(double3) | world space points | active during single return
	'hits'(list) | world space points | active during multi return
	'uv'(double2) | uv on surface of hit | only works for mesh surfaces
	
    :raises:
	Exception | if reached
	
    """       
    _str_funcName = 'createMeshSliceCurve'
    
    try:
	mi_obj = cgmMeta.validateObjArg(mi_obj,mType = cgmMeta.cgmObject, noneValid = True)
	if not mi_obj:
	    return False
	
	log.debug("mi_obj: {0}".format(mi_obj.mNode))
	
	mesh = cgmValid.objStringList(mesh,['mesh','nurbsSurface'], calledFrom = _str_funcName)
	#if len(mc.ls(mesh))>1:
	    #log.error("{0}>>> More than one mesh named. Using first: {1}".format(_str_funcName,mesh))
	#mesh = mesh[0]
	log.debug("mesh: {0}".format(mesh))
	log.debug("points: {0}".format(points))
	
    except Exception,error:
	raise ValueError,"Validation fail | {0}".format(error) 
Пример #4
0
def get_by_dist(source=None,
                targets=None,
                mode='close',
                resMode='point',
                sourcePivot='rp',
                targetPivot='rp'):
    """
    Get the the closest return based on a source and target and variable modes
    
    :parameters:
        :source(str): Our base object to measure from
        :targets(list): List of object types
        :mode(str):What mode are we checking data from
            close
            far
        :resMode(str):
            object -- return the [closest] target
            point -- return the [closest] point
            #component -- return [the closest] base component
            pointOnSurface -- [closest] point on the target shape(s)
            pointOnSurfaceLoc -- [closest] point on target shape(s) Loc'd
            shape -- gets closest point on every shape, returns closest
        resMode(str)
    :returns
        [res,distance]
    """
    def get_fromTargets(sourcePos, targets, targetPivot, resMode, mode):
        _l_distances = []
        _l_pos = []
        for t in targets:
            _tarPos = POS.get(t, targetPivot, space='world')
            _l_pos.append(_tarPos)
            _d = get_distance_between_points(sourcePos, _tarPos)
            log.debug(
                "|{0}| >> target: {1} | pivot: {4} | dist: {3} | pos: {2}...| mode: {5}"
                .format(_str_func, t, _tarPos, _d, targetPivot, mode))
            _l_distances.append(_d)
        if mode == 'close':
            _minDist = min(_l_distances)
            _minIdx = _l_distances.index(_minDist)
            if resMode == 'point': return _l_pos[_minIdx], _minDist
            return targets[_minIdx], _minDist
        else:
            _maxDist = max(_l_distances)
            _maxIdx = _l_distances.index(_maxDist)
            if resMode == 'point': return _l_pos[_maxIdx], _maxDist
            return targets[_maxIdx], _maxDist

    _d_by_dist_modes = {
        'close': ['closest', 'c', 'near'],
        'far': ['furthest', 'long']
    }

    _str_func = 'get_by_dist'
    _source = VALID.objString(source,
                              noneValid=False,
                              calledFrom=__name__ + _str_func +
                              ">> validate targets")
    _mode = VALID.kw_fromDict(mode,
                              _d_by_dist_modes,
                              noneValid=False,
                              calledFrom=__name__ + _str_func +
                              ">> validate mode")
    _resMode = resMode
    _l_targets = VALID.objStringList(targets,
                                     noneValid=False,
                                     calledFrom=__name__ + _str_func +
                                     ">> validate targets")

    _sourcePivot = VALID.kw_fromDict(sourcePivot,
                                     SHARED._d_pivotArgs,
                                     noneValid=False,
                                     calledFrom=__name__ + _str_func +
                                     ">> validate sourcePivot")
    _targetPivot = VALID.kw_fromDict(targetPivot,
                                     SHARED._d_pivotArgs,
                                     noneValid=False,
                                     calledFrom=__name__ + _str_func +
                                     ">> validate targetPivot")

    log.debug("|{0}| >> source: {1} | mode:{2} | resMode:{3}".format(
        _str_func, _source, _mode, _resMode))

    #Source==============================================================
    _sourcePos = POS.get(_source, _sourcePivot, space='ws')
    log.debug("|{0}| >> Source pos({2}): {1}...".format(
        _str_func, _sourcePos, _sourcePivot))

    #Modes
    if _resMode in ['object', 'point']:
        log.debug("|{0}| >> object resMode...".format(_str_func))
        mc.select(cl=True)

        _res = get_fromTargets(_sourcePos, _l_targets, _targetPivot, _resMode,
                               _mode)
        if resMode == 'object':
            mc.select(_res[0])
            return _res[0]
        return _res[0]
    elif _resMode == 'component':
        raise NotImplementedError, "component mode"
    elif _resMode in ['pointOnSurface', 'shape', 'pointOnSurfaceLoc']:
        log.debug("|{0}| >> Shape processing...".format(_str_func))
        #Targets=============================================================
        log.debug("|{0}| >> Targets processing...".format(_str_func))
        _d_targetTypes = {}
        _l_pos = []
        _l_dist = []
        _l_shapes = []
        """for t in _l_targets:
            _t = t
            _bfr_component = VALID.get_component(t)
            if _bfr_component:
                _t = _bfr_component[1]#...shape
            _type = VALID.get_mayaType(_t)
            if _type not in _d_targetTypes.keys():
                _d_targetTypes[_type] = [_t]
            else:
                _d_targetTypes[_type].append(_t)
            log.debug("|{0}| >> obj: {1} | type: {2}".format(_str_func,t,_type))"""
        #cgmGen.log_info_dict(_d_targetTypes,'Targets to type')

        for t in _l_targets:
            res = get_closest_point(_sourcePos, t)
            if not res:
                log.error("|{0}| >> {1} -- failed".format(_str_func, t))
            else:
                log.debug("|{0}| >> {1}: {2}".format(_str_func, t, res))
                _l_pos.append(res[0])
                _l_dist.append(res[1])
                _l_shapes.append(res[2])

        if not _l_dist:
            log.error("|{0}| >> Failed to find any points".format(_str_func))
            return False
        closest = min(_l_dist)
        _idx = _l_dist.index(closest)

        if _resMode == 'pointOnSurfaceLoc':
            _loc = mc.spaceLocator(n='get_by_dist_loc')[0]
            POS.set(_loc, _l_pos[_idx])
            return _loc
        if _resMode == 'shape':
            mc.select(_l_shapes[_idx])
            return _l_shapes[_idx]
        return _l_pos[_idx]
Пример #5
0
def create(target=None,
           position=None,
           tag=True,
           setMatchTarget=True,
           pivot='rp',
           mode='fromTarget',
           name=None):
    """
    Return the short name of an object

    :parameters
        :target(str): What to create a loc from
        :tag(bool): Whether to tag for updating or special naming
        :pivot: Whether to force it to be created at the rotatePivot, scalePivot or BoundingBox center
        :mode
            fromTarget -- can be component or transform
            midPoint -- mid point of specfied targets
            closestPointOnTarget -- closest point from source to targets
            closestTarget -- closest target from source
            rayCast -- create a rayCast locator. For more options, see LOCINATOR
            attachPoint -- Create a rayCast follicle, and parent your loc to that.
        :setMatchTarget
    :returns
        short name(str)
    """
    _str_func = "create"

    try:
        if mode == 'rayCast':
            #_catch = mc.group(em=True)
            class rayCastLoc(cgmDrag.clickMesh):
                def release_post_insert(self):
                    #ATTR.set_messagse(_catch, 'tmpMsg', self.l_created[-1])
                    _loc = self.l_created[-1]
                    _mLoc = r9Meta.MetaClass(_loc)
                    _buffer = _mLoc.cgmLocDat
                    _target = ATTR.get_message(_loc, 'meshTarget')[0]
                    _loc = mc.rename(
                        _loc, "{0}_u{1}_v{2}_rayCast_loc".format(
                            coreNames.get_base(_target),
                            "{0:.4f}".format(_buffer['uv'][0]),
                            "{0:.4f}".format(_buffer['uv'][1]),
                        ))
                    self.dropTool()

            rayCastLoc(create='locator')
            #_res = ATTR.get_message(_catch,'tmpMsg')[0]
            return True

        _loc = mc.spaceLocator()[0]

        if position:
            mc.move(position[0], position[1], position[2], _loc, ws=True)
            if name:
                return mc.rename(_loc, name)
            return mc.rename("pos_loc")
        if not target:
            if name:
                return mc.rename(_loc, name)
            return mc.rename(_loc, "world_center_loc")

        _targets = VALID.objStringList(target,
                                       noneValid=False,
                                       calledFrom=__name__ + _str_func +
                                       ">> validate target")
        #_targets = VALID.listArg(target)
        if tag or mode:
            _mi_loc = r9Meta.MetaClass(_loc)
            if not _mi_loc.hasAttr('cgmLocDat'):
                _mi_loc.addAttr('cgmLocDat', attrType='string')

        log.debug("|{0}| >> {1} mode...".format(_str_func, mode))

        if mode in ['fromTarget', 'attachPoint']:
            if len(_targets) != 1:
                log.warning("|{0}| >> mode: {1} | targets: {2} | ".format(
                    _str_func, mode, _targets))
                raise ValueError, "May only have one target for mode: {0} | targets: {1}".format(
                    mode, _targets)

            _target = _targets[0]

            if name:
                _loc = mc.rename(_loc, name)
            else:
                _loc = mc.rename(
                    _loc,
                    "{0}_fromTarget_loc".format(coreNames.get_base(_target)))

            if tag:  #store info
                ATTR.store_info(_loc,
                                'cgmName',
                                coreNames.get_base(_target),
                                attrType='string',
                                lock=True)
                ATTR.store_info(_loc, 'cgmLocMode', 'fromTarget', lock=True)
                ATTR.set_message(_loc, 'cgmLocSource', _target, 'cgmLocDat')
                if not VALID.is_component(_target) and setMatchTarget:
                    SNAP.matchTarget_set(_target, _loc)
                #_d = r9Meta.MetaClass(_loc).cgmLocDat

                _res = update(_loc)
            _res = update(_loc, _target, 'fromTarget')

            if mode == 'attachPoint':

                class follicleAttach(cgmDrag.clickMesh):
                    def release_post_insert(self):
                        _str_funcName = 'follicleAttach.release'
                        """if not self.b_dragStoreMode:#If not on drag, do it here. Otherwise do it on update
                            if self._posBuffer:
                                self.l_return.extend(self._posBuffer)
                                if self._posBufferRaw:
                                    self.l_returnRaw.extend(self._posBufferRaw)
                                else:
                                    self.l_returnRaw.extend(self._posBuffer)
                        
                            if self._createModeBuffer:
                                self.l_created.extend(self._createModeBuffer)"""

                        for pos in self.l_returnRaw:
                            log.debug("|{0}|...pos {1}".format(
                                _str_funcName, pos))
                            for i, m in enumerate(self.d_meshPos.keys()):
                                log.debug("|{0}|...mesh: {1}".format(
                                    _str_funcName, m))
                                for i2, h in enumerate(self.d_meshPos[m]):
                                    if h == pos:
                                        log.debug("Found follicle match!")
                                        try:
                                            _set = [
                                                m, self.d_meshUV[m][i2],
                                                "{0}_u{1}_v{2}".format(
                                                    coreNames.get_short(m),
                                                    "{0:.4f}".format(
                                                        self.d_meshUV[m][i2]
                                                        [0]), "{0:.4f}".format(
                                                            self.d_meshUV[m]
                                                            [i2][1]))
                                            ]
                                            self._l_folliclesToMake.append(
                                                _set)
                                            log.debug("|{0}|...uv {1}".format(
                                                _str_funcName, _set))
                                        except Exception, err:
                                            log.error(
                                                "|{0}| >> Failed to query uv for hit {2} on shape {2} | err:{1}"
                                                .format(
                                                    _str_funcName, err, pos,
                                                    m))
                            if self._l_folliclesToMake:
                                for f_dat in self._l_folliclesToMake:
                                    _follicle = NODES.add_follicle(
                                        f_dat[0], f_dat[2])
                                    log.debug(
                                        "|finalize| >> Follicle created: {0}".
                                        format(_follicle))
                                    ATTR.set(_follicle[0], 'parameterU',
                                             f_dat[1][0])
                                    ATTR.set(_follicle[0], 'parameterV',
                                             f_dat[1][1])
                                    mc.parent(_loc, _follicle[0])
                        mc.delete(self.l_created)
                        self.dropTool()

                follicleAttach()

            return _loc
        elif not _targets:
            raise ValueError, "Must have targets for mode: {0} | targets: {1}".format(
                mode, _targets)
Пример #6
0
 def _fnc_processInfluenceMode(self):
     '''
     Sort out the joint data
     
     If joitn list is passed, try to use that, if not,
     Try skin cluster on target, cluster on source
     '''
     _mode = self._influenceMode
     _l_configInfluenceList = self.get_ConfigJointList()#...get our config influence list
     self.l_configInfluenceList = _l_configInfluenceList#...store it
     _len_configList = len(_l_configInfluenceList)
     _targetMesh = self.mData.d_target['mesh']
     #...See if we have a skin cluster...
     _targetSkin = skinning.querySkinCluster(_targetMesh) or False            
     
     if _mode == 'config':
         _l_jointTargets = _l_configInfluenceList
         
     elif _mode == 'list':
         _l_joints = self.d_kws.get('jointList')
         if not _l_joints:
             return self._FailBreak_("jointList kw required. '{0}' influenceMode".format(_mode))                
         if not cgmValid.isListArg(_l_joints):
             return self._FailBreak_("jointList is not a list. '{0}' influenceMode".format(_mode))                
         if len(_l_joints) != len(_l_configInfluenceList):
             return self._FailBreak_("Non matching counts on target influences({0}) and config data({1}) | Cannot use '{2}' influenceMode".format(len(_l_joints),len(_l_configInfluenceList),_mode))                
         _l_jointTargets = _l_joints
        
     elif _mode == 'target':
         if not _targetSkin:
             return self._FailBreak_("Target mesh not skinned, cannot use '{0}' influenceMode".format(_mode))                
         _l_targetInfluences = mc.listConnections(_targetSkin+'.matrix') or []
         
         if len(_l_targetInfluences) != len(_l_configInfluenceList):
             #for i,jnt in enumerate(_l_configInfluenceList):
                 #try:_bfr = _l_targetInfluences[i]
                 #except:
                 #    _bfr = False    
                 #self.log_info("{0} | Config: {1} | target: {2}".format(i,jnt,_bfr))
             
             if self._b_addMissingInfluences:
                 self._b_case_addMissingInfluences = True#...set our case
             else: return self._FailBreak_("Non matching counts on target influences({0}) and config data({1}) | Cannot use '{2}' influenceMode".format(len(_l_targetInfluences),len(_l_configInfluenceList),_mode))                
             
         _l_jointTargets = _l_targetInfluences
         
     elif _mode == 'source':
         if not self.mData.d_source:
             return self._FailBreak_("No source data found, cannot use '{0}' influenceMode".format(_mode))                
         _sourceSkin = skinning.querySkinCluster(self.mData.d_source['mesh']) or False
         _l_sourceInfluences = mc.listConnections(_sourceSkin+'.matrix') or []
         
         if len(_l_sourceInfluences) != len(_l_configInfluenceList):
             return self._FailBreak_("Non matching counts on source influences({0}) and config data({1}) | Cannot use '{2}' influenceMode".format(len(_l_sourceInfluences),len(_l_configInfluenceList),_mode))                
         
         _l_jointTargets = _l_sourceInfluences
         
     
     if self._b_case_addMissingInfluences:#Missing Influence Add...
         self.log_info("addMissingInfluencesAttempt... "+ cgmGeneral._str_subLine)
         if _len_configList < len(_l_jointTargets):
             self.log_warning("More targetJoints({0}) than config joints({1}). Not implemented".format(len(_l_jointTargets),_len_configList))
         else:
             _d = {}
             
             for i,v in enumerate(_l_jointTargets):_d[i] = v#...push stuff to a list
             
             for i,jnt in enumerate(_l_configInfluenceList):
                 try:_bfr = _l_jointTargets[i]
                 except:
                     _l_search = [jnt, self.mData.d_sourceSkin['matrix'][i]]
                     self.log_info("{0} | Config: {1} | missing joint. Attempting to find: {2}".format(i,jnt,_l_search))
                     for o in _l_search:
                         foundJnt = cgmValid.objString(o, mayaType = _validObjTypes, noneValid=True)#...mayaType = 'joint', 
                         if foundJnt:
                             _d[i] = foundJnt
                             self._l_missingInfluences.append(foundJnt)
                             self.log_info("Found {0}".format(foundJnt))
                             break
                         return self._FailBreak_("{0} | Not able to fo find joint ({1})".format(i,jnt))                
             #...push back to our list
             _l_jointTargets = []
             for i in range(_len_configList):_l_jointTargets.append(False)
             for i,v in _d.iteritems():
                 _l_jointTargets[i] = v
                 #self.log_info("{0} | Config: {1} | target: {2}".format(i,jnt,_bfr))     
         #self.log_info("Joints to use....")
         #for i,j in enumerate(_l_jointsToUse):
             #self.log_info("{0} : {1} | config idxed to: {2}".format(i,j,_l_configInfluenceList[i]))
         
     #...see if they exist with no conflicts
     #_l_jointTargets = l_dataJoints#...this will change
     try:_l_jointsToUse = cgmValid.objStringList(_l_jointTargets,mayaType = _validObjTypes)#...mayaType = 'joint'
     except Exception,Error:return self._FailBreak_("influenceMode '{0}' joint check fail | {1}".format(_mode,Error))
     
     self.l_jointsToUse = _l_jointsToUse
Пример #7
0
def createWrapControlShape(
        targetObjects,
        targetGeo=None,
        latheAxis='z',
        aimAxis='y+',
        objectUp='y+',
        points=8,
        curveDegree=1,
        insetMult=None,  #Inset multiplier
        minRotate=None,
        maxRotate=None,
        posOffset=[],
        rootOffset=[],  #offset root before cast
        rootRotate=None,
        joinMode=False,
        extendMode=None,
        closedCurve=True,
        l_specifiedRotates=None,
        maxDistance=1000,
        closestInRange=True,
        vectorOffset=None,
        midMeshCast=False,
        subSize=None,  #For ball on loli for example
        rotateBank=None,
        joinHits=None,  #keys to processed hits to see what to join
        axisToCheck=['x', 'y'],
        **kws):  #'segment,radial,disc'
    """
    This function lathes an axis of an object, shoot rays out the aim axis at the provided mesh and returning hits. 
    it then uses this information to build a curve shape.

    :parameters:
        mesh(string) | Surface to cast at
    mi_obj(string/mObj) | our casting object
    latheAxis(str) | axis of the objec to lathe TODO: add validation
    aimAxis(str) | axis to shoot out of
    points(int) | how many points you want in the curve
    curveDegree(int) | specified degree
    minRotate(float) | let's you specify a valid range to shoot
    maxRotate(float) | let's you specify a valid range to shoot
    posOffset(vector) | transformational offset for the hit from a normalized locator at the hit. Oriented to the surface
    markHits(bool) | whether to keep the hit markers
    returnDict(bool) | whether you want all the infomation from the process.
    rotateBank (float) | let's you add a bank to the rotation object
    l_specifiedRotates(list of values) | specify where to shoot relative to an object. Ignores some other settings
    maxDistance(float) | max distance to cast rays
    closestInRange(bool) | True by default. If True, takes first hit. Else take the furthest away hit in range.

    :returns:
        Dict ------------------------------------------------------------------
    'source'(double3) |  point from which we cast
    'hit'(double3) | world space points | active during single return
    'hits'(list) | world space points | active during multi return
    'uv'(double2) | uv on surface of hit | only works for mesh surfaces

    :raises:
    Exception | if reached

    """
    _str_func = "createWrapControlShape"
    log.debug(">> %s >> " % (_str_func) + "=" * 75)
    _joinModes = []
    _extendMode = []

    if type(targetObjects) not in [list, tuple]:
        targetObjects = [targetObjects]
    targetGeo = VALID.objStringList(targetGeo, calledFrom=_str_func)

    assert type(points) is int, "Points must be int: %s" % points
    assert type(curveDegree) is int, "Points must be int: %s" % points
    assert curveDegree > 0, "Curve degree must be greater than 1: %s" % curveDegree
    if posOffset is not None and len(posOffset) and len(posOffset) != 3:
        raise StandardError, "posOffset must be len(3): %s | len: %s" % (
            posOffset, len(posOffset))
    if rootOffset is not None and len(rootOffset) and len(rootOffset) != 3:
        raise StandardError, "rootOffset must be len(3): %s | len: %s" % (
            rootOffset, len(rootOffset))
    if rootRotate is not None and len(rootRotate) and len(rootRotate) != 3:
        raise StandardError, "rootRotate must be len(3): %s | len: %s" % (
            rootRotate, len(rootRotate))

    if extendMode in ['loliwrap', 'cylinder', 'disc'] and insetMult is None:
        insetMult = 1
    for axis in ['x', 'y', 'z']:
        if axis in latheAxis.lower(): latheAxis = axis

    log.debug("targetObjects: %s" % targetObjects)

    if len(aimAxis) == 2: single_aimAxis = aimAxis[0]
    else: single_aimAxis = aimAxis
    mAxis_aim = VALID.simpleAxis(aimAxis)
    log.debug("Single aim: %s" % single_aimAxis)
    log.debug("createWrapControlShape>> midMeshCast: %s" % midMeshCast)
    log.debug("|{0}| >> extendMode: {1}".format(_str_func, extendMode))
    #>> Info
    l_groupsBuffer = []
    il_curvesToCombine = []
    l_sliceReturns = []
    #Need to do more to get a better size

    #>> Build curves
    #=================================================================
    #> Root curve #
    log.debug("RootRotate: %s" % rootRotate)
    mi_rootLoc = cgmMeta.cgmNode(targetObjects[0]).doLoc()
    if rootOffset:
        log.debug("rootOffset: %s" % rootOffset)
        mc.move(rootOffset[0],
                rootOffset[1],
                rootOffset[2], [mi_rootLoc.mNode],
                r=True,
                rpr=True,
                os=True,
                wd=True)
    if rootRotate is not None and len(rootRotate):
        log.debug("rootRotate: %s" % rootRotate)
        mc.rotate(rootRotate[0],
                  rootRotate[1],
                  rootRotate[2], [mi_rootLoc.mNode],
                  os=True,
                  r=True)

    #>> Root
    mi_rootLoc.doGroup()  #Group to zero
    if extendMode == 'segment':
        log.debug("segment mode. Target len: %s" % len(targetObjects[1:]))
        if len(targetObjects) < 2:
            log.warning(
                "Segment build mode only works with two objects or more")
        else:
            if insetMult is not None:
                rootDistanceToMove = distance.returnDistanceBetweenObjects(
                    targetObjects[0], targetObjects[1])
                log.debug("rootDistanceToMove: %s" % rootDistanceToMove)
                mi_rootLoc.__setattr__('t%s' % latheAxis,
                                       rootDistanceToMove * insetMult)
                #mi_rootLoc.tz = (rootDistanceToMove*insetMult)#Offset it

            #Notes -- may need to play with up object for aim snapping
            #mi_upLoc = cgmMeta.cgmNode(targetObjects[0]).doLoc()
            #mi_upLoc.doGroup()#To zero
            objectUpVector = dictionary.returnStringToVectors(objectUp)
            log.debug("objectUpVector: %s" % objectUpVector)
            #mi_uploc

            for i, obj in enumerate(targetObjects[1:]):
                log.debug("i: %s" % i)
                #> End Curve
                mi_endLoc = cgmMeta.cgmNode(obj).doLoc()
                aimVector = dictionary.returnStringToVectors(latheAxis + '-')
                log.debug("segment aimback: %s" % aimVector)
                #Snap.go(mi_endLoc.mNode,mi_rootLoc.mNode,move=False,aim=True,aimVector=aimVector,upVector=objectUpVector)
                #Snap.go(mi_endLoc.mNode,mi_rootLoc.mNode,move=False,orient=True)
                SNAP.go(mi_endLoc.mNode,
                        mi_rootLoc.mNode,
                        position=False,
                        rotation=True)

                mi_endLoc.doGroup()

                if i == len(targetObjects[1:]) - 1:
                    if insetMult is not None:
                        log.debug("segment insetMult: %s" % insetMult)
                        distanceToMove = distance.returnDistanceBetweenObjects(
                            targetObjects[-1], targetObjects[0])
                        log.debug("distanceToMove: %s" % distanceToMove)
                        #mi_endLoc.tz = -(distanceToMove*insetMult)#Offset it
                        mi_endLoc.__setattr__('t%s' % latheAxis,
                                              -(distanceToMove * insetMult))
                log.debug("segment lathe: %s" % latheAxis)
                log.debug("segment aim: %s" % aimAxis)
                log.debug("segment rotateBank: %s" % rotateBank)
                d_endCastInfo = createMeshSliceCurve(
                    targetGeo,
                    mi_endLoc,
                    midMeshCast=midMeshCast,
                    curveDegree=curveDegree,
                    latheAxis=latheAxis,
                    aimAxis=aimAxis,
                    posOffset=posOffset,
                    points=points,
                    returnDict=True,
                    closedCurve=closedCurve,
                    maxDistance=maxDistance,
                    closestInRange=closestInRange,
                    rotateBank=rotateBank,
                    l_specifiedRotates=l_specifiedRotates,
                    axisToCheck=axisToCheck)
                l_sliceReturns.append(d_endCastInfo)
                mi_end = cgmMeta.cgmObject(d_endCastInfo['curve'])
                il_curvesToCombine.append(mi_end)
                mc.delete(mi_endLoc.parent)  #delete the loc

    elif extendMode == 'radial':
        log.debug("|{0}| >> radial...".format(_str_func))
        d_handleInner = createMeshSliceCurve(
            targetGeo,
            mi_rootLoc,
            midMeshCast=midMeshCast,
            curveDegree=curveDegree,
            latheAxis=latheAxis,
            aimAxis=aimAxis,
            posOffset=0,
            points=points,
            returnDict=True,
            closedCurve=closedCurve,
            maxDistance=maxDistance,
            closestInRange=closestInRange,
            rotateBank=rotateBank,
            l_specifiedRotates=l_specifiedRotates,
            axisToCheck=axisToCheck)
        mi_buffer = cgmMeta.cgmObject(d_handleInner['curve'])  #instance curve
        l_sliceReturns.append(d_handleInner)
        il_curvesToCombine.append(mi_buffer)

    elif extendMode == 'disc':
        log.debug("|{0}| >> disc...".format(_str_func))
        d_size = returnBaseControlSize(mi_rootLoc, targetGeo,
                                       axis=[aimAxis])  #Get size
        #discOffset = d_size[ d_size.keys()[0]]*insetMult
        size = False
        l_absSize = [abs(i) for i in posOffset]
        if l_absSize: size = max(l_absSize)
        if not size:
            d_size = returnBaseControlSize(mi_rootLoc,
                                           targetGeo,
                                           axis=[aimAxis])  #Get size
            log.debug("d_size: %s" % d_size)
            size = d_size[d_size.keys()[0]] * insetMult

        discOffset = size
        log.debug("d_size: %s" % d_size)
        log.debug("discOffset is: %s" % discOffset)

        mi_rootLoc.__setattr__('t%s' % latheAxis, discOffset)
        if posOffset:
            tmp_posOffset = [
                posOffset[0] * .5, posOffset[1] * .5, posOffset[2] * .5
            ]
        d_handleInnerUp = createMeshSliceCurve(
            targetGeo,
            mi_rootLoc,
            curveDegree=curveDegree,
            midMeshCast=midMeshCast,
            latheAxis=latheAxis,
            aimAxis=aimAxis,
            posOffset=tmp_posOffset,
            points=points,
            returnDict=True,
            closedCurve=closedCurve,
            maxDistance=maxDistance,
            closestInRange=closestInRange,
            rotateBank=rotateBank,
            l_specifiedRotates=l_specifiedRotates,
            axisToCheck=axisToCheck)
        mi_buffer = cgmMeta.cgmObject(
            d_handleInnerUp['curve'])  #instance curve
        l_sliceReturns.append(d_handleInnerUp)
        il_curvesToCombine.append(mi_buffer)

        mi_rootLoc.__setattr__('t%s' % latheAxis, -discOffset)
        d_handleInnerDown = createMeshSliceCurve(
            targetGeo,
            mi_rootLoc,
            curveDegree=curveDegree,
            midMeshCast=midMeshCast,
            latheAxis=latheAxis,
            aimAxis=aimAxis,
            posOffset=tmp_posOffset,
            points=points,
            returnDict=True,
            closedCurve=closedCurve,
            maxDistance=maxDistance,
            closestInRange=closestInRange,
            rotateBank=rotateBank,
            l_specifiedRotates=l_specifiedRotates,
            axisToCheck=axisToCheck)
        mi_buffer = cgmMeta.cgmObject(
            d_handleInnerDown['curve'])  #instance curve
        l_sliceReturns.append(d_handleInnerDown)
        il_curvesToCombine.append(mi_buffer)

        mi_rootLoc.tz = 0

    elif extendMode == 'cylinder':
        log.debug("|{0}| >> cylinder...".format(_str_func))
        d_size = returnBaseControlSize(mi_rootLoc, targetGeo,
                                       axis=[aimAxis])  #Get size
        discOffset = d_size[d_size.keys()[0]] * insetMult
        log.debug("d_size: %s" % d_size)
        log.debug("discOffset is: %s" % discOffset)

        mi_rootLoc.__setattr__('t%s' % latheAxis, discOffset)
        d_handleInnerUp = createMeshSliceCurve(
            targetGeo,
            mi_rootLoc,
            curveDegree=curveDegree,
            midMeshCast=midMeshCast,
            latheAxis=latheAxis,
            aimAxis=aimAxis,
            posOffset=posOffset,
            points=points,
            returnDict=True,
            closedCurve=closedCurve,
            maxDistance=maxDistance,
            closestInRange=closestInRange,
            rotateBank=rotateBank,
            l_specifiedRotates=l_specifiedRotates,
            axisToCheck=axisToCheck)
        mi_buffer = cgmMeta.cgmObject(
            d_handleInnerUp['curve'])  #instance curve
        l_sliceReturns.append(d_handleInnerUp)
        il_curvesToCombine.append(mi_buffer)

        mi_rootLoc.__setattr__('t%s' % latheAxis, 0)

    elif extendMode == 'loliwrap':
        log.debug("|{0}| >> lolipop...".format(_str_func))
        #l_absSize = [abs(i) for i in posOffset]
        size = False
        #if l_absSize:
        #log.debug("l_absSize: %s"%l_absSize)
        #size = max(l_absSize)*1.25
        if subSize is not None:
            size = subSize
        if not size:
            d_size = returnBaseControlSize(mi_rootLoc,
                                           targetGeo,
                                           axis=[aimAxis])  #Get size
            log.info("d_size: %s" % d_size)
            l_size = d_size[single_aimAxis]
            size = l_size / 3
        log.info("loli size: %s" % size)
        i_ball = cgmMeta.cgmObject(
            curves.createControlCurve('sphere', size=size))

    elif extendMode == 'endCap':
        log.debug("|{0}| >> endCap...".format(_str_func))
        returnBuffer1 = createMeshSliceCurve(
            targetGeo,
            mi_rootLoc.mNode,
            aimAxis='{0}+'.format(latheAxis),
            latheAxis=objectUp[0],
            curveDegree=curveDegree,
            maxDistance=maxDistance,
            closestInRange=closestInRange,
            closedCurve=False,
            l_specifiedRotates=[-90, -60, -30, 0, 30, 60, 90],
            posOffset=posOffset)
        mi_rootLoc.rotate = [0, 0, 0]
        mi_rootLoc.__setattr__('r%s' % latheAxis, 90)
        returnBuffer2 = createMeshSliceCurve(
            targetGeo,
            mi_rootLoc.mNode,
            aimAxis='{0}+'.format(latheAxis),
            latheAxis=objectUp[0],
            curveDegree=curveDegree,
            maxDistance=maxDistance,
            closedCurve=False,
            closestInRange=closestInRange,
            l_specifiedRotates=[-90, -60, -30, 0, 30, 60, 90],
            posOffset=posOffset)
        l_sliceReturns.extend([returnBuffer1, returnBuffer2])
        il_curvesToCombine.append(cgmMeta.cgmObject(returnBuffer1))
        il_curvesToCombine.append(cgmMeta.cgmObject(returnBuffer2))
        mi_rootLoc.rotate = [0, 0, 0]

    #Now cast our root since we needed to move it with segment mode before casting
    if extendMode == 'cylinder':
        log.debug("|{0}| >> cylinder move...".format(_str_func))
        mi_rootLoc.__setattr__('t%s' % latheAxis, -discOffset)

    log.debug("|{0}| >> Rootcast...".format(_str_func))

    d_rootCastInfo = createMeshSliceCurve(
        targetGeo,
        mi_rootLoc,
        curveDegree=curveDegree,
        minRotate=minRotate,
        maxRotate=maxRotate,
        latheAxis=latheAxis,
        midMeshCast=midMeshCast,
        aimAxis=aimAxis,
        posOffset=posOffset,
        points=points,
        vectorOffset=vectorOffset,
        returnDict=True,
        closedCurve=closedCurve,
        maxDistance=maxDistance,
        closestInRange=closestInRange,
        rotateBank=rotateBank,
        l_specifiedRotates=l_specifiedRotates,
        axisToCheck=axisToCheck)
    #d_rootCastInfo = createMeshSliceCurve(targetGeo,mi_rootLoc,**kws)
    log.debug("|{0}| >> Rootcast done".format(_str_func) + cgmGEN._str_subLine)

    if extendMode == 'disc':
        l_sliceReturns.insert(1, d_rootCastInfo)
    else:
        l_sliceReturns.insert(0, d_rootCastInfo)

    #Special loli stuff
    if extendMode == 'loliwrap':
        SNAP.go(i_ball.mNode, mi_rootLoc.mNode, True,
                True)  #Snap to main object

        #log.debug("hitReturns: %s"%d_rootCastInfo['hitReturns'])
        #cgmGEN.walk_dat(d_rootCastInfo['hitReturns'],'hitReturns')

        mi_crv = cgmMeta.cgmObject(d_rootCastInfo['curve'])
        """
        d_return = RayCast.findMeshIntersectionFromObjectAxis(targetGeo,mi_rootLoc.mNode,mAxis_aim.p_string) or {}
        if not d_return.get('hit'):
            log.info(d_return)
            raise ValueError,"No hit on loli check"
        pos = d_return.get('hit')
        dist = distance.returnDistanceBetweenPoints(i_ball.getPosition(),pos) * 2"""

        if vectorOffset is not None:
            dist = vectorOffset + subSize * 4
        else:
            dist = max(posOffset) + subSize * 4

        if '-' in aimAxis:
            distM = -dist
        else:
            distM = dist
        log.debug("distM: %s" % distM)

        #Move the ball
        pBuffer = i_ball.doGroup()
        i_ball.__setattr__('t%s' % single_aimAxis, distM)
        i_ball.parent = False
        mc.delete(pBuffer)

        uPos = distance.returnClosestUPosition(i_ball.mNode, mi_crv.mNode)

        SNAP.aim(i_ball.mNode, mi_rootLoc.mNode, aimAxis='z-')
        #if posOffset:
        #mc.move(posOffset[0]*3,posOffset[1]*3,posOffset[2]*3, [i_ball.mNode], r = True, rpr = True, os = True, wd = True)
        #Make the curve between the two
        mi_traceCrv = cgmMeta.cgmObject(
            mc.curve(degree=1, ep=[uPos, i_ball.getPosition()]))

        #Combine
        il_curvesToCombine.extend([i_ball, mi_traceCrv])

    mi_root = cgmMeta.cgmObject(d_rootCastInfo['curve'])  #instance curve
    il_curvesToCombine.append(mi_root)

    mc.delete(mi_rootLoc.parent)  #delete the loc

    l_curvesToCombine = [mi_obj.mNode for mi_obj in il_curvesToCombine
                         ]  #Build our combine list before adding connectors
    log.debug("|{0}| >> processed: {1}".format(
        _str_func, d_rootCastInfo['processedHits']))

    if joinMode and extendMode not in ['loliwrap', 'endCap'
                                       ] and len(l_sliceReturns) > 1:
        if joinHits:
            keys = d_rootCastInfo['processedHits'].keys()
            keys.sort()
            #goodDegrees = []
            #for i,key in enumerate(keys):
            #if i in joinHits:
            #goodDegrees.append(key)
            goodDegrees = [key for i, key in enumerate(keys) if i in joinHits]
            log.debug("joinHits: %s" % joinHits)
            log.debug("goodDegrees: %s" % goodDegrees)
        else:
            goodDegrees = [
                key for key in d_rootCastInfo['processedHits'].keys()
            ]
        #> Side Curves
        for degree in goodDegrees:
            l_pos = []
            for d in l_sliceReturns:
                l_pos.append(d['processedHits'].get(degree) or False)
            while False in l_pos:
                l_pos.remove(False)
            log.debug("l_pos: %s" % l_pos)
            if len(l_pos) >= 2:
                try:
                    l_curvesToCombine.append(
                        mc.curve(d=curveDegree, ep=l_pos,
                                 os=True))  #Make the curve
                except:
                    log.debug(
                        "createWrapControlShape>>> skipping curve fail: %s" %
                        (degree))

    #>>Combine the curves
    newCurve = curves.combineCurves(l_curvesToCombine)
    mi_crv = cgmMeta.cgmObject(rigging.groupMeObject(targetObjects[0], False))
    curves.parentShapeInPlace(mi_crv.mNode, newCurve)  #Parent shape
    mc.delete(newCurve)

    #>>Copy tags and name
    mi_crv.doCopyNameTagsFromObject(targetObjects[0],
                                    ignore=['cgmType', 'cgmTypeModifier'])
    mi_crv.addAttr('cgmType',
                   attrType='string',
                   value='controlCurve',
                   lock=True)
    mi_crv.doName()

    #Store for return
    return {'curve': mi_crv.mNode, 'instance': mi_crv}
Пример #8
0
 def _fnc_processInfluenceMode(self):
     '''
     Sort out the joint data
     
     If joitn list is passed, try to use that, if not,
     Try skin cluster on target, cluster on source
     '''
     _mode = self._influenceMode
     _l_configInfluenceList = self.get_ConfigJointList()#...get our config influence list
     self.l_configInfluenceList = _l_configInfluenceList#...store it
     _len_configList = len(_l_configInfluenceList)
     _targetMesh = self.mData.d_target['mesh']
     #...See if we have a skin cluster...
     _targetSkin = skinning.querySkinCluster(_targetMesh) or False            
     
     if _mode == 'config':
         _l_jointTargets = _l_configInfluenceList
         
     elif _mode == 'list':
         _l_joints = self.d_kws.get('jointList')
         if not _l_joints:
             return self._FailBreak_("jointList kw required. '{0}' influenceMode".format(_mode))                
         if not cgmValid.isListArg(_l_joints):
             return self._FailBreak_("jointList is not a list. '{0}' influenceMode".format(_mode))                
         if len(_l_joints) != len(_l_configInfluenceList):
             return self._FailBreak_("Non matching counts on target influences({0}) and config data({1}) | Cannot use '{2}' influenceMode".format(len(_l_joints),len(_l_configInfluenceList),_mode))                
         _l_jointTargets = _l_joints
        
     elif _mode == 'target':
         if not _targetSkin:
             return self._FailBreak_("Target mesh not skinned, cannot use '{0}' influenceMode".format(_mode))                
         _l_targetInfluences = mc.listConnections(_targetSkin+'.matrix') or []
         
         if len(_l_targetInfluences) != len(_l_configInfluenceList):
             #for i,jnt in enumerate(_l_configInfluenceList):
                 #try:_bfr = _l_targetInfluences[i]
                 #except:
                 #    _bfr = False    
                 #self.log_info("{0} | Config: {1} | target: {2}".format(i,jnt,_bfr))
             
             if self._b_addMissingInfluences:
                 self._b_case_addMissingInfluences = True#...set our case
             else: return self._FailBreak_("Non matching counts on target influences({0}) and config data({1}) | Cannot use '{2}' influenceMode".format(len(_l_targetInfluences),len(_l_configInfluenceList),_mode))                
             
         _l_jointTargets = _l_targetInfluences
         
     elif _mode == 'source':
         if not self.mData.d_source:
             return self._FailBreak_("No source data found, cannot use '{0}' influenceMode".format(_mode))                
         _sourceSkin = skinning.querySkinCluster(self.mData.d_source['mesh']) or False
         _l_sourceInfluences = mc.listConnections(_sourceSkin+'.matrix') or []
         
         if len(_l_sourceInfluences) != len(_l_configInfluenceList):
             return self._FailBreak_("Non matching counts on source influences({0}) and config data({1}) | Cannot use '{2}' influenceMode".format(len(_l_sourceInfluences),len(_l_configInfluenceList),_mode))                
         
         _l_jointTargets = _l_sourceInfluences
         
     
     if self._b_case_addMissingInfluences:#Missing Influence Add...
         self.log_info("addMissingInfluencesAttempt... "+ cgmGeneral._str_subLine)
         if _len_configList < len(_l_jointTargets):
             self.log_warning("More targetJoints({0}) than config joints({1}). Not implemented".format(len(_l_jointTargets),_len_configList))
         else:
             _d = {}
             
             for i,v in enumerate(_l_jointTargets):_d[i] = v#...push stuff to a list
             
             for i,jnt in enumerate(_l_configInfluenceList):
                 try:_bfr = _l_jointTargets[i]
                 except:
                     _l_search = [jnt, self.mData.d_sourceSkin['matrix'][i]]
                     self.log_info("{0} | Config: {1} | missing joint. Attempting to find: {2}".format(i,jnt,_l_search))
                     for o in _l_search:
                         foundJnt = cgmValid.objString(o, mayaType = _validObjTypes, noneValid=True)#...mayaType = 'joint', 
                         if foundJnt:
                             _d[i] = foundJnt
                             self._l_missingInfluences.append(foundJnt)
                             self.log_info("Found {0}".format(foundJnt))
                             break
                         return self._FailBreak_("{0} | Not able to fo find joint ({1})".format(i,jnt))                
             #...push back to our list
             _l_jointTargets = []
             for i in range(_len_configList):_l_jointTargets.append(False)
             for i,v in _d.iteritems():
                 _l_jointTargets[i] = v
                 #self.log_info("{0} | Config: {1} | target: {2}".format(i,jnt,_bfr))     
         #self.log_info("Joints to use....")
         #for i,j in enumerate(_l_jointsToUse):
             #self.log_info("{0} : {1} | config idxed to: {2}".format(i,j,_l_configInfluenceList[i]))
         
     #...see if they exist with no conflicts
     #_l_jointTargets = l_dataJoints#...this will change
     try:_l_jointsToUse = cgmValid.objStringList(_l_jointTargets,mayaType = _validObjTypes)#...mayaType = 'joint'
     except Exception,Error:return self._FailBreak_("influenceMode '{0}' joint check fail | {1}".format(_mode,Error))
     
     self.l_jointsToUse = _l_jointsToUse
Пример #9
0
def createWrapControlShape(targetObjects,
                           targetGeo = None,
                           latheAxis = 'z',aimAxis = 'y+',objectUp = 'y+',
                           points = 8,
                           curveDegree = 1,
                           insetMult = None,#Inset multiplier
                           posOffset = [],
                           rootOffset = [],#offset root before cast
                           rootRotate = None,
                           joinMode = False,
                           extendMode = None,
                           closedCurve = True,
                           l_specifiedRotates = None,
                           maxDistance = 1000,
                           closestInRange = True,
                           midMeshCast = False,
                           rotateBank = None,
                           joinHits = None,#keys to processed hits to see what to join
                           axisToCheck = ['x','y'],
                           ):#'segment,radial,disc' 
    """
    This function lathes an axis of an object, shoot rays out the aim axis at the provided mesh and returning hits. 
    it then uses this information to build a curve shape.
    
    :parameters:
        mesh(string) | Surface to cast at
	mi_obj(string/mObj) | our casting object
	latheAxis(str) | axis of the objec to lathe TODO: add validation
	aimAxis(str) | axis to shoot out of
	points(int) | how many points you want in the curve
	curveDegree(int) | specified degree
	minRotate(float) | let's you specify a valid range to shoot
	maxRotate(float) | let's you specify a valid range to shoot
	posOffset(vector) | transformational offset for the hit from a normalized locator at the hit. Oriented to the surface
	markHits(bool) | whether to keep the hit markers
	returnDict(bool) | whether you want all the infomation from the process.
	rotateBank (float) | let's you add a bank to the rotation object
	l_specifiedRotates(list of values) | specify where to shoot relative to an object. Ignores some other settings
	maxDistance(float) | max distance to cast rays
	closestInRange(bool) | True by default. If True, takes first hit. Else take the furthest away hit in range.

    :returns:
        Dict ------------------------------------------------------------------
	'source'(double3) |  point from which we cast
	'hit'(double3) | world space points | active during single return
	'hits'(list) | world space points | active during multi return
	'uv'(double2) | uv on surface of hit | only works for mesh surfaces
	
    :raises:
	Exception | if reached
	
    """     
    _str_funcName = "createWrapControlShape"
    log.debug(">> %s >> "%(_str_funcName) + "="*75)  
    _joinModes = []
    _extendMode = []
    
    if type(targetObjects) not in [list,tuple]:targetObjects = [targetObjects]
    targetGeo = cgmValid.objStringList(targetGeo, calledFrom = _str_funcName)


    assert type(points) is int,"Points must be int: %s"%points
    assert type(curveDegree) is int,"Points must be int: %s"%points
    assert curveDegree > 0,"Curve degree must be greater than 1: %s"%curveDegree
    if posOffset is not None and len(posOffset) and len(posOffset)!=3:raise StandardError, "posOffset must be len(3): %s | len: %s"%(posOffset,len(posOffset))
    if rootOffset is not None and len(rootOffset) and len(rootOffset)!=3:raise StandardError, "rootOffset must be len(3): %s | len: %s"%(rootOffset,len(rootOffset))
    if rootRotate is not None and len(rootRotate) and len(rootRotate)!=3:raise StandardError, "rootRotate must be len(3): %s | len: %s"%(rootRotate,len(rootRotate))
    
    if extendMode in ['loliwrap','cylinder','disc'] and insetMult is None:insetMult = 1
    for axis in ['x','y','z']:
	if axis in latheAxis.lower():latheAxis = axis
    
    log.debug("targetObjects: %s"%targetObjects)
    
    if len(aimAxis) == 2:single_aimAxis = aimAxis[0]
    else:single_aimAxis = aimAxis
    log.debug("Single aim: %s"%single_aimAxis)
    log.debug("createWrapControlShape>> midMeshCast: %s"%midMeshCast)
        
    #>> Info
    l_groupsBuffer = []
    il_curvesToCombine = []
    l_sliceReturns = []
    #Need to do more to get a better size
    
    #>> Build curves
    #=================================================================
    #> Root curve #
    log.debug("RootRotate: %s"%rootRotate)
    mi_rootLoc = cgmMeta.cgmNode(targetObjects[0]).doLoc()
    if rootOffset:
	log.debug("rootOffset: %s"%rootOffset)
	mc.move(rootOffset[0],rootOffset[1],rootOffset[2], [mi_rootLoc.mNode], r=True, rpr = True, os = True, wd = True)
    if rootRotate is not None and len(rootRotate):
	log.debug("rootRotate: %s"%rootRotate)	
	mc.rotate(rootRotate[0],rootRotate[1],rootRotate[2], [mi_rootLoc.mNode], os = True,r=True)   
	    
    #>> Root
    mi_rootLoc.doGroup()#Group to zero    
    if extendMode == 'segment':
	log.debug("segment mode. Target len: %s"%len(targetObjects[1:]))	
	try:
	    if len(targetObjects) < 2:
		log.warning("Segment build mode only works with two objects or more")    
	    else:
		if insetMult is not None:
		    rootDistanceToMove = distance.returnDistanceBetweenObjects(targetObjects[0],targetObjects[1])
		    log.debug("rootDistanceToMove: %s"%rootDistanceToMove)
		    mi_rootLoc.__setattr__('t%s'%latheAxis,rootDistanceToMove*insetMult)
		    #mi_rootLoc.tz = (rootDistanceToMove*insetMult)#Offset it
		
		#Notes -- may need to play with up object for aim snapping
		#mi_upLoc = cgmMeta.cgmNode(targetObjects[0]).doLoc()
		#mi_upLoc.doGroup()#To zero
		objectUpVector = dictionary.returnStringToVectors(objectUp)
		log.debug("objectUpVector: %s"%objectUpVector)		    
		#mi_uploc
		
		for i,obj in enumerate(targetObjects[1:]):
		    log.debug("i: %s"%i)
		    #> End Curve
		    mi_endLoc = cgmMeta.cgmNode(obj).doLoc()
		    aimVector = dictionary.returnStringToVectors(latheAxis+'-')
		    log.debug("segment aimback: %s"%aimVector)		    
		    #Snap.go(mi_endLoc.mNode,mi_rootLoc.mNode,move=False,aim=True,aimVector=aimVector,upVector=objectUpVector)
		    Snap.go(mi_endLoc.mNode,mi_rootLoc.mNode,move=False,orient=True)		    
		    mi_endLoc.doGroup()
		    
		    if i == len(targetObjects[1:])-1:
			if insetMult is not None:
			    log.debug("segment insetMult: %s"%insetMult)			    
			    distanceToMove = distance.returnDistanceBetweenObjects(targetObjects[-1],targetObjects[0])
			    log.debug("distanceToMove: %s"%distanceToMove)
			    #mi_endLoc.tz = -(distanceToMove*insetMult)#Offset it  
			    mi_endLoc.__setattr__('t%s'%latheAxis,-(distanceToMove*insetMult))
		    log.debug("segment lathe: %s"%latheAxis)
		    log.debug("segment aim: %s"%aimAxis)
		    log.debug("segment rotateBank: %s"%rotateBank)		    
		    d_endCastInfo = createMeshSliceCurve(targetGeo,mi_endLoc,midMeshCast=midMeshCast,curveDegree=curveDegree,latheAxis=latheAxis,aimAxis=aimAxis,posOffset = posOffset,points = points,returnDict=True,closedCurve = closedCurve, maxDistance = maxDistance, closestInRange=closestInRange, rotateBank=rotateBank, l_specifiedRotates = l_specifiedRotates,axisToCheck = axisToCheck)  	
		    l_sliceReturns.append(d_endCastInfo)
		    mi_end = cgmMeta.cgmObject(d_endCastInfo['curve'])
		    il_curvesToCombine.append(mi_end)
		    mc.delete(mi_endLoc.parent)#delete the loc
		    
	except StandardError,error:
	    raise StandardError,"createWrapControlShape>> segment wrap fail! | %s"%error