Paths

Aug 2, 2011 at 9:58 AM
Edited Aug 2, 2011 at 10:10 AM

Hi Nich

Do you have anything for paths or is it only polygons? Like:

 

 <Path Data="M0,0 L164,0 164,10.312289 161.38177,10.478208 C80.867546,16.604429 16.604429,80.867546 10.478208,161.38177 L10.312289,164 0,164 z" Fill="Red" Height="164" Canvas.Left="0" Stretch="Fill" Canvas.Top="0" Width="164" >
        <Physics:PhysicalBox.Body>
                <Physics:PhysicalBody IgnoreGravity="True" IsStatic="True">    
                	<Physics:PhysicalBody.Geometries>
                		<Physics:PolygonGeometry RestitutionCoefficient="0.7"    />     			
			</Physics:PhysicalBody.Geometries>    
		</Physics:PhysicalBody>    	
	</Physics:PhysicalBox.Body>
</Path>
Coordinator
Aug 3, 2011 at 12:31 AM

There is no support for paths, just polygons. If you can point me to a resource on how to parse the data of a path I might be able to add support for it.

But it's possible to do something like this.

<Path Data="M0,0 L164,0 164,10.312289 161.38177,10.478208 C80.867546,16.604429 16.604429,80.867546 10.478208,161.38177 L10.312289,164 0,164 z" Fill="Red" Height="164" Canvas.Left="0" Stretch="Fill" Canvas.Top="0" Width="164" >
    <physics:PhysicalBox.Body>
        <physics:PhysicalBody IgnoreGravity="True" IsStatic="True">
            <physics:PhysicalBody.Geometries>
                <physics:PolygonGeometry Points="0,0, 165,0, 165,10" RestitutionCoefficient="0.7" />
            </physics:PhysicalBody.Geometries>
        </physics:PhysicalBody>
    </physics:PhysicalBox.Body>
</Path>

And roughly follow the outline of the path with the points.

But this highlights another issue. Polygons have to be convex. The path in your example is concave. So even if you write out points for that path it will still not work.

Fortunately the Farseer Physics engine does have decomposition built into it that can convert a concave polygon into more then one convex polygons. I've wanted to add support for it into Xaml Physics for a while but it raises some issues. The PollygonGeometry can only have one polygon so it can't be doing the decomposition. The PolygonBody could do it and add it's child PollygonGeometry collection at run time but that prevents you from setting the RestitutionCoefficient like you are in the example. I've been thinking about combining all the body and geometry classes anyway but I haven't really sat down to think about the consequences of that. I'm talking about changing the above example so it would be written like this.

<Path Data="M0,0 L164,0 164,10.312289 161.38177,10.478208 C80.867546,16.604429 16.604429,80.867546 10.478208,161.38177 L10.312289,164 0,164 z" Fill="Red" Height="164" Canvas.Left="0" Stretch="Fill" Canvas.Top="0" Width="164" >
    <physics:PhysicalBox.Body>
        <physics:PolygonBody Points="0,0, 165,0, 165,10" RestitutionCoefficient="0.7" IgnoreGravity="True" IsStatic="True" />
    </physics:PhysicalBox.Body>
</Path>

Essentially all the geometry classes would be gone and their properties merged into the body classes. That would make automatic decomposition possible. What do you think of that idea?

Right now the only way to do what you are trying is to make many PolygonGeomerty objects and make sure each is convex. Something like this.

<Path Data="M0,0 L164,0 164,10.312289 161.38177,10.478208 C80.867546,16.604429 16.604429,80.867546 10.478208,161.38177 L10.312289,164 0,164 z" Fill="Red" Height="164" Canvas.Left="0" Stretch="Fill" Canvas.Top="0" Width="164" >
    <physics:PhysicalBox.Body>
        <physics:PolygonBody IgnoreGravity="True" IsStatic="True">
            <physics:PhysicalBody.Geometries>
                <physics:PolygonGeometry Points="0,0, 165,0, 165,10" RestitutionCoefficient="0.7" />
                <physics:PolygonGeometry Points="0,0, 165,0, 165,10" RestitutionCoefficient="0.7" />
                <physics:PolygonGeometry Points="0,0, 165,0, 165,10" RestitutionCoefficient="0.7" />
                <physics:PolygonGeometry Points="0,0, 165,0, 165,10" RestitutionCoefficient="0.7" />
                ...
            </physics:PhysicalBody.Geometries>
        </physics:PhysicalBody>
    </physics:PhysicalBox.Body>
</Path>

I realize that it a big pain. I'm just not sure what to do about it.

Aug 3, 2011 at 9:04 AM
Edited Aug 3, 2011 at 12:03 PM

Yeah, I had a feeling this would be quite problematic. I have a 3D background, and converting beziers, paths and Nurbs to polygons is always an issue, because of the many parameters required for a more or less generic solution. Before switching to XAML Physics I used the Physics Helper Library in .NET 3.5, that have support for paths. But I dont know exactly how they interact with the Farseer Path detection algorithm.

They did merge all geometry-classes together, because they support bounding-objects. I've always found that rather silly - why use two pieces of geometry? I know performance can be an issue, why a lower resolution on bounding objects can really optimize the overall experience, but computers today are rather quick. But again they focus on Silverlight and WP7... i reckon that if no bounding-object is specified all geometry is parsed through the path detection algorithm - even if it's a primitive shape.

I reckon you know all about the Physics Helper Library, but here's a tutorial that shows their behaviours and path-alteration for inspiration:

http://channel9.msdn.com/coding4fun/articles/Creating-a-Pinball-Game-in-Silverlight-Using-the-Physics-Helper-Library--Farseer-Physics

On another note: I know a lot focusses on a shape being concave or convex. That is actually not the problem. It is the complexity of it. My path above could easily be parsed by a convex algorithm correctly, as it is a closed shape with linear angles (all vertexes within sight). If it had a hole in the middle, that COULD cause some overlapping triangulations, but it is not given, it depends on how smart the algorithm is, and which method(s) it uses. Take a look on the ear clipping algorithm and Bayazit in Farseer:

http://farseerphysics.codeplex.com/documentation

Right here and now I just created a polygon behind the path... But it makes the app go crazy. After two seconds all non-static objects are removed from the screen.

 

<Polygon Points="0,0 0,164 10,164 12,148 15,133 21,115 27,101 33,90 41,78 48,69 58,58 69,48 78,41 90,33 101,27 115,21 133,15 148,12 164,10 164,0"
         Fill="Yellow" >
                    <Physics:PhysicalBox.Body>
                        <Physics:PolygonBody IgnoreGravity="True" IsStatic="True">
                            <Physics:PhysicalBody.Geometries>
                                <Physics:PolygonGeometry RestitutionCoefficient="0.7" />

                            </Physics:PhysicalBody.Geometries>
                        </Physics:PolygonBody>
                     </Physics:PhysicalBox.Body>
</Polygon>

Also if I make the polygon more simple like

Points="0,0 0,164 10,164 164,10 164,0"
Coordinator
Aug 3, 2011 at 9:33 PM

There are a few things going wrong here.

First. you discovered another difference between Silverlight and WPF. In Silverlight when you don't set Canvas.Left and later call Canvas.GetLeft(Element) you get 0. In WPF you get -1.#IND which doesn't work so well. If you add Canvas.Left="0" Canvas.Right="0" it will fix this problem. I'll also be checking in some code to handle this better shortly.

Second, the points are listed counterclockwise (when Y points down). Reversing the second list of points them fixes.

Last, the first list of points is concave. If you correct the first problem and reverse the points like this

Points="164,0 164,10 148,12 133,15 115,21 101,27 90,33 78,41 69,48 58,58 48,69 41,78 33,90 27,101 21,115 15,133 12,148 10,164 0,164 0,0"

the simulation will mostly work but the edge direction on the curved surface doesn't work very well.

Like I said, this is something I want to fix but I just don't know how to restructure Xaml Physics to make it work yet. Here is a temporary fix for you. Inside of PolygonBody is a condition 

If Geometries.Count = 0 Then

If you replace the code in the condition with this it will decompose the points into more then one polygon.

 

Dim PhysicalPoints As New List(Of Microsoft.Xna.Framework.Vector2)
For Each Point In Points
    PhysicalPoints.Add(New Microsoft.Xna.Framework.Vector2(Point.X, Point.Y))
Next
        
Dim Vertices As New FarseerPhysics.Common.Vertices(PhysicalPoints.ToArray)
Dim Polygons = FarseerPhysics.Common.Decomposition.EarclipDecomposer.ConvexPartition(Vertices)
            
For Each Poly In Polygons
    Dim Geom As New PolygonGeometry
    For Each Vertex In Poly
        Geom.Points.Add(New Point(Vertex.X, Vertex.Y))
    Next
    Geometries.Add(Geom)
Next

Then you will have to remove the PolygonGeomtery from the xaml and let the PolygonBody build the collection for you. This has the added benefit of correcting the order of the points so that they are clockwise. That does mean you can't set the RestitutionCoefficient, but you could copy that property to PhysicalBody and then copy the value to each PolygonGeomtery created in that for loop. Or change the default value. I realize none of these options are ideal but they are short term solutions.