Skip to main content
Commonmark migration
Source Link

###Update: using another weighting function###

Update: using another weighting function

###Update: using another weighting function###

Update: using another weighting function

added 40 characters in body
Source Link
Alexey Popkov
  • 62.3k
  • 7
  • 154
  • 375
c = RegionCentroid[Polygon[list]];
Manipulate[Graphics[{Text[
    Row[{Dynamic[Length[list] - n], " points"}, BaseStyle -> FontSize -> 22], 
    Scaled[{.15, .92}]], EdgeForm[{Black, Thickness[.015]}], FaceForm[None], Red, 
   PointSize[.04], Point[seq[[n + 1, 2]][[seq[[n + 1, 1]]]]], Polygon[seq[[n + 1, 2]]], 
   Yellow, PointSize[.015], Point[seq[[n + 1, 2]]], EdgeForm[{Thickness[.01]}], 
   Translate[Scale[Polygon[seq[[n + 1, 2]]], 1/20, c], {-.5, 9}], 
   Translate[Scale[Polygon[list], 1/20, c], {.5, 9}], EdgeForm[], FaceForm[Blue], 
   Translate[Scale[Polygon[seq[[n + 1, 2]]], 1/20, c], {-.5, 10}], 
   Translate[Scale[Polygon[list], 1/20, c], {.5, 10}]}, 
  PlotRange -> {{0, 14}, {3, 22}}], {{n, Length[list] - 50}, Length[list] - 70, 
  Length[seq] - 1, 1, AnimationRate -> 5, AnimationRepetitions -> None, 
  RefreshRate -> 60}]
Manipulate[Graphics[{Text[
    Row[{Dynamic[Length[list] - n], " points"}, BaseStyle -> FontSize -> 22], 
    Scaled[{.15, .92}]], EdgeForm[{Black, Thickness[.015]}], FaceForm[None], Red, 
   PointSize[.04], Point[seq[[n + 1, 2]][[seq[[n + 1, 1]]]]], Polygon[seq[[n + 1, 2]]], 
   Yellow, PointSize[.015], Point[seq[[n + 1, 2]]], EdgeForm[{Thickness[.01]}], 
   Translate[Scale[Polygon[seq[[n + 1, 2]]], 1/20, c], {-.5, 9}], 
   Translate[Scale[Polygon[list], 1/20, c], {.5, 9}], EdgeForm[], FaceForm[Blue], 
   Translate[Scale[Polygon[seq[[n + 1, 2]]], 1/20, c], {-.5, 10}], 
   Translate[Scale[Polygon[list], 1/20, c], {.5, 10}]}, 
  PlotRange -> {{0, 14}, {3, 22}}], {{n, Length[list] - 50}, Length[list] - 70, 
  Length[seq] - 1, 1, AnimationRate -> 5, AnimationRepetitions -> None, 
  RefreshRate -> 60}]
c = RegionCentroid[Polygon[list]];
Manipulate[Graphics[{Text[
    Row[{Dynamic[Length[list] - n], " points"}, BaseStyle -> FontSize -> 22], 
    Scaled[{.15, .92}]], EdgeForm[{Black, Thickness[.015]}], FaceForm[None], Red, 
   PointSize[.04], Point[seq[[n + 1, 2]][[seq[[n + 1, 1]]]]], Polygon[seq[[n + 1, 2]]], 
   Yellow, PointSize[.015], Point[seq[[n + 1, 2]]], EdgeForm[{Thickness[.01]}], 
   Translate[Scale[Polygon[seq[[n + 1, 2]]], 1/20, c], {-.5, 9}], 
   Translate[Scale[Polygon[list], 1/20, c], {.5, 9}], EdgeForm[], FaceForm[Blue], 
   Translate[Scale[Polygon[seq[[n + 1, 2]]], 1/20, c], {-.5, 10}], 
   Translate[Scale[Polygon[list], 1/20, c], {.5, 10}]}, 
  PlotRange -> {{0, 14}, {3, 22}}], {{n, Length[list] - 50}, Length[list] - 70, 
  Length[seq] - 1, 1, AnimationRate -> 5, AnimationRepetitions -> None, 
  RefreshRate -> 60}]
added 2139 characters in body
Source Link
Alexey Popkov
  • 62.3k
  • 7
  • 154
  • 375

Here I present a very simple angle-based polygon reduction algorithm as described in the chapter "A Simple Algorithm" of David Eberly's "Polyline Reduction". ItThe only addition is that I treat the list as cyclic since we work with closed polygon, not with an open polyline. The algorithm is vastly inefficient and has no quality control (other than visual), but demonstrates the idea.

The implementation (as weighting function for vertex I use π minus vector angle at the vertex):

animation


###Update: using another weighting function###

A bit of experimentation showed that much better results can be obtained with more sophisticated weighting function:

nextPoint[list_] := 
  Ordering[((Pi - Re@VectorAngle[#2 - #1, #2 - #3])*
            (Norm[#2 - #1] Norm[#2 - #3])/(Norm[#2 - #1] + Norm[#2 - #3])) & @@@
                       Partition[ArrayPad[list, {{1, 1}}, "Periodic"], 3, 1], 1];

Selecting more initial sampling points allows to get better approximation:

list = sample[30];

seq = NestList[deleteOnePoint, {nextPoint[list], list}, Length[list] - 6];

Here is Manipulate where at the top at left shown current approximation and on the right shown initial sample:

Manipulate[Graphics[{Text[
    Row[{Dynamic[Length[list] - n], " points"}, BaseStyle -> FontSize -> 22], 
    Scaled[{.15, .92}]], EdgeForm[{Black, Thickness[.015]}], FaceForm[None], Red, 
   PointSize[.04], Point[seq[[n + 1, 2]][[seq[[n + 1, 1]]]]], Polygon[seq[[n + 1, 2]]], 
   Yellow, PointSize[.015], Point[seq[[n + 1, 2]]], EdgeForm[{Thickness[.01]}], 
   Translate[Scale[Polygon[seq[[n + 1, 2]]], 1/20, c], {-.5, 9}], 
   Translate[Scale[Polygon[list], 1/20, c], {.5, 9}], EdgeForm[], FaceForm[Blue], 
   Translate[Scale[Polygon[seq[[n + 1, 2]]], 1/20, c], {-.5, 10}], 
   Translate[Scale[Polygon[list], 1/20, c], {.5, 10}]}, 
  PlotRange -> {{0, 14}, {3, 22}}], {{n, Length[list] - 50}, Length[list] - 70, 
  Length[seq] - 1, 1, AnimationRate -> 5, AnimationRepetitions -> None, 
  RefreshRate -> 60}]

output

As one can see, an approximation containing only 50 points is indistinguishable from the original at the usual letter sizes. For comparison, the original Bézier curves extracted from the glyph contain 101 control points...

Here I present a very simple angle-based polygon reduction algorithm as described in the chapter "A Simple Algorithm" of David Eberly's "Polyline Reduction". It is vastly inefficient and has no quality control, but demonstrates the idea.

The implementation:

animation

Here I present a very simple angle-based polygon reduction algorithm as described in the chapter "A Simple Algorithm" of David Eberly's "Polyline Reduction". The only addition is that I treat the list as cyclic since we work with closed polygon, not with an open polyline. The algorithm is vastly inefficient and has no quality control (other than visual), but demonstrates the idea.

The implementation (as weighting function for vertex I use π minus vector angle at the vertex):

animation


###Update: using another weighting function###

A bit of experimentation showed that much better results can be obtained with more sophisticated weighting function:

nextPoint[list_] := 
  Ordering[((Pi - Re@VectorAngle[#2 - #1, #2 - #3])*
            (Norm[#2 - #1] Norm[#2 - #3])/(Norm[#2 - #1] + Norm[#2 - #3])) & @@@
                       Partition[ArrayPad[list, {{1, 1}}, "Periodic"], 3, 1], 1];

Selecting more initial sampling points allows to get better approximation:

list = sample[30];

seq = NestList[deleteOnePoint, {nextPoint[list], list}, Length[list] - 6];

Here is Manipulate where at the top at left shown current approximation and on the right shown initial sample:

Manipulate[Graphics[{Text[
    Row[{Dynamic[Length[list] - n], " points"}, BaseStyle -> FontSize -> 22], 
    Scaled[{.15, .92}]], EdgeForm[{Black, Thickness[.015]}], FaceForm[None], Red, 
   PointSize[.04], Point[seq[[n + 1, 2]][[seq[[n + 1, 1]]]]], Polygon[seq[[n + 1, 2]]], 
   Yellow, PointSize[.015], Point[seq[[n + 1, 2]]], EdgeForm[{Thickness[.01]}], 
   Translate[Scale[Polygon[seq[[n + 1, 2]]], 1/20, c], {-.5, 9}], 
   Translate[Scale[Polygon[list], 1/20, c], {.5, 9}], EdgeForm[], FaceForm[Blue], 
   Translate[Scale[Polygon[seq[[n + 1, 2]]], 1/20, c], {-.5, 10}], 
   Translate[Scale[Polygon[list], 1/20, c], {.5, 10}]}, 
  PlotRange -> {{0, 14}, {3, 22}}], {{n, Length[list] - 50}, Length[list] - 70, 
  Length[seq] - 1, 1, AnimationRate -> 5, AnimationRepetitions -> None, 
  RefreshRate -> 60}]

output

As one can see, an approximation containing only 50 points is indistinguishable from the original at the usual letter sizes. For comparison, the original Bézier curves extracted from the glyph contain 101 control points...

fixed mistake: now taken into account that the polyline is periodic (closed)
Source Link
Alexey Popkov
  • 62.3k
  • 7
  • 154
  • 375
Loading
Source Link
Alexey Popkov
  • 62.3k
  • 7
  • 154
  • 375
Loading