我正在尝试使用WPF和画布实现捕捉网格。我在想我的数学是关闭的,因为UIElement不会在后台捕捉到网格。下面是我用来创建网格的xaml以及我用来尝试将UIElement捕捉到最近网格线的方法。一旦触发鼠标按钮事件,就会触发使用的方法。如果这不是正确的WPF方法,有人能指出我正确的方向吗?
XAML
<Border x:Name="dragBorder"
BorderBrush="Black"
BorderThickness="1"
Margin="5"
CornerRadius="3">
<Canvas x:Name="dragCanvas"
AllowDragging="true"
AllowDragOutOfView="False"
Height="{Binding ElementName=dragBorder, Path=ActualHeight}"
Width="{Binding ElementName=dragBorder, Path=ActualWidth}">
<Canvas.Background>
<VisualBrush TileMode="Tile"
Viewport="0,0,16,16"
ViewportUnits="Absolute"
Viewbox="0,0,16,16"
ViewboxUnits="Absolute">
<VisualBrush.Visual>
<Ellipse Fill="#FF000000"
Width="2"
Height="2" />
</VisualBrush.Visual>
</VisualBrush>
</Canvas.Background>
</Canvas>
</Border>
方法
private void SnapToGrid(UIElement element)
{
double xSnap = (Canvas.GetLeft(element) / gridWidth) * gridWidth;
double ySnap = (Canvas.GetTop(element) / gridWidth) * gridWidth;
Canvas.SetLeft(element, xSnap);
Canvas.SetTop(element, ySnap);
double tempX = Canvas.GetLeft(element);
double tempY = Canvas.GetTop(element);
}
答案 0 :(得分:7)
你的问题是你的功能实际上并没有做任何事情。你除以网格大小然后乘以网格大小,所以实际上你什么都不做(2 * 16/16 = 2)。您需要使用的是模%
运算符,并根据与网格大小的距离调整x / y位置。
这是一个工作函数,如果更靠近左/顶部网格线或向右/向下,则向左/向上捕捉:
private void SnapToGrid( UIElement element ) {
double xSnap = Canvas.GetLeft( element ) % GRID_SIZE;
double ySnap = Canvas.GetTop( element ) % GRID_SIZE;
// If it's less than half the grid size, snap left/up
// (by subtracting the remainder),
// otherwise move it the remaining distance of the grid size right/down
// (by adding the remaining distance to the next grid point).
if( xSnap <= GRID_SIZE / 2.0 )
xSnap *= -1;
else
xSnap = GRID_SIZE - xSnap;
if( ySnap <= GRID_SIZE / 2.0 )
ySnap *= -1;
else
ySnap = GRID_SIZE - ySnap;
xSnap += Canvas.GetLeft( element );
ySnap += Canvas.GetTop( element );
Canvas.SetLeft( element, xSnap );
Canvas.SetTop( element, ySnap );
}
答案 1 :(得分:1)
Canvas.GetLeft(element)
将返回一个double,因此即使gridWidth
是一个整数,它将进行双重算术,并且除法和乘法会或多或少地抵消掉。我想你想做一个:
double xSnap = Math.Floor(Canvas.GetLeft(element) / gridWidth) * gridWidth;
double xSnap = Math.Ceiling(Canvas.GetLeft(element) / gridWidth) * gridWidth;
double xSnap = Math.Round(Canvas.GetLeft(element) / gridWidth) * gridWidth;
这些会将除法结果舍入为整数并返回gridWidth的倍数。
答案 2 :(得分:0)
我们的想法是确保任何物体的位置都限制在一定数量的范围内;即,最终位置应该是圆形的并且落在该组内。
该集合包含任意数字的所有因子j
; j
控制“snap”的强度,并确定哪些数字出现在集合中。同样,新位置必须只包含出现在集合中的数字。
例如,假设对象的原始位置为(5, 0)
,我们希望将其移至(16, 23)
。让我们继续并快速点击 5 :这意味着对象的位置可能只包含 5 因子。原来的位置已经落在这个位置,但新的位置没有。
为了模拟“捕捉”,新位置必须落在(15,20)
或(20, 25)
上。找到最近的因子 16 和 23 ,将为您提供正确的观点。在大多数情况下,有必要对结果进行舍入。
示例强>
//Get original point of object relative to container element
var original_point = e.GetPosition(sender);
//Calculate new x and y position based on mouse
//var new_x = ...
//var new_y = ...
//New position must be multiple of 8
var snap = 8;
//Get nearest factor of result position
new_x = original_point.X.NearestFactor(snap);
new_y = original_point.Y.NearestFactor(snap);
public static double NearestFactor(this double Value, double Factor)
{
return Math.Round((Value / Factor), MidpointRounding.AwayFromZero) * Factor;
}
不言而喻,在调整对象大小时也可以使用此算法,以确保对象的位置和大小“快照”。