移除预计算检测间隙扩大率配置,优化碰撞检测逻辑和高亮显示功能
This commit is contained in:
parent
001b45cc9a
commit
075fd5c602
@ -40,10 +40,6 @@ duration_seconds = 10.0
|
||||
# 检测间隙(米)
|
||||
detection_gap_meters = 0.05
|
||||
|
||||
# 预计算检测间隙扩大率(>0,表示扩大的倍数)
|
||||
# 例如:0.5表示检测间隙增大0.5倍,即使用1.5倍的检测间隙进行预计算
|
||||
precomputed_detection_gap_expansion_rate = 0.5
|
||||
|
||||
[logistics]
|
||||
# 可通行性(默认值:true)
|
||||
traversable = true
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
2. [x] (BUG)碰撞结果高亮,应该显示clashdetective检测的结果
|
||||
3. [x] (优化)对clashdetective的检测结果,进行向上合并,找到集合对象。
|
||||
4. [x] (功能)碰撞检测结果保存数据库,列表展示
|
||||
5. [x] (优化)系统设置中增加预计算检测间隙扩大率,扩大预计算碰撞检测范围。
|
||||
|
||||
### [2025/12/25]
|
||||
|
||||
|
||||
@ -218,8 +218,7 @@ namespace NavisworksTransport.Commands
|
||||
var highlightIntegration = ClashDetectiveIntegration.Instance;
|
||||
if (highlightIntegration != null)
|
||||
{
|
||||
var highlightColor = Color.Green; // 绿色 (Navisworks API中没有Orange)
|
||||
ModelHighlightHelper.HighlightCollisionResults(collisionData.AllCollisions, highlightColor, true);
|
||||
ModelHighlightHelper.HighlightCollisionResults(collisionData.AllCollisions, clearPrevious: true);
|
||||
LogManager.Info($"自动高亮显示报告中的 {collisionData.AllCollisions.Count} 个碰撞对象");
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,10 +190,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
|
||||
var detectionGapMeters = config.Animation.DetectionGapMeters;
|
||||
_detectionGap = UnitsConverter.ConvertFromMeters(detectionGapMeters);
|
||||
|
||||
var expansionRate = config.Animation.PrecomputedDetectionGapExpansionRate;
|
||||
var expandedGapInMeters = detectionGapMeters * (1.0 + expansionRate);
|
||||
_precomputedDetectionGap = UnitsConverter.ConvertFromMeters(expandedGapInMeters);
|
||||
_precomputedDetectionGap = _detectionGap;
|
||||
|
||||
// 初始化动画模式
|
||||
_frameInterval = 1000.0 / _animationFrameRate; // 计算帧间隔
|
||||
@ -611,13 +608,16 @@ namespace NavisworksTransport.Core.Animation
|
||||
{
|
||||
var colliderBox = collider.BoundingBox();
|
||||
|
||||
// 使用改进的精确距离检测方法(先检查相交,再计算精确距离)
|
||||
double preciseDistance = BoundingBoxGeometryUtils.CalculatePreciseDistance(virtualBoundingBox, colliderBox);
|
||||
bool intersects = preciseDistance <= _precomputedDetectionGap;
|
||||
// 使用包围盒距离检测方法
|
||||
double distance = BoundingBoxGeometryUtils.CalculateDistance(virtualBoundingBox, colliderBox);
|
||||
bool intersects = distance <= _precomputedDetectionGap;
|
||||
|
||||
if (intersects)
|
||||
{
|
||||
LogManager.Debug($"帧 {i} 检测到碰撞: {_animatedObject.DisplayName} <-> {collider.DisplayName}, 精确距离: {preciseDistance:F4},阈值: {_precomputedDetectionGap:F4}");
|
||||
LogManager.Debug($"帧 {i} 检测到碰撞: {_animatedObject.DisplayName} <-> {collider.DisplayName}, 距离: {distance:F4},阈值: {_precomputedDetectionGap:F4}");
|
||||
LogManager.Debug($"移动物体位置: {framePosition.X:F2},{framePosition.Y:F2},{framePosition.Z:F2}");
|
||||
LogManager.Debug($"被撞物体位置:{GetObjectPosition(collider).X:F2},{GetObjectPosition(collider).Y:F2},{GetObjectPosition(collider).Z:F2}");
|
||||
|
||||
var collisionResult = new CollisionResult
|
||||
{
|
||||
ClashGuid = Guid.NewGuid(),
|
||||
@ -955,6 +955,14 @@ namespace NavisworksTransport.Core.Animation
|
||||
ModelHighlightHelper.ClearCollisionHighlights();
|
||||
LogManager.Debug("[动画开始] 已清除所有碰撞高亮");
|
||||
|
||||
// 高亮车辆对象(绿色)
|
||||
if (_animatedObject != null)
|
||||
{
|
||||
var vehicleItems = new List<ModelItem> { _animatedObject };
|
||||
ModelHighlightHelper.HighlightItems(ModelHighlightHelper.AnimatedObjectCategory, vehicleItems);
|
||||
LogManager.Debug("[动画开始] 已高亮车辆对象为绿色");
|
||||
}
|
||||
|
||||
// 启动动画播放
|
||||
StartAnimationPlayback();
|
||||
|
||||
@ -1073,6 +1081,10 @@ namespace NavisworksTransport.Core.Animation
|
||||
_pausedProgress = 0.0; // 重置暂停进度
|
||||
_currentFrameIndex = 0; // 重置帧索引
|
||||
|
||||
// 清除所有高亮(包括车辆和碰撞)
|
||||
ModelHighlightHelper.ClearAllHighlights();
|
||||
LogManager.Info("动画停止:已清除所有高亮");
|
||||
|
||||
// 将物体移回起点位置并恢复初始朝向
|
||||
if (_pathPoints != null && _pathPoints.Count > 0 && _animatedObject != null)
|
||||
{
|
||||
@ -1166,6 +1178,10 @@ namespace NavisworksTransport.Core.Animation
|
||||
// 直接设置为完成状态,避免中间状态切换
|
||||
SetState(AnimationState.Finished);
|
||||
|
||||
// 清除所有高亮(包括车辆和碰撞)
|
||||
ModelHighlightHelper.ClearAllHighlights();
|
||||
LogManager.Info("动画完成:已清除所有高亮");
|
||||
|
||||
// 修复:显示正确的总帧数,而不是最后一帧的索引
|
||||
var actualTotalFrames = _animationFrames?.Count ?? 0;
|
||||
LogManager.Info($"动画播放完成,总帧数: {actualTotalFrames}, 平均FPS: {_actualFPS:F1}");
|
||||
@ -2144,13 +2160,8 @@ namespace NavisworksTransport.Core.Animation
|
||||
_detectionGap = roundedGapInModelUnits;
|
||||
LogManager.Info($"检测间隙设置为: {gapInMeters:F2}米");
|
||||
|
||||
// 计算预计算时使用的扩大检测间隙
|
||||
var config = ConfigManager.Instance.Current;
|
||||
var expansionRate = config?.Animation?.PrecomputedDetectionGapExpansionRate ?? 0.0;
|
||||
var expandedGapInMeters = gapInMeters * (1.0 + expansionRate);
|
||||
var expandedGapInModelUnits = UnitsConverter.ConvertFromMeters(expandedGapInMeters);
|
||||
_precomputedDetectionGap = Math.Round(expandedGapInModelUnits, 4);
|
||||
LogManager.Info($"预计算检测间隙设置为: {expandedGapInMeters:F2}米(扩大率: {expansionRate:F2})");
|
||||
// 预计算检测间隙与检测间隙相同
|
||||
_precomputedDetectionGap = _detectionGap;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2316,15 +2327,15 @@ namespace NavisworksTransport.Core.Animation
|
||||
{
|
||||
if (currentHasCollision)
|
||||
{
|
||||
// 有碰撞:高亮当前帧的碰撞对象
|
||||
// 有碰撞:高亮当前帧的碰撞对象(使用CollisionResultsCategory的默认颜色)
|
||||
ModelHighlightHelper.HighlightCollisionResults(currentFrame.Collisions);
|
||||
LogManager.Debug($"[高亮状态] 帧{_currentFrameIndex}: 高亮碰撞 ({currentFrame.Collisions.Count}个, 对象{currentCollisionObjects.Count}个)");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 无碰撞:清除高亮
|
||||
ModelHighlightHelper.ClearCollisionHighlights();
|
||||
LogManager.Debug($"[高亮状态] 帧{_currentFrameIndex}: 清除高亮");
|
||||
// 无碰撞:清除碰撞高亮(保留车辆高亮)
|
||||
ModelHighlightHelper.ClearCategory(ModelHighlightHelper.CollisionResultsCategory);
|
||||
LogManager.Debug($"[高亮状态] 帧{_currentFrameIndex}: 清除碰撞高亮");
|
||||
}
|
||||
|
||||
// 更新状态记录
|
||||
|
||||
@ -198,7 +198,6 @@ namespace NavisworksTransport.Core.Config
|
||||
config.Animation.FrameRate = GetRequiredIntValue(anim, "frame_rate");
|
||||
config.Animation.DurationSeconds = GetRequiredDoubleValue(anim, "duration_seconds");
|
||||
config.Animation.DetectionGapMeters = GetRequiredDoubleValue(anim, "detection_gap_meters");
|
||||
config.Animation.PrecomputedDetectionGapExpansionRate = GetRequiredDoubleValue(anim, "precomputed_detection_gap_expansion_rate");
|
||||
|
||||
// 加载物流属性配置
|
||||
if (!model.ContainsKey("logistics"))
|
||||
@ -345,7 +344,6 @@ namespace NavisworksTransport.Core.Config
|
||||
anim["frame_rate"] = config.Animation.FrameRate;
|
||||
anim["duration_seconds"] = config.Animation.DurationSeconds;
|
||||
anim["detection_gap_meters"] = config.Animation.DetectionGapMeters;
|
||||
anim["precomputed_detection_gap_expansion_rate"] = config.Animation.PrecomputedDetectionGapExpansionRate;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -127,11 +127,6 @@ namespace NavisworksTransport.Core.Config
|
||||
/// 检测间隙(米)
|
||||
/// </summary>
|
||||
public double DetectionGapMeters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 预计算检测间隙扩大率(>0,表示扩大的倍数)
|
||||
/// </summary>
|
||||
public double PrecomputedDetectionGapExpansionRate { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -1397,8 +1397,7 @@ namespace NavisworksTransport
|
||||
if (selectedItems.Count > 0)
|
||||
{
|
||||
// 高亮显示选中的通道
|
||||
var navisColor = new Autodesk.Navisworks.Api.Color(0.0, 1.0, 0.0); // 绿色
|
||||
ModelHighlightHelper.HighlightItems(ChannelPreviewHighlightCategory, selectedItems, navisColor);
|
||||
ModelHighlightHelper.HighlightItems(ChannelPreviewHighlightCategory, selectedItems);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@ -192,8 +192,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
private const int ManualCollisionTargetLimit = 60;
|
||||
private const string ManualTargetsHighlightCategory = ModelHighlightHelper.ManualTargetsCategory;
|
||||
private const string CollisionResultsHighlightCategory = ModelHighlightHelper.CollisionResultsCategory;
|
||||
private static readonly Color ManualTargetHighlightColor = Color.FromByteRGB(255, 170, 0);
|
||||
private static readonly Color CollisionResultHighlightColor = Color.FromByteRGB(244, 67, 54); // Material Red(与路径终点颜色一致)
|
||||
|
||||
#endregion
|
||||
|
||||
@ -1704,7 +1702,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
LogManager.Debug($"[预计算碰撞结果高亮] 碰撞{i+1}: {collision.DisplayName}, Item1={collision.Item1?.DisplayName}, Item2={collision.Item2?.DisplayName}");
|
||||
}
|
||||
|
||||
ModelHighlightHelper.HighlightCollisionResults(deduplicatedResults, CollisionResultHighlightColor, false);
|
||||
ModelHighlightHelper.HighlightCollisionResults(deduplicatedResults, clearPrevious: false);
|
||||
UpdateMainStatus($"已高亮 {deduplicatedResults.Count} 个去重预计算碰撞结果");
|
||||
LogManager.Info($"[预计算碰撞结果高亮] 已高亮 {deduplicatedResults.Count} 个结果");
|
||||
}
|
||||
@ -2003,7 +2001,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
|
||||
if (IsManualTargetModeActive || forceHighlight)
|
||||
{
|
||||
ModelHighlightHelper.HighlightItems(ManualTargetsHighlightCategory, validItems, ManualTargetHighlightColor);
|
||||
ModelHighlightHelper.HighlightItems(ManualTargetsHighlightCategory, validItems);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -884,8 +884,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
if (clashIntegration != null)
|
||||
{
|
||||
var collisions = new List<CollisionResult> { item.CollisionData };
|
||||
var highlightColor = Autodesk.Navisworks.Api.Color.Green; // 使用Navisworks API中可用的绿色
|
||||
ModelHighlightHelper.HighlightCollisionResults(collisions, highlightColor, true);
|
||||
ModelHighlightHelper.HighlightCollisionResults(collisions, clearPrevious: true);
|
||||
LogManager.Info($"高亮碰撞对象: {item.Title}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,63 +177,6 @@ namespace NavisworksTransport.Utils
|
||||
box1.Min.Z <= box2.Max.Z && box1.Max.Z >= box2.Min.Z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用ClosestPoint方法计算两个包围盒之间的精确距离
|
||||
/// 这种方法比简单的包围盒相交检测更精确,可以避免AABB扩大导致的误报
|
||||
/// </summary>
|
||||
/// <param name="box1">第一个包围盒</param>
|
||||
/// <param name="box2">第二个包围盒</param>
|
||||
/// <returns>两个包围盒之间的精确距离</returns>
|
||||
public static double CalculatePreciseDistance(BoundingBox3D box1, BoundingBox3D box2)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 先检查包围盒是否相交
|
||||
bool intersects = box1.Intersects(box2);
|
||||
|
||||
if (intersects)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// 如果不相交,使用ClosestPoint方法计算精确距离
|
||||
// 计算box1上距离box2最近的点
|
||||
Point3D closestPointOnBox1 = box1.ClosestPoint(box2.Center);
|
||||
|
||||
// 计算box2上距离closestPointOnBox1最近的点
|
||||
Point3D closestPointOnBox2 = box2.ClosestPoint(closestPointOnBox1);
|
||||
|
||||
// 计算两个最近点之间的距离
|
||||
double dx = closestPointOnBox1.X - closestPointOnBox2.X;
|
||||
double dy = closestPointOnBox1.Y - closestPointOnBox2.Y;
|
||||
double dz = closestPointOnBox1.Z - closestPointOnBox2.Z;
|
||||
|
||||
double distance = Math.Sqrt(dx * dx + dy * dy + dz * dz);
|
||||
return distance;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// API调用失败,记录错误并抛出异常
|
||||
LogManager.Error($"[CalculatePreciseDistance] API调用失败: {ex.Message}");
|
||||
throw new InvalidOperationException($"CalculatePreciseDistance API调用失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用ClosestPoint方法检查两个包围盒是否在容差范围内相交
|
||||
/// 这种方法比简单的包围盒相交检测更精确,可以避免AABB扩大导致的误报
|
||||
/// </summary>
|
||||
/// <param name="box1">第一个包围盒</param>
|
||||
/// <param name="box2">第二个包围盒</param>
|
||||
/// <param name="tolerance">容差值</param>
|
||||
/// <returns>如果包围盒在容差范围内相交则返回true</returns>
|
||||
public static bool BoundingBoxesIntersectWithTolerancePrecise(BoundingBox3D box1, BoundingBox3D box2, double tolerance)
|
||||
{
|
||||
double preciseDistance = CalculatePreciseDistance(box1, box2);
|
||||
return preciseDistance <= tolerance;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取包围盒的中心点
|
||||
/// </summary>
|
||||
|
||||
@ -14,6 +14,7 @@ namespace NavisworksTransport.Utils
|
||||
public const string ManualTargetsCategory = "manualTargets";
|
||||
public const string ChannelPreviewCategory = "channelPreview";
|
||||
public const string ClashDetectiveResultsCategory = "clashDetectiveResults";
|
||||
public const string AnimatedObjectCategory = "animatedObject";
|
||||
|
||||
private class HighlightEntry
|
||||
{
|
||||
@ -42,15 +43,16 @@ namespace NavisworksTransport.Utils
|
||||
{ "report", Color.Green },
|
||||
{ "preview", Color.Blue },
|
||||
{ ManualTargetsCategory, Color.FromByteRGB(255, 170, 0) },
|
||||
{ CollisionResultsCategory, Color.Green },
|
||||
{ CollisionResultsCategory, Color.FromByteRGB(244, 67, 54) }, // Material Red(预计算碰撞)
|
||||
{ ChannelPreviewCategory, Color.Green },
|
||||
{ ClashDetectiveResultsCategory, Color.Red }
|
||||
{ ClashDetectiveResultsCategory, Color.Red },
|
||||
{ AnimatedObjectCategory, Color.FromByteRGB(76, 175, 80) } // Material Green(动画车辆)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 高亮指定对象集合。
|
||||
/// 高亮指定对象集合(使用类别默认颜色)。
|
||||
/// </summary>
|
||||
public static void HighlightItems(string category, IEnumerable<ModelItem> items, Color color)
|
||||
public static void HighlightItems(string category, IEnumerable<ModelItem> items)
|
||||
{
|
||||
if (items == null)
|
||||
return;
|
||||
@ -64,6 +66,8 @@ namespace NavisworksTransport.Utils
|
||||
category = "default";
|
||||
}
|
||||
|
||||
var color = GetCategoryColor(category);
|
||||
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (_activeHighlights.ContainsKey(category))
|
||||
@ -91,17 +95,6 @@ namespace NavisworksTransport.Utils
|
||||
}
|
||||
}
|
||||
|
||||
public static void HighlightItems(string category, IEnumerable<ModelItem> items)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(category))
|
||||
{
|
||||
category = "default";
|
||||
}
|
||||
|
||||
var color = GetCategoryColor(category);
|
||||
HighlightItems(category, items, color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除指定类别的高亮。
|
||||
/// </summary>
|
||||
@ -248,22 +241,11 @@ namespace NavisworksTransport.Utils
|
||||
#region 碰撞结果高亮相关方法
|
||||
|
||||
/// <summary>
|
||||
/// 高亮显示碰撞对象(使用默认红色)
|
||||
/// 高亮显示碰撞对象(使用类别默认颜色)
|
||||
/// </summary>
|
||||
/// <param name="results">碰撞结果列表</param>
|
||||
/// <param name="clearPrevious">是否清除之前的高亮</param>
|
||||
public static void HighlightCollisionResults(List<CollisionResult> results, bool clearPrevious = true)
|
||||
{
|
||||
HighlightCollisionResults(results, Color.Red, clearPrevious);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 高亮显示碰撞对象(支持自定义颜色)
|
||||
/// </summary>
|
||||
/// <param name="results">碰撞结果列表</param>
|
||||
/// <param name="highlightColor">高亮颜色</param>
|
||||
/// <param name="clearPrevious">是否清除之前的高亮</param>
|
||||
public static void HighlightCollisionResults(List<CollisionResult> results, Color highlightColor, bool clearPrevious = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -289,18 +271,15 @@ namespace NavisworksTransport.Utils
|
||||
var item1 = collision.Item1;
|
||||
var item2 = collision.Item2;
|
||||
|
||||
if (item1 != null && !highlightItems.Contains(item1))
|
||||
{
|
||||
highlightItems.Add(item1);
|
||||
}
|
||||
|
||||
// 只高亮被撞物体(Item2),排除车辆对象(Item1)
|
||||
// 车辆对象由 AnimatedObjectCategory 单独高亮为绿色
|
||||
if (item2 != null && !highlightItems.Contains(item2))
|
||||
{
|
||||
highlightItems.Add(item2);
|
||||
}
|
||||
}
|
||||
|
||||
HighlightItems(CollisionResultsCategory, highlightItems, highlightColor);
|
||||
HighlightItems(CollisionResultsCategory, highlightItems);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -313,10 +292,9 @@ namespace NavisworksTransport.Utils
|
||||
/// </summary>
|
||||
/// <param name="category">类别名称</param>
|
||||
/// <param name="results">碰撞结果列表</param>
|
||||
/// <param name="highlightColor">高亮颜色</param>
|
||||
/// <param name="clearOtherCategories">是否清除其他类别</param>
|
||||
public static void ManageCollisionHighlightsByCategory(string category, List<CollisionResult> results,
|
||||
Color highlightColor, bool clearOtherCategories = false)
|
||||
bool clearOtherCategories = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -329,11 +307,7 @@ namespace NavisworksTransport.Utils
|
||||
var item1 = result.Item1;
|
||||
var item2 = result.Item2;
|
||||
|
||||
if (item1 != null && !collidingItems.Contains(item1))
|
||||
{
|
||||
collidingItems.Add(item1);
|
||||
}
|
||||
|
||||
// 只高亮被撞物体(Item2),排除车辆对象(Item1)
|
||||
if (item2 != null && !collidingItems.Contains(item2))
|
||||
{
|
||||
collidingItems.Add(item2);
|
||||
@ -346,7 +320,7 @@ namespace NavisworksTransport.Utils
|
||||
ClearCategory(category);
|
||||
}
|
||||
|
||||
HighlightItems(category, collidingItems, highlightColor);
|
||||
HighlightItems(category, collidingItems);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -382,11 +356,7 @@ namespace NavisworksTransport.Utils
|
||||
var highlightItems = new List<ModelItem>();
|
||||
foreach (var clash in clashResults)
|
||||
{
|
||||
if (clash.Item1 != null && !highlightItems.Contains(clash.Item1))
|
||||
{
|
||||
highlightItems.Add(clash.Item1);
|
||||
}
|
||||
|
||||
// 只高亮被撞物体(Item2),排除车辆对象(Item1)
|
||||
if (clash.Item2 != null && !highlightItems.Contains(clash.Item2))
|
||||
{
|
||||
highlightItems.Add(clash.Item2);
|
||||
@ -395,7 +365,7 @@ namespace NavisworksTransport.Utils
|
||||
|
||||
if (highlightItems.Count > 0)
|
||||
{
|
||||
HighlightItems(ClashDetectiveResultsCategory, highlightItems, Color.Red);
|
||||
HighlightItems(ClashDetectiveResultsCategory, highlightItems);
|
||||
LogManager.Info($"[ClashDetective高亮] 已高亮 {highlightItems.Count} 个对象,来自 {clashResults.Count} 个碰撞结果");
|
||||
}
|
||||
else
|
||||
|
||||
Loading…
Reference in New Issue
Block a user