add:直线拉直与端点吸附
This commit is contained in:
@@ -389,10 +389,11 @@
|
||||
<TextBlock Foreground="#fafafa" Text="屏蔽压感" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchDisablePressure"
|
||||
IsOn="False" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchDisablePressure_Toggled" />
|
||||
</ui:SimpleStackPanel>
|
||||
<TextBlock Text="# 开启后,将忽略所有设备的压感信息,使所有笔画具有统一的粗细。与压感触屏模式互斥。" TextWrapping="Wrap" Foreground="#a1a1aa" />
|
||||
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<TextBlock Foreground="#fafafa" Text="橡皮大小" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
@@ -569,7 +570,46 @@
|
||||
</CheckBox>
|
||||
</ui:SimpleStackPanel>
|
||||
</ui:SimpleStackPanel>
|
||||
|
||||
<Line HorizontalAlignment="Center" X1="0" Y1="0" X2="400" Y2="0"
|
||||
Stroke="#3f3f46" StrokeThickness="1" Margin="0,4,0,4" />
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<TextBlock Foreground="#fafafa" Text="直线自动拉直" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchAutoStraightenLine"
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchAutoStraightenLine_Toggled" />
|
||||
</ui:SimpleStackPanel>
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left"
|
||||
Visibility="{Binding ElementName=ToggleSwitchAutoStraightenLine, Path=IsOn, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<TextBlock Foreground="#fafafa" Text="长度阈值" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
<Slider Name="AutoStraightenLineThresholdSlider" Width="150" Minimum="30" Maximum="300"
|
||||
Value="30" TickFrequency="30" IsSnapToTickEnabled="True"
|
||||
ValueChanged="AutoStraightenLineThresholdSlider_ValueChanged" />
|
||||
<TextBlock Foreground="#fafafa" Text="{Binding ElementName=AutoStraightenLineThresholdSlider, Path=Value, StringFormat={}{0:0}}"
|
||||
VerticalAlignment="Center" FontSize="14" Margin="16,0,0,0" />
|
||||
</ui:SimpleStackPanel>
|
||||
<TextBlock Text="# 开启后,当绘制的直线超过设定长度阈值时,将自动调整为完美直线。" TextWrapping="Wrap" Foreground="#a1a1aa" />
|
||||
<Line HorizontalAlignment="Center" X1="0" Y1="0" X2="400" Y2="0"
|
||||
Stroke="#3f3f46" StrokeThickness="1" Margin="0,4,0,4" />
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<TextBlock Foreground="#fafafa" Text="直线端点吸附" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchLineEndpointSnapping"
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchLineEndpointSnapping_Toggled" />
|
||||
</ui:SimpleStackPanel>
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left"
|
||||
Visibility="{Binding ElementName=ToggleSwitchLineEndpointSnapping, Path=IsOn, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<TextBlock Foreground="#fafafa" Text="吸附距离" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
<Slider Name="LineEndpointSnappingThresholdSlider" Width="150" Minimum="5" Maximum="50"
|
||||
Value="15" TickFrequency="5" IsSnapToTickEnabled="True"
|
||||
ValueChanged="LineEndpointSnappingThresholdSlider_ValueChanged" />
|
||||
<TextBlock Foreground="#fafafa" Text="{Binding ElementName=LineEndpointSnappingThresholdSlider, Path=Value, StringFormat={}{0:0}}"
|
||||
VerticalAlignment="Center" FontSize="14" Margin="16,0,0,0" />
|
||||
</ui:SimpleStackPanel>
|
||||
<TextBlock Text="# 开启后,当绘制的直线端点靠近其他直线端点时,将自动吸附连接。" TextWrapping="Wrap" Foreground="#a1a1aa" />
|
||||
</ui:SimpleStackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Name="GroupBoxAppearanceNewUI">
|
||||
|
||||
@@ -722,6 +722,34 @@ namespace Ink_Canvas {
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void ToggleSwitchAutoStraightenLine_Toggled(object sender, RoutedEventArgs e) {
|
||||
if (!isLoaded) return;
|
||||
|
||||
Settings.Canvas.AutoStraightenLine = ToggleSwitchAutoStraightenLine.IsOn;
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void AutoStraightenLineThresholdSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) {
|
||||
if (!isLoaded) return;
|
||||
|
||||
Settings.Canvas.AutoStraightenLineThreshold = (int)e.NewValue;
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void ToggleSwitchLineEndpointSnapping_Toggled(object sender, RoutedEventArgs e) {
|
||||
if (!isLoaded) return;
|
||||
|
||||
Settings.Canvas.LineEndpointSnapping = ToggleSwitchLineEndpointSnapping.IsOn;
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void LineEndpointSnappingThresholdSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) {
|
||||
if (!isLoaded) return;
|
||||
|
||||
Settings.Canvas.LineEndpointSnappingThreshold = (int)e.NewValue;
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Canvas
|
||||
@@ -1477,6 +1505,10 @@ namespace Ink_Canvas {
|
||||
Settings.Canvas.FitToCurve = true;
|
||||
Settings.Canvas.EnablePressureTouchMode = false;
|
||||
Settings.Canvas.DisablePressure = false;
|
||||
Settings.Canvas.AutoStraightenLine = true;
|
||||
Settings.Canvas.AutoStraightenLineThreshold = 30;
|
||||
Settings.Canvas.LineEndpointSnapping = true;
|
||||
Settings.Canvas.LineEndpointSnappingThreshold = 15;
|
||||
Settings.Canvas.UsingWhiteboard = false;
|
||||
Settings.Canvas.HyperbolaAsymptoteOption = 0;
|
||||
|
||||
|
||||
@@ -506,6 +506,14 @@ namespace Ink_Canvas {
|
||||
ToggleSwitchFitToCurve.IsOn = false;
|
||||
drawingAttributes.FitToCurve = false;
|
||||
}
|
||||
|
||||
// 初始化直线自动拉直相关设置
|
||||
ToggleSwitchAutoStraightenLine.IsOn = Settings.Canvas.AutoStraightenLine;
|
||||
AutoStraightenLineThresholdSlider.Value = Settings.Canvas.AutoStraightenLineThreshold;
|
||||
|
||||
// 初始化直线端点吸附相关设置
|
||||
ToggleSwitchLineEndpointSnapping.IsOn = Settings.Canvas.LineEndpointSnapping;
|
||||
LineEndpointSnappingThresholdSlider.Value = Settings.Canvas.LineEndpointSnappingThreshold;
|
||||
} else {
|
||||
Settings.Canvas = new Canvas();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,108 @@ namespace Ink_Canvas {
|
||||
|
||||
try {
|
||||
inkCanvas.Opacity = 1;
|
||||
|
||||
// 直线自动拉直功能
|
||||
if (Settings.Canvas.AutoStraightenLine && e.Stroke.StylusPoints.Count > 1 && drawingShapeMode == 0 && penType == 0) {
|
||||
// 获取起点和终点
|
||||
StylusPoint startPoint = e.Stroke.StylusPoints[0];
|
||||
StylusPoint endPoint = e.Stroke.StylusPoints[e.Stroke.StylusPoints.Count - 1];
|
||||
|
||||
// 计算直线长度
|
||||
double length = Math.Sqrt(Math.Pow(endPoint.X - startPoint.X, 2) + Math.Pow(endPoint.Y - startPoint.Y, 2));
|
||||
|
||||
// 判断是否需要拉直
|
||||
if (length >= Settings.Canvas.AutoStraightenLineThreshold) {
|
||||
// 判断是否符合直线特征(计算点到直线的最大距离)
|
||||
double maxDistance = 0;
|
||||
for (int i = 1; i < e.Stroke.StylusPoints.Count - 1; i++) {
|
||||
StylusPoint point = e.Stroke.StylusPoints[i];
|
||||
double distance = DistanceFromPointToLine(point, startPoint, endPoint);
|
||||
maxDistance = Math.Max(maxDistance, distance);
|
||||
}
|
||||
|
||||
// 如果最大距离小于线长的15%,认为是直线
|
||||
if (maxDistance < length * 0.15) {
|
||||
// 创建新的直线点集合
|
||||
StylusPointCollection newPoints = new StylusPointCollection();
|
||||
|
||||
// 直线端点吸附功能
|
||||
if (Settings.Canvas.LineEndpointSnapping) {
|
||||
bool startPointSnapped = false;
|
||||
bool endPointSnapped = false;
|
||||
|
||||
// 获取画布上的所有笔画
|
||||
StrokeCollection allStrokes = inkCanvas.Strokes;
|
||||
|
||||
// 排除当前笔画
|
||||
StrokeCollection otherStrokes = new StrokeCollection();
|
||||
foreach (Stroke stroke in allStrokes) {
|
||||
if (stroke != e.Stroke) {
|
||||
otherStrokes.Add(stroke);
|
||||
}
|
||||
}
|
||||
|
||||
// 查找最近的端点
|
||||
double minStartDistance = Settings.Canvas.LineEndpointSnappingThreshold;
|
||||
double minEndDistance = Settings.Canvas.LineEndpointSnappingThreshold;
|
||||
StylusPoint nearestToStart = startPoint;
|
||||
StylusPoint nearestToEnd = endPoint;
|
||||
|
||||
foreach (Stroke stroke in otherStrokes) {
|
||||
// 只考虑直线(只有两个点的笔画)
|
||||
if (stroke.StylusPoints.Count == 2) {
|
||||
StylusPoint strokeStart = stroke.StylusPoints[0];
|
||||
StylusPoint strokeEnd = stroke.StylusPoints[1];
|
||||
|
||||
// 计算当前笔画起点到其他笔画端点的距离
|
||||
double distanceToStrokeStart = Distance(startPoint, strokeStart);
|
||||
double distanceToStrokeEnd = Distance(startPoint, strokeEnd);
|
||||
|
||||
// 如果距离小于阈值且小于当前最小距离,更新最近点
|
||||
if (distanceToStrokeStart < minStartDistance) {
|
||||
minStartDistance = distanceToStrokeStart;
|
||||
nearestToStart = strokeStart;
|
||||
startPointSnapped = true;
|
||||
}
|
||||
if (distanceToStrokeEnd < minStartDistance) {
|
||||
minStartDistance = distanceToStrokeEnd;
|
||||
nearestToStart = strokeEnd;
|
||||
startPointSnapped = true;
|
||||
}
|
||||
|
||||
// 计算当前笔画终点到其他笔画端点的距离
|
||||
double distanceEndToStrokeStart = Distance(endPoint, strokeStart);
|
||||
double distanceEndToStrokeEnd = Distance(endPoint, strokeEnd);
|
||||
|
||||
// 如果距离小于阈值且小于当前最小距离,更新最近点
|
||||
if (distanceEndToStrokeStart < minEndDistance) {
|
||||
minEndDistance = distanceEndToStrokeStart;
|
||||
nearestToEnd = strokeStart;
|
||||
endPointSnapped = true;
|
||||
}
|
||||
if (distanceEndToStrokeEnd < minEndDistance) {
|
||||
minEndDistance = distanceEndToStrokeEnd;
|
||||
nearestToEnd = strokeEnd;
|
||||
endPointSnapped = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 应用吸附结果
|
||||
newPoints.Add(startPointSnapped ? nearestToStart : startPoint);
|
||||
newPoints.Add(endPointSnapped ? nearestToEnd : endPoint);
|
||||
} else {
|
||||
// 不启用吸附,直接使用原始端点
|
||||
newPoints.Add(startPoint);
|
||||
newPoints.Add(endPoint);
|
||||
}
|
||||
|
||||
// 替换原有笔迹
|
||||
e.Stroke.StylusPoints = newPoints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Settings.InkToShape.IsInkToShapeEnabled && drawingShapeMode == 0 && !isInMultiTouchMode && penType == 0) {
|
||||
void InkToShapeProcess() {
|
||||
try {
|
||||
@@ -554,5 +656,31 @@ namespace Ink_Canvas {
|
||||
public StylusPoint GetCenterPoint(StylusPoint point1, StylusPoint point2) {
|
||||
return new StylusPoint((point1.X + point2.X) / 2, (point1.Y + point2.Y) / 2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算点到直线的距离
|
||||
/// </summary>
|
||||
/// <param name="point">点</param>
|
||||
/// <param name="lineStart">直线起点</param>
|
||||
/// <param name="lineEnd">直线终点</param>
|
||||
/// <returns>距离</returns>
|
||||
private double DistanceFromPointToLine(StylusPoint point, StylusPoint lineStart, StylusPoint lineEnd) {
|
||||
double lineLength = Math.Sqrt(Math.Pow(lineEnd.X - lineStart.X, 2) + Math.Pow(lineEnd.Y - lineStart.Y, 2));
|
||||
if (lineLength == 0) return 0;
|
||||
|
||||
double area = Math.Abs(
|
||||
(lineEnd.X - lineStart.X) * (lineStart.Y - point.Y) -
|
||||
(lineStart.X - point.X) * (lineEnd.Y - lineStart.Y)
|
||||
);
|
||||
|
||||
return area / lineLength;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算两点之间的距离
|
||||
/// </summary>
|
||||
private double Distance(StylusPoint p1, StylusPoint p2) {
|
||||
return Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,14 @@ namespace Ink_Canvas
|
||||
public bool EnablePressureTouchMode { get; set; } = false; // 是否启用压感触屏模式
|
||||
[JsonProperty("disablePressure")]
|
||||
public bool DisablePressure { get; set; } = false; // 是否屏蔽压感
|
||||
[JsonProperty("autoStraightenLine")]
|
||||
public bool AutoStraightenLine { get; set; } = true; // 是否启用直线自动拉直
|
||||
[JsonProperty("autoStraightenLineThreshold")]
|
||||
public int AutoStraightenLineThreshold { get; set; } = 30; // 直线自动拉直的长度阈值(像素)
|
||||
[JsonProperty("lineEndpointSnapping")]
|
||||
public bool LineEndpointSnapping { get; set; } = true; // 是否启用直线端点吸附
|
||||
[JsonProperty("lineEndpointSnappingThreshold")]
|
||||
public int LineEndpointSnappingThreshold { get; set; } = 15; // 直线端点吸附的距离阈值(像素)
|
||||
|
||||
[JsonProperty("usingWhiteboard")]
|
||||
public bool UsingWhiteboard { get; set; }
|
||||
|
||||
BIN
Binary file not shown.
Binary file not shown.
+2705
-2637
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user