File size: 6,139 Bytes
3bd69a8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
"""Tests for aesthetic optimization functions."""

import sys
import traceback

def test_shape_quality():
    """Test shape quality analysis functions."""
    print("Testing shape quality functions...")
    try:
        from shapely.geometry import Polygon
        from core.geometry.shape_quality import (
            analyze_shape_quality,
            get_dominant_edge_vector,
            classify_lot_type,
            get_obb_dimensions
        )
        
        # Test 1: Perfect rectangle should have high score and be valid
        # Must be > 1000 m² to pass min area check
        rect = Polygon([(0, 0), (50, 0), (50, 40), (0, 40)])  # 2000 m²
        score, valid = analyze_shape_quality(rect)
        print(f"  Rectangle (2000m²): score={score:.3f}, valid={valid}")
        assert valid, "Rectangle should be valid"
        assert score > 0.8, "Rectangle should have high score"
        
        # Test 2: Triangle should have low rectangularity and be invalid
        tri = Polygon([(0, 0), (40, 0), (20, 30)])
        score, valid = analyze_shape_quality(tri)
        print(f"  Triangle: score={score:.3f}, valid={valid}")
        assert not valid, "Triangle should be invalid (low rectangularity)"
        
        # Test 3: Very elongated shape should be invalid
        elongated = Polygon([(0, 0), (200, 0), (200, 10), (0, 10)])
        score, valid = analyze_shape_quality(elongated)
        print(f"  Elongated: score={score:.3f}, valid={valid}")
        assert not valid, "Elongated shape should be invalid"
        
        # Test 4: Small lot should be invalid
        small = Polygon([(0, 0), (10, 0), (10, 10), (0, 10)])  # 100 m²
        score, valid = analyze_shape_quality(small)
        print(f"  Small lot: score={score:.3f}, valid={valid}")
        assert not valid, "Small lot should be invalid"
        
        # Test 5: Dominant edge vector
        vec = get_dominant_edge_vector(rect)
        print(f"  Dominant edge vector: {vec}")
        assert vec is not None, "Should return vector"
        
        # Test 6: OBB dimensions
        w, l, angle = get_obb_dimensions(rect)
        print(f"  OBB dimensions: width={w:.1f}, length={l:.1f}, angle={angle:.1f}°")
        assert abs(w - 40) < 1, "Width should be ~40"
        assert abs(l - 50) < 1, "Length should be ~50"
        
        # Test 7: Lot classification
        lot_type = classify_lot_type(rect)
        print(f"  Rectangle type: {lot_type}")
        assert lot_type == 'commercial', "Good lot should be commercial"
        
        # Triangle must be large enough (>1000m²) to be green_space, otherwise it's unusable
        large_tri = Polygon([(0, 0), (60, 0), (30, 50)])  # 1500 m²
        lot_type = classify_lot_type(large_tri)
        print(f"  Triangle type: {lot_type}")
        assert lot_type == 'green_space', "Bad lot (large enough) should be green_space"
        
        print("✅ Shape quality tests passed")
        return True
    except Exception as e:
        print(f"❌ Shape quality test failed: {e}")
        traceback.print_exc()
        return False


def test_orthogonal_slicer():
    """Test orthogonal slicing functions."""
    print("\nTesting orthogonal slicer functions...")
    try:
        from shapely.geometry import Polygon
        from core.geometry.orthogonal_slicer import (
            orthogonal_slice,
            subdivide_with_uniform_widths
        )
        
        # Test 1: Subdivide a rectangular block
        block = Polygon([(0, 0), (100, 0), (100, 50), (0, 50)])
        widths = [25, 25, 25, 25]
        
        lots = orthogonal_slice(block, widths)
        print(f"  Orthogonal slice: {len(lots)} lots from 4 widths")
        assert len(lots) == 4, "Should create 4 lots"
        
        # Test 2: Uniform width subdivision
        lots2, actual_widths = subdivide_with_uniform_widths(block, target_width=20)
        print(f"  Uniform subdivision: {len(lots2)} lots, widths={[round(w,1) for w in actual_widths]}")
        assert len(lots2) > 0, "Should create lots"
        
        print("✅ Orthogonal slicer tests passed")
        return True
    except Exception as e:
        print(f"❌ Orthogonal slicer test failed: {e}")
        traceback.print_exc()
        return False


def test_settings():
    """Test aesthetic settings in config."""
    print("\nTesting aesthetic settings...")
    try:
        from core.config.settings import (
            DEFAULT_SETTINGS,
            MIN_RECTANGULARITY,
            MAX_ASPECT_RATIO,
            MIN_LOT_AREA,
            DEVIATION_PENALTY_WEIGHT,
            ENABLE_LEFTOVER_MANAGEMENT
        )
        
        print(f"  MIN_RECTANGULARITY = {MIN_RECTANGULARITY}")
        print(f"  MAX_ASPECT_RATIO = {MAX_ASPECT_RATIO}")
        print(f"  MIN_LOT_AREA = {MIN_LOT_AREA}")
        print(f"  DEVIATION_PENALTY_WEIGHT = {DEVIATION_PENALTY_WEIGHT}")
        print(f"  ENABLE_LEFTOVER_MANAGEMENT = {ENABLE_LEFTOVER_MANAGEMENT}")
        
        assert MIN_RECTANGULARITY == 0.75, "Should match Beauti_mode spec"
        assert MAX_ASPECT_RATIO == 4.0, "Should match Beauti_mode spec"
        assert MIN_LOT_AREA == 1000.0, "Should match Beauti_mode spec"
        
        print("✅ Settings tests passed")
        return True
    except Exception as e:
        print(f"❌ Settings test failed: {e}")
        traceback.print_exc()
        return False


if __name__ == "__main__":
    print("=" * 50)
    print("Aesthetic Optimization Test Suite")
    print("=" * 50)
    
    results = []
    results.append(("Shape Quality", test_shape_quality()))
    results.append(("Orthogonal Slicer", test_orthogonal_slicer()))
    results.append(("Settings", test_settings()))
    
    print("\n" + "=" * 50)
    print("Test Results:")
    print("=" * 50)
    
    for name, passed in results:
        status = "✅ PASS" if passed else "❌ FAIL"
        print(f"{status} - {name}")
    
    all_passed = all(r[1] for r in results)
    
    print("\n" + "=" * 50)
    if all_passed:
        print("✅ ALL AESTHETIC TESTS PASSED")
        sys.exit(0)
    else:
        print("❌ SOME TESTS FAILED")
        sys.exit(1)