Image
-- WARNING! This script requires AE_Utilities!

-- **************************************************
-- Provide Moho with the name of this script object
-- **************************************************

ScriptName = "AE_Curvature"

-- **************************************************
-- General information about this script
-- **************************************************

AE_Curvature = {}

AE_Curvature.BASE_STR = 2070

function AE_Curvature:Name()
	return "Curvature"
end

function AE_Curvature:Version()
	return "6.30"
end

function AE_Curvature:Description()
	return MOHO.Localize("/Scripts/Tool/Curvature/Description=Drag side to side to adjust the curvature through the selected points (hold <ctrl/cmd> to select points, <alt> to maintain peaked points)")
end

function AE_Curvature:Creator()
	return "Smith Micro Software, Inc., improved by Alexandra Evseeva, modified by Stan"
end

function AE_Curvature:UILabel()
	return(MOHO.Localize("/Scripts/Tool/Curvature/Curvature=Curvature"))
end

-- **************************************************
-- Recurring values
-- **************************************************

AE_Curvature.numSel = 0
AE_Curvature.selID = -1
AE_Curvature.savedVal = 0
AE_Curvature.MIN_CURVATURE = MOHO.PEAKED -- The built-in minimum for a long time was MOHO.PEAKED
AE_Curvature.MAX_CURVATURE = 1.0 -- The built-in maximum for a long time was 2 / 3
AE_Curvature.selectMode = false
AE_Curvature.correctionMode = false
AE_Curvature.flipDirection = false



-- **************************************************
-- The guts of this script
-- **************************************************

function AE_Curvature:IsEnabled(moho)
	if (moho:CountPoints() > 0) then
		return true
	end
	return false
end

function AE_Curvature:IsRelevant(moho)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return false
	end
	return true
end

function AE_Curvature:OnInputDeviceEvent(moho, deviceEvent)
	return AE_TransformPoints:OnInputDeviceEvent(moho, deviceEvent)
end


function AE_Curvature:TestForClosestHandle(moho, mouseEvent)
	self.selID = -1
	self.handleSide = 0
	self.correctionMode = false

	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end

	local g = mouseEvent.view:Graphics()
	local layerMatrix = LM.Matrix:new_local()
	moho.drawingLayer:GetFullTransform(moho.frame, layerMatrix, moho.document)
	g:Push()
	g:ApplyMatrix(layerMatrix)

	local minDistance = 1000000
	local markerR = 6
	local pt = LM.Point:new_local()
	if (MOHO.IsMohoPro()) then
	for i = 0, mesh:CountCurves() - 1 do
		local curve = mesh:Curve(i)
		for j = 0, curve:CountPoints() - 1 do
			if (not curve:Point(j).fHidden) then			
				if (math.abs(curve:GetCurvature(j, moho.drawingLayerFrame)) > MOHO.PEAKED + 0.00001) then
					local testHandle = curve:GetControlHandle(j, moho.drawingLayerFrame, true)
					mouseEvent.view:Graphics():WorldToScreen(testHandle, pt)
	--				if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR and not(j == 0 and not curve.fClosed)) then
					if (not(j == 0 and not curve.fClosed)) then
						local distance = math.sqrt((pt.x - mouseEvent.pt.x) * (pt.x - mouseEvent.pt.x) + (pt.y - mouseEvent.pt.y) * (pt.y - mouseEvent.pt.y))
						if (distance < minDistance) then
							minDistance = distance
							self.selID = mesh:PointID(curve:Point(j))
							self.startHandle = testHandle
							self.handleSide = -1
							self.handleCurveID = i
							self.handlePointID = j
						end
					end
			
					testHandle = curve:GetControlHandle(j, moho.drawingLayerFrame, false)
					mouseEvent.view:Graphics():WorldToScreen(testHandle, pt)
	--				if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR and not(j == curve:CountPoints() - 1 and not curve.fClosed)) then
					if (not(j == curve:CountPoints() - 1 and not curve.fClosed)) then
						local distance = math.sqrt((pt.x - mouseEvent.pt.x) * (pt.x - mouseEvent.pt.x) + (pt.y - mouseEvent.pt.y) * (pt.y - mouseEvent.pt.y))
						if (distance < minDistance) then
							minDistance = distance
							self.selID = mesh:PointID(curve:Point(j))
							self.startHandle = testHandle
							self.handleSide = 1
							self.handleCurveID = i
							self.handlePointID = j
						end
					end
				end
			end
		end
	end
	end

	local ptID = mesh:ClosestPoint(mouseEvent.startVec)
	if (ptID >= 0) then
		local selPt = mesh:Point(ptID)
		mouseEvent.view:Graphics():WorldToScreen(selPt.fPos, pt)
		local distance = math.sqrt((pt.x - mouseEvent.pt.x) * (pt.x - mouseEvent.pt.x) + (pt.y - mouseEvent.pt.y) * (pt.y - mouseEvent.pt.y))
		if (distance < minDistance) then
			minDistance = distance
			self.selID = ptID
			self.handleSide = 0
		end
	end
	
  if not self.handlePointID then return end
  
  local keyValue = AE_Utilities:GetBezierValue(mesh:Curve(self.handleCurveID), self.handlePointID, moho.drawingLayerFrame, (self.handleSide == -1))
  self.delta = self.startHandle - keyValue
  --print(self.delta:Mag())
  --if self.delta:Mag() > 0.001 then self.correctionMode = true end
  self.correctionMode = true
  
  local pointDelta = mesh:Curve(self.handleCurveID):Point(self.handlePointID).fPos - mesh:Curve(self.handleCurveID):Point(self.handlePointID).fAnimPos:GetValue(moho.frame)
  self.pointDelta = pointDelta
  
  local keyLength
  local resultLength
  local pp = self.handlePointID + self.handleSide
  if mesh:Curve(self.handleCurveID).fClosed then
     if pp < 0 then pp = mesh:Curve(self.handleCurveID):CountPoints()-1 end
     if pp >= mesh:Curve(self.handleCurveID):CountPoints() then pp = 0  end
  else
     if pp < 0 then pp = 0 end
     if pp >= mesh:Curve(self.handleCurveID):CountPoints() then pp = mesh:Curve(self.handleCurveID):CountPoints()-1 end    
  end
  
  if(pp == self.handlePointID) then 
    self.lengthMultiply = 1
    keyLength = 0.00001
    resultLength = 0.00001
  else
    keyLength = (mesh:Curve(self.handleCurveID):Point(pp).fAnimPos:GetValue(moho.frame) - mesh:Curve(self.handleCurveID):Point(self.handlePointID).fAnimPos:GetValue(moho.frame)):Mag()
    resultLength = (mesh:Curve(self.handleCurveID):Point(pp).fPos - mesh:Curve(self.handleCurveID):Point(self.handlePointID).fPos):Mag()
    self.lengthMultiply = resultLength/keyLength
  end
  
  self.startWeight = mesh:Curve(self.handleCurveID):GetWeight(self.handlePointID, moho.frame, (self.handleSide == -1))
  self.startOffset = mesh:Curve(self.handleCurveID):GetOffset(self.handlePointID, moho.frame, (self.handleSide == -1)) 
  self.startFPos =  mesh:Curve(self.handleCurveID):Point(self.handlePointID).fPos
  self.startVector = self.startHandle - self.startFPos
  self.startVectorMag = self.startVector:Mag()

  

  local channelNumberBase = 0
  for p=0, mesh:PointID(mesh:Curve(self.handleCurveID):Point(self.handlePointID))-1 do
     local nextPoint = mesh:Point(p)
     channelNumberBase = channelNumberBase + nextPoint:CountCurves()*5
  end    
  local curvatureChannel = moho.drawingLayer:Channel(3,channelNumberBase, moho.document)
  local weightChannel = moho:ChannelAsAnimVal(moho.drawingLayer:Channel(3,channelNumberBase+1+self.handleSide/2+0.5, moho.document)) 
  local curvatureDelta = AE_Utilities:SumActionInfluences(moho, moho.frame, moho:ChannelAsAnimVal(curvatureChannel), moho.drawingLayer)
  --local weightDelta = AE_Utilities:SumActionInfluences(moho, moho.frame, moho:ChannelAsAnimVal(weightChannel), moho.drawingLayer)
  local weightDelta = weightChannel.value - weightChannel:GetValue(moho.layerFrame)


  
  self.weightDelta = weightDelta
  self.weightMultiplier = resultLength * (mesh:Curve(self.handleCurveID):GetCurvature(self.handlePointID, moho.frame) + curvatureDelta)
		
	g:Pop()
  
  --[[
  print("vertex ", self.handlePointID, " handle ", self.handleSide, "\n startHandle: ", self.startHandle.x, ", ", self.startHandle.y)
  print("keyValue ", keyValue.x, ", ", keyValue.y)
  print("startWeight ", self.startWeight)
  print("startVectorMag ", self.startVectorMag)
  print("weightDelta ", self.weightDelta)
  --]]
end

function AE_Curvature:OnMouseDown(moho, mouseEvent)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end

	self.selectMode = false
	if (mouseEvent.ctrlKey) then
		self.selectMode = true
		mouseEvent.ctrlKey = false
		LM_SelectPoints:OnMouseDown(moho, mouseEvent)
		return
	end

	moho.document:PrepUndo(moho.drawingLayer)
	moho.document:SetDirty()

	self.isDragging = true
	self.selID = -1
	self.handleSide = 0
	self.selList = MOHO.SelectedPointList(mesh)
	self.numSel = #self.selList

	if (self.numSel < 2) then -- work with only the closest selection
		-- find the closest point here
		self:TestForClosestHandle(moho, mouseEvent)

		if (self.selID >= 0) then
			self.numSel = 1
			mesh:SelectNone()
			local pt = mesh:Point(self.selID)
			pt.fSelected = true
			moho:UpdateSelectedChannels()
		end
	end

	local curve = nil
	local ptPos = -1
	self.startPeaked = false

	if (mouseEvent.altKey) then
		self.startPeaked = true
	end

	if (self.numSel == 1) then
		local pt = mesh:Point(self.selID)
		for j = 0, pt:CountCurves() - 1 do
			curve, ptPos = pt:Curve(j, ptPos)
			local c = curve:GetCurvature(ptPos, moho.drawingLayerFrame)
			if (math.abs(c) > 0.0015) then
				self.startPeaked = false
			end
			curve:SetCurvature(ptPos, c, moho.drawingLayerFrame)
		end
	else
		for i, pt in ipairs(self.selList) do
			for j = 0, pt:CountCurves() - 1 do
				curve, ptPos = pt:Curve(j, ptPos)
				local c = curve:GetCurvature(ptPos, moho.drawingLayerFrame)
				if (math.abs(c) > 0.0015) then
					self.startPeaked = false
				end
				curve:SetCurvature(ptPos, c, moho.drawingLayerFrame)
			end
		end
	end

	self.savedVal = 0
	moho.drawingLayer:UpdateCurFrame()
	mouseEvent.view:DrawMe()
end

function AE_Curvature:OnMouseMoved(moho, mouseEvent)

	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end

	if (self.selectMode) then
		mouseEvent.ctrlKey = false
		LM_SelectPoints:OnMouseMoved(moho, mouseEvent)
		return
	end

	local newVal = (mouseEvent.pt.x - mouseEvent.startPt.x) / mouseEvent.view:Graphics():Width()
	local curve = nil
	local ptPos = -1

	if (self.numSel == 1) then
		if (self.handleSide ~= 0) then
			local curve = mesh:Curve(self.handleCurveID)
			local syncHandles = true
			if (mouseEvent.altKey) then
				syncHandles = false
			end
			local handlePt = self.startHandle + (mouseEvent.vec - mouseEvent.startVec)
			if (moho.gridOn) then
				moho:SnapToGrid(handlePt)
			end
			if (math.abs(curve:GetCurvature(self.handlePointID, moho.drawingLayerFrame)) < 0.001) then
				curve:SetCurvature(self.handlePointID, 0.001, moho.drawingLayerFrame)
			end
		--original
			if not self.correctionMode then 
			   curve:SetControlHandle(self.handlePointID, handlePt, moho.drawingLayerFrame, self.handleSide == -1, syncHandles)
			else 
				local oldOffset = curve:GetOffset(self.handlePointID, moho.drawingLayerFrame, (self.handleSide == -1))
				local oldOppOffset = curve:GetOffset(self.handlePointID, moho.drawingLayerFrame, (self.handleSide == 1)) 
				--if oldOffset ~= oldOppOffset then syncHandles = false end
				if math.abs(oldOffset - oldOppOffset) > 0.01 then syncHandles = false end

				--print("handlePt: ", handlePt.x, " ", handlePt.y)
				--print("self.startFPos: ", self.startFPos.x, " ", self.startFPos.y)		
				local newVector = handlePt - self.startFPos
				local weightMultiply = newVector:Mag()/self.startVectorMag
				--print("weightMultiply: ", weightMultiply)
				local angleAdd = AE_Utilities:GetAngleBetween(self.startVector, newVector)
			
				-- if AE_Curvature.flipDirectionCB and AE_Curvature.flipDirectionCB:Value() then angleAdd = -angleAdd end
				if self.flipDirection then
					angleAdd = -angleAdd
				end
			
				local newOffset = self.startOffset + angleAdd  
				--print("self.weightMultiplier: ", self.weightMultiplier)
				--print("newVector:Mag(): ", newVector:Mag())
				--print("self.weightDelta: ", self.weightDelta)
				local newWeight = newVector:Mag()/self.weightMultiplier - self.weightDelta
				--local newWeight = (self.startWeight - self.weightDelta)*weightMultiply + self.weightDelta
				curve:SetWeight(self.handlePointID, newWeight, moho.drawingLayerFrame, (self.handleSide == -1))
				curve:SetOffset(self.handlePointID, newOffset, moho.drawingLayerFrame, (self.handleSide == -1))
			 
				if syncHandles then curve:SetOffset(self.handlePointID, newOffset, moho.drawingLayerFrame, (self.handleSide == 1)) end
												
			end
      
		  --[[
		  print("mouse: ", mouseEvent.vec, ", ", mouseEvent.vec.y)
		  print("new handle: ", handlePt.x, ", ", handlePt.y)
		  print("new length: ", newVector:Mag(), " K= ", weightMultiply)
		  --]]
      
		else
			local pt = mesh:Point(self.selID)
			for j = 0, pt:CountCurves() - 1 do
				curve, ptPos = pt:Curve(j, ptPos)
				local c = curve:GetCurvature(ptPos, moho.drawingLayerFrame)
				local negative = false
				if (c < 0.0) then
					negative = true
				end
				local weight = (curve:GetWeight(ptPos, moho.drawingLayerFrame, true) + curve:GetWeight(ptPos, moho.drawingLayerFrame, false)) / 2.0
				c = c + (newVal - self.savedVal) / weight
				if (negative) then
					c = LM.Clamp(c, -self.MAX_CURVATURE, -self.MIN_CURVATURE)
				else
					c = LM.Clamp(c, self.MIN_CURVATURE, self.MAX_CURVATURE)
				end
				curve:SetCurvature(ptPos, c, moho.drawingLayerFrame)
				if (self.startPeaked) then -- preserve the peaked nature of this control point
					curve:AimControlHandleAtNeighbor(ptPos, moho.drawingLayerFrame, true)
					curve:AimControlHandleAtNeighbor(ptPos, moho.drawingLayerFrame, false)
					curve:CorrectControlHandleAngles(ptPos, moho.drawingLayerFrame, true)
				end
			end
		end
	else
		for i, pt in ipairs(self.selList) do
			for j = 0, pt:CountCurves() - 1 do
				curve, ptPos = pt:Curve(j, ptPos)
				local c = curve:GetCurvature(ptPos, moho.drawingLayerFrame)
				local negative = false
				if (c < 0.0) then
					negative = true
				end
				local weight = (curve:GetWeight(ptPos, moho.drawingLayerFrame, true) + curve:GetWeight(ptPos, moho.drawingLayerFrame, false)) / 2.0
				c = c + (newVal - self.savedVal) / weight
				if (negative) then
					c = LM.Clamp(c, -self.MAX_CURVATURE, -self.MIN_CURVATURE)
				else
					c = LM.Clamp(c, self.MIN_CURVATURE, self.MAX_CURVATURE)
				end
				curve:SetCurvature(ptPos, c, moho.drawingLayerFrame)
				if (self.startPeaked) then -- preserve the peaked nature of this control point
					curve:AimControlHandleAtNeighbor(ptPos, moho.drawingLayerFrame, true)
					curve:AimControlHandleAtNeighbor(ptPos, moho.drawingLayerFrame, false)
					curve:CorrectControlHandleAngles(ptPos, moho.drawingLayerFrame, true)
				end
			end
		end
	end

	self.savedVal = newVal
	moho.drawingLayer:UpdateCurFrame()
	mouseEvent.view:DrawMe()
end

function AE_Curvature:OnMouseUp(moho, mouseEvent)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end

	if (self.selectMode) then
		mouseEvent.ctrlKey = false
		LM_SelectPoints:OnMouseUp(moho, mouseEvent)
		self.selectMode = false
		self.selList = nil
		if (mouseEvent.pt.x == mouseEvent.startPt.x and mouseEvent.pt.y == mouseEvent.startPt.y) then
			mouseEvent.shiftKey = false
			mouseEvent.ctrlKey = false
			mouseEvent.altKey = false
			LM_SelectPoints:SingleClickSelect(moho, mouseEvent, false, true)
		end
		mouseEvent.view:DrawMe()
		return
	end

	if (self.numSel == 1 and self.handleSide ~= 0) then
		local curve = mesh:Curve(self.handleCurveID)
		curve:CorrectControlHandleAngles(self.handlePointID, moho.drawingLayerFrame, true)
	end

	moho.drawingLayer:UpdateCurFrame()
	moho:NewKeyframe(CHANNEL_CURVE)
	self.selList = nil
	self.isDragging = false
end

function AE_Curvature:OnKeyDown(moho, keyEvent)
	LM_SelectPoints:OnKeyDown(moho, keyEvent)
end

function AE_Curvature:DrawMe(moho, view)
	if (moho:IsPlaying()) then
		return
	end

	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end

	if (self.selectMode) then
		LM_SelectPoints:DrawMe(moho, view)
	else
		local g = view:Graphics()
		local layerMatrix = LM.Matrix:new_local()
		moho.drawingLayer:GetFullTransform(moho.frame, layerMatrix, moho.document)
		g:Push()
		g:ApplyMatrix(layerMatrix)
		g:SetSmoothing(true)
		
		local meshLayer = moho:LayerAsVector(moho.drawingLayer)
		local selectedOnly = false
		if (self.isDragging) then
			if (self.numSel > 1) then
				selectedOnly = true
			end
		elseif (moho:CountSelectedPoints() > 1) then
			selectedOnly = true
		end
		if (moho:CountSelectedPoints() < 2) then
			meshLayer:DrawHandles(moho.document, g, selectedOnly)
		end
		
		g:Pop()
	end
end

-- **************************************************
-- Tool options - create and respond to tool's UI
-- **************************************************

AE_Curvature.PEAK = MOHO.MSG_BASE
AE_Curvature.SMOOTH = MOHO.MSG_BASE + 1
AE_Curvature.CHANGE = MOHO.MSG_BASE + 2
AE_Curvature.NEGATIVE = MOHO.MSG_BASE + 3
AE_Curvature.RESET = MOHO.MSG_BASE + 4
AE_Curvature.DUMMY = MOHO.MSG_BASE + 5
AE_Curvature.SELECTITEM = MOHO.MSG_BASE + 50
AE_Curvature.FLIPDIRECTION = MOHO.MSG_BASE + 7
AE_Curvature.SELECTPEAK = MOHO.MSG_BASE + 8

function AE_Curvature:DoLayout(moho, layout)
	self.menu = LM.GUI.Menu(MOHO.Localize("/Scripts/Tool/Curvature/SelectGroup=Select Group"))

	self.popup = LM.GUI.PopupMenu(128, false)
	self.popup:SetMenu(self.menu)
	layout:AddChild(self.popup)

	layout:AddChild(LM.GUI.StaticText(MOHO.Localize("/Scripts/Tool/Curvature/CurvatureField=Curvature:")))
	self.curvatureText = LM.GUI.TextControl(0, "00.0000", self.CHANGE, LM.GUI.FIELD_FLOAT)
	self.curvatureText:SetWheelInc(0.01)
	layout:AddChild(self.curvatureText)

	self.peak = LM.GUI.ImageButton("ScriptResources/peak", MOHO.Localize("/Scripts/Tool/Curvature/Peak=Peak"), false, self.PEAK, true)
	layout:AddChild(self.peak)
	self.peak:SetAlternateMessage(self.SELECTPEAK)

	self.smooth = LM.GUI.ImageButton("ScriptResources/smooth", MOHO.Localize("/Scripts/Tool/Curvature/Smooth=Smooth"), false, self.SMOOTH, true)
	layout:AddChild(self.smooth)

	layout:AddChild(LM.GUI.Button("+/-", self.NEGATIVE))
	
	self.resetBut = LM.GUI.Button(MOHO.Localize("/Scripts/Tool/Curvature/Reset=Reset"), self.RESET)
	layout:AddChild(self.resetBut)
  
	self.flipDirectionCB = LM.GUI.CheckBox("Flip direction", self.FLIPDIRECTION)
	layout:AddChild(self.flipDirectionCB)
end

function AE_Curvature:UpdateWidgets(moho)
	if (moho:CurrentTool() ~= "AE_Curvature") then
		return -- this could get called when doing a double-tap on a multitouch Wacom device with a different active tool
	end

	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end

	MOHO.BuildGroupMenu(self.menu, mesh, self.SELECTITEM, self.DUMMY)

	local curvature = 0
	local count = 0
	local selList = MOHO.SelectedPointList(mesh)
	local curve = nil
	local ptPos = -1

	for i, pt in ipairs(selList) do
		for j = 0, pt:CountCurves() - 1 do
			curve, ptPos = pt:Curve(j, ptPos)
			curvature = curvature + curve:GetCurvature(ptPos, moho.drawingLayerFrame)
			count = count + 1
		end
	end
	if (count < 1) then
		self.curvatureText:SetValue("")
	else
		curvature = curvature / count
		if (math.abs(curvature) < self.MIN_CURVATURE + 0.0001) then
			curvature = 0
		end
		self.curvatureText:SetValue(curvature)
	end
	
	self.flipDirectionCB:SetValue(self.flipDirection)
end

function AE_Curvature:HandleMessage(moho, view, msg)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end

	if (msg == self.PEAK) then
		moho.document:PrepUndo(moho.drawingLayer)
		moho.document:SetDirty()
	
		for i = 0, mesh:CountPoints() - 1 do
			local pt = mesh:Point(i)
			if (pt.fSelected) then
				pt:SetCurvature(MOHO.PEAKED, moho.drawingLayerFrame)
				pt:ResetControlHandles(moho.drawingLayerFrame)
			end
		end
		moho:NewKeyframe(CHANNEL_CURVE)
		moho:UpdateUI()
	elseif (msg == self.SELECTPEAK) then	
		moho.document:PrepUndo(moho.drawingLayer)
		moho.document:SetDirty()
	
		for i = 0, mesh:CountPoints() - 1 do
			local pt = mesh:Point(i)
			local isPeaked = true
			for c = 0, pt:CountCurves() - 1 do
				local curve, where = pt:Curve(c)
				if curve:GetCurvature(where, moho.frame) > 0 and 
				(curve:GetWeight(where, moho.frame, true) > 0.001 or curve:GetWeight(where, moho.frame, false) > 0.001) then 
					isPeaked = false
					break
				end
			end
			pt.fSelected = isPeaked
		end		
	elseif (msg == self.SMOOTH) then
		moho.document:PrepUndo(moho.drawingLayer)
		moho.document:SetDirty()
	
		for i = 0, mesh:CountPoints() - 1 do
			local pt = mesh:Point(i)
			if (pt.fSelected) then
				pt:SetCurvature(MOHO.SMOOTH, moho.drawingLayerFrame)
				pt:ResetControlHandles(moho.drawingLayerFrame)
			end
		end
		moho:NewKeyframe(CHANNEL_CURVE)
		moho:UpdateUI()
	elseif (msg == self.CHANGE) then
		moho.document:PrepUndo(moho.drawingLayer)
		moho.document:SetDirty()
	
		local curvature = self.curvatureText:FloatValue()
		if (curvature > self.MAX_CURVATURE) then
			curvature = self.MAX_CURVATURE
		end
		if (curvature < -self.MAX_CURVATURE) then
			curvature = -self.MAX_CURVATURE
		end
		if (math.abs(curvature) < self.MIN_CURVATURE) then
			if (curvature < 0) then
				curvature = -self.MIN_CURVATURE
			else
				curvature = self.MIN_CURVATURE
			end
		end
		for i = 0, mesh:CountPoints() - 1 do
			local pt = mesh:Point(i)
			if (pt.fSelected) then
				pt:SetCurvature(curvature, moho.drawingLayerFrame)
			end
		end
		moho:NewKeyframe(CHANNEL_CURVE)
		moho:UpdateUI()
	elseif (msg == self.NEGATIVE) then
		moho.document:PrepUndo(moho.drawingLayer)
		moho.document:SetDirty()

		local curvature = 0
		local selList = MOHO.SelectedPointList(mesh)
		local curve = nil
		local ptPos = -1

		for i, pt in ipairs(selList) do
			for j = 0, pt:CountCurves() - 1 do
				curve, ptPos = pt:Curve(j, ptPos)
				curvature = curve:GetCurvature(ptPos, moho.drawingLayerFrame)
				curve:SetCurvature(ptPos, -curvature, moho.drawingLayerFrame)
			end
		end
		moho:NewKeyframe(CHANNEL_CURVE)
		moho:UpdateUI()
	elseif (msg == self.RESET) then
		moho.document:PrepUndo(moho.drawingLayer)
		moho.document:SetDirty()

		local curvature = 0
		local selList = MOHO.SelectedPointList(mesh)
		local curve = nil
		local ptPos = -1

		for i, pt in ipairs(selList) do
			for j = 0, pt:CountCurves() - 1 do
				curve, ptPos = pt:Curve(j, ptPos)
				if (moho.drawingLayerFrame == 0) then
					curve:SetCurvature(ptPos, MOHO.SMOOTH, moho.drawingLayerFrame)
					curve:ResetControlHandles(ptPos, moho.drawingLayerFrame)
				else
					curve:SetCurvature(ptPos, curve:GetCurvature(ptPos, 0), moho.drawingLayerFrame)
					
					curve:SetWeight(ptPos, curve:GetWeight(ptPos, 0, true), moho.drawingLayerFrame, true)
					curve:SetWeight(ptPos, curve:GetWeight(ptPos, 0, false), moho.drawingLayerFrame, false)
					
					curve:SetOffset(ptPos, curve:GetOffset(ptPos, 0, true), moho.drawingLayerFrame, true)
					curve:SetOffset(ptPos, curve:GetOffset(ptPos, 0, false), moho.drawingLayerFrame, false)
				end
			end
		end
		moho:NewKeyframe(CHANNEL_CURVE)
		moho:UpdateUI()
    elseif (msg == self.FLIPDIRECTION) then
		self.flipDirection = self.flipDirectionCB:Value()
	elseif (msg >= self.SELECTITEM) then
		mesh:SelectNone()
		local i = msg - self.SELECTITEM
		local name = mesh:Group(i):Name()
		mesh:SelectGroup(name)
		moho:UpdateUI()
	end
end

Icon
AE curvature
Unlisted

Script type: Tool

Uploaded: Sep 15 2020, 01:21

Last modified: Jul 20 2023, 14:04

Tweak for built-in curvature tool to fix errors on smartbones driven bezier handles






This script, and all other scripts on this site are distributed as free software under the GNU General Public License 3.0 or later.
Downloads count: 1496