Fire protection systems represent a sophisticated engineering discipline with substantial industry presence running in to billions annually. Beyond simple extinguishers and smoke detectors, these systems encompass complex infrastructure including water supply networks, hydrant installations, sprinkler networks, gas-based suppression, smoke management, and fire detection systems. Each subsystem contains dozens to hundreds of distinct components designed for specific architectural applications.
Fire Protection System Overview
Water Supply Systems deliver water-based fire suppression through coordinated networks of storage facilities, distribution piping, pump stations, and delivery fixtures.
Hydrant Systems utilize primary and backup pump configurations with sequential startup logic—when the primary unit fails, the secondary activates automatically.
Sprinkler Systems employ spray heads, control valves, and flow detection components to automatically suppress fires through targeted water distribution.
Gas Suppression Systems serve environments where traditional water-based approaches prove impractical.
Smoke Management Systems combine supply and exhaust ductwork with fire dampers, control devices, and motorized fans to maintain tenable conditions during emergencies.
Fire Detection Systems integrate triggering mechanisms, alarm panels, control outputs, and supplementary devices into comprehensive monitoring networks.
Implementation Architecture
System Initialization
The framework employs modular architecture where each fire protection system extends a base prototype, enabling clean separation of concerns:
$(function() {
applicationController = new MainApplication();
applicationController.initialize();
for(var i = 1; i <= 6; i++) {
if(window['FireSystem' + i]) {
window['systemInstance' + i] = new window['FireSystem' + i]();
window['systemInstance' + i].initialize();
}
}
});
System Navigation
Each system exposes configurable navigation hierarchies controlling perspective transitions:
$('.navigation-panel .system-button').on('click', function() {
$('#mainNavigation').hide();
$('#primaryNav').show();
$('#secondaryNav').show();
var systemId = $(this).attr('data-system-index');
if(window['systemInstance' + systemId]) {
window['systemInstance' + systemId].display();
}
});
Dynamic Navigation Generation
Navigation structures populate dynamically based on system configuration:
ApplicationController.prototype.renderPrimaryNavigation = function(navigationItems) {
layer.closeAll();
$('#navigationBack').nextAll().remove();
if(navigationItems && navigationItems.length > 0) {
var htmlContent = '';
$.each(navigationItems, function(index, item) {
htmlContent += '<div id="' + item.elementId + '" class="nav-item ' + item.initialState + '" ' +
'onclick="if(applicationController.isProcessing){return false;};' +
'applicationController.isProcessing=true;' +
'setTimeout(function(){applicationController.isProcessing=false},500);' +
item.executionString + ';">' +
'<img src="../assets/' + (item.initialState === 'inactive' ? 'indicator_off.png' : 'indicator_on.png') + '" />' +
'<span class="label-text">' + item.displayName + '</span>' +
'</div>';
});
$('#navigationBack').after(htmlContent);
}
};
Perspective Switching and Model Visibility
The implementation suppports multiple viewing modes including panoramic, cross-sectional, and network diagram perspectives:
modelController.hideAllSubsystemDevices(200, function() {
layer.display('loading...', { duration: 1000 });
if(configuration.optimalPosition) {
var viewSettings = configuration.optimalPosition[currentState];
var cameraState = { x: 0, y: 0, z: 0 };
var targetState = { x: 0, y: 0, z: 0 };
var targetModels = null;
var modelObjects = null;
if(viewSettings) {
cameraState = viewSettings.camera;
targetState = viewSettings.target;
targetModels = viewSettings.targetModelNames;
}
if(targetModels === 'All') {
modelController.displayAllDeviceModels(1);
} else if(targetModels && targetModels.length > 0) {
modelObjects = sceneUtils.locateObjectsByNames(targetModels);
if(modelObjects && modelObjects.length > 0) {
$.each(modelObjects, function(idx, obj) {
obj.visible = true;
});
}
}
sceneUtils.transitionCamera(cameraState, targetState, 1000, function() {
if(categoryId === 'hydrant_outdoor' || categoryId === 'hydrant_indoor') {
if(objects) {
$.each(objects, function(idx, obj) {
if(obj.name === 'fixture_base_1') {
sceneUtils.adjustOpacity([obj], 1, 0.2, 50, function() {});
}
if(obj.name === 'fixture_internal' && categoryId === 'hydrant_indoor') {
obj.visible = false;
}
if(obj.name === 'fixture_internal' && categoryId === 'hydrant_outdoor') {
obj.visible = true;
}
});
}
}
});
}
});
Animated Sequence Execution
Fire protection scenarios execute through configurable animation sequences defined as action arrays:
SprinklerSystem.prototype.executeAnimationSequence = function() {
modelController.displayAllSubsystemDevices(50, function() {
modelController.hideBuildingGeometry();
modelController.adjustDeviceTransparency(function() {
modelController.applyStandardMaterial();
sceneUtils.transitionCamera(
{ x: -34, y: -331, z: -546 },
{ x: -412, y: -260, z: 135 },
1000,
function() {}
);
var actionSequence = sprinklerSystem.secondaryNav[2].children;
if(actionSequence && actionSequence.length > 0) {
function executeAction(actionIndex) {
$('#' + actionSequence[actionIndex].id).attr('class', 'nav-item active');
if(actionIndex > 0) {
$('#' + actionSequence[actionIndex - 1].id).attr('class', 'nav-item inactive');
}
actionSequence[actionIndex].callback(function() {
if(actionSequence[actionIndex + 1] && actionSequence[actionIndex + 1].callback) {
executeAction(actionIndex + 1);
}
});
}
executeAction(0);
}
});
});
};
Animation Sequence Configuration
var animationSteps = [
{
name: 'Fire Detection',
id: 'scenario_step01',
optimalView: {
camera: { x: -1388, y: -781, z: -309 },
target: { x: -2119, y: -1106, z: 873 }
},
callback: function(completion) {
simulationController.generateFire(function() {
setTimeout(completion, 2000);
});
}
},
{
name: 'Sprinkler Activation',
id: 'scenario_step02',
optimalView: {
camera: { x: -1388, y: -781, z: -309 },
target: { x: -2119, y: -1106, z: 873 }
},
callback: function(completion) {
var sprinklers = sceneUtils.locateObjectsByNames([
'sprinkler_unit_1', 'sprinkler_segment_a',
'sprinkler_segment_b', 'sprinkler_segment_c'
]);
sceneUtils.flashObjects(sprinklers, 'alertPulse', 0xff0000, 10, 200, 0);
setTimeout(function() {
var primarySprinkler = sprinklers[0];
primarySprinkler.children[1].visible = false;
primarySprinkler.children[3].visible = false;
var segA = sprinklers[1];
var posX = segA.position.x;
var posZ = segA.position.z;
var segB = sprinklers[2];
var segC = sprinklers[3];
segA.storedPosition = { x: segA.position.x, y: segA.position.y, z: segA.position.z };
new TWEEN.Tween(segA.position).to({
x: posX + 100 * (Math.random() < 0.5 ? -5 * Math.random() : 3 * Math.random()),
y: -2000,
z: posZ + 100 * (Math.random() < 0.5 ? -5 * Math.random() : 3 * Math.random())
}, 8000).start();
new TWEEN.Tween(segB.position).to({
x: posX + 100 * (Math.random() < 0.5 ? -5 * Math.random() : 3 * Math.random()),
y: -2000,
z: posZ + 100 * (Math.random() < 0.5 ? -5 * Math.random() : 3 * Math.random())
}, 8000).start();
new TWEEN.Tween(segC.position).to({
x: posX + 100 * (Math.random() < 0.5 ? -5 * Math.random() : 3 * Math.random()),
y: -2000,
z: posZ + 100 * (Math.random() < 0.5 ? -5 * Math.random() : 3 * Math.random())
}, 8000).start();
simulationController.generateWaterEffect(function() {
setTimeout(completion, 1000);
});
}, 2000);
}
}
];
Model Creation Strategies
Procedural Model Definition
Code-based models optimize bandwidth and memory while providing precise control over geometry:
[
{
visible: true,
name: 'equipment_cabinet_6',
type: 'cube',
dimensions: { length: 200, width: 200, height: 200 },
position: { x: 0, y: 200, z: 0 },
materials: {
color: 0xffffff,
surfaces: {
top: { color: 0xffffff, texture: '../../assets/interior_rack.jpg', type: 'basic' },
bottom: { color: 0xffffff },
front: { color: 0xffffff },
back: { color: 0xffffff },
left: { color: 0xffffff },
right: { color: 0xffffff }
}
}
}
]
External Asset Loading
External model loading simplifies development for complex geometries:
{
name: 'equipment_rack_7',
type: 'externalModel',
position: { x: 0, y: 0, z: 0 },
scale: { x: 1, y: 1, z: 1 },
visible: true,
rotation: [{ axis: 'x', angle: 0 }],
assetPath: '../../js/3dAssets/models/rack/',
materialFile: 'rack.mtl',
geometryFile: 'rack.obj',
sharedMaterials: false
}
Scene Management
Model Visibility Control
Efficient scene management requires coordinated visibility transitions:
SceneController.prototype.hideAllDeviceGeometry = function(transitionDuration, callback) {
var controller = this;
var deviceObjects = controller.retrieveAllDeviceObjects();
if(deviceObjects && deviceObjects.length > 0) {
sceneUtils.transitionOpacity(deviceObjects, 1, 0.01, transitionDuration || 1000, function() {
$.each(deviceObjects, function(index, object) {
object.visible = false;
});
sceneUtils.transitionOpacity(deviceObjects, 0.9, 1, 1, function() {
if(callback) {
callback();
}
});
});
}
};
SceneController.prototype.displayAllDeviceGeometry = function(transitionDuration, callback) {
var controller = this;
var deviceObjects = controller.retrieveAllDeviceObjects();
if(deviceObjects && deviceObjects.length > 0) {
$.each(deviceObjects, function(index, object) {
object.visible = true;
});
sceneUtils.transitionOpacity(deviceObjects, 0.5, 1, transitionDuration || 1000, function() {
if(callback) {
callback();
}
});
}
};
Smoke Exhaust System Animation
Smoke management scenarios demonstrate complex multi-step animations:
SmokeSystem.prototype.executeScenarioAnimation = function(stepIndex, elementId) {
var systemInstance = this;
modelController.clearSingleDeviceDisplay();
if((systemInstance.primaryState === 'zone_a' || systemInstance.primaryState === 'zone_b') && systemInstance.animationInProgress) {
layer.display('Animation in progress');
return;
}
$('#' + systemInstance.secondaryState).attr('class', 'nav-item inactive');
$('#' + elementId).attr('class', 'nav-item active');
systemInstance.secondaryState = elementId;
var parameters = systemInstance.retrieveSecondaryNavParameters(stepIndex, elementId);
if(!parameters) {
console.error('Configuration initialization failed');
return;
}
layer.closeAll();
systemInstance.playAudioFeedback(stepIndex, elementId);
if(parameters.dataReference && elementId !== 'duct_section') {
modelController.displayDeviceInventory(parameters.dataReference);
}
function performHighlightSequence() {
if(parameters && parameters.highlightNames && parameters.highlightNames.length > 0) {
var targetNames = [];
$.each(parameters.highlightNames, function(idx, nameRef) {
var resolvedName = nameRef;
if(nameRef.indexOf('_child_') > 0) {
resolvedName = nameRef.split('_child_')[0];
}
targetNames.push(resolvedName);
});
targetObjects = sceneUtils.locateObjectsByNames(targetNames);
if(parameters.highlightNames[0] === 'All') {
targetObjects = modelController.getAllSubsystemDevices();
}
setTimeout(function() {
sceneUtils.flashObjects(targetObjects, 'highlightPulse', 0x00ff00, 8, 150, 0);
}, 1000);
}
}
performHighlightSequence();
switch(systemInstance.primaryState) {
case 'panoramic_view':
case 'cross_section':
case 'network_diagram':
if(parameters.optimalView) {
var viewConfig = parameters.optimalView[systemInstance.primaryState];
if(viewConfig) {
sceneUtils.transitionCamera(viewConfig.camera, viewConfig.target, 1000, function() {});
}
}
break;
case 'animation_sequence':
break;
}
};
Fire Detection System Implementation
Detection scenarios combine camera transitions with visual indicators:
function initializeDraggablePanel(elementId) {
var panelElement = document.getElementById(elementId);
var startX = 0, startY = 0;
var offsetLeft = 0, offsetTop = 0;
var dragActive = false;
panelElement.addEventListener('mousedown', function(event) {
startX = event.clientX;
startY = event.clientY;
offsetLeft = panelElement.offsetLeft;
offsetTop = panelElement.offsetTop;
dragActive = true;
panelElement.style.cursor = 'grabbing';
});
window.addEventListener('mousemove', function(event) {
if(!dragActive) return;
var currentX = event.clientX;
var currentY = event.clientY;
var newLeft = currentX - (startX - offsetLeft);
var newTop = currentY - (startY - offsetTop);
panelElement.style.left = newLeft + 'px';
panelElement.style.top = newTop + 'px';
layer.closeAll();
});
panelElement.addEventListener('mouseup', function() {
dragActive = false;
panelElement.style.cursor = 'default';
});
}
initializeDraggablePanel('animationOverlay');
System Class Definition
Each fire protection system extends a prototype with standardized lifecycle methods:
function WaterSupplySystem() {}
WaterSupplySystem.prototype.initialize = function() {};
WaterSupplySystem.prototype.display = function() {
console.log('Activating water supply system visualization');
this.loadAudioAssets();
this.initializeInterface();
modelController.loadDeviceModels(1, function() {
modelController.hideInternalEnclosures();
});
};
WaterSupplySystem.prototype.initializeInterface = function() {
this.primaryNavigation = [
{ state: '', name: 'Panoramic View', id: 'nav_panoramic', action: 'waterSystem.displayView(\'nav_panoramic\')' },
{ state: 'inactive', name: 'Cross Section', id: 'nav_section', action: 'waterSystem.displayView(\'nav_section\')' },
{ state: 'inactive', name: 'Network View', id: 'nav_network', action: 'waterSystem.displayView(\'nav_network\')' },
{ state: 'inactive', name: 'Components', id: 'nav_components', action: 'waterSystem.displayView(\'nav_components\')' }
];
this.secondaryNavigation = [
// Component-specific sub-items
];
appController.renderPrimaryNavigation(this.primaryNavigation);
this.primaryState = 'nav_panoramic';
appController.renderSecondaryNavigation(this.secondaryNavigation[0]);
this.secondaryState = '';
};
This architectural approach enables scalable implementation of complex fire protection visualizations while maintaining clean separation between business logic, scene management, and presentation layers.