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

Stroke has incorrect geometry when the thickness is very large #132

Open
alexeevilya opened this issue Apr 20, 2015 · 38 comments
Open

Stroke has incorrect geometry when the thickness is very large #132

alexeevilya opened this issue Apr 20, 2015 · 38 comments

Comments

@alexeevilya
Copy link

Hi, guys! I've got a problem when trying to scale the stroke, keeping the thickness. When I change the stroke thickness to some large value, it draws incorrectly.

Please, look at the picture:
img

Here is project src:
https://www.dropbox.com/s/om7v84i2iibpp53/pathTest.zip?dl=0

Thanks!

@alexeevilya
Copy link
Author

Another artifact:
img
I think it has the same cause.

@IonSwitz
Copy link
Member

Yeah, setting the thickness to a large value ( you dont have to scale the stroke to make it appear) can make the joints degenerate. It is an unfortunate side effect of the math code. The rectangles that are created to draw the lines become overlapped and it looks very bad.

You can try to solve the same problem by drawing 2 quadrilaterals on a piece of paper to fit every type of joint in every angle. It rapidly becomes very hard to make the joint look good without overdraw or disfigured shapes as a result :)

@alexeevilya
Copy link
Author

Ion, thanx, but are you sure that nothing can be done? (until a certain scale, everything looks great).
For my app it is a catastrophic problem (

@IonSwitz
Copy link
Member

What is the actual problem you are trying to solve?

Is it the scaling? Or is it when you need to draw lines with many control points?

If it is the scaling, you can do the scaling math on the vertices of the Stroke yourself, before you add them as vertices to the Stroke, and keep the thickness constant (and small) so the artifacts aren't as visible.

In the second example, what is the goal there? If you wish to draw smooth curves, check out the ShapeEx.graphics.NaturalCubicSplineTo method

@IonSwitz
Copy link
Member

Well, I have to agree that I do find something odd that goes beyond what should be expected when the line turns on itself with large thickness... There is definitely something wrong. I will try to look into it, even though I doubt I will find the bug tonight.

@IonSwitz
Copy link
Member

Could you please test with the following additional code:

                if ( elbowThickness > d0 )
                    elbowThickness = d0;
                if ( elbowThickness > d1 )
                    elbowThickness = d1;

Add that to the Stroke class, around line 353, as the last four lines in the "if ( treatAsRegular )" statement.

I know this is probably cumbersome for you to test, but I would like to see the effect of this on the problems you are seeing. I don't want to submit it as a fix, but it seems to make some of my test cases look better (if not perfect)

Just let me know what happens, ok?

@alexeevilya
Copy link
Author

Ion, Thank you very much for your care and help to solve this problem! Unfortunately, that kills one problem, but born another. There's a new artifact:
img1
In the real application, it looks like this,
before:
img3
after:
img2

@IonSwitz
Copy link
Member

Ah, ok. Can I ask you how many points you have per stroke in your "real" application? It looks like a program to map sailing boats, perhaps?

The original problem occurs when the thickness of a joint gets thicker than the distance of the line segments, and the fix tried to correct that. It seems to me that you have a very large amount of data points in your "real" application, making each line segment between two vertices pretty small compared to the thickness?

IF that is the case, the thickness will rapidly get thicker than each line segment, and what I would do in that case would be to "clean" the input data, removing points that are (more or less) on the same line, or points that create "dents" in the line.

@IonSwitz
Copy link
Member

If you try this instead:
if ( elbowThickness > d0 )
elbowThickness = vThickness;
if ( elbowThickness > d1 )
elbowThickness = vThickness;

could you let me know the difference?

@alexeevilya
Copy link
Author

Ion, yes, it is a sailing boats map application. As for the number of vertices, then I use simplify algorithm, and there is a one vertex for the one really map point after simplifying.
Sorry for my English, one moment ... ;)

@IonSwitz
Copy link
Member

Don't worry about your English, I understand you fine. I am sorry I can't help you very well.

@alexeevilya
Copy link
Author

Thank you, now I'm testing the new changes by you.

@alexeevilya
Copy link
Author

img4
Oh my God! ;)

@alexeevilya
Copy link
Author

By the way, my other sandbox to test an application is project, that reference is attached above.
https://www.dropbox.com/s/om7v84i2iibpp53/pathTest.zip?dl=0

@IonSwitz
Copy link
Member

The lines get very thin in some places, but the bad joints look better.. Hmmm..

@alexeevilya
Copy link
Author

Please, look at the dropbox example...
img5

@IonSwitz
Copy link
Member

I am away from my Flash dev environment today, so I cant test any code. Sorry.

@alexeevilya
Copy link
Author

Oh, no problem. But as you can see, the line in dropbox example is very thin, although there is only four vertexes in that.

@alexeevilya
Copy link
Author

Please, look at this example - https://www.dropbox.com/s/wr1cu8ynz2axioa/PathTest.swf?dl=0
You need to scroll by the wheel.

@alexeevilya
Copy link
Author

In short, the problem occurs when the thickness of a joint gets thicker than the distance of the line segments. Unfortunately, the fix does not correct that problem.

@IonSwitz
Copy link
Member

Yeah, I figured it doesnt solve it. And I wrote that earlier: "The original problem occurs when the thickness of a joint gets thicker than the distance of the line segments" :) Unfortunately, I can't do any work on this for a few days (Going to Berlin for the Quo Vadis game conference)

@alexeevilya
Copy link
Author

All clear. However, I will be very grateful to you, Ion, if you can find time to fix the problem after coming back.

@IonSwitz
Copy link
Member

I will try. In the mean while, if you wish to try something different, you can check out the FastStroke class. It doesnt make such nice joints between line segments, as it just creates rectangles for the lines, but it might help you if the joints look too bad. It should work very similar to the Stroke class.

However, it is much less used and might not work very well. It was one of my experiments at one point

Also, of course, that will not support the "postProcess" method

@alexeevilya
Copy link
Author

Thank you, Ion! That looks nice, but:

  1. It has same trouble with premultiplied alpha, as Stroke (issue Stroke with antialiasing has black edges #131);
  2. NOTE! This reduces the FPS to 45-50 frames!!! It looks, like SlowStroke, unfortunatelly ;((

..and what capacity is?Is it the number of lineTo()/moveTo() calls? Or lineTo() calls * 2?

@alexeevilya
Copy link
Author

Number one is fixed by change line 307 at FastStroke class:

RenderSupport.setBlendFactors(_material.premultipliedAlpha, this.blendMode == BlendMode.AUTO ? renderSupport.blendMode : this.blendMode);

but fps is bad (the fan on my laptop is working like crazy now)

@IonSwitz
Copy link
Member

Ok, thank you for trying that out at least.

@alexeevilya
Copy link
Author

Hmmm.. Maybe I'm doing something wrong again? If you call it fast, then is it probably really fast? ;)

@IonSwitz
Copy link
Member

I was hoping it would be faster in certain scenarios but it turned out it wasn't a whole lot better than the regular Stroke, except for some very specific cases. As I said, it was an experiment. Thanks for trying it out.

@alexeevilya
Copy link
Author

Don"t mention it! Thank YOU!
By the way, I found comparison of FastStroke, Stroke and 'StrokeGraphics' in #92 thread. What 'StrokeGraphics' is? Should I try it?

@IonSwitz
Copy link
Member

The "StrokeGraphics" mentioned is the Stroke you get when using the Shape.graphics API

So, no, it's not a separate class.

@alexeevilya
Copy link
Author

Hi Ion! Have you any news about our problem? Do you try to fix that?

@IonSwitz
Copy link
Member

No, sorry, I have no new ideas for a solution to this problem, except making a dynamic cleaning of the in-data points depending on the zoom value. When the view covers a large area of the map, fewer points should be needed in order to present a good line, and it should be possible to clean them up a bit in those scenarios

@alexeevilya
Copy link
Author

Thank you, IonSwitz! Yea, dynamic cleaning of the in-data points is a way to fix the problem and many cartografical tools uses simplification algorithms for that, but its reduce the performance itself (especially if uses in every frame actions such as follow-zoom animation) ;(

@IonSwitz
Copy link
Member

I have submitted some new code that will help you when scaling a Stroke.

when you scale the stroke, do this to maintain screen-relative stroke thickness:

this.scale = scaleValue;
stroke.scaleGeometry( scaleValue); // new method on Stroke class

Note: Combining this with adding new points to the Stroke during the same frame is a bit nasty, and should be avoided. If you generate your full Stroke once, and then just use this for scaling, it should work fine, and be relatively fast. Currently, it's probably a good idea to set the "scaleGeometry" to 1.0 before calling "lineTo" on the Stroke.

So, instead of having to re-add all stroke points ( "lineTo" ) to the Stroke when scaling, you can just do this extra call. It should be a lot faster than re-adding all stroke points, but it is still some math that has to be done. Please try it, if you are still using this functionality.

Also, I have added some fixes that improves the quality of drawing thick lines, so your sharp turns should look a lot better.

Also, as an experiment, I have added a method on Stroke allowing a "cullDistance". Basically, when a new point is added to the Stroke, it can be ignored if the cullDistance is higher than the distance from the last point. This is situationally good, I believe, but might not help you much, since you already do some "cleaning" of the point data sets

@alexeevilya
Copy link
Author

Thank you, IonSwitz!

Now I use the FastStroke in my app that gives me a satisfactory quality of visualization and performance. But it very good news! I'll try it and post here my experience soon. Thank you very much! ;)

@alexeevilya
Copy link
Author

IonSwitz, sorry that took so long to reply! I tried your new solution and want to tell you that it's very clean and good idea to transform existing geometry instead of create new. However, the problem with the artifacts in the Stroke class still remained in some cases, so I use the FastStroke class. I've added to it your adjustThicknessOfGeometry function and now it works faster in zoom animations. As for cullDistance functionality it would be nice if it were somehow integrated into the adjustThicknessOfGeometry func. Otherwise, I need to recreate all geometry again to use the 'cullDistance' (in zoom animations) instead of use adjustThicknessOfGeometry transformation. But I understand that this is not possible.

ps. Sorry for my eng, I hope you understand what I keep in mind ;)

@IonSwitz
Copy link
Member

Hello again. Yes, I understand how you mean, and don't worry about your English :)

I will look into such an integration, but I am not sure if it will be fully possible. Can I ask how many data points you have in your plots?`It sounds like there are quite many :)

@alexeevilya
Copy link
Author

Hello, IonSwitz! Thanx ;)
"How many data points...?" - Oh, this is a hard question. I have not so many data points. It sounds like one or two thousands. But the difficulty lies in the fact that I need to draw smooth curves (bezier). I tried to use the Loop-Blinn method (something like http://blog.bwhiting.co.uk/?p=423) and draw all in the fragment shader, but it has so many troubles... Now I use your curveTo() realization, adapted to FastStroke class - and this means that I need to have many straight segments to make a curve really smooths. So there are very many "data points" ;)

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

2 participants