Как работает упрощение полилинии в Adobe Illustrator?
Я работаю над приложением, которое записывает штрихи, которые вы рисуете указательным устройством.
на изображении выше я нарисовал один штрих, который содержит 453 точки данных. Моей целью было бы резко уменьшить количество точек данных, сохраняя при этом форму исходного штриха.
для тех, кто заинтересован, координаты для Штриха, изображенного выше, доступны как суть в На GitHub.
на самом деле, Adobe Illustrator имеет отличную реализацию того, что я пытаюсь достичь. Если я нарисую аналогичный штрих (каллиграфической кистью) в Illustrator, полученная форма будет упрощена до того, что мы видим ниже. При рисовании Штриха он будет выглядеть очень похожим на тот, что есть в моем приложении. Как только я отпущу кнопку мыши, кривая будет упрощена до того, что мы видим здесь:
Как видим, инсульт только 14 точек данных. Хотя есть дополнительные контрольные точки, которые определяют наклон сплайна Безье (или любого сплайна, который они используют). Здесь мы можем увидеть несколько из этих контрольных точек:
Я посмотрел на алгоритмы, такие как алгоритм Рамера–Дугласа–Пекера, но они, похоже, удаляют только точки из входного набора. Если я не ошибаюсь, подход, который я ищу, также должен был бы ввести новые точки в набор достигните желаемой кривой.
Я столкнулся с такими вопросами, как iPhone гладкий алгоритм рисования эскиза, которые, кажется, связаны. Но они, похоже, сосредоточены на создании гладкой кривой из небольшого набора входных точек. Я чувствую, что у меня противоположный случай.
1 ответов
я наткнулся на вопрос сглаживание рисованной кривой (который этот вопрос на самом деле может быть обманут), который имеет ответ, который предлагает использовать Ramer-Douglas-Peucker, а затем применять подгонку кривой в соответствии с Philip J. Schneiders подход.
быстрая адаптация предоставленного образца кода к моим методам рисования приводит к следующей кривой:
входные данные из вопроса были уменьшены до 28 точек (которые рисуются с использованием сплайнов Безье).
Я не уверен, какой именно подход использует Adobe, но этот служит мне очень хорошо до сих пор.
адаптация
и код, предоставленный Kris написано для WPF и делает некоторые предположения в этом отношении. Чтобы работать в моем случае (и потому, что я не хотел корректировать его код), я написал следующий фрагмент:
private List<Point> OptimizeCurve( List<Point> curve ) {
const float tolerance = 1.5f;
const double error = 100.0;
// Remember the first point in the series.
Point startPoint = curve.First();
// Simplify the input curve.
List<Point> simplified = Douglas.DouglasPeuckerReduction( curve, tolerance ).ToList();
// Create a new curve from the simplified one.
List<System.Windows.Point> fitted = FitCurves.FitCurve( simplified.Select( p => new System.Windows.Point( p.X, p.Y ) ).ToArray(), error );
// Convert the points back to our desired type.
List<Point> fittedPoints = fitted.Select( p => new Point( (int)p.X, (int)p.Y ) ).ToList();
// Add back our first point.
fittedPoints.Insert( 0, startPoint );
return fittedPoints;
}
полученный список будет иметь формат Начало, Контрольная Точка 1, Контрольная Точка 2, Конечный Пункт.