def _create_connector_controls(self):

        self._global_control = control.RigControl(name=self._get_name('global', node_type='control'))
        global_circle1 = maya.cmds.circle(normal=(0, 1, 0), radius=0.3)[0]
        dcc.move_node(global_circle1, 0, 0, -self._length)
        global_circle2 = maya.cmds.circle(normal=(0, 1, 0), radius=0.3)[0]
        dcc.move_node(global_circle2, 0, 0, self._length)
        dcc.freeze_transforms(global_circle1)
        dcc.freeze_transforms(global_circle2)
        self._global_control.set_shape([global_circle1, global_circle2])
        self._global_control.set_color_rgb(255, 255, 0)
        dcc.delete_node([global_circle1, global_circle2])
        for shape in dcc.list_shapes(self._global_control.get()):
            dcc.rename_node(shape, '{}Shape'.format(self._global_control.get()))
        self._global_control.create_root_group()
        dcc.set_parent(self._global_control.get_top(), self._top_group)
        dcc.set_parent(self._global_move_group, self._global_control.get())

        top_end_distance = self._num_joints
        self._start_control = control.RigControl(name=self._get_name('startConnector', node_type='control'))
        self._start_control.set_curve_type(
            'square', color=(255, 255, 0), axis_order='YXZ', control_size=self._control_size)
        dcc.move_node(self._start_control.get_top(), -top_end_distance, 0, 0)

        self._end_control = control.RigControl(name=self._get_name('endConnector', node_type='control'))
        self._end_control.set_curve_type(
            'square', color=(255, 255, 0), axis_order='YXZ', control_size=self._control_size)
        dcc.move_node(self._end_control.get_top(), top_end_distance, 0, 0)

        sphere_control = maya.cmds.polySphere(subdivisionsX=12, subdivisionsY=12, radius=0.3)
        sphere_shape = dcc.list_shapes(sphere_control)[0]
        sphere_material = self._get_name('flexiBendControlMat', node_type='material')
        if not dcc.node_exists(sphere_material):
            self._mid_control_material = dcc.create_surface_shader(shader_name=sphere_material)
            dcc.set_attribute_value(self._mid_control_material, 'outColor', (1, 1, 0))
        else:
            self._mid_control_material = sphere_material
        dcc.apply_shader(self._mid_control_material, sphere_shape)
        dcc.set_node_renderable(sphere_shape, False)
        self._mid_control = control.RigControl(name=self._get_name('midBend', node_type='control'))
        self._mid_control.set_shape(sphere_control)
        maya.cmds.delete(sphere_control)
        mid_control_shape = dcc.list_shapes(self._mid_control.get())[0]
        dcc.rename_node(mid_control_shape, '{}Shape'.format(self._mid_control.get()))

        for connector_control in [self._start_control, self._mid_control, self._end_control]:
            connector_control.create_root_group()
            connector_control.create_auto_group()
            dcc.set_parent(connector_control.get_top(), self._controls_group)

        # Mid control will be positioned in the mid position between start and end controls
        dcc.create_point_constraint(
            self._mid_control.get_buffer_group('auto'), (self._start_control.get(), self._end_control.get()),
            maintain_offset=False)
    def _create_wire_setup(self):
        # NOTE: We use wire deform to deform the blendShape plane because allow us to maintain the uniform spacing
        # NOTE: between surface patches while deforming the wired curve

        points_list = [(-self._num_joints, 0, -self._num_joints),
                       (0, 0, -self._num_joints),
                       (self._num_joints, 0, -self._num_joints)]
        self._wire_curve = curve.create_from_point_list(
            points_list, degree=2, name=self._get_name('flexiPlaneWire', node_type='curve'))
        dcc.hide_node(self._wire_curve)
        dcc.center_pivot(self._wire_curve)
        dcc.set_parent(self._wire_curve, self._extras_group)

        # NOTE: We create clusters in relative mode so the transforms in their above groups does not affect them
        start_cluster, start_handle = cluster.create_cluster(
            ['{}.cv[{}]'.format(self._wire_curve, i) for i in range(2)],
            name=self._get_name('wireStart', node_type='cluster'), relative=True, exclusive=False)
        dcc.set_attribute_value(start_handle, 'originX', -(self._num_joints + 1))
        dcc.move_pivot_in_object_space(start_handle, -self._num_joints / 2, 0, 0)

        end_cluster, end_handle = cluster.create_cluster(
            ['{}.cv[{}]'.format(self._wire_curve, i) for i in range(1, 3)],
            name=self._get_name('wireEnd', node_type='cluster'), relative=True, exclusive=False)
        dcc.set_attribute_value(end_handle, 'originX', self._num_joints + 1)
        dcc.move_pivot_in_object_space(end_handle, self._num_joints / 2, 0, 0)

        mid_cluster, mid_handle = cluster.create_cluster(
            '{}.cv[1]'.format(self._wire_curve), name=self._get_name('wireMid', node_type='cluster'),
            relative=True, exclusive=False)
        for cls, handle in zip([start_cluster, mid_cluster, end_cluster], [start_handle, mid_handle, end_handle]):
            self._clusters.append({'node': cls, 'handle': handle})
            dcc.set_parent(handle, self._clusters_group)

        # Make sure that mid CV is only deformer 0.5 by start/end clusters
        # This will give us a linear deformation
        maya.cmds.percent(start_cluster, '{}.cv[1]'.format(self._wire_curve), value=0.5)
        maya.cmds.percent(end_cluster, '{}.cv[1]'.format(self._wire_curve), value=0.5)

        wire_curve_shape = dcc.list_shapes(self._wire_curve)[0]
        wire_tweak = maya.cmds.listConnections(wire_curve_shape, type='tweak')[0]
        dcc.rename_node(wire_tweak, self._get_name('wireCurveClusters', node_type='tweak'))

        # TODO: Dropoff distance should be multiplied by global scale
        blendshape_curve_shape = dcc.list_shapes(self._nurbs_blendshape_plane)[0]
        self._wire_node = maya.cmds.wire(
            self._nurbs_blendshape_plane, wire=self._wire_curve,
            name=self._get_name('wireDeformer', node_type='wire'), dropoffDistance=[0, 20])
        wire_plane_tweak = maya.cmds.listConnections(blendshape_curve_shape, type='tweak')[0]
        dcc.rename_node(wire_plane_tweak, self._get_name('flexiPlaneBshpWire', node_type='tweak'))
    def _create_nurbs_plane(self):
        """
        Internal function that creates the NURBS plane that will drive the rig system
        """

        self._nurbs_plane = dcc.create_nurbs_plane(
            name=self._get_name('flexiPlane', node_type='surface'),
            axis=(0, 1, 0), width=self._num_joints * 2, length=self._length, patches_u=self._num_joints,
            construction_history=False)
        dcc.freeze_transforms(self._nurbs_plane, translate=True, rotate=True, scale=True)
        dcc.hide_keyable_attributes(self._nurbs_plane, skip_visibility=True)

        material_name = self._get_name('flexiMat', node_type='material')
        if not dcc.node_exists(material_name):
            self._nurbs_plane_material = dcc.create_lambert_material(
                name=material_name, no_surface_shader=True, color=(0.0, 0.85, 1.0), transparency=(0.8, 0.8, 0.8))
        else:
            self._nurbs_plane_material = material_name
        dcc.apply_shader(self._nurbs_plane_material, self._nurbs_plane)

        if self._display_nurbs_plane_as_template:
            dcc.set_node_template_display(self._nurbs_plane, True)

        nurbs_plane_shape = dcc.list_shapes(self._nurbs_plane)[0]
        dcc.set_node_renderable(nurbs_plane_shape, False)
        dcc.set_attribute_value(nurbs_plane_shape, 'doubleSided', True)

        dcc.set_parent(self._nurbs_plane, self._global_move_group)
    def _create_squash_stretch_setup(self):

        dcc.add_title_attribute(self._global_control.get(), 'volume')
        dcc.add_bool_attribute(self._global_control.get(), 'enable')

        curve_shape = dcc.list_shapes(self._wire_curve)[0]
        curve_info = dcc.create_node('curveInfo', self._get_name('curveLength', node_type='curveInfo'))
        dcc.connect_attribute(curve_shape, 'worldSpace[0]', curve_info, 'inputCurve')
        current_length = dcc.get_attribute_value(curve_info, 'arcLength')
        squash_stretch_divide = dcc.create_node(
            'multiplyDivide', node_name=self._get_name('squashStretchDivide', node_type='multiplyDivide'))
        dcc.set_attribute_value(squash_stretch_divide, 'operation', 2)    # divide
        dcc.set_attribute_value(squash_stretch_divide, 'input1X', current_length)
        dcc.connect_attribute(curve_info, 'arcLength', squash_stretch_divide, 'input2X')
        squash_stretch_volume_multiplier = dcc.create_node(
            'multiplyDivide', node_name=self._get_name('squashStretchVolume', node_type='multiplyDivide'))
        dcc.set_attribute_value(squash_stretch_volume_multiplier, 'input1X', 1.0)
        dcc.connect_attribute(squash_stretch_divide, 'outputX', squash_stretch_volume_multiplier, 'input2X')

        squash_stretch_enabled = dcc.create_node(
            'condition', node_name=self._get_name('squashStretchEnable', node_type='condition'))
        dcc.connect_attribute(self._global_control.get(), 'enable', squash_stretch_enabled, 'firstTerm')
        dcc.set_attribute_value(squash_stretch_enabled, 'secondTerm', 1.0)
        dcc.connect_attribute(squash_stretch_volume_multiplier, 'outputX', squash_stretch_enabled, 'colorIfTrueR')

        for joint in self._joints:
            dcc.connect_attribute(squash_stretch_enabled, 'outColorR', joint, 'scaleY')
            dcc.connect_attribute(squash_stretch_enabled, 'outColorR', joint, 'scaleZ')
def set_shape(crv,
              crv_shape_list,
              size=None,
              select_new_shape=False,
              keep_color=False):
    """
    Creates a new shape on the given curve
    :param crv:
    :param crv_shape_list:
    :param size:
    :param select_new_shape: bool
    :param keep_color: bool
    """

    crv_shapes = controlutils.validate_curve(crv)

    orig_size = None
    orig_color = None
    if crv_shapes:
        orig_size = dcc.node_bounding_box_size(crv)

        # If there are multiple shapes, we only take into account the color of the first shape
        orig_color = dcc.node_color(crv_shapes[0])

    if crv_shapes:
        dcc.delete_node(crv_shapes)

    for i, c in enumerate(crv_shape_list):
        new_shape = dcc.list_shapes(c)[0]
        new_shape = dcc.rename_node(
            new_shape,
            dcc.node_short_name(crv) + 'Shape' + str(i + 1).zfill(2))
        dcc.enable_overrides(new_shape)
        if orig_color is not None and keep_color:
            dcc.set_node_color(new_shape, orig_color)
        dcc.combine_shapes(crv, new_shape, delete_after_combine=True)

    new_size = dcc.node_bounding_box_size(crv)

    if orig_size and new_size:
        scale_size = orig_size / new_size
        dcc.scale_shapes(crv, scale_size, relative=False)

    if size:
        dcc.scale_shapes(crv, size, relative=True)

    if select_new_shape:
        dcc.select_node(crv)

    return crv
    def _create_blendshape_setup(self):
        if not self._nurbs_plane:
            return

        self._nurbs_blendshape_plane = dcc.duplicate_node(
            self._nurbs_plane, new_node_name=self._get_name('flexiPlaneBshp', node_type='surface'))[0]
        dcc.move_node(self._nurbs_blendshape_plane, 0, 0, -self._num_joints)

        self._nurbs_blendshape_node = blendshape.create(
            self._nurbs_plane, self._nurbs_blendshape_plane, name=self._get_name('flexiPlane', node_type='blendShape'))
        dcc.set_attribute_value(self._nurbs_blendshape_node, self._nurbs_blendshape_plane, 1.0)

        # Rename blendshape tweak node
        nurbs_plane_shape = dcc.list_shapes(self._nurbs_plane)[0]
        bs_tweak = maya.cmds.listConnections(nurbs_plane_shape, type='tweak')[0]
        dcc.rename_node(bs_tweak, self._get_name('flexiPlaneBshp', node_type='tweak'))