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

Adding Validate utility network topology sample #1689

Merged
merged 6 commits into from
Mar 21, 2024

Conversation

har13205
Copy link
Collaborator

Description

This PR is to add Validate utility network topology sample

Type of change

  • Bug fix
  • New sample implementation
  • Sample viewer enhancement
  • Other enhancement

Platforms tested on:

  • Windows
  • Android
  • Linux
  • macOS
  • iOS

Checklist

  • Runs and compiles on all active platforms as a standalone sample
  • Runs and compiles in the sample viewer(s)
  • Branch is up to date with the latest main/v.next
  • All merge conflicts have been resolved
  • Self-review of changes
  • There are no warnings related to changes
  • No unrelated changes have been made to any other code or project files
  • Code is commented with correct formatting (CTRL+i)
  • All variable and method names are camel case
  • There is no leftover commented code
  • Screenshots are correct size and display in description tab (500px by 500px, platform agnostic)
  • If adding a new sample, it is added to the sample viewer
  • Cherry-picked to Main branch (if applicable)

@har13205 har13205 self-assigned this Mar 11, 2024
Copy link
Contributor

@JamesMBallard JamesMBallard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few things to review. See comments. Mainly, I think the general workflows should be split into smaller functions rather than lengthy connect lambdas and .then lambdas.

Comment on lines 133 to 139
bool m_isUpdateVisible;
bool m_validateBtn;
bool m_traceBtn;
bool m_busy;
bool m_clearBtn;
bool m_stateBtn;
int m_attributeValue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These all need default values.

Also, I don't understand what m_traceBtn means as a bool. Same comment for many of these bools.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to m_isTraceBtnEnabled and similar for others

void setupTraceParameters();
void connectSignals();

Esri::ArcGISRuntime::Map* m_map = nullptr;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need all these class members? I would think some of these objects are only needed temporarily, for example do you ever reference m_cred or many of these in different functions?

I would trim this list as much as reasonably possible. It gives an impression that this workflow is more complicated than necessary.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

void setMapView(Esri::ArcGISRuntime::MapQuickView* mapView);
Esri::ArcGISRuntime::LabelDefinition* createDeviceLabelDefinition();
Esri::ArcGISRuntime::LabelDefinition* createLineLabelDefinition();
void getLabelDefinitions();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you consider another name for this function? It begins with 'get' but does not return anything.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to displayLabelDefinitions

signals:
void mapViewChanged();
void messageChanged();
void addChoices();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name doesn't match the naming convention for a signal. It should convey a change of some kind, like choicesChanged.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

Comment on lines 85 to 92
void isUpdateVisible();
void updateFieldName();
void validateBtn();
void traceBtn();
void isBusy();
void clearBtn();
void stateBtn();
void attributeValue();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review these signals names. They don't follow typical guidelines for events.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed


void ValidateUtilityNetworkTopology::onValidate()
{
m_utilityNetwork = m_mapView->map()->utilityNetworks()->first();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does your logic prevent this from being called before all these are available? If not this will crash. If the service is down, for example, will the user be able to get into this logic?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added checking

Comment on lines 523 to 529
m_deviceFeatureLayer->selectFeaturesAsync(deviceParams, SelectionMode::Add).then(this, [](FeatureQueryResult*)
{
});

m_lineFeatureLayer->selectFeaturesAsync(lineParams, SelectionMode::Add).then(this, [](FeatureQueryResult*)
{
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense if you don't need to do anything here, but you could clean up unused memory here.

Suggested change
m_deviceFeatureLayer->selectFeaturesAsync(deviceParams, SelectionMode::Add).then(this, [](FeatureQueryResult*)
{
});
m_lineFeatureLayer->selectFeaturesAsync(lineParams, SelectionMode::Add).then(this, [](FeatureQueryResult*)
{
});
m_deviceFeatureLayer->selectFeaturesAsync(deviceParams, SelectionMode::Add).then(this, [](FeatureQueryResult* rawResult)
{
std::unique_ptr<FeatureQueryResult> {rawResult};
});
m_lineFeatureLayer->selectFeaturesAsync(lineParams, SelectionMode::Add).then(this, [](FeatureQueryResult* rawResult)
{
std::unique_ptr<FeatureQueryResult> {rawResult};
});

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Comment on lines 576 to 580
m_utilityAssetType = m_utilityNetwork
->definition()
->networkSource("Electric Distribution Device")
->assetGroup("Circuit Breaker")
->assetType("Three Phase");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is concise, but if anything goes wrong this will crash. Consider some minimal checking here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

return deviceLabelDefinition;
}

LabelDefinition* ValidateUtilityNetworkTopology::createLineLabelDefinition()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this function can be const. Everything that can be const, should be const.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

emit isBusy();
}

LabelDefinition* ValidateUtilityNetworkTopology::createDeviceLabelDefinition()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be const?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

@har13205 har13205 requested a review from JamesMBallard March 19, 2024 02:46
Comment on lines 170 to 178
connect(m_serviceGeodatabase, &ServiceGeodatabase::doneLoading, this, [this, params](const Esri::ArcGISRuntime::Error &loadError)
{
onServiceGeodatabaseLoaded(params, loadError);
});

connect(m_utilityNetwork, &UtilityNetwork::doneLoading, this, [this]()
{
setupTraceParameters();
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the done loading connections should be setup before load is called. Otherwise, it's possible that the load will complete before the signal emits.

ServiceVersionParameters* params = new ServiceVersionParameters(this);
params->setName("ValidateNetworkTopology_" + randomVersionUuid);
params->setAccess(VersionAccess::Private);
params->setDescription("Validate network topology with ArcGIS Runtime");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
params->setDescription("Validate network topology with ArcGIS Runtime");
params->setDescription("Validate network topology with ArcGIS Maps SDK");

Comment on lines 247 to 250
m_updateFieldName = m_feature->featureTable()->tableName() == "Electric Distribution Device" ? "devicestatus" : "nominalvoltage";
Field m_field = m_feature->featureTable()->field(m_updateFieldName);
CodedValueDomain m_codedValueDomain = static_cast<CodedValueDomain>(m_field.domain());
m_codedValues = m_codedValueDomain.codedValues();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

following James's comment, it still feels like more things are member variables than are probably required. In the case of Field, that is now changed to be a local variable, but it still uses the m_ convention, which suggests it's a member when it's really not. We should only make things members if we need to, and if we make them local, they shouldn't use m_


m_choices.clear();

m_choices.append("");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you need to append an empty string?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, to get the attributevalue of the selected feature as the current option in the choices dropdown, first I'm assigning a empty value and replacing it with the feature's attribute value when it's found in the for loop

emit updateFieldName();
}

void ValidateUtilityNetworkTopology::onApplyEdits(QString choice)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
void ValidateUtilityNetworkTopology::onApplyEdits(QString choice)
void ValidateUtilityNetworkTopology::onApplyEdits(const QString& choice)

if (m_map->loadStatus() != LoadStatus::Loaded)
return;

Point m_clickPoint = m_mapView->screenToLocation(mouseEvent.position().x(), mouseEvent.position().y());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't seem to be used anywhere. The identify takes the position in directly


// Get the validation result
UtilityNetworkValidationJob* job = m_utilityNetwork->validateNetworkTopology(m_extent);
job->start();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

start should be called after the signal connection is made

UtilityNetworkValidationJob* job = m_utilityNetwork->validateNetworkTopology(m_extent);
job->start();

QObject::connect(job, &UtilityNetworkValidationJob::statusChanged, this, [this, job](JobStatus status)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we don't need to specify QObject::

Suggested change
QObject::connect(job, &UtilityNetworkValidationJob::statusChanged, this, [this, job](JobStatus status)
connect(job, &UtilityNetworkValidationJob::statusChanged, this, [this, job](JobStatus status)

Comment on lines 643 to 645
SimpleLabelExpression* labelExpression = new SimpleLabelExpression("[devicestatus]");

TextSymbol* textSymbol = new TextSymbol();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing parents - any time you use new, you know you'll need to specify a parent object

Suggested change
SimpleLabelExpression* labelExpression = new SimpleLabelExpression("[devicestatus]");
TextSymbol* textSymbol = new TextSymbol();
SimpleLabelExpression* labelExpression = new SimpleLabelExpression("[devicestatus]", this);
TextSymbol* textSymbol = new TextSymbol(this);

id: updateWindow
visible: model.isUpdateWindowVisible
enabled: visible
anchors.centerIn: parent
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typically we put the anchors at the top, right under the id

Comment on lines 204 to 205
m_deviceFeatureLayer->clearSelection();
m_lineFeatureLayer->clearSelection();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to be careful when accessing members without a null check. I tested the branch locally, and got a crash right away. I believe it is because I tried clicking on a feature on the map before the map/utility network were fully loaded, and something was in a null state.

@har13205 har13205 requested a review from ldanzinger March 20, 2024 17:17

LabelDefinition* ValidateUtilityNetworkTopology::createDeviceLabelDefinition() const
{
SimpleLabelExpression* labelExpression = new SimpleLabelExpression("[devicestatus]", new QObject());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all of these new QObject() need to be changed to this

Suggested change
SimpleLabelExpression* labelExpression = new SimpleLabelExpression("[devicestatus]", new QObject());
SimpleLabelExpression* labelExpression = new SimpleLabelExpression("[devicestatus]", this);

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per our offline discussion, removed const from the methods and parent is changed to this

@har13205 har13205 requested a review from ldanzinger March 20, 2024 19:56
Copy link
Contributor

@ldanzinger ldanzinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@har13205 har13205 merged commit 937a7ab into v.next Mar 21, 2024
1 check passed
@har13205 har13205 deleted the har13205/validateUtilityNetworkTopology branch March 21, 2024 04:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants