WPF InkCanvas 访问笔划下的所有像素
WPF InkCanvas access all pixels under the strokes
WPF的InkCanvas
好像只能提供笔画的点(与笔画的宽高无关)。对于应用程序,我需要知道 InkCanvas
绘制的所有点。
例如,假设笔划的宽度和高度为 16。使用此笔划大小,我在 InkCanvas
上画了一个点。有没有一种简单的方法来获取这个点中的所有 256 个像素(而不是单独的这个巨点的中心点)?
我为什么关心:
在我的应用程序中,用户使用 InkCanvas
在显示一些 3D 对象的 Viewport3D
之上绘图。我想使用笔画的所有点进行光线投射,并确定 Viewport3D
中的哪些对象已被用户的笔画覆盖。
我发现了一种非常肮脏的处理方式。如果有人知道更好的方法,我将非常乐意投票并接受他们的回复作为答案。
基本上我的方法涉及获取每个笔划的 Geometry
,遍历该几何边界内的所有点并确定该点是否在几何内部。
这是我现在使用的代码:
foreach (var stroke in inkCanvas.Strokes)
{
List<Point> pointsInside = new List<Point>();
Geometry sketchGeo = stroke.GetGeometry();
Rect strokeBounds = sketchGeo.Bounds;
for (int x = (int)strokeBounds.TopLeft.X; x < (int)strokeBounds.TopRight.X + 1; x++)
for (int y = (int)strokeBounds.TopLeft.Y; y < (int)strokeBounds.BottomLeft.Y + 1; y++)
{
Point p = new Point(x, y);
if (sketchGeo.FillContains(p))
pointsInside.Add(p);
}
}
您可以使用 StrokeCollection 的 HitTest 方法。我将您的解决方案的性能与此实现进行了比较,发现 HitTest 方法的性能更好。您的里程等
// get our position on our parent.
var ul = TranslatePoint(new Point(0, 0), this.Parent as UIElement);
// get our area rect
var controlArea = new Rect(ul, new Point(ul.X + ActualWidth, ul.Y + ActualHeight));
// hit test for any strokes that have at least 5% of their length in our area
var strokes = _formInkCanvas.Strokes.HitTest(controlArea, 5);
if (strokes.Any())
{
// do something with this new knowledge
}
此外,如果你只关心任何点是否在你的矩形中,你可以使用下面的代码。它比 StrokeCollection.HitTest 快一个数量级,因为它不关心笔画的百分比,所以它做的工作少得多。
private bool StrokeHitTest(Rect bounds, StrokeCollection strokes)
{
for (int ix = 0; ix < strokes.Count; ix++)
{
var stroke = strokes[ix];
var stylusPoints = stroke.DrawingAttributes.FitToCurve ?
stroke.GetBezierStylusPoints() :
stroke.StylusPoints;
for (int i = 0; i < stylusPoints.Count; i++)
{
if (bounds.Contains((Point)stylusPoints[i]))
{
return true;
}
}
}
return false;
}
WPF的InkCanvas
好像只能提供笔画的点(与笔画的宽高无关)。对于应用程序,我需要知道 InkCanvas
绘制的所有点。
例如,假设笔划的宽度和高度为 16。使用此笔划大小,我在 InkCanvas
上画了一个点。有没有一种简单的方法来获取这个点中的所有 256 个像素(而不是单独的这个巨点的中心点)?
我为什么关心:
在我的应用程序中,用户使用 InkCanvas
在显示一些 3D 对象的 Viewport3D
之上绘图。我想使用笔画的所有点进行光线投射,并确定 Viewport3D
中的哪些对象已被用户的笔画覆盖。
我发现了一种非常肮脏的处理方式。如果有人知道更好的方法,我将非常乐意投票并接受他们的回复作为答案。
基本上我的方法涉及获取每个笔划的 Geometry
,遍历该几何边界内的所有点并确定该点是否在几何内部。
这是我现在使用的代码:
foreach (var stroke in inkCanvas.Strokes)
{
List<Point> pointsInside = new List<Point>();
Geometry sketchGeo = stroke.GetGeometry();
Rect strokeBounds = sketchGeo.Bounds;
for (int x = (int)strokeBounds.TopLeft.X; x < (int)strokeBounds.TopRight.X + 1; x++)
for (int y = (int)strokeBounds.TopLeft.Y; y < (int)strokeBounds.BottomLeft.Y + 1; y++)
{
Point p = new Point(x, y);
if (sketchGeo.FillContains(p))
pointsInside.Add(p);
}
}
您可以使用 StrokeCollection 的 HitTest 方法。我将您的解决方案的性能与此实现进行了比较,发现 HitTest 方法的性能更好。您的里程等
// get our position on our parent.
var ul = TranslatePoint(new Point(0, 0), this.Parent as UIElement);
// get our area rect
var controlArea = new Rect(ul, new Point(ul.X + ActualWidth, ul.Y + ActualHeight));
// hit test for any strokes that have at least 5% of their length in our area
var strokes = _formInkCanvas.Strokes.HitTest(controlArea, 5);
if (strokes.Any())
{
// do something with this new knowledge
}
此外,如果你只关心任何点是否在你的矩形中,你可以使用下面的代码。它比 StrokeCollection.HitTest 快一个数量级,因为它不关心笔画的百分比,所以它做的工作少得多。
private bool StrokeHitTest(Rect bounds, StrokeCollection strokes)
{
for (int ix = 0; ix < strokes.Count; ix++)
{
var stroke = strokes[ix];
var stylusPoints = stroke.DrawingAttributes.FitToCurve ?
stroke.GetBezierStylusPoints() :
stroke.StylusPoints;
for (int i = 0; i < stylusPoints.Count; i++)
{
if (bounds.Contains((Point)stylusPoints[i]))
{
return true;
}
}
}
return false;
}