yutannihilation / string2path

An experimental R package to convert string to path
https://yutannihilation.github.io/string2path/
Other
97 stars 5 forks source link

'tolerance' behaves differently in `string2path()` vs `string2fill()` #69

Closed coolbutuseless closed 1 month ago

coolbutuseless commented 1 month ago

The tolerance setting behaves differently depending on whether running string2path() or string2fill()

I expected the same letter at the same tolerance to have the exact same outline.

Instead the outline of string2path() (shown in RED below) and string2fill() (shown in BLACK) are different.

Why I need aligment:

I'm wanting to create 3d letters by extruding the string2path() result to create the extruded edges and duplicating the string2fill() result to create the front and back faces. The mismatch in outline shapes means that the 3d letters are not closed shapes, and there are gaps in the model.

  library(string2path)
  font <- string2path::dump_fontdb()[1,]

  tol <- 3e-3

  path <- string2path::string2path('s', font = font$family, tolerance = tol)
  poly <- string2path::string2fill('s', font = font$family, tolerance = tol)

  library(ggplot2)
  ggplot() + 
    geom_polygon(data = poly, aes(x, y, group = triangle_id), color = 'black', fill = 'grey70') + 
    geom_polygon(data = path, aes(x, y), fill = NA, color = 'red') +
    coord_equal() + 
    theme_minimal()

Created on 2024-09-28 with reprex v2.1.1

coolbutuseless commented 1 month ago

Example render. Glyph rendered with string2path/string2fill at a tolerance = 5e-3 to illustrate issue.

prism-bug

yutannihilation commented 1 month ago

Thanks for the details! I was aware of the difference of tolerance (README mention this regarding stroke vs fill), but couldn't figure out the mechanism yet. Under the hood, savvy just passes the parameter to the underlying library (lyon). Reading the document, path or fill shouldn't matter, so I have no idea at the moment...

https://github.com/yutannihilation/string2path/blob/3ef8cfc0f0699640fa70a429b5bdb428831bd9e7/src/rust/src/into_fill_stroke.rs#L61 https://github.com/yutannihilation/string2path/blob/3ef8cfc0f0699640fa70a429b5bdb428831bd9e7/src/rust/src/into_fill_stroke.rs#L99 https://github.com/yutannihilation/string2path/blob/3ef8cfc0f0699640fa70a429b5bdb428831bd9e7/src/rust/src/into_path.rs#L58

coolbutuseless commented 1 month ago

Thanks for looking. It does look like the path line almost does every second vertex.

string2stroke() (shown in blue, below) matches string2fill() vertices

  library(string2path)
  font <- string2path::dump_fontdb()[1,]

  tol <- 3e-3

  path   <- string2path::string2path  ('s', font = font$family, tolerance = tol)
  poly   <- string2path::string2fill  ('s', font = font$family, tolerance = tol)
  stroke <- string2path::string2stroke('s', font = font$family, tolerance = tol)

  library(ggplot2)
  ggplot() + 
    geom_polygon(data = poly  , aes(x, y, group = triangle_id), color = 'black', fill = 'grey70') + 
    geom_polygon(data = stroke, aes(x, y, group = triangle_id), color = 'blue' , fill = NA) + 
    geom_polygon(data = path  , aes(x, y), fill = NA, color = 'red') +
    coord_equal() + 
    theme_minimal()

Created on 2024-09-28 with reprex v2.1.1

yutannihilation commented 1 month ago

Interesting. Here's the result on my Linux laptop. It seems it depends on the font.

plot

yutannihilation commented 1 month ago

This should be fixed now. The binary will be available on R-universe (https://yutannihilation.r-universe.dev/string2path). Thanks for reporting!

library(string2path)
font <- string2path::dump_fontdb()[1,]

tol <- 3e-3

path <- string2path::string2path('s', font = font$family, tolerance = tol)
poly <- string2path::string2fill('s', font = font$family, tolerance = tol)

library(ggplot2)
#> 
#> Attaching package: 'ggplot2'
#> The following object is masked from 'package:base':
#> 
#>     is.element
ggplot() + 
  geom_polygon(data = poly, aes(x, y, group = triangle_id), color = 'black', fill = 'grey70') + 
  geom_polygon(data = path, aes(x, y), fill = NA, color = 'red') +
  coord_equal() + 
  theme_minimal()

Created on 2024-09-28 with reprex v2.1.1

coolbutuseless commented 1 month ago

Brilliant! All lines up now. Thanks!