Commit f4889223 authored by Rushikesh Padsala's avatar Rushikesh Padsala
Browse files

Upload New File

parent b4ebbf16
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxYjBlYmYyNC1kNWRhLTRiNTUtOGNlYi02NGY1YWVhNjI2MjIiLCJpZCI6MTEwNzEsImlhdCI6MTYxOTcwNjI0M30.tlpaagcH93SjaHIn7eEVpanGSiH2yDylbGJZr2gsXnY';
//////////////////////////////////////////////////////////////////////////
// Loading Custom Terrain
//////////////////////////////////////////////////////////////////////////
var customterrain = new Cesium.CesiumTerrainProvider({
//url: 'https://w2.iaf-ex.hft-stuttgart.de/CesiumData/QuantizedMesh/DigiTwins4PEDs/Nordbahnhof/',
url: 'https://web3d.basemap.de/cesium/dgm5-mesh'
});
var terrainProviderViewModels = [];
terrainProviderViewModels.push(new Cesium.ProviderViewModel({
name: 'Custom Terrain',
iconUrl: Cesium.buildModuleUrl('https://w2.iaf-ex.hft-stuttgart.de/CesiumData/Images/TerrainProviders/Terrain.png'),
tooltip: 'Custom Terrain',
creationFunction: function () {
return customterrain;
}
}));
//////////////////////////////////////////////////////////////////////////
// Creating the Viewer
//////////////////////////////////////////////////////////////////////////
var viewer = new Cesium.Viewer('cesiumContainer', {
scene3DOnly: true,
selectionIndicator: false,
timeline: false,
animation: false,
shadow: false,
imageryProvider: new Cesium.WebMapServiceImageryProvider({
url: 'https://sgx.geodatenzentrum.de/wms_basemapde?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities',
layers: "de_basemapde_web_raster_farbe",
enablePickFeatures: false,
parameters: {
transparent: true,
format: "image/png",
}
}),
baseLayerPicker: true,
terrainProviderViewModels: terrainProviderViewModels
});
viewer.clock.shouldAnimate = false;
viewer.clock.currentTime = Cesium.JulianDate.fromIso8601('2024-07-05T12:00:00Z');
viewer.clock.multiplier = 0; // pause the time
viewer.scene.globe.enableLighting = true;
viewer.scene.globe.depthTestAgainstTerrain = true;
//////////////////////////////////////////////////////////////////////////
// Set the camera to Nordbahnhof, Stuttgart, Germany with a slanted view
//////////////////////////////////////////////////////////////////////////
// Define the Nordbahnhof initial position and orientation
var nordbahnhofPosition = {
destination: Cesium.Cartesian3.fromDegrees(9.201653, 48.791294, 1047.54), // Nordbahnhof coordinates with height
orientation: {
heading: Cesium.Math.toRadians(313.31), // Heading: 19.98°
pitch: Cesium.Math.toRadians(-38.18), // Pitch: -28.11°
roll: Cesium.Math.toRadians(360) // Roll: 0°
}
};
// Ensure the camera moves to Nordbahnhof once the viewer is fully loaded
viewer.scene.camera.setView(nordbahnhofPosition);
// Override the home button behavior to fly to Nordbahnhof
viewer.homeButton.viewModel.command.beforeExecute.addEventListener(function (e) {
e.cancel = true; // Prevent default home behavior
viewer.scene.camera.flyTo(nordbahnhofPosition); // Fly to Nordbahnhof
});
//////////////////////////////////////////////////////////////////////////
// Log Camera Heading, Pitch, and Roll in Console
//////////////////////////////////////////////////////////////////////////
function logCameraPosition() {
var camera = viewer.camera;
// Get the camera position in Cartographic coordinates (longitude, latitude, height)
var cartographic = Cesium.Cartographic.fromCartesian(camera.position);
// Convert the longitude and latitude from radians to degrees
var longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6); // 6 decimal places for precision
var latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(6);
var height = cartographic.height.toFixed(2); // Height in meters
// Get the heading, pitch, and roll in degrees
var heading = Cesium.Math.toDegrees(camera.heading).toFixed(2);
var pitch = Cesium.Math.toDegrees(camera.pitch).toFixed(2);
var roll = Cesium.Math.toDegrees(camera.roll).toFixed(2);
// Log the camera settings to the console
console.log(`Camera Settings:
Longitude: ${longitude}°, Latitude: ${latitude}°, Height: ${height}m
Heading: ${heading}°, Pitch: ${pitch}°, Roll: ${roll}°`);
}
// Add event listener to track and log camera changes
viewer.scene.camera.changed.addEventListener(logCameraPosition);
//////////////////////////////////////////////////////////////////////////
// Load 3D Tileset
//////////////////////////////////////////////////////////////////////////
var tileset = viewer.scene.primitives.add(
new Cesium.Cesium3DTileset({
//url: 'https://w2.iaf-ex.hft-stuttgart.de/CesiumData/3DTiles/Buildings/BuildingSolid/DigiTwin4PEDs/Nordbahnhof/tileset.json'
url: 'https://web3d.basemap.de/cesium/buildings-fly/root.json'
})
);
var hiddenGmlIds = ['DEBW_522100053we', 'DEBW_52210003ulx', 'DEBW_52210006LHY', 'DEBW_52210005gIu', 'DEBW_52210006LNk', 'DEBW_52210005zbD', 'DEBW_52210005O8W', 'DEBW_52210005Kxc', 'DEBW_52210004zZb', 'DEBW_52210005PEz', 'DEBW_52210004IRl', 'DEBW_52210004ddl', 'DEBW_5221KL0002V', 'DEBW_52210005hsz', 'DEBW_52210003wlS', 'DEBW_522100050sv', 'DEBW_52210004FnS', 'DEBW_52210003ulG', 'DEBW_52210003ryU', 'DEBW_5221KL0002i', 'DEBW_52210003uU7', 'DEBW_52210004LH0', 'DEBW_522100050IF', 'DEBW_52210003vqL', 'DEBW_52210004gZA', 'DEBW_522100053qO', 'DEBW_522100063PZ', 'DEBW_52210006Iup', 'DEBW_522100053z0', 'DEBW_52210004eqA', 'DEBW_52210005O0q', 'DEBW_52210004cou', 'DEBW_5221000604Q', 'DEBW_52210004KLX', 'DEBW_52210004Jdv', 'DEBW_522100050KK', 'DEBW_52210004G1X', 'DEBW_52210006LTL', 'DEBW_52210005437', 'DEBW_52210004IDK', 'DEBW_52210006JQT', 'DEBW_5221000cD5u', 'DEBW_522Hc00000C', 'DEBW_52210004yts', 'DEBW_52210005Lb3', 'DEBW_52210005fhl', 'DEBW_52210004ffc', 'DEBW_522100052gA', 'DEBW_5221000549l', 'DEBW_52210004iD6', 'DEBW_522100060N7', 'DEBW_52210006LGU', 'DEBW_52210005NyR', 'DEBW_52210006Gc3', 'DEBW_522100052qj', 'DEBW_5221KL0002w', 'DEBW_52210005PXk', 'DEBW_52210005fgO', 'DEBW_52210004Hvv', 'DEBW_52210006MbW', 'DEBW_52210005LV4', 'DEBW_52210006LFU', 'DEBW_52210005J6x', 'DEBW_52210005y5N', 'DEBW_522100050IN', 'DEBW_52210006K64', 'DEBW_52210005PVy', 'DEBW_52210004L6O', 'DEBW_52210005gJc', 'DEBW_52210003wdH', 'DEBW_5221KL0002j', 'DEBW_52210005MWw', 'DEBW_52210006LIF', 'DEBW_52210004gf4', 'DEBW_52210006IuB', 'DEBW_52210004yYG', 'DEBW_52210004gZp', 'DEBW_52210004Lfg', 'DEBW_52210005z4h', 'DEBW_52210004zc1', 'DEBW_52210005JuM', 'DEBW_5221000c0RS', 'DEBW_52210005fXo', 'DEBW_52210003sn8', 'DEBW_5221KL0002l', 'DEBW_522100060xG', 'DEBW_52210005k1O', 'DEBW_52210004emI', 'DEBW_52210006MpT', 'DEBW_522100052p6', 'DEBW_52210004eUw', 'DEBW_52210004yr0', 'DEBW_522100061MX', 'DEBW_52210004hlr', 'DEBW_522Xh00003r', 'DEBW_52210005euN', 'DEBW_52210004Lfv', 'DEBW_52210004fqi', 'DEBW_522100060k1', 'DEBW_5221KL0002h', 'DEBW_52210004IqN', 'DEBW_52210005PxG', 'DEBW_52210004ft9', 'DEBW_52210004HGq', 'DEBW_52210005Oal', 'DEBW_5221KL0002k', 'DEBW_52210004iSX', 'DEBW_52210005PJM', 'DEBW_52210006KCK', 'DEBW_52210004gRP', 'DEBW_5221000642S', 'DEBW_522100052OM', 'DEBW_52210005fW2', 'DEBW_5221000542S', 'DEBW_52210004ebt', 'DEBW_522100063Nh', 'DEBW_52210005O3B', 'DEBW_52210005gGA', 'DEBW_52210003wCB', 'DEBW_52210005LEX', 'DEBW_52210004eU8', 'DEBW_52210006NPu', 'DEBW_52210004fqX', 'DEBW_52210005gUI', 'DEBW_52210005LgX', 'DEBW_5221KL0002y', 'DEBW_52210003suT', 'DEBW_52210004LoD', 'DEBW_52210004gJD', 'DEBW_5221KL00034', 'DEBW_52210005geZ', 'DEBW_52210005Pir', 'DEBW_52210004ISg', 'DEBW_52210005kDu', 'DEBW_52210003y1J', 'DEBW_522100062FH', 'DEBW_52210004dL7', 'DEBW_52210004JcN', 'DEBW_52210005MdK', 'DEBW_52210004yij', 'DEBW_52210004gcl', 'DEBW_522100052iz', 'DEBW_52210006LwJ', 'DEBW_522100050cr', 'DEBW_52210003uMg', 'DEBW_52210006LBH', 'DEBW_52210004iXp', 'DEBW_52210004Li3', 'DEBW_522100060iV', 'DEBW_5221KL0002m', 'DEBW_52210006N8X', 'DEBW_52210005z6J', 'DEBW_52210004LfC', 'DEBW_52210005h9F', 'DEBW_52210004Lq8', 'DEBW_52210006LLL', 'DEBW_52210005MFs', 'DEBW_52210004dRb', 'DEBW_52210004Kwz', 'DEBW_522100060ek', 'DEBW_522100063Ju', 'DEBW_52210004dIo', 'DEBW_522100050of', 'DEBW_52210004LA9', 'DEBW_52210004I9P', 'DEBW_52210005MMb', 'DEBW_52210004gVz', 'DEBW_52210004HIV', 'DEBW_52210006Ldu', 'DEBW_52210003why', 'DEBW_52210004gd4', 'DEBW_52210005NF0', 'DEBW_52210004fBX', 'DEBW_52210006LOT', 'DEBW_52210003w3N', 'DEBW_52210005yib', 'DEBW_52210003vCA', 'DEBW_52210005L7q', 'DEBW_52210004Hcg', 'DEBW_52210004cpx', 'DEBW_52210005gNM', 'DEBW_52210006LBZ', 'DEBW_522100047AC', 'DEBW_5221000Bwee', 'DEBW_522100061yV', 'DEBW_522100051dE', 'DEBW_52210004dKI', 'DEBW_52210005kDi', 'DEBW_52210006LFe', 'DEBW_52210005Nq8', 'DEBW_52210004zpT', 'DEBW_5221000626z', 'DEBW_52210004L3T', 'DEBW_52210004fiz', 'DEBW_522100060uC', 'DEBW_52210003w8x', 'DEBW_52210004GFF', 'DEBW_522100060fJ', 'DEBW_52210003xs3', 'DEBW_52210004hyo', 'DEBW_52210004KO9', 'DEBW_52210006NHq', 'DEBW_522100051ti', 'DEBW_52210005ikT', 'DEBW_52210003y0j', 'DEBW_52210005hz1', 'DEBW_52210003w3q', 'DEBW_52210004gRL', 'DEBW_52210005O7K', 'DEBW_52210005Lhw', 'DEBW_522100051AL', 'DEBW_522100051wF', 'DEBW_52210006LHQ', 'DEBW_52210004Jc6', 'DEBW_52210004hkG', 'DEBW_52210004fN8', 'DEBW_522100054Pb', 'DEBW_522100063Kw', 'DEBW_52210003y5u', 'DEBW_52210004Lcb', 'DEBW_52210004fHT', 'DEBW_52210005yty', 'DEBW_52210005jOj', 'DEBW_52210005405', 'DEBW_52210004fIR', 'DEBW_52210005PDa', 'DEBW_52210006NFb', 'DEBW_52210005gb6', 'DEBW_52210005N6a', 'DEBW_52210005zY9', 'DEBW_52210003uF8', 'DEBW_52210004gUn', 'DEBW_52210006M3d', 'DEBW_52210004cmm', 'DEBW_52210005Pv1', 'DEBW_52210005iXk', 'DEBW_52210005fT0', 'DEBW_52210004fgQ', 'DEBW_52210005kZo', 'DEBW_52210004GRa', 'DEBW_52210006LoV', 'DEBW_52210003yDp', 'DEBW_52210003yD2', 'DEBW_522u500004c', 'DEBW_522100051xB', 'DEBW_52210004hoB', 'DEBW_52210005hHy', 'DEBW_52210005yyX', 'DEBW_52210003y56', 'DEBW_52210004LhX', 'DEBW_52210003xu6', 'DEBW_52210005KAK', 'DEBW_52210004ga4', 'DEBW_52210003wcg', 'DEBW_52210004zPg', 'DEBW_52210005K2F', 'DEBW_52210004cav', 'DEBW_52210005PJP', 'DEBW_52210004IIN', 'DEBW_52210003v5F', 'DEBW_52210003uIy', 'DEBW_52210005O0m', 'DEBW_52210005yK7', 'DEBW_52210004fVM', 'DEBW_522100054FE', 'DEBW_522100050Yc', 'DEBW_52210006HyA', 'DEBW_522u500004Q', 'DEBW_52210006Llm', 'DEBW_52210003vsq', 'DEBW_52214b0003K', 'DEBW_52210003ta1', 'DEBW_52210006N9P', 'DEBW_52210005khP', 'DEBW_52210006NJd', 'DEBW_52210006NFS', 'DEBW_52210004IHr', 'DEBW_52210005PM3', 'DEBW_522100061sD', 'DEBW_522100051DC', 'DEBW_52210005hHL', 'DEBW_522100051A7', 'DEBW_52210003wBi', 'DEBW_52210004GYQ', 'DEBW_522100064Bf', 'DEBW_52210005ilS', 'DEBW_52210004fmV', 'DEBW_522100062iU', 'DEBW_52210005eKj', 'DEBW_52210006Jy0', 'DEBW_522100052bs', 'DEBW_52210005O8I', 'DEBW_52210006Nt4', 'DEBW_522100060bS', 'DEBW_52210003wFg', 'DEBW_52210005O3N', 'DEBW_5221000528Z', 'DEBW_5221000543U', 'DEBW_5221000626Z', 'DEBW_522100063UQ', 'DEBW_52210003w0u', 'DEBW_522100063po', 'DEBW_522100053ul', 'DEBW_52210003vlS', 'DEBW_52210006NSo', 'DEBW_52210005k8O', 'DEBW_5221000514t', 'DEBW_52210004LVZ', 'DEBW_52210005N4U', 'DEBW_52210003y9v', 'DEBW_52210004fhQ', 'DEBW_52210006KWm', 'DEBW_52210006NP1', 'DEBW_52210003ubf', 'DEBW_522100061Lp', 'DEBW_52210006456', 'DEBW_52210006M21', 'DEBW_52210003uX2', 'DEBW_522100047Gk', 'DEBW_522100060oe', 'DEBW_52210005Pbk', 'DEBW_52210004FoN', 'DEBW_52210004zWG', 'DEBW_522100060aT', 'DEBW_522100063SY', 'DEBW_52210005MXr', 'DEBW_52210005h8J', 'DEBW_52210005eSD', 'DEBW_52210004fCv', 'DEBW_52210004LWA', 'DEBW_52210004Lac', 'DEBW_52210005hM5', 'DEBW_522100051H6', 'DEBW_52210004GLJ', 'DEBW_52210004Fu7', 'DEBW_52210006KYS', 'DEBW_52210005jno', 'DEBW_52210006IMR', 'DEBW_52210004Izg', 'DEBW_52210005hN6', 'DEBW_52210003uXD', 'DEBW_52210005h5h', 'DEBW_52210005fbP', 'DEBW_52210004L6M', 'DEBW_52210005yo6', 'DEBW_52210005igA', 'DEBW_52210003uQ6', 'DEBW_52210006NbS', 'DEBW_522100051GL', 'DEBW_5221000547y', 'DEBW_52210005MxA', 'DEBW_52210003rs0', 'DEBW_52210003xzp', 'DEBW_52210005KsH', 'DEBW_52210005PwT', 'DEBW_52210004ggT', 'DEBW_52210005yvi', 'DEBW_522100051I9', 'DEBW_522100051Bn', 'DEBW_52210003yBb', 'DEBW_5221000649X', 'DEBW_522100060AK', 'DEBW_52210003xxF', 'DEBW_52210003run', 'DEBW_52210004GZK', 'DEBW_52210003sVG', 'DEBW_52210006Lut', 'DEBW_52210005iFY', 'DEBW_52210004LV4', 'DEBW_52210005fZi', 'DEBW_52210003w5n', 'DEBW_52210006N4A', 'DEBW_52210003rtb', 'DEBW_52210005gZO', 'DEBW_52210005hLi']; // Replace with actual gml_ids you want to hide
// Apply style to hide specific buildings
tileset.style = new Cesium.Cesium3DTileStyle({
color: {
conditions: hiddenGmlIds.map(gmlId => {
return [`\${gml_id} === '${gmlId}'`, 'color("rgba(255, 255, 255, 0.0)")'];
}).concat([['true', 'color("white")']])
},
show: {
conditions: hiddenGmlIds.map(gmlId => {
return [`\${gml_id} === '${gmlId}'`, false]; // Hide the building
}).concat([['true', true]]) // Show all others
}
});
var tilesetnord = viewer.scene.primitives.add(
new Cesium.Cesium3DTileset({
url: 'https://w2.iaf-ex.hft-stuttgart.de/CesiumData/3DTiles/Buildings/BuildingSolid/DigiTwin4PEDs/Nordbahnhof/tileset.json'
//url: 'https://web3d.basemap.de/cesium/buildings-fly/root.json'
})
);
//viewer.zoomTo(tileset);
function setDefaultColor() {
tilesetnord.style = new Cesium.Cesium3DTileStyle({
color: 'color("white")'
});
}
//////////////////////////////////////////////////////////////////////////
// Fetch building attributes from WFS service
//////////////////////////////////////////////////////////////////////////
async function fetchBuildingAttributes() {
const loadingIndicator = document.getElementById('spinner');
loadingIndicator.style.display = 'block';
try {
const response = await fetch('https://w2-8080.iaf-ex.hft-stuttgart.de/vcs-wfsT/wfs?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=bldg:Building');
const text = await response.text();
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(text, 'application/xml');
return parseWFSResponse(xmlDoc);
} catch (error) {
console.error('Error fetching building attributes:', error);
return null;
} finally {
loadingIndicator.style.display = 'none';
}
}
function parseWFSResponse(xmlDoc) {
const buildings = {};
const buildingElements = xmlDoc.getElementsByTagName('bldg:Building');
for (let i = 0; i < buildingElements.length; i++) {
const buildingElement = buildingElements[i];
const gmlId = buildingElement.getAttribute('gml:id');
const energyDemands = buildingElement.getElementsByTagName('energy:EnergyDemand');
const energyEnduses = [];
const buildingFunction = buildingElement.getElementsByTagName('bldg:function')[0]?.textContent;
const yearOfConstruction = buildingElement.getElementsByTagName('bldg:yearOfConstruction')[0]?.textContent;
const measuredHeight = buildingElement.getElementsByTagName('bldg:measuredHeight')[0]?.textContent;
const measuredHeightUnit = buildingElement.getElementsByTagName('bldg:measuredHeight')[0]?.getAttribute('uom')?.replace('urn:adv:uom:', '');
const buildingType = buildingElement.getElementsByTagName('energy:buildingType')[0]?.textContent;
// Updated Floor Area extraction
const floorAreaElements = buildingElement.getElementsByTagName('energy:FloorArea');
let floorAreaValue = null;
let floorAreaUom = null;
if (floorAreaElements.length > 0) {
const valueElement = floorAreaElements[0].getElementsByTagName('energy:value')[0];
floorAreaValue = valueElement?.textContent;
floorAreaUom = valueElement?.getAttribute('uom')?.replace('urn:adv:uom:', '');
}
// Updated Volume extraction
const volumeElements = buildingElement.getElementsByTagName('energy:VolumeType');
let volumeValue = null;
let volumeUom = null;
if (volumeElements.length > 0) {
const valueElement = volumeElements[0].getElementsByTagName('energy:value')[0];
volumeValue = valueElement?.textContent;
volumeUom = valueElement?.getAttribute('uom')?.replace('urn:adv:uom:', '');
}
for (let j = 0; j < energyDemands.length; j++) {
const energyDemand = energyDemands[j];
const regularTimeSeries = energyDemand.getElementsByTagName('energy:RegularTimeSeries')[0];
const thematicDescription = regularTimeSeries?.getElementsByTagName('energy:thematicDescription')[0]?.textContent;
const values = regularTimeSeries?.getElementsByTagName('energy:values')[0]?.textContent;
const uom = regularTimeSeries?.getElementsByTagName('energy:values')[0]?.getAttribute('uom');
const acquisitionMethod = regularTimeSeries?.getElementsByTagName('energy:acquisitionMethod')[0]?.textContent;
const source = regularTimeSeries?.getElementsByTagName('energy:source')[0]?.textContent;
const timeInterval = regularTimeSeries?.getElementsByTagName('energy:timeInterval')[0]?.textContent;
const timeIntervalUnit = regularTimeSeries?.getElementsByTagName('energy:timeInterval')[0]?.getAttribute('unit');
const endUse = energyDemand.getElementsByTagName('energy:endUse')[0]?.textContent;
energyEnduses.push({
end_use: endUse,
thematic_description: thematicDescription,
regular_timeseries_values: values,
regular_timeseries_values_uom: uom,
acquisition_method: acquisitionMethod,
acquisition_source: source,
time_interval: timeInterval,
time_interval_unit: timeIntervalUnit
});
}
buildings[gmlId] = {
gml_id: gmlId,
building_function: buildingFunction,
year_of_construction: yearOfConstruction,
measured_height: measuredHeight,
measured_height_unit: measuredHeightUnit,
building_type: buildingType,
floorarea_value: floorAreaValue,
floorarea_value_uom: floorAreaUom,
volumetype_value: volumeValue,
volumetype_value_uom: volumeUom,
energy_enduses: energyEnduses
};
}
return buildings;
}
// Declare buildingAttributes globally
var buildingAttributes = {};
// Fetch and populate the building attributes globally
async function fetchAndStoreBuildingAttributes() {
try {
const data = await fetchBuildingAttributes();
if (data) {
buildingAttributes = data;
}
} catch (error) {
console.error("Failed to fetch building attributes", error);
}
}
fetchAndStoreBuildingAttributes();
//////////////////////////////////////////////////////////////////////////
// Function to map regular_timeseries_values to a color gradient
//////////////////////////////////////////////////////////////////////////
function getColorFromTimeseriesValue(value) {
if (value <=25) {
return 'color("rgb(97, 185, 73)")'; // Low energy consumption
} else if (value <= 50) {
return 'color("rgb(164, 199, 17)")'; // Medium energy consumption
} else if (value <= 75) {
return 'color("rgb(178, 213, 49)")'; // Medium energy consumption
} else if (value <= 100) {
return 'color("rgb(209, 224, 35)")'; // Medium energy consumption
} else if (value <= 125) {
return 'color("rgb(246, 236, 0)")'; // Medium energy consumption
} else if (value <= 150) {
return 'color("rgb(254, 206, 2)")'; // Medium energy consumption
} else if (value <= 200) {
return 'color("rgb(249, 167, 23)")'; // Medium energy consumption
} else if (value <= 250) {
return 'color("rgb(245, 109, 31)")'; // Medium energy consumption
} else {
return 'color("rgb(242, 46, 34)")'; // High energy consumption
}
}
//////////////////////////////////////////////////////////////////////////
// Apply color based on the selected energy demand type
//////////////////////////////////////////////////////////////////////////
async function applyColorToBuildings(thematicDescriptionToSearch) {
const webServiceData = await fetchBuildingAttributes(); // Fetch building attributes
if (!webServiceData) {
console.error('Failed to fetch or parse web service data.');
return;
}
const conditions = Object.keys(webServiceData).map((gml_id) => {
const buildingData = webServiceData[gml_id];
let color = 'color("rgba(255, 255, 255, 0.0)")'; // Default color
//////////////////////////////////////////////////////////////////////////
// Check for energy_enduses array and specific thematic_description
//////////////////////////////////////////////////////////////////////////
if (buildingData.energy_enduses && Array.isArray(buildingData.energy_enduses)) {
buildingData.energy_enduses.forEach((enduse) => {
if (enduse.thematic_description === thematicDescriptionToSearch) {
const timeseriesValue = enduse.regular_timeseries_values;
color = getColorFromTimeseriesValue(timeseriesValue);
}
});
}
return [`\${gml_id} === '${gml_id}'`, color];
});
conditions.push(['true', 'color("rgba(255, 255, 255, 0.1)")']); // Default color for unmatched buildings
// Apply the style to the 3D tileset
tilesetnord.style = new Cesium.Cesium3DTileStyle({
color: {
conditions: conditions
}
});
// After the buildings are colored, display the legend box
const legendBox = document.getElementById('legendBox');
legendBox.style.display = 'block'; // Show the legend after the buildings are colored
}
//////////////////////////////////////////////////////////////////////////
// Handle dropdown selection
//////////////////////////////////////////////////////////////////////////
// Show the legend when an option is selected
document.getElementById('colorByEndUse').addEventListener('change', function (event) {
const selectedValue = event.target.value;
if (selectedValue === 'specificDomesticHotWater') {
applyColorToBuildings('specific domestic hot water demand for a typical year'); // Color buildings and display legend
} else if (selectedValue === 'specificSpaceHeating') {
applyColorToBuildings('specific space heating demand for a typical year'); // Color buildings and display legend
} else if (selectedValue === 'specificSpaceCooling') {
applyColorToBuildings('specific space cooling demand for a typical year'); // Color buildings and display legend
} else {
setDefaultColor(); // Reset to default white if no specific option is selected
document.getElementById('legendBox').style.display = 'none'; // Hide the legend when no selection
}
});
// Set the default color when the tileset is ready
tilesetnord.readyPromise.then(setDefaultColor).catch(function(error) {
console.error('Error loading tileset:', error);
});
//////////////////////////////////////////////////////////////////////////
// Function to format and filter energy end uses with collapsible sections
//////////////////////////////////////////////////////////////////////////
function filterEnergyEnduses(enduses) {
return enduses.filter(enduse =>
!enduse.thematic_description.includes("monthly space heating demand for a typical year") &&
!enduse.thematic_description.includes("monthly space cooling demand for a typical year")
);
}
function formatEnergyEnduses(energyEnduses) {
let filteredEnduses = filterEnergyEnduses(energyEnduses); // Apply the filter
let groupedEnduses = {};
// Group energy end uses by type using <energy:endUse> values
filteredEnduses.forEach(enduse => {
if (!groupedEnduses[enduse.end_use]) {
groupedEnduses[enduse.end_use] = [];
}
groupedEnduses[enduse.end_use].push(enduse);
});
// Generate HTML for energy end uses with collapsible details
let result = '<tr><th colspan="2">Energy End Uses</th></tr>';
for (let [enduse, entries] of Object.entries(groupedEnduses)) {
result += `<tr><td colspan="2">
<details>
<summary>${enduse || 'N/A'}</summary>
<table>`;
entries.forEach((entry, index) => {
result += `
<tr><th>Thematic Description (${index + 1})</th><td>${entry.thematic_description || 'N/A'}</td></tr>
<tr><th>Regular Timeseries Value (${index + 1})</th><td>${entry.regular_timeseries_values || 'N/A'} ${entry.regular_timeseries_values_uom || ''}</td></tr>
<tr><th>Time Interval (${index + 1})</th><td>${entry.time_interval || 'N/A'} ${entry.time_interval_unit || ''}</td></tr>
<tr><th>Acquisition Method (${index + 1})</th><td>${entry.acquisition_method || 'N/A'}</td></tr>
<tr><th>Acquisition Source (${index + 1})</th><td>${entry.acquisition_source || 'N/A'}</td></tr>
`;
});
result += `</table></details></td></tr>`;
}
return result;
}
//////////////////////////////////////////////////////////////////////////
// Function to format building attributes into HTML and include energy end uses
//////////////////////////////////////////////////////////////////////////
function formatBuildingAttributes(buildingData) {
const buildingInfo = `
<tr><th>Building Function</th><td>${buildingData.building_function || 'N/A'}</td></tr>
<tr><th>Year of Construction</th><td>${buildingData.year_of_construction || 'N/A'}</td></tr>
<tr><th>Measured Height</th><td>${buildingData.measured_height || 'N/A'} ${buildingData.measured_height_unit || ''}</td></tr>
<tr><th>Building Type</th><td>${buildingData.building_type || 'N/A'}</td></tr>
<tr><th>Floor Area</th><td>${buildingData.floorarea_value || 'N/A'} ${buildingData.floorarea_value_uom || ''}</td></tr>
<tr><th>Volume Type</th><td>${buildingData.volumetype_value || 'N/A'} ${buildingData.volumetype_value_uom || ''}</td></tr>
`;
const energyEnduses = buildingData.energy_enduses ? formatEnergyEnduses(buildingData.energy_enduses) : '';
return buildingInfo + energyEnduses;
}
//////////////////////////////////////////////////////////////////////////
// Function to extract monthly demand values from building attributes
//////////////////////////////////////////////////////////////////////////
function extractMonthlyDemand(buildingData, thematicDescription) {
const enduses = buildingData.energy_enduses;
// Find the specific enduse matching the given thematic description
const matchingEnduse = enduses.find(enduse => enduse.thematic_description === thematicDescription);
if (matchingEnduse && matchingEnduse.regular_timeseries_values) {
// Split the space-separated values into an array of numbers (monthly values)
return matchingEnduse.regular_timeseries_values.split(' ').map(Number);
} else {
// Return an array of 0's if no data is found for the description
return new Array(12).fill(0);
}
}
//////////////////////////////////////////////////////////////////////////
// Function to load graphs using Highcharts directly into the page
//////////////////////////////////////////////////////////////////////////
function loadGraph(heatingData, coolingData) {
const chartContainer = document.getElementById('chartContainer');
chartContainer.style.display = 'block'; // Show the chart container
const chart = Highcharts.chart('chart', {
accessibility: {
enabled: false // Disable accessibility to avoid the warning
},
title: {
text: 'Energy Time Series Data',
align: 'left'
},
yAxis: {
title: {
text: 'Monthly Energy Demand (kWh)'
},
softMin: 0, // Set the min for dragging
softMax: 400 // Set a soft max for dragging
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
labels: {
style: {
fontSize: '12px'
}
}
},
legend: {
align: 'right', // Align legend to the right
verticalAlign: 'top', // Place legend at the top
layout: 'horizontal', // Keep legend items horizontal
floating: true, // Allow manual positioning
x: 0, // Fine-tune horizontal position
y: 20 // Align vertically with the title
},
chart: {
marginBottom: 80, // Add margin at the bottom for x-axis labels
},
plotOptions: {
series: {
stickyTracking: false, // Disable sticky tracking
dragDrop: {
draggableX: false, // We only want Y draggable
draggableY: false // Set to false by default (edit mode off)
},
point: {
events: {
drag: function (e) {
console.log(`Dragging point: x: ${e.newPoint.x}, y: ${e.newPoint.y}`);
},
drop: function () {
console.log(`Dropped point: ${this.y}`);
}
}
}
}
},
series: [{
name: 'Space Heating Demand',
data: heatingData,
type: 'line' // Define the chart type
}, {
name: 'Space Cooling Demand',
data: coolingData,
type: 'line'
}],
tooltip: {
formatter: function () {
return `<b>${this.series.name}</b><br>${this.x}: ${Highcharts.numberFormat(this.y, 0)} kWh`;
}
}
});
//////////////////////////////////////////////////////////////////////////
// Toggle Button for Edit Mode
//////////////////////////////////////////////////////////////////////////
const editToggleButton = document.getElementById('editToggle');
let editMode = false; // Set initial state (edit mode is off by default)
// Set initial button style for "Edit Off"
editToggleButton.style.backgroundColor = 'red';
editToggleButton.style.color = 'white';
// Event listener to toggle edit mode
editToggleButton.addEventListener('click', function () {
editMode = !editMode; // Toggle edit mode
if (editMode) {
// Enable draggable points and change cursor to grab
toggleDraggable(true);
editToggleButton.innerText = 'Edit On'; // Update button text
editToggleButton.style.backgroundColor = 'green'; // Change button color to green
} else {
// Disable draggable points and revert cursor
toggleDraggable(false);
editToggleButton.innerText = 'Edit Off'; // Update button text
editToggleButton.style.backgroundColor = 'red'; // Change button color to red
}
});
// Function to enable or disable draggable points and cursor change
function toggleDraggable(enable) {
chart.series.forEach(function (series) {
series.update({
dragDrop: {
draggableY: enable // Enable or disable dragging on Y-axis
},
cursor: enable ? 'grab' : 'default' // Set cursor to grab when draggable
});
});
}
}
//////////////////////////////////////////////////////////////////////////
// Function to hide the graph and checkbox containers
//////////////////////////////////////////////////////////////////////////
function hideGraphAndCheckbox() {
document.getElementById('chartContainer').style.display = 'none'; // Hide the chart container
document.getElementById('checkboxContainer').style.display = 'none'; // Hide the checkbox container
}
//////////////////////////////////////////////////////////////////////////
// Function to hide the graph container
//////////////////////////////////////////////////////////////////////////
function hideGraph() {
document.getElementById('chartContainer').style.display = 'none'; // Hide the chart container
}
//////////////////////////////////////////////////////////////////////////
// Function to handle building selection and dynamically update graph
//////////////////////////////////////////////////////////////////////////
function active3DTilePicker() {
var selected = {
feature: undefined,
originalColor: new Cesium.Color()
}; // Declare the selected object
var selectedEntity = new Cesium.Entity();
var clickHandler = viewer.screenSpaceEventHandler.getInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
// Select feature on click and display metadata (turns aqua on click)
viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) {
// Reset the color of the previously selected feature back to its original color
if (Cesium.defined(selected.feature)) {
selected.feature.color = selected.originalColor; // Restore original color
selected.feature = undefined;
viewer.selectedEntity = undefined;
}
// Pick a new feature on click
var picked3DtileFeature = viewer.scene.pick(movement.position);
if (!Cesium.defined(picked3DtileFeature)) {
clickHandler(movement);
return;
}
// Set the selected feature to aqua and store its original color
selected.feature = picked3DtileFeature;
Cesium.Color.clone(picked3DtileFeature.color, selected.originalColor); // Store original color
picked3DtileFeature.color = Cesium.Color.WHEAT ; // Change selected building to aqua
// Match gml_id with building attributes from the fetched data
var gmlId = picked3DtileFeature.getProperty('gml_id');
var buildingData = buildingAttributes[gmlId];
if (buildingData) {
// Extract space heating and cooling data for this building
const heatingData = extractMonthlyDemand(buildingData, 'monthly space heating demand for a typical year');
const coolingData = extractMonthlyDemand(buildingData, 'monthyl space cooling demand for a typical year');
// Display gml ID, gml parent ID, and building attributes in the infoBox
var featureName = "Building Attributes";
selectedEntity.name = featureName;
var description =
'<table class="cesium-infoBox-defaultTable"><tbody>' +
'<tr><th>gml ID</th><td>' + picked3DtileFeature.getProperty('gml_id') + '</td></tr>';
description += formatBuildingAttributes(buildingData);
description += '</tbody></table>';
selectedEntity.description = description;
viewer.selectedEntity = selectedEntity;
// Update the chart with the new heating and cooling data
const checkbox = document.getElementById('showTimeSeriesCheckbox');
if (checkbox) {
checkbox.checked = false; // Reset checkbox on new selection
checkbox.style.display = 'block'; // Ensure checkbox is visible
checkbox._heatingData = heatingData; // Store heating data in checkbox
checkbox._coolingData = coolingData; // Store cooling data in checkbox
}
hideGraph(); // Hide the graph initially
// Attach event listener to checkbox to toggle graph display
if (checkbox && !checkbox._hasEventListener) {
checkbox.addEventListener('change', function () {
if (checkbox.checked) {
loadGraph(checkbox._heatingData, checkbox._coolingData); // Show graph with stored data
} else {
hideGraph(); // Hide the graph when unchecked
}
});
checkbox._hasEventListener = true; // Prevent duplicate listeners
}
} else {
console.error("No data found for gml_id: ", gmlId);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
//////////////////////////////////////////////////////////////////////////
// Attach viewer.selectedEntityChanged listener on initialization
//////////////////////////////////////////////////////////////////////////
viewer.selectedEntityChanged.addEventListener(function(entity) {
if (entity) {
// Delay to ensure InfoBox is fully rendered before positioning the checkbox and chart
setTimeout(() => {
const infoBox = document.querySelector('.cesium-infoBox');
const checkboxContainer = document.getElementById('checkboxContainer');
const chartContainer = document.getElementById('chartContainer');
if (infoBox && checkboxContainer && chartContainer) {
// Get dimensions of the InfoBox
const infoBoxRect = infoBox.getBoundingClientRect();
// Position checkbox below InfoBox
checkboxContainer.style.display = 'block';
checkboxContainer.style.top = infoBoxRect.bottom + 10 + 'px';
checkboxContainer.style.left = infoBoxRect.left + 'px';
// Calculate available space below the checkbox
const spaceBelowCheckbox = window.innerHeight - checkboxContainer.getBoundingClientRect().bottom - 20;
// Adjust the height of the chart container to fit within the available space
const chartHeight = Math.min(430, spaceBelowCheckbox);
// Set width and height of the chart container
chartContainer.style.width = infoBoxRect.width + 'px';
chartContainer.style.height = chartHeight + 'px';
// Position chart container below the checkbox
chartContainer.style.top = checkboxContainer.getBoundingClientRect().bottom + 10 + 'px';
chartContainer.style.left = checkboxContainer.getBoundingClientRect().left + 'px';
}
}, 500); // Delay to ensure InfoBox is fully rendered
} else {
hideGraphAndCheckbox(); // Hide the checkbox and graph if no entity is selected
}
});
//////////////////////////////////////////////////////////////////////////
// Initialize active picker for 3D tile interaction
//////////////////////////////////////////////////////////////////////////
active3DTilePicker();
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment