Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updated ThreeD, Radar, Map area calculation method #1379

Merged
merged 2 commits into from
Nov 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 17 additions & 25 deletions src/client/app/components/MapChartComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { readingsApi } from '../redux/api/readingsApi';
import { selectUnitDataById } from '../redux/api/unitsApi';
import { useAppSelector } from '../redux/reduxHooks';
import { selectMapChartQueryArgs } from '../redux/selectors/chartQuerySelectors';
import { selectAreaScalingFromEntity } from '../redux/selectors/entitySelectors';
import { DataType } from '../types/Datasources';
import { State } from '../types/redux/state';
import { UnitRepresentType } from '../types/redux/units';
Expand All @@ -30,7 +31,7 @@ import {
itemMapInfoOk,
normalizeImageDimensions
} from '../utils/calibration';
import { AreaUnitType, getAreaUnitConversion } from '../utils/getAreaUnitConversion';
import { AreaUnitType } from '../utils/getAreaUnitConversion';
import getGraphColor from '../utils/getGraphColor';
import { useTranslate } from '../redux/componentHooks';
import SpinnerComponent from './SpinnerComponent';
Expand Down Expand Up @@ -144,25 +145,20 @@ export default function MapChartComponent() {

for (const meterID of selectedMeters) {
// Get meter id number.
// Get meter GPS value.
const gps = meterDataById[meterID].gps;
const entity = meterDataById[meterID];
// filter meters with actual gps coordinates.
if (gps !== undefined && gps !== null && meterReadings !== undefined) {
let meterArea = meterDataById[meterID].area;
if (entity.gps !== undefined && entity.gps !== null && meterReadings !== undefined) {
// we either don't care about area, or we do in which case there needs to be a nonzero area
if (!areaNormalization || (meterArea > 0 && meterDataById[meterID].areaUnit != AreaUnitType.none)) {
if (areaNormalization) {
// convert the meter area into the proper unit, if needed
meterArea *= getAreaUnitConversion(meterDataById[meterID].areaUnit, selectedAreaUnit);
}
if (!areaNormalization || (entity.area > 0 && entity.areaUnit != AreaUnitType.none)) {
const meterArea = selectAreaScalingFromEntity(entity, selectedAreaUnit, areaNormalization);
// Convert the gps value to the equivalent Plotly grid coordinates on user map.
// First, convert from GPS to grid units. Since we are doing a GPS calculation, this happens on the true north map.
// It must be on true north map since only there are the GPS axis parallel to the map axis.
// To start, calculate the user grid coordinates (Plotly) from the GPS value. This involves calculating
// it coordinates on the true north map and then rotating/shifting to the user map.
const meterGPSInUserGrid: CartesianPoint = gpsToUserGrid(imageDimensionNormalized, gps, origin, scaleOfMap, map.northAngle);
const meterGPSInUserGrid: CartesianPoint = gpsToUserGrid(imageDimensionNormalized, entity.gps, origin, scaleOfMap, map.northAngle);
// Only display items within valid info and within map.
if (itemMapInfoOk(meterID, DataType.Meter, map, gps) && itemDisplayableOnMap(imageDimensionNormalized, meterGPSInUserGrid)) {
if (itemMapInfoOk(meterID, DataType.Meter, map, entity.gps) && itemDisplayableOnMap(imageDimensionNormalized, meterGPSInUserGrid)) {
// The x, y value for Plotly to use that are on the user map.
x.push(meterGPSInUserGrid.x);
y.push(meterGPSInUserGrid.y);
Expand All @@ -174,7 +170,7 @@ export default function MapChartComponent() {
// This protects against there being no readings or that the data is being updated.
if (readingsData !== undefined && !meterIsFetching) {
// Meter name to include in hover on graph.
const label = meterDataById[meterID].identifier;
const label = entity.identifier;
// The usual color for this meter.
colors.push(getGraphColor(meterID, DataType.Meter));
if (!readingsData) {
Expand Down Expand Up @@ -220,24 +216,20 @@ export default function MapChartComponent() {

for (const groupID of selectedGroups) {
// Get group id number.
// Get group GPS value.
const gps = groupDataById[groupID].gps;
const entity = groupDataById[groupID];
// Filter groups with actual gps coordinates.
if (gps !== undefined && gps !== null && groupData !== undefined) {
let groupArea = groupDataById[groupID].area;
if (!areaNormalization || (groupArea > 0 && groupDataById[groupID].areaUnit != AreaUnitType.none)) {
if (areaNormalization) {
// convert the meter area into the proper unit, if needed
groupArea *= getAreaUnitConversion(groupDataById[groupID].areaUnit, selectedAreaUnit);
}
if (entity.gps !== undefined && entity.gps !== null && groupData !== undefined) {
// we either don't care about area, or we do in which case there needs to be a nonzero area
if (!areaNormalization || (entity.area > 0 && entity.areaUnit != AreaUnitType.none)) {
const groupArea = selectAreaScalingFromEntity(entity, selectedAreaUnit, areaNormalization);
// Convert the gps value to the equivalent Plotly grid coordinates on user map.
// First, convert from GPS to grid units. Since we are doing a GPS calculation, this happens on the true north map.
// It must be on true north map since only there are the GPS axis parallel to the map axis.
// To start, calculate the user grid coordinates (Plotly) from the GPS value. This involves calculating
// it coordinates on the true north map and then rotating/shifting to the user map.
const groupGPSInUserGrid: CartesianPoint = gpsToUserGrid(imageDimensionNormalized, gps, origin, scaleOfMap, map.northAngle);
const groupGPSInUserGrid: CartesianPoint = gpsToUserGrid(imageDimensionNormalized, entity.gps, origin, scaleOfMap, map.northAngle);
// Only display items within valid info and within map.
if (itemMapInfoOk(groupID, DataType.Group, map, gps) && itemDisplayableOnMap(imageDimensionNormalized, groupGPSInUserGrid)) {
if (itemMapInfoOk(groupID, DataType.Group, map, entity.gps) && itemDisplayableOnMap(imageDimensionNormalized, groupGPSInUserGrid)) {
// The x, y value for Plotly to use that are on the user map.
x.push(groupGPSInUserGrid.x);
y.push(groupGPSInUserGrid.y);
Expand All @@ -248,7 +240,7 @@ export default function MapChartComponent() {
// This protects against there being no readings or that the data is being updated.
if (readingsData && !groupIsFetching) {
// Group name to include in hover on graph.
const label = groupDataById[groupID].name;
const label = entity.name;
// The usual color for this group.
colors.push(getGraphColor(groupID, DataType.Group));
if (!readingsData) {
Expand Down
27 changes: 10 additions & 17 deletions src/client/app/components/RadarChartComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ import { readingsApi } from '../redux/api/readingsApi';
import { selectUnitDataById } from '../redux/api/unitsApi';
import { useAppSelector } from '../redux/reduxHooks';
import { selectRadarChartQueryArgs } from '../redux/selectors/chartQuerySelectors';
import { selectScalingFromEntity } from '../redux/selectors/entitySelectors';
import {
selectAreaUnit, selectGraphAreaNormalization, selectLineGraphRate,
selectSelectedGroups, selectSelectedMeters, selectSelectedUnit
} from '../redux/slices/graphSlice';
import { DataType } from '../types/Datasources';
import Locales from '../types/locales';
import { AreaUnitType, getAreaUnitConversion } from '../utils/getAreaUnitConversion';
import { AreaUnitType } from '../utils/getAreaUnitConversion';
import getGraphColor from '../utils/getGraphColor';
import { lineUnitLabel } from '../utils/graphics';
import { useTranslate } from '../redux/componentHooks';
Expand Down Expand Up @@ -71,17 +72,13 @@ export default function RadarChartComponent() {
// Add all valid data from existing meters to the radar plot
for (const meterID of selectedMeters) {
if (meterReadings) {
const meterArea = meterDataById[meterID].area;
const entity = meterDataById[meterID];
// We either don't care about area, or we do in which case there needs to be a nonzero area.
if (!areaNormalization || (meterArea > 0 && meterDataById[meterID].areaUnit != AreaUnitType.none)) {
// Convert the meter area into the proper unit if normalizing by area or use 1 if not so won't change reading values.
const areaScaling = areaNormalization ?
meterArea * getAreaUnitConversion(meterDataById[meterID].areaUnit, selectedAreaUnit) : 1;
// Divide areaScaling into the rate so have complete scaling factor for readings.
const scaling = rateScaling / areaScaling;
if (!areaNormalization || (entity.area > 0 && entity.areaUnit != AreaUnitType.none)) {
const scaling = selectScalingFromEntity(entity, selectedAreaUnit, areaNormalization, rateScaling);
const readingsData = meterReadings[meterID];
if (readingsData) {
const label = meterDataById[meterID].identifier;
const label = entity.identifier;
const colorID = meterID;
// TODO If we are sure the data is always defined then remove this commented out code.
// Be consistent for all graphing and groups below.
Expand Down Expand Up @@ -132,17 +129,13 @@ export default function RadarChartComponent() {
for (const groupID of selectedGroups) {
// const byGroupID = state.readings.line.byGroupID[groupID];
if (groupData) {
const groupArea = groupDataById[groupID].area;
const entity = groupDataById[groupID];
// We either don't care about area, or we do in which case there needs to be a nonzero area.
if (!areaNormalization || (groupArea > 0 && groupDataById[groupID].areaUnit != AreaUnitType.none)) {
// Convert the group area into the proper unit if normalizing by area or use 1 if not so won't change reading values.
const areaScaling = areaNormalization ?
groupArea * getAreaUnitConversion(groupDataById[groupID].areaUnit, selectedAreaUnit) : 1;
// Divide areaScaling into the rate so have complete scaling factor for readings.
const scaling = rateScaling / areaScaling;
if (!areaNormalization || (entity.area > 0 && entity.areaUnit != AreaUnitType.none)) {
const scaling = selectScalingFromEntity(entity, selectedAreaUnit, areaNormalization, rateScaling);
const readingsData = groupData[groupID];
if (readingsData) {
const label = groupDataById[groupID].name;
const label = entity.name;
const colorID = groupID;
// if (readingsData.readings === undefined) {
// throw new Error('Unacceptable condition: readingsData.readings is undefined.');
Expand Down
23 changes: 7 additions & 16 deletions src/client/app/components/ThreeDComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ import { selectUnitDataById } from '../redux/api/unitsApi';
import { useAppSelector } from '../redux/reduxHooks';
import { selectThreeDQueryArgs } from '../redux/selectors/chartQuerySelectors';
import { selectThreeDComponentInfo } from '../redux/selectors/threeDSelectors';
import { selectScalingFromEntity } from '../redux/selectors/entitySelectors';
import { selectGraphState } from '../redux/slices/graphSlice';
import { ThreeDReading } from '../types/readings';
import { GraphState, MeterOrGroup } from '../types/redux/graph';
import { GroupDataByID } from '../types/redux/groups';
import { MeterDataByID } from '../types/redux/meters';
import { UnitDataById } from '../types/redux/units';
import { isValidThreeDInterval, roundTimeIntervalForFetch } from '../utils/dateRangeCompatibility';
import { AreaUnitType, getAreaUnitConversion } from '../utils/getAreaUnitConversion';
import { AreaUnitType } from '../utils/getAreaUnitConversion';
import { lineUnitLabel } from '../utils/graphics';
// Both translates are used since some are in the function component where the React Hook is okay
// and some are in other functions where the older method is needed.
Expand Down Expand Up @@ -138,23 +139,13 @@ function formatThreeDData(
// The rate will be 1 if it is per hour (since state readings are per hour) or no rate scaling so no change.
const rateScaling = needsRateScaling ? currentSelectedRate.rate : 1;

const meterArea = meterOrGroup === MeterOrGroup.meters ?
meterDataById[selectedMeterOrGroupID].area
const entity = meterOrGroup === MeterOrGroup.meters ?
meterDataById[selectedMeterOrGroupID]
:
groupDataById[selectedMeterOrGroupID].area;
groupDataById[selectedMeterOrGroupID];
const scaling = selectScalingFromEntity(entity, graphState.selectedAreaUnit, graphState.areaNormalization, rateScaling);

const areaUnit = meterOrGroup === MeterOrGroup.meters ?
meterDataById[selectedMeterOrGroupID].areaUnit
:
groupDataById[selectedMeterOrGroupID].areaUnit;

// We either don't care about area, or we do in which case there needs to be a nonzero area.
if (!graphState.areaNormalization || (meterArea > 0 && areaUnit != AreaUnitType.none)) {
// Convert the meter area into the proper unit if normalizing by area or use 1 if not so won't change reading values.
const areaScaling = graphState.areaNormalization ?
meterArea * getAreaUnitConversion(areaUnit, graphState.selectedAreaUnit) : 1;
// Divide areaScaling into the rate so have complete scaling factor for readings.
const scaling = rateScaling / areaScaling;
if (!graphState.areaNormalization || (entity.area > 0 && entity.areaUnit != AreaUnitType.none)) {
zDataToRender = data.zData.map(day => day.map(reading => reading === null ? null : reading * scaling));
}
}
Expand Down
Loading