public void Transform(MeshPartType type, List<Vector2> points, Vector2 center)
        {
            var movedPoints = new List<int>();
            var linkedIndices = new Dictionary<int, int>();
            var rects = Rects.Where(r => r.Type == type).ToList();
            foreach (var rect in rects)
            {
                for (var i = 0; i < rect.Points.Length; i++)
                {
                    var idx = rect.ShapeIndices[i];
                    if (movedPoints.Contains(idx))
                        continue;
                    movedPoints.Add(idx);
                }
                if (rect.LinkedShapeRect != null)
                {
                    linkedIndices.Add(rect.ShapeIndices.First(), rect.LinkedShapeRect.ShapeIndices.First());
                    linkedIndices.Add(rect.ShapeIndices.Last(), rect.LinkedShapeRect.ShapeIndices.Last());
                }
            }
            switch (type)
            {
                case MeshPartType.LEye:
                case MeshPartType.REye:
                case MeshPartType.Head:
                    foreach (var key in movedPoints)
                    {
                        var p = ShapeInfo.Points[key].Value;
                        float ua, ub;
                        Vector2 p0, p1, target;
                        for (int i = 0, j = points.Count - 1; i < points.Count; j = i, i++)
                        {
                            p0 = points[j];
                            p1 = points[i];
                            if (GetUaUb(ref center, ref p, ref p0, ref p1, out ua, out ub) && ub > 0.0f && ub < 1.0f && ua > 0.0f)
                            {
                                target = center + (p - center) * ua;
                                ShapeInfo.Points[key].Value = target;
                                break;
                            }
                        }
                    }
                    break;
                case MeshPartType.Nose:
                    if ((points[points.Count - 1] - points[0]).X < 0.0f)
                        points.Reverse();
                    var plist = movedPoints.Select(i => ShapeInfo.Points[i].Value).ToList();
                    plist = TransformLine(plist, points);
                    for (var i = 0; i < movedPoints.Count; i++)
                    {
                        var key = movedPoints[i];
                        var p = plist[i];
                        ShapeInfo.Points[key].Value = p;
                    }
                    break;

                case MeshPartType.Lip:
                    #region Lip
                    {
                        if (points.Count < 5)
                            return;
                        var lipPoints = new List<Vector2>();
                        var indices = new List<int>();
                        var pointnsDict = new Dictionary<Vector2, int>(new VectorEqualityComparer());
                        var centerLine = false;
                        for (var i = 0; i < points.Count; i++)
                        {
                            var p = points[i];
                            if (i > 0 && !centerLine && p.Equals(points[0]))
                            {
                                centerLine = true;
                                continue;
                            }
                            int index;
                            if (!pointnsDict.TryGetValue(p, out index))
                            {
                                index = lipPoints.Count;
                                pointnsDict.Add(p, index);
                                lipPoints.Add(p);
                            }
                            indices.Add(index);
                        }

                        var lipLists = new List<Vector2>[3];
                        for (var i = 0; i < 3; i++)
                            lipLists[i] = new List<Vector2>();
                        for (var i = 0; i < indices.Count; i++)
                            if (indices[i] < i)
                            {
                                var first = indices[i];
                                var last = indices[indices.Count - 1];
                                for (var j = first; j <= last; j++)
                                    lipLists[0].Add(lipPoints[indices[j]]);
                                for (var j = last; j < i; j++)
                                    lipLists[1].Add(lipPoints[indices[j]]);
                                for (var j = 0; j <= first; j++)
                                    lipLists[1].Add(lipPoints[indices[j]]);
                                for (var j = i; j < indices.Count; j++)
                                    lipLists[2].Add(lipPoints[indices[j]]);
                                break;
                            }
                        for (var i = 0; i < 3; i++)
                            if (lipLists[i].Count == 0)
                                return;
                        var lipCenter = lipLists[2];
                        var c = (lipCenter[0] + lipPoints[lipCenter.Count - 1]) * 0.5f;
                        var c0 = new Vector2(c.X, c.Y + 1000.0f);
                        var c1 = new Vector2(c.X, c.Y - 1000.0f);
                        for (var i = 2; i > 0; i--)
                        {
                            var list = lipLists[i];
                            for (var j = 0; j < list.Count - 1; j++)
                            {
                                var p0 = list[j];
                                var p1 = list[j + 1];
                                float ua, ub;
                                if (GetUaUb(ref p0, ref p1, ref c0, ref c1, out ua, out ub) &&
                                    ua > 0.0f && ua < 1.0f && ub > 0.0f && ub < 1.0f)
                                {
                                    var p = p0 + (p1 - p0) * ua;
                                    if (i == 2)
                                        c = p;
                                    else if (p.Y >= c.Y)
                                    {
                                        lipLists[1] = lipLists[0];
                                        lipLists[0] = list;
                                    }
                                    break;
                                }
                            }
                        }
                        var tmpIndices = new[] { 3, 4, 2 };
                        var idx = 0;
                        var sourcePoints = new List<Vector2>();
                        var sourceIndices = new List<int>();
                        for (var i = 0; i < 3; i++)
                        {
                            sourcePoints.Clear();
                            sourceIndices.Clear();
                            for (var j = 0; j < tmpIndices[i]; j++, idx++)
                            {
                                var rect = rects[idx];
                                sourcePoints.AddRange(rect.Points);
                                sourceIndices.AddRange(rect.ShapeIndices);
                            }
                            var list = lipLists[i];
                            if ((sourcePoints[sourcePoints.Count - 1].X - sourcePoints[0].X) * (list[list.Count - 1].X - list[0].X) < 0.0f)
                                list.Reverse();
                            sourcePoints = TransformLine(sourcePoints, list);
                            for (var j = 0; j < sourcePoints.Count; j++)
                            {
                                var id = sourceIndices[j];
                                if (movedPoints.Contains(id))
                                {
                                    var p = sourcePoints[j];
                                    ShapeInfo.Points[id].Value = p;
                                    movedPoints.Remove(id);
                                }
                            }
                        }
                    }
                    #endregion
                    break;
                case MeshPartType.ProfileBottom:
                case MeshPartType.ProfileTop:
                    #region Profile
                    {
                        var index = 0;
                        var isFirst = true;
                        movedPoints.Clear();
                        foreach (var rect in ProfileRects)
                        {
                            if (rect.LinkedShapeRect == null || rect.Type != type)
                                continue;
                            //Подгоняем основные точки по Y
                            Vector2 a = rect.Points[0], b = rect.Points.Last();

                            var v = new Vector2(1.0f, 0.0f);
                            var a1 = a + v;
                            var b1 = b + v;
                            //Подгоняем точки по Z
                            float? az = null, bz = null;
                            var tmpPoints = new List<Vector2>();
                            if (isFirst)
                            {
                                az = a.X;
                                tmpPoints.Add(a);
                            }
                            if (rect.IsLast)
                                bz = b.X;
                            //Идем от index и ищем пересечение линии [i, i + 1] с прямой, парралельной oX проходящей через a.Y и b.Y
                            //Если дошли до конца и не нашли - что-то пошло не так, прекращаем все
                            for (var i = index; i < points.Count - 1; i++)
                            {
                                float ua, ub;
                                var p0 = points[i];
                                var p1 = points[i + 1];
                                if (az == null && GetUaUb(ref p0, ref p1, ref a, ref a1, out ua, out ub) && ua > 0.0f && ua < 1.0f)
                                {
                                    var tmp = p0 + (p1 - p0) * ua;
                                    tmpPoints.Add(tmp);
                                    az = tmp.X;
                                }
                                if (az != null)
                                {
                                    if (rect.IsLast)
                                    {
                                        for (var j = i + 1; j < points.Count - 1; j++)
                                            tmpPoints.Add(points[j]);
                                        tmpPoints.Add(b);
                                        break;
                                    }
                                    if (i != index && p0.Y < a.Y)
                                        tmpPoints.Add(points[i]);
                                    if (GetUaUb(ref p0, ref p1, ref b, ref b1, out ua, out ub) && ua > 0.0f && ua < 1.0f)
                                    {
                                        var tmp = p0 + (p1 - p0) * ua;
                                        tmpPoints.Add(tmp);
                                        bz = tmp.X;
                                        index = i;
                                        break;
                                    }
                                }
                            }
                            if (az == null || bz == null)
                                return;
                            a.X = az.Value;
                            b.X = bz.Value;
                            rect.Transform(ref a, ref b);
                            //Строим линию
                            rect.Points = TransformLine(rect.Points.ToList(), tmpPoints).ToArray();
                            //Обновляем точки для шейпа
                            var count = rect.IsLast ? rect.Points.Length - 1 : rect.Points.Length;
                            var start = isFirst ? 1 : 0;
                            for (var i = start; i < count; i++)
                            {
                                var idx = rect.ShapeIndices[i];
                                if (movedPoints.Contains(idx))
                                    continue;
                                movedPoints.Add(idx);
                                ShapeProfileInfo.Points[idx].Value = rect.Points[i];
                            }
                            isFirst = false;
                        }
                        headMeshesController.UpdateProfileShape(ref ShapeProfileInfo);
                        headMeshesController.UpdateNormals();
                        //headMeshesController.UpdateShape(ref ShapeInfo);
                        return;
                    }
                    #endregion
            }

            foreach (var rect in rects)
            {
                if (rect.LinkedShapeRect != null)
                {
                    Vector2 a = ShapeInfo.Points[rect.ShapeIndices.First()].Value, b = ShapeInfo.Points[rect.ShapeIndices.Last()].Value;
                    a = rect.LinkedShapeRect.Points.First() + a - rect.Points.First();
                    b = rect.LinkedShapeRect.Points.Last() + b - rect.Points.Last();

                    rect.LinkedShapeRect.Transform(ref a, ref b, false);
                    for (var i = 0; i < rect.LinkedShapeRect.Points.Length; i++)
                    {
                        var pos = rect.LinkedShapeRect.Points[i];
                        var idx = rect.LinkedShapeRect.ShapeIndices[i];
                        ShapeInfo.Points[idx].Value = pos;
                    }
                }

                for (var i = 0; i < rect.Points.Length; i++)
                {
                    var idx = rect.ShapeIndices[i];
                    rect.Points[i] = ShapeInfo.Points[idx].Value;
                }
                rect.Points = rect.Points;
            }

            headMeshesController.UpdateShape(ref ShapeInfo);
        }
 public void ResetPoints(MeshPartType type)
 {
     if (type == MeshPartType.None)
         return;
     var movedPoints = new Dictionary<int, Vector2>();
     var rects = Rects.Where(r => r.Type == type).ToList();
     var linked = rects.Where(r => r.LinkedShapeRect != null).Select(r => r.LinkedShapeRect).ToList();
     rects.AddRange(linked);
     foreach (var rect in rects)
     {
         for (var i = 0; i < rect.Points.Length; i++)
         {
             var idx = rect.ShapeIndices[i];
             if (movedPoints.ContainsKey(idx))
             {
                 rect.Points[i] = movedPoints[idx];
                 continue;
             }
             movedPoints.Add(idx, rect.OriginalPoints[i]);
             var dv = rect.OriginalPoints[i] - rect.Points[i];
             if (Math.Abs(dv.LengthSquared) < 0.000001f)
                 continue;
             rect.Points[i] = rect.OriginalPoints[i];
             ShapeInfo.Points[idx].Value = rect.OriginalPoints[i];
         }
         rect.Points = rect.Points;
     }
     headMeshesController.UpdateShape(ref ShapeInfo);
     headMeshesController.UpdateNormals();
 }