It is currently March 29th, 2024, 7:37 am

Shape meter Path problem

Report bugs with the Rainmeter application and suggest features.
User avatar
balala
Rainmeter Sage
Posts: 16110
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

Shape meter Path problem

Post by balala »

Hello everybody,

A few days ago when I wanted to draw a mouth with Shape meters, I faced a problem which I couldn't figure out how to fix. So I came and posted a question into the Help: Rainmeter Skins section. Finally got two smart solutions, one from ikarus1969 and another from Yincognito. There might be a bug, at least this is our opinion, however I'm not sure. Devs should take a look I suppose and tell what's going on.
So I did draw a mouth with Path. But got a line which in my opinion (and others as well) should not be there. Here is the description of the problem: https://forum.rainmeter.net/viewtopic.php?f=5&t=37644#p191410
Am I missing something or there indeed is a little inadvertence?
As usually, thank for the help.
User avatar
Brian
Developer
Posts: 2674
Joined: November 24th, 2011, 1:42 am
Location: Utah

Re: Shape meter Path problem

Post by Brian »

This is caused by the "miter" corner limit of joined stroke lines. Different types of joined lines can fix this, or just using a "limit" of 0.
https://docs.rainmeter.net/manual-beta/meters/shape/#StrokeLineJoin

Here is some examples:

"Miter" limit is 0:

Code: Select all

[Rainmeter]
Update=-1
BackgroundMode=2
SolidColor=220,220,220
SkinWidth=140
SkinHeight=200

[MeterMouth1]
Meter=Shape
X=0
Y=0

Shape=Path MyPath | StrokeWidth 2 | Stroke Color 0,0,0 | Fill Color 255,255,255 | StrokeLineJoin Miter,0
MyPath=10,65 | ArcTo 130,65,60,20,0,1,0 | ArcTo 10,65,60,80,1,0,0
Using a different line join: (you can use "Bevel" as well)

Code: Select all

[Rainmeter]
Update=-1
BackgroundMode=2
SolidColor=220,220,220
SkinWidth=140
SkinHeight=200

[MeterMouth1]
Meter=Shape
X=0
Y=0

Shape=Path MyPath | StrokeWidth 2 | Stroke Color 0,0,0 | Fill Color 255,255,255 | StrokeLineJoin Round
MyPath=10,65 | ArcTo 130,65,60,20,0,1,0 | ArcTo 10,65,60,80,1,0,0
You can also "force" a round line join within the path:

Code: Select all

[Rainmeter]
Update=-1
BackgroundMode=2
SolidColor=220,220,220
SkinWidth=140
SkinHeight=200

[MeterMouth1]
Meter=Shape
X=0
Y=0

Shape=Path MyPath | StrokeWidth 2 | Stroke Color 0,0,0 | Fill Color 255,255,255
MyPath=10,65 | SetRoundJoin 1 | ArcTo 130,65,60,20,0,1,0 | ArcTo 10,65,60,80,1,0,0
-Brian
User avatar
balala
Rainmeter Sage
Posts: 16110
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

Re: Shape meter Path problem

Post by balala »

Brian wrote: June 9th, 2021, 12:56 pm This is caused by the "miter" corner limit of joined stroke lines. Different types of joined lines can fix this, or just using a "limit" of 0.
https://docs.rainmeter.net/manual-beta/meters/shape/#StrokeLineJoin

Here is some examples:

"Miter" limit is 0:

Code: Select all

[Rainmeter]
Update=-1
BackgroundMode=2
SolidColor=220,220,220
SkinWidth=140
SkinHeight=200

[MeterMouth1]
Meter=Shape
X=0
Y=0

Shape=Path MyPath | StrokeWidth 2 | Stroke Color 0,0,0 | Fill Color 255,255,255 | StrokeLineJoin Miter,0
MyPath=10,65 | ArcTo 130,65,60,20,0,1,0 | ArcTo 10,65,60,80,1,0,0
Using a different line join: (you can use "Bevel" as well)

Code: Select all

[Rainmeter]
Update=-1
BackgroundMode=2
SolidColor=220,220,220
SkinWidth=140
SkinHeight=200

[MeterMouth1]
Meter=Shape
X=0
Y=0

Shape=Path MyPath | StrokeWidth 2 | Stroke Color 0,0,0 | Fill Color 255,255,255 | StrokeLineJoin Round
MyPath=10,65 | ArcTo 130,65,60,20,0,1,0 | ArcTo 10,65,60,80,1,0,0
You can also "force" a round line join within the path:

Code: Select all

[Rainmeter]
Update=-1
BackgroundMode=2
SolidColor=220,220,220
SkinWidth=140
SkinHeight=200

[MeterMouth1]
Meter=Shape
X=0
Y=0

Shape=Path MyPath | StrokeWidth 2 | Stroke Color 0,0,0 | Fill Color 255,255,255
MyPath=10,65 | SetRoundJoin 1 | ArcTo 130,65,60,20,0,1,0 | ArcTo 10,65,60,80,1,0,0
-Brian
Ok, thanks for the details. This in fact is the same as what ikarus1969 has proposed, so this will I use.
Thanks again. :great:
User avatar
Yincognito
Rainmeter Sage
Posts: 7029
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Shape meter Path problem

Post by Yincognito »

EDIT: Disregard the below, closing the paths makes all workarounds (bar my first one) work. The open path was present ever since the initial version of the OP's code.
Brian wrote: June 9th, 2021, 12:56 pmThis is caused by the "miter" corner limit of joined stroke lines. Different types of joined lines can fix this, or just using a "limit" of 0.
Sorry, Brian, this is not going to cut it - the issue is not fixed, it's just a workaround that partially alleviates the problem. All workarounds STILL produce artefacts in terms of symmetry, for higher stroke widths (thus, the bug exists, and is NOT fixed). These are the workarounds that have been proposed so far by me, ikarus1969 and you (I drew a line to better see the obvious - scroll to change the stroke width; only the last attempt / meter that I talked about here - check the bold parts - fixes the symmetry issue completely):

Code: Select all

[Variables]
StrokeWidth=10

[Rainmeter]
Update=-1
DynamicWindowSize=1
AccurateText=1

[Background]
Meter=Image
W=1000
H=200
SolidColor=220,220,220
MouseScrollUpAction=[!SetVariable StrokeWidth (#StrokeWidth#+1)][!UpdateMeter *][!Redraw]
MouseScrollDownAction=[!SetVariable StrokeWidth (#StrokeWidth#-1)][!UpdateMeter *][!Redraw]
DynamicVariables=1

[MeterMouth_Yincognito]
Meter=Shape
X=0
Shape=Path MyPath | StrokeWidth #StrokeWidth# | Stroke Color 0,0,0 | Fill Color 255,255,255
MyPath=10,65 | ArcTo 130,65,60,20,0,1,0 | LineTo 130,65 | ArcTo 10,65,60,80,0,0,0
DynamicVariables=1

[MeterMouth_ikarus1969]
Meter=Shape
X=10R
Shape=Path MyPath | StrokeWidth #StrokeWidth# | Stroke Color 0,0,0 | Fill Color 255,255,255 | StrokeLineJoin Round
MyPath=10,65 | ArcTo 130,65,60,20,0,1,0 | ArcTo 10,65,60,80,1,0,0
DynamicVariables=1

[MeterMouth_Brian_Miter]
Meter=Shape
X=10R
Shape=Path MyPath | StrokeWidth #StrokeWidth# | Stroke Color 0,0,0 | Fill Color 255,255,255 | StrokeLineJoin Miter,0
MyPath=10,65 | ArcTo 130,65,60,20,0,1,0 | ArcTo 10,65,60,80,1,0,0
DynamicVariables=1

[MeterMouth_Brian_Bevel]
Meter=Shape
X=10R
Shape=Path MyPath | StrokeWidth #StrokeWidth# | Stroke Color 0,0,0 | Fill Color 255,255,255 | StrokeLineJoin Round
MyPath=10,65 | ArcTo 130,65,60,20,0,1,0 | ArcTo 10,65,60,80,1,0,0
DynamicVariables=1

[MeterMouth_Brian_Round]
Meter=Shape
X=10R
Shape=Path MyPath | StrokeWidth #StrokeWidth# | Stroke Color 0,0,0 | Fill Color 255,255,255
MyPath=10,65 | SetRoundJoin 1 | ArcTo 130,65,60,20,0,1,0 | ArcTo 10,65,60,80,1,0,0
DynamicVariables=1

[MeterMouth_Yincognito_TrueFix]
Meter=Shape
X=10R
Shape=Ellipse 70,65,60,80 | StrokeWidth #StrokeWidth# | Stroke Color 0,0,0 | Fill Color 255,255,255 | StrokeLineJoin Round
Shape2=Ellipse 70,0,100,85
Shape3=Combine Shape | Exclude Shape2
DynamicVariables=1

[Line]
Meter=Shape
Shape=Line 0,65,1000,65 | StrokeWidth 1 | Stroke Color 255,0,0,255
DynamicVariables=1
Comparison.jpg
You do not have the required permissions to view the files attached to this post.
Last edited by Yincognito on June 9th, 2021, 4:13 pm, edited 1 time in total.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
User avatar
death.crafter
Rainmeter Sage
Posts: 1399
Joined: April 24th, 2021, 8:13 pm

Re: Shape meter Path problem

Post by death.crafter »

Yincognito wrote: June 9th, 2021, 3:35 pm Sorry, Brian, this is not going to cut it - the issue is not fixed, it's just a workaround that partially alleviates the problem. All workarounds STILL produce artefacts in terms of symmetry, for higher stroke widths (thus, the bug exists, and is NOT fixed). These are the workarounds that have been proposed so far by me, ikarus1969 and you (I drew a line to better see the obvious - scroll to change the stroke width; only the last attempt / meter that I talked about here - check the bold parts - fixes the symmetry issue completely):

Code: Select all

[Variables]
StrokeWidth=10

[Rainmeter]
Update=-1
DynamicWindowSize=1
AccurateText=1

[Background]
Meter=Image
W=1000
H=200
SolidColor=220,220,220
MouseScrollUpAction=[!SetVariable StrokeWidth (#StrokeWidth#+1)][!UpdateMeter *][!Redraw]
MouseScrollDownAction=[!SetVariable StrokeWidth (#StrokeWidth#-1)][!UpdateMeter *][!Redraw]
DynamicVariables=1

[MeterMouth_Yincognito]
Meter=Shape
X=0
Shape=Path MyPath | StrokeWidth #StrokeWidth# | Stroke Color 0,0,0 | Fill Color 255,255,255
MyPath=10,65 | ArcTo 130,65,60,20,0,1,0 | LineTo 130,65 | ArcTo 10,65,60,80,0,0,0
DynamicVariables=1

[MeterMouth_ikarus1969]
Meter=Shape
X=10R
Shape=Path MyPath | StrokeWidth #StrokeWidth# | Stroke Color 0,0,0 | Fill Color 255,255,255 | StrokeLineJoin Round
MyPath=10,65 | ArcTo 130,65,60,20,0,1,0 | ArcTo 10,65,60,80,1,0,0
DynamicVariables=1

[MeterMouth_Brian_Miter]
Meter=Shape
X=10R
Shape=Path MyPath | StrokeWidth #StrokeWidth# | Stroke Color 0,0,0 | Fill Color 255,255,255 | StrokeLineJoin Miter,0
MyPath=10,65 | ArcTo 130,65,60,20,0,1,0 | ArcTo 10,65,60,80,1,0,0
DynamicVariables=1

[MeterMouth_Brian_Bevel]
Meter=Shape
X=10R
Shape=Path MyPath | StrokeWidth #StrokeWidth# | Stroke Color 0,0,0 | Fill Color 255,255,255 | StrokeLineJoin Round
MyPath=10,65 | ArcTo 130,65,60,20,0,1,0 | ArcTo 10,65,60,80,1,0,0
DynamicVariables=1

[MeterMouth_Brian_Round]
Meter=Shape
X=10R
Shape=Path MyPath | StrokeWidth #StrokeWidth# | Stroke Color 0,0,0 | Fill Color 255,255,255
MyPath=10,65 | SetRoundJoin 1 | ArcTo 130,65,60,20,0,1,0 | ArcTo 10,65,60,80,1,0,0
DynamicVariables=1

[MeterMouth_Yincognito_TrueFix]
Meter=Shape
X=10R
Shape=Ellipse 70,65,60,80 | StrokeWidth #StrokeWidth# | Stroke Color 0,0,0 | Fill Color 255,255,255 | StrokeLineJoin Round
Shape2=Ellipse 70,0,100,85
Shape3=Combine Shape | Exclude Shape2
DynamicVariables=1

[Line]
Meter=Shape
Shape=Line 0,65,1000,65 | StrokeWidth 1 | Stroke Color 255,0,0,255
DynamicVariables=1
Comparison.jpg
You forgot to close the path with ClosePath 1
from the Realm of Death
User avatar
Yincognito
Rainmeter Sage
Posts: 7029
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Shape meter Path problem

Post by Yincognito »

death.crafter wrote: June 9th, 2021, 3:51 pm You forgot to close the path with ClosePath 1
Damn, you're right - now it's all good, only my 1st workaround fails. I take back what I said earlier. :oops:
Comparison II.jpg
That being said, the open path was not my mistake (I actually always look to close paths in my codes) - it was present in the original code and somehow propagated even to Brian's examples... O.O
You do not have the required permissions to view the files attached to this post.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
User avatar
Brian
Developer
Posts: 2674
Joined: November 24th, 2011, 1:42 am
Location: Utah

Re: Shape meter Path problem

Post by Brian »

Another thing to keep in mind is that the Shape meter uses DIP's, or "device independent pixels", rather than exact integer pixel coordinates. Well technically all of D2D uses DIP's, but in Rainmeter, the Shape meter is the only meter that allows the use of fractional DIP's within the meter definition itself.

https://docs.rainmeter.net/manual/meters/shape/#DeviceIndependentPixels

What this means is complex shapes (like the ones using arcs and curves) might not intersect the exact coordinate defined by the Shape. There might be 0.000000001 or more difference to where the line is actually drawn. Most of the time D2D figures it out without help, but in this particular case, changing the miter cornering limit was the key (or just changing the type of line join).

Here is some more information on these stroke properties:
https://docs.microsoft.com/en-us/windows/win32/api/d2d1/ns-d2d1-d2d1_stroke_style_properties - specifically the "miterLimit" parameter.
https://docs.microsoft.com/en-us/windows/win32/api/d2d1/ne-d2d1-d2d1_line_join#remarks
https://docs.microsoft.com/en-us/windows/win32/api/d2d1/nf-d2d1-id2d1strokestyle-getmiterlimit#return-value - specifically the "return" value portion. This is the best description of the miter limit I could find in the official MS docs.

Note: I had a mistake in my example of using a miter limit of 0. The minimum is 1.0. Rainmeter accepts anything over 0, but D2D obviously treats anything between 0 and 1 as 1.



It is also worth noting the using ClosePath 1 changes things as well. Obviously, this closes the path by drawing a line from the last position to the first position, but it also still follows the line joining rules. Hence the sharp corners. Honestly, with a small stroke width, a round line join is probably best to avoid these issues.

I left out the ClosePath 1 option since it wasn't used in the post I was looking at, although I should have read a bit more closely at the other posts. To be honest with you, ClosePath 1 should probably be used every time there is a fill on the shape.

-Brian
User avatar
Yincognito
Rainmeter Sage
Posts: 7029
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Shape meter Path problem

Post by Yincognito »

Brian wrote: June 9th, 2021, 5:56 pmWhat this means is complex shapes (like the ones using arcs and curves) might not intersect the exact coordinate defined by the Shape. There might be 0.000000001 or more difference to where the line is actually drawn.
Yeah, that was the thing I alluded to in my final workaround post as well, albeit not in such a technical and professional way as you did. ;-)
Brian wrote: June 9th, 2021, 5:56 pmTo be honest with you, ClosePath 1 should probably be used every time there is a fill on the shape.
Indeed - I surely do, usually. Can't believe I missed it when later working with the code - I guess I was thinking that balala posted the issue and I wouldn't have to double check everything. Fortunately, death.crafter's cool head helped in noticing the missing piece here. All in all, it's both the miter / bevel / round join parameters AND closing the path that fully fix the issue. In the end, it wasn't an actual issue or a bug, but rather some little known detail regarding shape intersections - maybe a small note in the manual about it would be useful.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth