diff --git a/app/src/main/java/com/ckkj/defense_device/liveVideo/StrikePositionActivity.kt b/app/src/main/java/com/ckkj/defense_device/liveVideo/StrikePositionActivity.kt index d5709e9..a73e035 100644 --- a/app/src/main/java/com/ckkj/defense_device/liveVideo/StrikePositionActivity.kt +++ b/app/src/main/java/com/ckkj/defense_device/liveVideo/StrikePositionActivity.kt @@ -45,7 +45,7 @@ class StrikePositionActivity : AppCompatActivity() { private var selectedZone: Zone = Zone.CHEST - // Touch tracking for ImageView (captured in onTouch, used in ACTION_UP for click detection) + // ImageView 的触控追踪(在 onTouch 中捕获,ACTION_UP 用于点击检测) private var lastTouchX = 0f private var lastTouchY = 0f @@ -67,7 +67,7 @@ class StrikePositionActivity : AppCompatActivity() { binding.ivBack.setOnClickListener { finish() } binding.btnSubmit.setOnClickListener { showConfirmDialog() } - // Use OnTouchListener to track touch coordinates + // 使用 OnTouchListen 来跟踪触摸坐标 binding.ivHumanBody.setOnTouchListener { _, event -> lastTouchX = event.x lastTouchY = event.y @@ -77,7 +77,7 @@ class StrikePositionActivity : AppCompatActivity() { false } - // OnClick fires on ACTION_UP; coordinates captured from lastTouchX/Y + // OnClick 对ACTION_UP开火;坐标来自lastTouchXY binding.ivHumanBody.setOnClickListener { val imageView = it as ImageView val (nx, ny) = resolveTapLocation(lastTouchX, lastTouchY, imageView) @@ -100,10 +100,12 @@ class StrikePositionActivity : AppCompatActivity() { } /** - * Converts a screen coordinate (from onTouch) into a normalised [0..1] offset - * inside the drawable, accounting for: - * - ImageView scaling (scaleType="fitCenter" adds letterboxing) - * - Letterbox / pillarbox margins when image aspect ≠ view aspect + * 这段代码将触摸坐标转换为图片内部的归一化位置: + * + * 1. 计算图片等比缩放后的实际尺寸 + * 2. 计算letterbox/pillarbox的偏移量 + * 3. 将触摸点限制在图片有效区域内 + * 4. 返回相对于图片的归一化坐标(0-1范围) */ private fun resolveTapLocation(rawX: Float, rawY: Float, imageView: ImageView): Pair { val drawable = imageView.drawable ?: return Pair(0f, 0f) @@ -114,22 +116,22 @@ class StrikePositionActivity : AppCompatActivity() { val intrinsicWidth = drawable.intrinsicWidth.toFloat() val intrinsicHeight = drawable.intrinsicHeight.toFloat() - // scale: the uniform factor the image is scaled by to fit the view + // 比例:图像被缩放以适应视图的均匀因子 val scale = min(ivWidth / intrinsicWidth, ivHeight / intrinsicHeight) - // Physical pixel size of the drawable after scaling + // 缩放后绘制的物理像素大小 val drawnW = intrinsicWidth * scale val drawnH = intrinsicHeight * scale - // Letterbox offsets (top / left) when aspect ratios differ + // 当宽高比不同时,信箱偏移(左上角) val drawableLeft = (ivWidth - drawnW) / 2f val drawableTop = (ivHeight - drawnH) / 2f - // Clamp touch to the actual drawable area + // 夹紧触地接触实际可绘制区域 val clampedX = max(drawableLeft, min(rawX, drawableLeft + drawnW)) val clampedY = max(drawableTop, min(rawY, drawableTop + drawnH)) - // Normalised offset [0..1] within the drawable + // 可绘制物内的归一化偏移 [0..1] val normalizedX = (clampedX - drawableLeft) / drawnW val normalizedY = (clampedY - drawableTop) / drawnH @@ -137,14 +139,11 @@ class StrikePositionActivity : AppCompatActivity() { } /** - * Zones are divided by: - * - Horizontal boundary at ny = 0.5 → top = HEAD, bottom = shoulders - * - Vertical boundary 1 at nx = 1/3 → left = LEFT_SHOULDER - * - Vertical boundary 2 at nx = 2/3 → right = RIGHT_SHOULDER, middle = CHEST + * 这段代码根据归一化坐标确定触摸区域: * - * If the touch falls within ±tolerance of any boundary line, the nearest - * zone centre (Euclidean distance in normalised space) is used to avoid - * arbitrary assignments at boundary pixels. + * 1. 将图片分为头部、左肩、胸部、右肩四个区域 + * 2. 边界附近±0.04范围内,使用最近区域中心避免误判 + * 3. 上半部分为头部,下半部分按1/3和2/3垂直线划分 */ private fun zoneForLocation(nx: Float, ny: Float): Zone { val hBoundary = 0.5f @@ -168,7 +167,14 @@ class StrikePositionActivity : AppCompatActivity() { } } - /** Returns the Zone whose normalised centre is closest (Euclidean) to (nx, ny). */ + /** + * 这段代码找到距离触摸点最近的区域: + * + * 1. 遍历所有Zone,计算与触摸点的欧氏距离平方 + * 2. 返回距离最小的Zone作为结果 + * 3. 若无匹配则默认返回CHEST + * */ + private fun nearestZone(nx: Float, ny: Float): Zone { return Zone.values().minByOrNull { zone -> val dx = nx - zone.normalizedX @@ -178,12 +184,12 @@ class StrikePositionActivity : AppCompatActivity() { } /** - * Positions the marker (ivStrikeMarker) at the zone's centre, clamped so the - * marker never goes out of the ivHumanBody bounds. - * - * Because the marker is a child of ivHumanBody and starts at its center - * (layout_gravity="center"), we compute the offset from that center point - * and apply it via translationX/Y so the marker's layout bounds stay intact. + 这段代码更新标记位置到区域中心: + + 1. 根据Zone的归一化坐标计算目标位置 + 2. 限制标记不超出图片边界(Y仅限制上限) + 3. 相对于ImageView中心计算偏移量并应用 + 4. 支持动画或即时移动两种方式 */ private fun updateMarkerPosition(zone: Zone, animated: Boolean) { if (humanBodyWidth <= 0 || humanBodyHeight <= 0) return @@ -198,9 +204,7 @@ class StrikePositionActivity : AppCompatActivity() { val rawX = humanBodyWidth * zone.normalizedX val rawY = humanBodyHeight * zone.normalizedY - // Clamp X so the marker never extends beyond the drawable edges. - // Y clamp only has an upper bound — HEAD at normalizedY=0 is allowed to go - // all the way to the top (translationY can be negative). + //用X夹住,使标记永远不会超出可绘制的边缘。Y钳只有一个上界——在归一化Y=0处的HEAD可以一直达到顶端(平移Y可以为负)。 val clampedX = min(max(rawX, halfMarkerW), humanBodyWidth - halfMarkerW) val clampedY = min(rawY, humanBodyHeight - halfMarkerH)