Reputation: 429
I need to determine the intersection of objects moving on the canvas (not necessarily on the canvas, any other panel).
I'm trying to determine the intersection with FillContainsWithDetail. It seems that the intersection ignores the relative location of objects.
XAML:
<Window x:Class="WpfCollisionTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCollisionTest"
Title="Collisions" Height="400" Width="500">
<Window.DataContext>
<local:CProvider x:Name="Provider"/>
</Window.DataContext>
<Window.Resources>
<PathGeometry x:Key="geoPoly">
<PathGeometry.Figures>
<PathFigure StartPoint="0,0" IsClosed="True">
<PolyLineSegment Points="0,0 50,0 50,50 0,50"/>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Window.Resources>
<Grid>
<Canvas Background="White" MouseMove="Canvas_OnMouseMove">
<Path Name="rectangle1" Data="{StaticResource geoPoly}" Stroke="Black"
Canvas.Left="175" Canvas.Top="100"/>
<Path Name="rectangle2" Data="{StaticResource geoPoly}" Stroke="Black"
Canvas.Left="{Binding rectLeft}" Canvas.Top="{Binding rectTop}"/>
</Canvas>
<TextBlock Text="{Binding intersectionDetail}" VerticalAlignment="Bottom"/>
</Grid>
CS:
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace WpfCollisionTest
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private void Canvas_OnMouseMove(object sender, MouseEventArgs e)
{
var pos = e.GetPosition(sender as FrameworkElement);
Provider.rectLeft = pos.X;
Provider.rectTop = pos.Y;
var g1 = rectangle1.RenderedGeometry.GetFlattenedPathGeometry();
var g2 = rectangle2.RenderedGeometry.GetFlattenedPathGeometry();
var intersect = g1.FillContainsWithDetail(g2);
Provider.intersectionDetail = intersect.ToString();
}
}
}
In this example result is always: Intersects.
What am I missing?
Upvotes: 0
Views: 2205
Reputation: 59
Recently I have had to deal with the same problem. So,
We need a method that extracts all transformations from the source object. In my application, I use only RenderTransform in Canvas. Also, make sure that this transform is applied before TranslateTransform with Canvas.Top and Canvas.Left parameters:
private static Transform GetFullTransform(UIElement e)
{
// The order in which transforms are applied is important!
var transforms = new TransformGroup();
if(e.RenderTransform != null)
transforms.Children.Add(e.RenderTransform);
var xTranslate = (double)e.GetValue(Canvas.LeftProperty);
if (double.IsNaN(xTranslate))
xTranslate = 0D;
var yTranslate = (double)e.GetValue(Canvas.TopProperty);
if (double.IsNaN(yTranslate))
yTranslate = 0D;
var translateTransform = new TranslateTransform(xTranslate, yTranslate);
transforms.Children.Add(translateTransform);
return transforms;
}
Introduce a method that converts a given object to a Geometry. Here for demonstration purpose, I convert a Shape object:
public Geometry GetGeometry(Shape s)
{
var g = s.RenderedGeometry.Clone();
g.Transform = GetFullTransform(s);
return g;
}
And finally, use FillContainsWithDetail method. The condition below returns True in 2 cases: when there is an intersection, or when one of the geometries is completely inside another:
private static bool HasIntersection(Geometry g1, Geometry g2) =>
g1.FillContainsWithDetail(g2) != IntersectionDetail.Empty;
Upvotes: 2