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]:
|
for lane in [-1.0, 1.0]:
|
||||||
var lane_mid: Vector2 = flight_mid + flight_perpendicular * lane * w * 0.010
|
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_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_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(source, w * 0.005, Color(path_color, 0.55))
|
||||||
draw_circle(target, w * 0.029, Color(path_color, 0.13))
|
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)
|
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.
|
# 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:
|
# 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
|
# 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).
|
# rendered carrier is returned (so the measurement can still fail honestly).
|
||||||
var first_any := {}
|
# A first valid pixel inside an actor portrait is a sprite occluder, not a
|
||||||
var first_outside_actor := {}
|
# carrier: the point is reported as occluded and excluded (M110 A5 rule).
|
||||||
for step in range(7):
|
for step in range(7):
|
||||||
var distance := 1.6 + 0.5 * float(step)
|
var distance := 1.6 + 0.5 * float(step)
|
||||||
var probe := point + normal * distance * side
|
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)
|
var color := image.get_pixel(px, py)
|
||||||
if _is_palette_blend(color, stroke, underlays):
|
if _is_palette_blend(color, stroke, underlays):
|
||||||
continue
|
continue
|
||||||
var entry := {"color": color, "distance": distance, "over_actor": _point_in_any_rect(actor_rects, pixel_position)}
|
return {
|
||||||
if first_any.is_empty():
|
"color": color,
|
||||||
first_any = entry
|
"distance": distance,
|
||||||
if not bool(entry.over_actor):
|
"occluded": _point_in_any_rect(actor_rects, pixel_position),
|
||||||
first_outside_actor = entry
|
}
|
||||||
break
|
return {}
|
||||||
if not first_outside_actor.is_empty():
|
|
||||||
return first_outside_actor
|
|
||||||
return first_any
|
|
||||||
|
|
||||||
|
|
||||||
func _ring_carrier_ratio(image: Image, center: Vector2, radius: float, stroke: Color, underlays: Array, ui_rects: Array) -> float:
|
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):
|
for step in range(24):
|
||||||
var angle := TAU * float(step) / 24.0
|
var angle := TAU * float(step) / 24.0
|
||||||
var direction := Vector2(cos(angle), sin(angle))
|
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 probe: Vector2 = center + direction * (radius + float(offset))
|
||||||
var px := int(round(probe.x))
|
var px := int(round(probe.x))
|
||||||
var py := int(round(probe.y))
|
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))
|
return _contrast_ratio(stroke, _median_color(samples))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func _path_contrast(image: Image, shell: Control) -> Dictionary:
|
func _path_contrast(image: Image, shell: Control) -> Dictionary:
|
||||||
var art := shell.find_child("BattleLiveArt", true, false) as CanvasItem
|
var art := shell.find_child("BattleLiveArt", true, false) as CanvasItem
|
||||||
if art == null or image.is_empty():
|
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 actor_rects := _visible_actor_rects(shell)
|
||||||
var measured: Array = []
|
var measured: Array = []
|
||||||
var skipped := 0
|
var skipped := 0
|
||||||
|
var occluded := 0
|
||||||
for index in range(2, 19):
|
for index in range(2, 19):
|
||||||
var point: Vector2 = points[index]
|
var point: Vector2 = points[index]
|
||||||
var tangent: Vector2 = (Vector2(points[index + 1]) - Vector2(points[index - 1])).normalized()
|
var tangent: Vector2 = (Vector2(points[index + 1]) - Vector2(points[index - 1])).normalized()
|
||||||
@@ -1347,7 +1346,11 @@ func _path_contrast(image: Image, shell: Control) -> Dictionary:
|
|||||||
var point_carriers: Array = []
|
var point_carriers: Array = []
|
||||||
for side in [-1.0, 1.0]:
|
for side in [-1.0, 1.0]:
|
||||||
var entry := _core_carrier_at(image, point, normal, side, stroke, underlays, ui_rects, actor_rects)
|
var entry := _core_carrier_at(image, point, normal, side, stroke, underlays, ui_rects, actor_rects)
|
||||||
if not entry.is_empty():
|
if entry.is_empty():
|
||||||
|
continue
|
||||||
|
if bool(entry.get("occluded", false)):
|
||||||
|
occluded += 1
|
||||||
|
continue
|
||||||
point_carriers.append(entry)
|
point_carriers.append(entry)
|
||||||
if point_carriers.is_empty():
|
if point_carriers.is_empty():
|
||||||
skipped += 1
|
skipped += 1
|
||||||
@@ -1361,17 +1364,23 @@ func _path_contrast(image: Image, shell: Control) -> Dictionary:
|
|||||||
"ratio": _contrast_ratio(stroke, worst_entry.color),
|
"ratio": _contrast_ratio(stroke, worst_entry.color),
|
||||||
"carrier": worst_entry.color,
|
"carrier": worst_entry.color,
|
||||||
"distance": float(worst_entry.distance),
|
"distance": float(worst_entry.distance),
|
||||||
"over_actor": bool(worst_entry.over_actor),
|
|
||||||
})
|
})
|
||||||
if measured.is_empty():
|
if measured.size() < 8:
|
||||||
return {"status": "NOT_PROVEN", "reason": "no valid carrier pixel around the rendered core", "stroke": stroke.to_html(false)}
|
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))
|
measured.sort_custom(func(a, b): return float(a.ratio) < float(b.ratio))
|
||||||
var worst: Dictionary = measured[0]
|
var worst: Dictionary = measured[0]
|
||||||
var core_ratio := float(worst.ratio)
|
var core_ratio := float(worst.ratio)
|
||||||
var core_carrier: Color = worst.carrier
|
var core_carrier: Color = worst.carrier
|
||||||
var core_median := float(measured[measured.size() / 2].ratio)
|
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 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)
|
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))
|
var worst_ratio := minf(core_ratio, minf(source_ratio, target_ratio))
|
||||||
return {
|
return {
|
||||||
"method": _path_contrast_method(),
|
"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": core_carrier.to_html(false),
|
||||||
"core_carrier_luminance": snappedf(_luminance(core_carrier), 0.0001),
|
"core_carrier_luminance": snappedf(_luminance(core_carrier), 0.0001),
|
||||||
"core_carrier_distance_px": snappedf(float(worst.distance), 0.1),
|
"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_measured": measured.size(),
|
||||||
"core_points_skipped": skipped,
|
"core_points_skipped": skipped,
|
||||||
|
"core_points_occluded": occluded,
|
||||||
"source_marker_ratio": snappedf(source_ratio, 0.01),
|
"source_marker_ratio": snappedf(source_ratio, 0.01),
|
||||||
"target_marker_ratio": snappedf(target_ratio, 0.01),
|
"target_marker_ratio": snappedf(target_ratio, 0.01),
|
||||||
"worst_ratio": snappedf(worst_ratio, 0.01),
|
"worst_ratio": snappedf(worst_ratio, 0.01),
|
||||||
|
|||||||
Reference in New Issue
Block a user