Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

atParam differs significantly from expected value #335

Open
bacchanalia opened this issue Mar 28, 2019 · 3 comments
Open

atParam differs significantly from expected value #335

bacchanalia opened this issue Mar 28, 2019 · 3 comments

Comments

@bacchanalia
Copy link

bacchanalia commented Mar 28, 2019

The difference between atParam on circle 1 vs trig functions can be high enough to be easily seen on reasonably sized renders.

import Data.List
import Data.Ord
import Diagrams.Prelude

c = circle 1 :: Located (Trail V2 Double)
atParamVsTrig a = norm $ (c `atParam` a) .-. (p2 (cos (a*tau), sin (a*tau)))
maxDiff = maximum $ map atParamVsTrig [0,2**(-10)..1]
main = print maxDiff -- 7.3487762815497674e-3
@byorgey
Copy link
Member

byorgey commented Mar 28, 2019

Right, this is because we approximate circles by four cubic bezier segments, one for each quadrant. circle depends on Diagrams.TwoD.Arc.arcT, which ultimately depends on Diagrams.TwoD.Arc.bezierFromSweepQ1:

https://github.com/diagrams/diagrams-lib/blob/master/src/Diagrams/TwoD/Arc.hs#L57

We could use a more accurate approximation, with the downside that render times would increase, as well as the output size for any vector graphics format.

Many years ago, @fryguybob and I discussed at great length the possibility of including circular arcs as a new primitive kind of segment, alongside straight and cubic bezier segments. That would allow atParam to be as precise as possible, and rendering could be equally accurate for backends which natively support drawing circular arcs. For backends which don't support them we could of course still fall back to approximating with cubic beziers. However, as I recall it was very tricky figuring out the right meaning of things like glueLine when circular segments are involved. But I'm happy to reconsider the question.

@bacchanalia
Copy link
Author

I don't think this is causing me any problems in practice at the moment, and if needed it's possible to work around by using

circle' n r = cubicSpline True $ map p (init [0,2**(-n)..1])
  where p a = p2 (r*cos (a*tau), r*sin (a*tau))

@fryguybob
Copy link
Member

@bacchanalia Note that your circle' 2 is not as precise as circle for the same number of segments. I think there is enough description in the primer to make a better circle':

https://pomax.github.io/bezierinfo/#circles_cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants