feat: Implement aircraft type differentiation and movement indicators
Adds comprehensive visual differentiation system for 3D radar aircraft: Aircraft Type Differentiation: - Different 3D geometries for aircraft categories (helicopter, heavy, medium, light) - Color coding: cyan=helicopter, blue=heavy, green=medium, yellow=light - Size scaling based on aircraft weight class - Emergency override: red color for emergency squawks and alerts Movement Indicators: - Aircraft orientation based on track/heading data - Climb/descent indicators with 500 fpm threshold - Green upward arrows for climbing aircraft - Red downward arrows for descending aircraft - Dynamic indicator management (add/remove based on vertical rate) Technical Implementation: - Modular aircraft geometry creation system - Visual type detection based on Category field - Enhanced material system with emissive properties - Proper cleanup of climb/descent indicators - Updated selection system to restore original aircraft colors Addresses core visual enhancement requirements from issue #42. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
c6aab821a3
commit
51a74ac85e
1 changed files with 165 additions and 10 deletions
|
|
@ -801,8 +801,7 @@ class SkyView {
|
|||
if (!this.radar3d.aircraftMeshes.has(key)) {
|
||||
// Create new aircraft mesh only if within range
|
||||
if (withinRange) {
|
||||
const geometry = new THREE.ConeGeometry(0.5, 2, 6);
|
||||
const material = new THREE.MeshLambertMaterial({ color: 0x00ff00 });
|
||||
const { geometry, material } = this.create3DAircraftGeometry(aircraft);
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
this.radar3d.aircraftMeshes.set(key, mesh);
|
||||
this.radar3d.scene.add(mesh);
|
||||
|
|
@ -838,10 +837,8 @@ class SkyView {
|
|||
|
||||
mesh.position.set(x, y, z);
|
||||
|
||||
// Orient mesh based on track
|
||||
if (aircraft.Track !== undefined) {
|
||||
mesh.rotation.y = -aircraft.Track * Math.PI / 180;
|
||||
}
|
||||
// Update aircraft visual indicators (direction, climb/descent)
|
||||
this.update3DAircraftVisuals(mesh, aircraft);
|
||||
|
||||
// Update trail if trails are enabled
|
||||
if (this.radar3d.showTrails && aircraft.position_history) {
|
||||
|
|
@ -1056,11 +1053,15 @@ class SkyView {
|
|||
|
||||
const icao = this.radar3d.selectedAircraft;
|
||||
|
||||
// Reset mesh appearance
|
||||
// Reset mesh appearance to original aircraft color
|
||||
const mesh = this.radar3d.aircraftMeshes.get(icao);
|
||||
if (mesh) {
|
||||
mesh.material.color.setHex(0x00ff00); // Back to green
|
||||
mesh.material.emissive.setHex(0x000000); // Remove glow
|
||||
const aircraft = this.aircraftManager.aircraftData.get(icao);
|
||||
if (mesh && aircraft) {
|
||||
const visualType = this.getAircraftVisualType(aircraft);
|
||||
const originalColor = this.getAircraftColor(aircraft, visualType);
|
||||
mesh.material.color.setHex(originalColor);
|
||||
mesh.material.emissive.setHex(originalColor);
|
||||
mesh.material.emissiveIntensity = 0.1; // Restore original glow
|
||||
}
|
||||
|
||||
// Reset label appearance
|
||||
|
|
@ -1185,6 +1186,160 @@ class SkyView {
|
|||
}
|
||||
}
|
||||
|
||||
// Aircraft visual type determination based on category and other data
|
||||
getAircraftVisualType(aircraft) {
|
||||
const category = aircraft.Category || '';
|
||||
|
||||
// Helicopter detection
|
||||
if (category.toLowerCase().includes('helicopter') ||
|
||||
category.toLowerCase().includes('rotorcraft')) {
|
||||
return 'helicopter';
|
||||
}
|
||||
|
||||
// Weight-based categories
|
||||
if (category.includes('Heavy')) return 'heavy';
|
||||
if (category.includes('Medium')) return 'medium';
|
||||
if (category.includes('Light')) return 'light';
|
||||
|
||||
// Size-based categories (fallback)
|
||||
if (category.includes('Large')) return 'heavy';
|
||||
if (category.includes('Small')) return 'light';
|
||||
|
||||
// Default to medium commercial aircraft
|
||||
return 'medium';
|
||||
}
|
||||
|
||||
// Get aircraft color based on type and status
|
||||
getAircraftColor(aircraft, visualType) {
|
||||
// Emergency override
|
||||
if (aircraft.Emergency && aircraft.Emergency !== 'None') {
|
||||
return 0xff0000; // Red for emergencies
|
||||
}
|
||||
|
||||
// Special squawk codes
|
||||
if (aircraft.Squawk) {
|
||||
if (aircraft.Squawk === '7500' || aircraft.Squawk === '7600' || aircraft.Squawk === '7700') {
|
||||
return 0xff0000; // Red for emergency squawks
|
||||
}
|
||||
}
|
||||
|
||||
// Type-based colors
|
||||
switch (visualType) {
|
||||
case 'helicopter':
|
||||
return 0x00ffff; // Cyan for helicopters
|
||||
case 'heavy':
|
||||
return 0x0088ff; // Blue for heavy aircraft
|
||||
case 'medium':
|
||||
return 0x00ff00; // Green for medium aircraft (default)
|
||||
case 'light':
|
||||
return 0xffff00; // Yellow for light aircraft
|
||||
default:
|
||||
return 0x00ff00; // Default green
|
||||
}
|
||||
}
|
||||
|
||||
// Create appropriate 3D geometry and material for aircraft type
|
||||
create3DAircraftGeometry(aircraft) {
|
||||
const visualType = this.getAircraftVisualType(aircraft);
|
||||
const color = this.getAircraftColor(aircraft, visualType);
|
||||
|
||||
let geometry, scale = 1;
|
||||
|
||||
switch (visualType) {
|
||||
case 'helicopter':
|
||||
// Helicopter: Wider, flatter shape with rotor disk
|
||||
geometry = new THREE.CylinderGeometry(0.8, 0.4, 0.6, 8);
|
||||
scale = 1.0;
|
||||
break;
|
||||
|
||||
case 'heavy':
|
||||
// Heavy aircraft: Large, wide fuselage
|
||||
geometry = new THREE.CylinderGeometry(0.4, 0.8, 3.0, 8);
|
||||
scale = 1.3;
|
||||
break;
|
||||
|
||||
case 'light':
|
||||
// Light aircraft: Small, simple shape
|
||||
geometry = new THREE.ConeGeometry(0.3, 1.5, 6);
|
||||
scale = 0.7;
|
||||
break;
|
||||
|
||||
case 'medium':
|
||||
default:
|
||||
// Medium/default: Standard cone shape
|
||||
geometry = new THREE.ConeGeometry(0.5, 2, 6);
|
||||
scale = 1.0;
|
||||
break;
|
||||
}
|
||||
|
||||
const material = new THREE.MeshLambertMaterial({
|
||||
color: color,
|
||||
emissive: color,
|
||||
emissiveIntensity: 0.1
|
||||
});
|
||||
|
||||
// Scale geometry if needed
|
||||
if (scale !== 1.0) {
|
||||
geometry.scale(scale, scale, scale);
|
||||
}
|
||||
|
||||
return { geometry, material };
|
||||
}
|
||||
|
||||
// Update aircraft visual indicators (direction, climb/descent)
|
||||
update3DAircraftVisuals(mesh, aircraft) {
|
||||
// Set aircraft direction based on track
|
||||
if (aircraft.Track !== undefined && aircraft.Track !== 0) {
|
||||
mesh.rotation.y = -aircraft.Track * Math.PI / 180;
|
||||
}
|
||||
|
||||
// Add climb/descent indicator
|
||||
this.update3DClimbDescentIndicator(mesh, aircraft);
|
||||
}
|
||||
|
||||
// Add or update climb/descent visual indicator
|
||||
update3DClimbDescentIndicator(mesh, aircraft) {
|
||||
const verticalRate = aircraft.VerticalRate || 0;
|
||||
const threshold = 500; // feet per minute
|
||||
|
||||
// Remove existing indicator
|
||||
const existingIndicator = mesh.getObjectByName('climbIndicator');
|
||||
if (existingIndicator) {
|
||||
mesh.remove(existingIndicator);
|
||||
}
|
||||
|
||||
// Add new indicator if significant vertical movement
|
||||
if (Math.abs(verticalRate) > threshold) {
|
||||
let indicatorGeometry, indicatorMaterial;
|
||||
|
||||
if (verticalRate > threshold) {
|
||||
// Climbing - green upward arrow
|
||||
indicatorGeometry = new THREE.ConeGeometry(0.2, 0.8, 4);
|
||||
indicatorMaterial = new THREE.MeshBasicMaterial({
|
||||
color: 0x00ff00,
|
||||
transparent: true,
|
||||
opacity: 0.8
|
||||
});
|
||||
} else if (verticalRate < -threshold) {
|
||||
// Descending - red downward arrow
|
||||
indicatorGeometry = new THREE.ConeGeometry(0.2, 0.8, 4);
|
||||
indicatorMaterial = new THREE.MeshBasicMaterial({
|
||||
color: 0xff0000,
|
||||
transparent: true,
|
||||
opacity: 0.8
|
||||
});
|
||||
indicatorGeometry.rotateX(Math.PI); // Flip for downward arrow
|
||||
}
|
||||
|
||||
if (indicatorGeometry && indicatorMaterial) {
|
||||
const indicator = new THREE.Mesh(indicatorGeometry, indicatorMaterial);
|
||||
indicator.name = 'climbIndicator';
|
||||
indicator.position.set(0, 2, 0); // Position above aircraft
|
||||
mesh.add(indicator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initialize3DControls() {
|
||||
// Enable and initialize the Reset View button
|
||||
const resetButton = document.getElementById('radar3d-reset');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue