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
164
165
166
167
168
169
170
171
172
173
174
175
|
/**
* glamac_view.h - header file from glamac_view.c.
*/
#ifndef GLAMAC_VIEW_H
#define GLAMAC_VIEW_H
#include <SDL3/SDL.h>
#include "glamacdef.h"
// Constants for view
#define MIN_PADDING 20 // Minimum padding in pixels
#define MAX_PADDING_PERCENT 0.04f // Maximum padding as percentage of window size
#define PAN_STEP 0.05f // Step size for keyboard panning
#define ZOOM_FACTOR 1.2f // Zoom factor for zoom operations
#define MIN_ZOOM 0.5f // Minimum zoom level
#define MAX_ZOOM 10.0f // Maximum zoom level
// Glass label positioning constants (adjustable parameters)
#define LABEL_OFFSET_X 12 // Horizontal offset from glass point (pixels)
#define LABEL_OFFSET_Y -8 // Vertical offset from glass point (pixels)
#define LABEL_SIZE_SCALE 1.4f // Scale factor for glass name labels
// Tight clustering parameters
#define MAX_CLUSTER_SIZE 8 // Maximum glasses per cluster
#define DEFAULT_TIGHT_CLUSTER_ND_THRESHOLD 0.0005f // Default nd difference threshold
#define DEFAULT_TIGHT_CLUSTER_VD_THRESHOLD 0.15f // Default vd difference threshold
// Loose clustering parameters (zoom-dependent)
#define DEFAULT_LOOSE_CLUSTER_ND_THRESHOLD 0.3f // Default nd base threshold
#define DEFAULT_LOOSE_CLUSTER_VD_THRESHOLD 0.55f // Default vd base threshold
#define DEFAULT_LOOSE_CLUSTER_ND_FRACTION 4.9f // Default nd fraction of visible range
#define DEFAULT_LOOSE_CLUSTER_VD_FRACTION 0.9f // Default vd fraction of visible range
// Global tight cluster thresholds (adjustable parameters)
extern f32 g_tight_cluster_nd_threshold;
extern f32 g_tight_cluster_vd_threshold;
// Global loose cluster parameters (adjustable parameters)
extern f32 g_loose_cluster_nd_threshold; // Base threshold
extern f32 g_loose_cluster_vd_threshold; // Base threshold
extern f32 g_loose_cluster_nd_fraction; // Zoom scaling fraction
extern f32 g_loose_cluster_vd_fraction; // Zoom scaling fraction
// Tight cluster structure
typedef struct {
i32 glassIndices[MAX_CLUSTER_SIZE]; // Indices of glasses in this cluster
i32 count; // Number of glasses in cluster
i32 representativeIndex; // Index of glass with shortest name
f32 avgAbbeNumber; // Average position for reference
f32 avgRefractiveIndex;
} TightCluster;
// Loose cluster structure (zoom-dependent)
typedef struct {
i32 glassIndices[MAX_CLUSTER_SIZE]; // Indices of glasses in this cluster
i32 count; // Number of glasses in cluster
i32 representativeIndex; // Index of glass with shortest name
f32 avgAbbeNumber; // Average position for reference
f32 avgRefractiveIndex;
} LooseCluster;
// State for zooming and panning
typedef struct {
f32 zoomLevel;
f32 offsetX;
f32 offsetY;
i32 windowWidth;
i32 windowHeight;
f32 minAbbe;
f32 maxAbbe;
f32 minRI;
f32 maxRI;
b32 showHelp; // Flag to show/hide help window
b32 gKeyPressed; // Flag to track if 'g' was pressed
u32 gKeyTime; // Time when 'g' was pressed for sequence timing
i32 selectedGlass; // Index of selected glass (-1 if none)
i32 selectedCluster; // Index of selected tight cluster (-1 if none)
// Tight cluster data (per catalog)
TightCluster* tightClusters; // Array of tight clusters for current catalog
i32 tightClusterCount; // Number of tight clusters
// Loose cluster data (per catalog, zoom-dependent)
LooseCluster* looseClusters; // Array of loose clusters for current catalog
i32 looseClusterCount; // Number of loose clusters
// Label recalculation tracking
f32 lastZoomLevel; // Last zoom level for which labels were calculated
i32 lastWindowWidth; // Last window width for labels
i32 lastWindowHeight; // Last window height for labels
f32 lastOffsetX; // Last X offset for labels
f32 lastOffsetY; // Last Y offset for labels
} ViewState;
// Initialize a view state with default values
void init_view_state(ViewState* view, i32 windowWidth, i32 windowHeight);
// Refresh view state data range when catalog changes
void refresh_view_data_range(ViewState* view);
// Helper function to calculate adaptive padding
static inline i32 get_adaptive_padding(const ViewState* view) {
i32 padding = (i32)(view->windowWidth * MAX_PADDING_PERCENT);
return padding > MIN_PADDING ? padding : MIN_PADDING;
}
// Convert glass data to screen coordinates with zoom and offset
static inline void data_to_screen_coords(f32 abbeNumber, f32 refractiveIndex,
const ViewState* view, i32 *x, i32 *y) {
const i32 padding = get_adaptive_padding(view);
// Apply zoom and offset transformation
// FLIPPED: Use 1.0f - normalized to flip the Abbe number axis
f32 normalizedX = 1.0f - (abbeNumber - view->minAbbe) / (view->maxAbbe - view->minAbbe);
f32 normalizedY = (refractiveIndex - view->minRI) / (view->maxRI - view->minRI);
// Transform with zoom and offset
normalizedX = (normalizedX - 0.5f) * view->zoomLevel + 0.5f + view->offsetX;
normalizedY = (normalizedY - 0.5f) * view->zoomLevel + 0.5f + view->offsetY;
// Convert to screen coordinates
*x = padding + (i32)(normalizedX * (view->windowWidth - 2 * padding));
*y = view->windowHeight - padding - (i32)(normalizedY * (view->windowHeight - 2 * padding));
}
// Convert screen coordinates to data values
static inline void screen_to_data_coords(i32 x, i32 y, const ViewState* view,
f32 *abbeNumber, f32 *refractiveIndex) {
const i32 padding = get_adaptive_padding(view);
// Convert to normalized coordinates
f32 normalizedX = (f32)(x - padding) / (view->windowWidth - 2 * padding);
f32 normalizedY = (f32)(view->windowHeight - y - padding) / (view->windowHeight - 2 * padding);
// Reverse transform with zoom and offset
normalizedX = (normalizedX - view->offsetX - 0.5f) / view->zoomLevel + 0.5f;
normalizedY = (normalizedY - view->offsetY - 0.5f) / view->zoomLevel + 0.5f;
// Convert to data values - FLIPPED axis logic for Abbe
*abbeNumber = view->maxAbbe - normalizedX * (view->maxAbbe - view->minAbbe);
*refractiveIndex = view->minRI + normalizedY * (view->maxRI - view->minRI);
}
// Find the nearest glass to a given screen position
i32 find_nearest_glass(i32 x, i32 y, const ViewState* view, f32 maxDistance);
// Calculate visible data range based on current view
void get_visible_data_range(const ViewState* view, f32 *visibleMinAbbe, f32 *visibleMaxAbbe,
f32 *visibleMinRI, f32 *visibleMaxRI);
// Handle mouse wheel zoom
void handle_mouse_wheel_zoom(i32 wheelY, i32 mouseX, i32 mouseY, ViewState* view);
// Toggle fullscreen
void toggle_fullscreen(SDL_Window* window);
// Reset view to default
void reset_view(ViewState* view);
// Tight clustering functions
void create_tight_clusters(ViewState* view);
void free_tight_clusters(ViewState* view);
i32 find_tight_cluster_for_glass(i32 glassIndex, const ViewState* view);
// Loose clustering functions (zoom-dependent)
void create_loose_clusters(ViewState* view);
void free_loose_clusters(ViewState* view);
i32 find_loose_cluster_for_glass(i32 glassIndex, const ViewState* view);
// Combined clustering logic
b32 should_show_glass_label(i32 glassIndex, const ViewState* view);
#endif /* GLAMAC_VIEW_H */
|