﻿

Moho curvature to bezier handles conversion

Bezier handles is not the way Moho stores keys for curvature. Handles can be obtained by M_Curve:GetControlHandle or M_Curve:GetControlPoints, but these values are not directly from channels with keys. These values may also include deformations made by smartbones.
Clean keys are stored in curvature, weight and offset subchannels of the "Point Curvature" channel, so "Point Curvature" channel has M_Curve:CountPoints * 5 subchannels, five for each point: smoothness (curvature itself), weight_in, weight_out, offset_in and offset_out.

Here is the way to convert these three values to XY coordinates of a handle.
```function GetBezierHandle(curve, pointID, frame, prePoint)
local curvature = curve:GetCurvature(pointID, frame)
local weight = curve:GetWeight(pointID, frame, prePoint)
local offset = curve:GetOffset(pointID, frame, prePoint)
local pointToRange = function(p)
if curve.fClosed then
if p < 0 then p = curve:CountPoints()-1 end
if p >= curve:CountPoints() then p = 0  end
else
if p < 0 then p = 0 end
if p >= curve:CountPoints() then p = curve:CountPoints()-1 end
end
return p
end
local postPointID = pointToRange(pointID + 1)
local prePointID = pointToRange(pointID - 1)
local secondPointID = postPointID
if prePoint then secondPointID = prePointID end
if secondPointID == pointID then
return curve:Point(pointID).fAnimPos:GetValue(frame)
end
local N = curve:Point(postPointID).fAnimPos:GetValue(frame) - curve:Point(prePointID).fAnimPos:GetValue(frame)
N:NormMe()
if prePoint then N = N*-1 end
local L = (curve:Point(secondPointID).fAnimPos:GetValue(frame) - curve:Point(pointID).fAnimPos:GetValue(frame)):Mag()
L = L * curvature * weight
local vec = N * L
vec:Rotate(offset)
return curve:Point(pointID).fAnimPos:GetValue(frame) + vec
end
```