import os from shapely.geometry import Polygon class DamageCalculator: def __init__(self): self.cost_ranges = { "Scratch": { "Minor": (1000, 3000), "Moderate": (3000, 5000), "Severe": (5000, 10000) }, "Dent": { "Minor": (2000, 4000), "Moderate": (4000, 10000), "Severe": (10000, 15000) }, "Paint chip": { "Minor": (1000, 2000), "Moderate": (2000, 4000), "Severe": (4000, 10000) }, "Broken part": (1000, 7000) } def parse_coordinates(self, file_path): polygons = [] class_names = [] with open(file_path, 'r') as file: for line in file: parts = line.strip().split() class_name = [] coordinates = [] for part in parts: try: coordinates.append(float(part)) except ValueError: class_name.append(part) if class_name and coordinates: class_name = " ".join(class_name) try: if len(coordinates) % 2 != 0: raise ValueError("Coordinates are not in pairs.") polygon = Polygon([(coordinates[i], coordinates[i+1]) for i in range(0, len(coordinates), 2)]) polygons.append(polygon) class_names.append(class_name) except ValueError as e: print(f"Skipping line due to error: {e}") else: print(f"Skipping line due to insufficient data: {line.strip()}") return class_names, polygons def calculate_severity(self, coverage_percentage): if 3 < coverage_percentage <= 30: return "Minor" elif 30 < coverage_percentage <= 60: return "Moderate" elif coverage_percentage > 60: return "Severe" return "N/A" def calculate_cost(self, damage_class, severity): if damage_class == "Broken part": return self.cost_ranges["Broken part"] elif severity in self.cost_ranges[damage_class]: return self.cost_ranges[damage_class][severity] return (0, 0) def summarize_damage_by_part(self, damage_polygons, part_polygons): intersection_info = self.calculate_intersection_area(damage_polygons, part_polygons) summary = {} for info in intersection_info: part_class = info['part_class'] damage_class = info['damage_class'] coverage_percentage = info['coverage_percentage'] if part_class not in summary: summary[part_class] = {'total_coverage': 0, 'damage_types': {}} summary[part_class]['total_coverage'] += coverage_percentage if damage_class not in summary[part_class]['damage_types']: summary[part_class]['damage_types'][damage_class] = 0 summary[part_class]['damage_types'][damage_class] += coverage_percentage for part_class in summary: total_coverage = summary[part_class]['total_coverage'] for damage_class in summary[part_class]['damage_types']: summary[part_class]['damage_types'][damage_class] = ( summary[part_class]['damage_types'][damage_class] / total_coverage * 100 ) summary[part_class]['undamaged'] = 100 - total_coverage return summary def calculate_intersection_area(self, damage_polygons, part_polygons): intersection_info = [] front_back_door_detected = any(part_class in ['Front-door', 'Back-door'] for part_class, _ in part_polygons) for damage_class, damage_polygon in damage_polygons: for part_class, part_polygon in part_polygons: if damage_polygon.intersects(part_polygon): intersection = damage_polygon.intersection(part_polygon) intersection_area = intersection.area part_area = part_polygon.area coverage_percentage = (intersection_area / part_area) * 100 # Condition 1: Ignore damage coverage <= 3% if coverage_percentage <= 3: continue # Condition 2: Apply weights based on the new conditions if part_class in ['Front-bumper', 'Back-bumper']: if front_back_door_detected: coverage_percentage *= 0.2 else: coverage_percentage *= 0.6 if coverage_percentage <= 3: continue # Updated Condition 3: Include Headlight and tail light only with broken part if damage > 50% if part_class in ['Headlight', 'Tail-light']: if damage_class == 'Broken part' and coverage_percentage > 50: intersection_info.append({ "damage_class": damage_class, "part_class": part_class, "intersection_area": intersection_area, "part_area": part_area, "coverage_percentage": coverage_percentage }) continue # Condition 4: Exclude damage with front-wheel, back wheel, and license plate if part_class in ['Front-wheel', 'Back-wheel', 'License-plate']: continue intersection_info.append({ "damage_class": damage_class, "part_class": part_class, "intersection_area": intersection_area, "part_area": part_area, "coverage_percentage": coverage_percentage }) # Condition 5: Sum coverage for the same type of defect on the same part summarized_info = {} for info in intersection_info: key = (info['damage_class'], info['part_class']) if key not in summarized_info: summarized_info[key] = { "intersection_area": 0, "part_area": info['part_area'], "coverage_percentage": 0, "count": 0 } summarized_info[key]["intersection_area"] += info["intersection_area"] summarized_info[key]["coverage_percentage"] += info["coverage_percentage"] summarized_info[key]["count"] += 1 final_info = [] for (damage_class, part_class), values in summarized_info.items(): part_area = values["part_area"] intersection_area = values["intersection_area"] coverage_percentage = values["coverage_percentage"] count = values["count"] severity = self.calculate_severity(coverage_percentage) cost_min, cost_max = self.calculate_cost(damage_class, severity) final_info.append({ "damage_class": damage_class, "part_class": part_class, "intersection_area": intersection_area, "part_area": part_area, "coverage_percentage": coverage_percentage, "severity": severity, "cost_min": cost_min, "cost_max": cost_max, "count": count }) return final_info