def storeMeshMotionMapperDataToBlender(motion_mapper_object, motion_mapper):
    if not motion_mapper.IsBond():
        return False;
    if not motion_mapper_object.hi_phy:
        return False;
    n_verts = motion_mapper.DrivenNumVertices()
    id_array = np.zeros((n_verts), dtype=np.int32)
    weight_array = np.zeros((n_verts * 3), dtype=np.float32)
    if not motion_mapper.GetBondData(id_array, weight_array):
        return False
    motion_mapper_object["hi_phy_mesh_motion_mapper_id_array"] = id_array.tolist()
    motion_mapper_object["hi_phy_mesh_motion_mapper_weight_array"] = weight_array.tolist()
    motion_mapper_object.hi_phy.motion_mapper_is_bond = True;

from ..cAPI import SimulationAPI
import numpy as np
def constructMeshMotionMapperFromBlender(motion_mapper_object, guide_object):
    if (not "hi_phy_mesh_motion_mapper_id_array" in motion_mapper_object or
        not "hi_phy_mesh_motion_mapper_weight_array" in motion_mapper_object):
        return None
    # assume guide_object is evaluated
    motion_mapper = SimulationAPI.MeshMotionMapper();
    faces = guide_object.data.polygons
    n_faces = len(faces);
    # First check it is a triangle mesh
    face_data = np.zeros((n_faces, 3), dtype=np.int32)
    for f in range(0, n_faces):
        if (not len(faces[f].vertices) == 3) :
            return None
        face_data[f][0] = faces[f].vertices[0]
        face_data[f][1] = faces[f].vertices[1]
        face_data[f][2] = faces[f].vertices[2]
    if not motion_mapper.SetGuideMeshTriangles(face_data):
        return None

    n_verts = guide_object.data.attributes.domain_size('POINT')
    guide_positions = np.zeros((n_verts, 3), dtype=np.float32)
    guide_object.data.attributes['position'].data.foreach_get('vector', np.ravel(guide_positions))

    identity_transform = SimulationAPI.TransformMatrix();
    # We perform computation in guide space
    if not motion_mapper.SetGuidePosition(guide_positions, identity_transform):
        return None
    id_array = motion_mapper_object["hi_phy_mesh_motion_mapper_id_array"].to_list()
    weight_array = motion_mapper_object["hi_phy_mesh_motion_mapper_weight_array"].to_list()
    if not (motion_mapper.SetBondData(id_array, weight_array)):
        return None    
    return motion_mapper

def storeCurvesMotionMapperDataToBlender(motion_mapper_object, motion_mapper):
    if not motion_mapper.IsBond():
        return False;
    if not motion_mapper_object.hi_phy:
        return False;
    motion_mapper_object.hi_phy.motion_mapper_curve_bond_with_frame = motion_mapper.UseFrame();
    n_guides = motion_mapper.NumGuides();
    motion_mapper_object.hi_phy.motion_mapper_curve_bond_with_num_guides = n_guides;
    n_guide_cvs = motion_mapper.GuideNumCVs()
    n_driven_cvs = motion_mapper.DrivenNumCVs()
    n_driven_curves = motion_mapper.DrivenNumCurves()
    guide_parameterization = np.zeros((n_guide_cvs), dtype=np.float32)
    driven_parameterization = np.zeros((n_driven_cvs), dtype=np.float32)
    id_array = np.zeros((n_driven_curves * n_guides), dtype=np.int32)
    weight_array = np.zeros((n_driven_cvs * n_guides), dtype=np.float32)
    offset_array = np.zeros((n_driven_cvs * n_guides * 3), dtype=np.float32)
    if not motion_mapper.GetBondData(guide_parameterization, driven_parameterization, id_array, weight_array, offset_array):
        return False
    motion_mapper_object["hi_phy_curves_motion_mapper_guide_parameterization"] = guide_parameterization .tolist()
    motion_mapper_object["hi_phy_curves_motion_mapper_driven_parameterization"] = driven_parameterization .tolist()
    motion_mapper_object["hi_phy_curves_motion_mapper_id_array"] = id_array.tolist()
    motion_mapper_object["hi_phy_curves_motion_mapper_weight_array"] = weight_array.tolist()
    motion_mapper_object["hi_phy_curves_motion_mapper_offset_array"] = offset_array.tolist()
    motion_mapper_object.hi_phy.motion_mapper_is_bond = True;
    return True

def constructCurvesMotionMapperFromBlender(motion_mapper_object, guide_object, driven_object):
    if (not "hi_phy_curves_motion_mapper_guide_parameterization" in motion_mapper_object or
        not "hi_phy_curves_motion_mapper_driven_parameterization" in motion_mapper_object or
        not "hi_phy_curves_motion_mapper_id_array" in motion_mapper_object or
        not "hi_phy_curves_motion_mapper_weight_array" in motion_mapper_object or
        not "hi_phy_curves_motion_mapper_offset_array" in motion_mapper_object):
        return None
    if (guide_object.type != 'CURVES'):
        return None
    if (driven_object.type != 'CURVES'):
        return None

    # assume guide_object is evaluated
    motion_mapper = SimulationAPI.CurvesMotionMapper();
    n_guide_curves = len(guide_object.data.curves)
    guide_offset_data = np.zeros(n_guide_curves + 1, dtype=np.int32)
    # blender stores the first offset as 0 there are totally n_curves + 1 offsets
    for i in range(n_guide_curves + 1):
        guide_offset_data[i] = guide_object.data.curve_offset_data[i].value
    n_guide_cvs = guide_offset_data[-1]
    motion_mapper.SetGuideCurvesStartCV(guide_offset_data)

    n_driven_curves = len(driven_object.data.curves)
    driven_offset_data = np.zeros(n_driven_curves + 1, dtype=np.int32)
    # blender stores the first offset as 0 there are totally n_curves + 1 offsets
    for i in range(n_driven_curves + 1):
        driven_offset_data[i] = driven_object.data.curve_offset_data[i].value
    n_driven_cvs = driven_offset_data[-1]
    motion_mapper.SetDrivenCurvesStartCV(driven_offset_data)

    use_frame = motion_mapper_object.hi_phy.motion_mapper_curve_bond_with_frame
    num_guides = motion_mapper_object.hi_phy.motion_mapper_curve_bond_with_num_guides
    guide_parameterization = motion_mapper_object["hi_phy_curves_motion_mapper_guide_parameterization"].to_list()
    driven_parameterization = motion_mapper_object["hi_phy_curves_motion_mapper_driven_parameterization"].to_list()
    id_array = motion_mapper_object["hi_phy_curves_motion_mapper_id_array"].to_list()
    weight_array = motion_mapper_object["hi_phy_curves_motion_mapper_weight_array"].to_list()
    offset_array = motion_mapper_object["hi_phy_curves_motion_mapper_offset_array"].to_list()
    if not (motion_mapper.SetBondData(use_frame, guide_parameterization, driven_parameterization, num_guides, id_array, weight_array, offset_array)):
        return None
    return motion_mapper
