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

Allow dash lengths < line width #355

Closed
meetar opened this issue Jul 12, 2016 · 10 comments
Closed

Allow dash lengths < line width #355

meetar opened this issue Jul 12, 2016 · 10 comments

Comments

@meetar
Copy link
Member

meetar commented Jul 12, 2016

Currently dash patterns specified with the dash parameter must be defined in integers, where 1 = the width of the line. It would be nice to be able to specify dash lengths which are < line width, and possibly also to specify them in px.

@bcamper
Copy link
Member

bcamper commented Jul 15, 2016

@karimnaaji this is a limitation in the current approach that hadn't occurred to me when we initially implemented it: because the pattern is scaled by the line width, and the unit are whole pixels, it's not possible to make a pattern that is less than the width of the line.

I was thinking of a simple way to extend this: multiply the dash array values by a number (say by 20) before rendering the texture to provide additional precision (and then adjust texture coord scale to compensate). This allows for reasonable precision (fractions 0.25 and 0.5 can both be expressed if a scaling factor of 20 is used), and even for an unusually long dash pattern, for example 25 units, the resulting texture stays under 512px. Having a bigger texture size might also be useful in the future for providing alpha transition (avoiding harder edges) and/or rendering rounded corners on the dashes.

@karimnaaji
Copy link
Member

karimnaaji commented Jul 15, 2016

Yes that would work, I don't see how we couldn't perform an operation in both the dash-array and the uvs at the same time.

Another solution to always have the maximum amount of precision is to take the minimum of the two values and scale it to an integer value.

Say we have:

dash: [0.1, 1]

We create a dash array of [1, 10], and then scale the uvs by the scale factor in the shader:

line_st.y = mod(line_st.y * scale, 1.0); // scale = 10.0 in the example

Just before sampling the texture here.

@bcamper
Copy link
Member

bcamper commented Jul 15, 2016

You can have more than two dash array entries though! So using the minimum value wouldn't necessarily give you all integers, e.g, [1, 0.3, 0.2]. But yes I was thinking of just choosing a scale and applying it both to the dash array and in the shader before the texture is sampled, as you suggested.

@bcamper
Copy link
Member

bcamper commented Jul 15, 2016

@bcamper bcamper added this to the v0.9.0 milestone Jul 15, 2016
@karimnaaji
Copy link
Member

I see, yes when speaking of minimum I was thinking of the least common denominator to convert all of them to integers, LCD([1, 0.3, 0.2]) = 10.

@bcamper
Copy link
Member

bcamper commented Jul 26, 2016

Hmm, that would be interesting, but wouldn't it leave us open to issues with someone putting in values that will cause very high LCDs? We need to constrain it to something reasonable to keep the texture within a maximum size, I supposed we could just put a max cap on the LCD? Also from a quick search, the LCD implementations I'm seeing don't require the output to be integers (which we need to determine the scaling factor), e.g. [0.1, 0.2, 0.3] returns 0.1 since it's the common multiple. Any ideas? I was just looking for a quick solution, and we're going to have to limit the precision one way or another :)

@bcamper bcamper removed this from the v0.9.0 milestone Jul 28, 2016
@pnorman
Copy link
Contributor

pnorman commented Aug 23, 2016

Also from a quick search, the LCD implementations I'm seeing don't require the output to be integers (which we need to determine the scaling factor), e.g. [0.1, 0.2, 0.3] returns 0.1 since it's the common multiple. Any ideas?

The LCM is not defined for non-integer input. I think what you need to do is...

Starting with [0.6, 1.2, .15]

  1. Express all values in fractional form (denominator of 10^n works here if all else fails): [6/10, 12/10, 15/100]
  2. Multiply by the LCM of the denominators: [60, 120, 15] * 1/100. At this point you are guaranteed to have integers, but not an optimal set.
  3. Divide by the GCF of the components [4, 8, 1] * 15/100

You now have the minimal set of integers to represent the dash and the multiplier to turn it back into the original form.

You may find you've ended up with something like [1, 1000]. I'm not sure what to do here if you have a maximum pattern size, but this is already an issue.

You could have something like [0.313, 0.601] which gives you [313, 601], both prime numbers. I have no good suggestions here except something which ends up approximating.

@bcamper
Copy link
Member

bcamper commented Sep 1, 2016

Right, thanks @pnorman :)

Given all this I'm going back to my original suggestion to just pick a reasonable max resolution, which is used to scale up the pattern in pixels.

Does that work for you @karimnaaji?

@karimnaaji
Copy link
Member

Yes the solution with fixed scaling should give good results, we can think more with the common denominator if the result's precision happens to be an issue.

@bcamper
Copy link
Member

bcamper commented Sep 15, 2016

Support for this released in v0.10.0!

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

No branches or pull requests

4 participants