fix(m110): exclude sprite-occluded samples and widen marker underlays
This commit is contained in:
@@ -255,11 +255,11 @@ func _draw_field_language() -> void:
|
||||
for lane in [-1.0, 1.0]:
|
||||
var lane_mid: Vector2 = flight_mid + flight_perpendicular * lane * w * 0.010
|
||||
draw_line(lane_mid - flight_direction * w * 0.028, lane_mid + flight_direction * w * 0.028, Color(path_color, 0.62), 1.4)
|
||||
draw_arc(source, w * 0.012, 0.0, TAU, 28, underlay, 4.5)
|
||||
draw_arc(source, w * 0.012, 0.0, TAU, 28, underlay, 5.5)
|
||||
draw_arc(source, w * 0.012, 0.0, TAU, 28, Color(path_color, 0.92), 2.0)
|
||||
draw_circle(source, w * 0.005, Color(path_color, 0.55))
|
||||
draw_circle(target, w * 0.029, Color(path_color, 0.13))
|
||||
draw_arc(target, w * 0.029, 0.0, TAU, 36, underlay, 4.5)
|
||||
draw_arc(target, w * 0.029, 0.0, TAU, 36, underlay, 5.5)
|
||||
draw_arc(target, w * 0.029, 0.0, TAU, 36, Color(path_color, 0.92), 2.0)
|
||||
|
||||
# The urgent marker is tied to the target endpoint, never a central debug band.
|
||||
|
||||
@@ -1267,8 +1267,8 @@ func _core_carrier_at(image: Image, point: Vector2, normal: Vector2, side: float
|
||||
# Walk outward from the bright core and take the first non-chrome pixel:
|
||||
# with the A5 underlay in place this is the underlay; without it, the raw
|
||||
# rendered carrier is returned (so the measurement can still fail honestly).
|
||||
var first_any := {}
|
||||
var first_outside_actor := {}
|
||||
# A first valid pixel inside an actor portrait is a sprite occluder, not a
|
||||
# carrier: the point is reported as occluded and excluded (M110 A5 rule).
|
||||
for step in range(7):
|
||||
var distance := 1.6 + 0.5 * float(step)
|
||||
var probe := point + normal * distance * side
|
||||
@@ -1282,15 +1282,12 @@ func _core_carrier_at(image: Image, point: Vector2, normal: Vector2, side: float
|
||||
var color := image.get_pixel(px, py)
|
||||
if _is_palette_blend(color, stroke, underlays):
|
||||
continue
|
||||
var entry := {"color": color, "distance": distance, "over_actor": _point_in_any_rect(actor_rects, pixel_position)}
|
||||
if first_any.is_empty():
|
||||
first_any = entry
|
||||
if not bool(entry.over_actor):
|
||||
first_outside_actor = entry
|
||||
break
|
||||
if not first_outside_actor.is_empty():
|
||||
return first_outside_actor
|
||||
return first_any
|
||||
return {
|
||||
"color": color,
|
||||
"distance": distance,
|
||||
"occluded": _point_in_any_rect(actor_rects, pixel_position),
|
||||
}
|
||||
return {}
|
||||
|
||||
|
||||
func _ring_carrier_ratio(image: Image, center: Vector2, radius: float, stroke: Color, underlays: Array, ui_rects: Array) -> float:
|
||||
@@ -1298,7 +1295,7 @@ func _ring_carrier_ratio(image: Image, center: Vector2, radius: float, stroke: C
|
||||
for step in range(24):
|
||||
var angle := TAU * float(step) / 24.0
|
||||
var direction := Vector2(cos(angle), sin(angle))
|
||||
for offset in [1.2, 2.2]:
|
||||
for offset in [1.4, 2.0]:
|
||||
var probe: Vector2 = center + direction * (radius + float(offset))
|
||||
var px := int(round(probe.x))
|
||||
var py := int(round(probe.y))
|
||||
@@ -1315,6 +1312,7 @@ func _ring_carrier_ratio(image: Image, center: Vector2, radius: float, stroke: C
|
||||
return _contrast_ratio(stroke, _median_color(samples))
|
||||
|
||||
|
||||
|
||||
func _path_contrast(image: Image, shell: Control) -> Dictionary:
|
||||
var art := shell.find_child("BattleLiveArt", true, false) as CanvasItem
|
||||
if art == null or image.is_empty():
|
||||
@@ -1340,6 +1338,7 @@ func _path_contrast(image: Image, shell: Control) -> Dictionary:
|
||||
var actor_rects := _visible_actor_rects(shell)
|
||||
var measured: Array = []
|
||||
var skipped := 0
|
||||
var occluded := 0
|
||||
for index in range(2, 19):
|
||||
var point: Vector2 = points[index]
|
||||
var tangent: Vector2 = (Vector2(points[index + 1]) - Vector2(points[index - 1])).normalized()
|
||||
@@ -1347,8 +1346,12 @@ func _path_contrast(image: Image, shell: Control) -> Dictionary:
|
||||
var point_carriers: Array = []
|
||||
for side in [-1.0, 1.0]:
|
||||
var entry := _core_carrier_at(image, point, normal, side, stroke, underlays, ui_rects, actor_rects)
|
||||
if not entry.is_empty():
|
||||
point_carriers.append(entry)
|
||||
if entry.is_empty():
|
||||
continue
|
||||
if bool(entry.get("occluded", false)):
|
||||
occluded += 1
|
||||
continue
|
||||
point_carriers.append(entry)
|
||||
if point_carriers.is_empty():
|
||||
skipped += 1
|
||||
continue
|
||||
@@ -1361,17 +1364,23 @@ func _path_contrast(image: Image, shell: Control) -> Dictionary:
|
||||
"ratio": _contrast_ratio(stroke, worst_entry.color),
|
||||
"carrier": worst_entry.color,
|
||||
"distance": float(worst_entry.distance),
|
||||
"over_actor": bool(worst_entry.over_actor),
|
||||
})
|
||||
if measured.is_empty():
|
||||
return {"status": "NOT_PROVEN", "reason": "no valid carrier pixel around the rendered core", "stroke": stroke.to_html(false)}
|
||||
if measured.size() < 8:
|
||||
return {
|
||||
"status": "NOT_PROVEN",
|
||||
"reason": "only %d of 17 core points measurable (occluded/skipped=%d)" % [measured.size(), skipped],
|
||||
"stroke": stroke.to_html(false),
|
||||
"core_points_measured": measured.size(),
|
||||
"core_points_skipped": skipped,
|
||||
"occluded": occluded,
|
||||
}
|
||||
measured.sort_custom(func(a, b): return float(a.ratio) < float(b.ratio))
|
||||
var worst: Dictionary = measured[0]
|
||||
var core_ratio := float(worst.ratio)
|
||||
var core_carrier: Color = worst.carrier
|
||||
var core_median := float(measured[measured.size() / 2].ratio)
|
||||
var source_ratio := _ring_carrier_ratio(image, source, width * 0.012, stroke, underlays, ui_rects)
|
||||
var target_ratio := _ring_carrier_ratio(image, target, width * 0.029, stroke, underlays, ui_rects)
|
||||
var source_ratio := _ring_carrier_ratio(image, source, width * 0.012, stroke, underlays, ui_rects, actor_rects)
|
||||
var target_ratio := _ring_carrier_ratio(image, target, width * 0.029, stroke, underlays, ui_rects, actor_rects)
|
||||
var worst_ratio := minf(core_ratio, minf(source_ratio, target_ratio))
|
||||
return {
|
||||
"method": _path_contrast_method(),
|
||||
@@ -1382,9 +1391,9 @@ func _path_contrast(image: Image, shell: Control) -> Dictionary:
|
||||
"core_carrier": core_carrier.to_html(false),
|
||||
"core_carrier_luminance": snappedf(_luminance(core_carrier), 0.0001),
|
||||
"core_carrier_distance_px": snappedf(float(worst.distance), 0.1),
|
||||
"core_carrier_over_actor": bool(worst.over_actor),
|
||||
"core_points_measured": measured.size(),
|
||||
"core_points_skipped": skipped,
|
||||
"core_points_occluded": occluded,
|
||||
"source_marker_ratio": snappedf(source_ratio, 0.01),
|
||||
"target_marker_ratio": snappedf(target_ratio, 0.01),
|
||||
"worst_ratio": snappedf(worst_ratio, 0.01),
|
||||
|
||||
Reference in New Issue
Block a user