![]() |
NAVTOR SDK
v.3.0
Software Development Kit for fast and efficient development of ECDIS, ECS and generic marine applications
|
Manual updating of a chart is a way to edit the chart without modifying its content. A manual update is a separate chart linked to its owner. Manual updating affects the chart access and as a result it also affects the chart display, anti-grounding task, and all other tasks related to the access to the chart content.
The front-end of the chart manual updating is the ManualUpdates component that implements the IManualUpdates interface.
/datalayer/inc/manual_update/component_ids.h file. /datalayer/inc/manual_update/manual_updates_interface.h file.To initialize manual updating the application has to pass the path to a manual updates database in the workspace configuration at the time when it opens a SENC geodatabase. See an example below (namespaces are omitted):
IWorkspaceConfigurationSP config;
if (SDK_FAILED(wks_factory->CreateWorkspaceConfiguration(&config)))
return;
if (SDK_FAILED(config->SetConfigurationParameter(
kWorkspaceConfigurationParameter_RootPath, ScopedAny(path))))
return;
if (SDK_OK(config->SetConfigurationParameter(
kWorkspaceConfigurationParameter_ManualUpdateRootPath,
ScopedAny(manual_update_path))))
return;
IWokspaceSP wks;
wks_factory->Open(config, &wks);
For the manual updates path we recommend to use the same last path component as in the SENC geodatabase path, e.g. geodatabases/PRIMAR and for the manual updates manual_update/PRIMAR.
To perform manual updating operations you can use the following methods of the IManualUpdates interface:
virtual SDKResult SDK_CALLTYPE CreateFeature(const IFeatureDatasetSP& dataset, sdk::geometry::GeometryType type, sdk::geometry::PointDimension coord_dim, IFeatureEditSP& feature_editor) throw() = 0;
virtual SDKResult SDK_CALLTYPE EditFeature(const IFeatureSP& feature, IFeatureEditSP& feature_editor) throw() = 0;
virtual SDKResult SDK_CALLTYPE DeleteFeature(const IFeatureSP& feature, DeleteMode mode) throw() = 0;
With the DeleteFeature you can physically delete a manual update record if you pass a feature from the manual update dataset and DeleteMode_DestroyRecord as a mode.
virtual SDKResult SDK_CALLTYPE ClearUpdates(const SDK_GDB_NAMRSPACE::IFeatureDatasetSP & dataset) throw() = 0;
If you want to make a manual update invisible you can use the IObjectEdit::SetFlags method. Pass the senc::FEATS_TRP_FLAGS.m_IS_INVISIBLE. See the sample code below:
senc::FEATS_TRP_FLAGS feature_flags; feature_flags.m_IS_INVISIBLE = 1; IObjectEditSP object_edit; object_edit->SetFlags(feature_flags.m_RAWF);
For the visibility flag to come into effect, use the kGetFeaturesFlags_MU_SkipInvisibleManualUpdates flag in the kGetFeaturesParameter_Flags of the IFeatureDataset::GetFeatures call.
To remove manual updates created 3 months back from the operations, use the kGetFeaturesParameter_MU_DeltaTimeLimitToSkipManualUpdates for the IFeatureDataset::GetFeatures method. The parameter is set in milliseconds.
For the GetFeatures parameters to come into effect for the chart display, the application can pass them via the visualization manager IDataSourceView::SetFeatureQueryFilter.
There are several flags and enumeration parameters that can be used to control the dataset and/or feature enumeration.
To get the relationship between a feature and one of its manual updates, use kRelationshipClass_ManualUpdates in IObject.GetRelationships.
To get the relationship between a manual update and its feature, use the IObject.GetRelationships method of the manual update feature with the kRelationshipClass_ManualUpdates class.
To encode date/time attributes of manual updates, use the ANY_TIME_PACKED structure.
// --gtest_filter=mu_feature_editor_tests.add_date_attribute
TEST_F(mu_feature_editor_tests, add_date_attribute)
{
std::wstring dataset_name = kTdsDatasets[0];
std::wstring senc_dataset_name = kTdsDatasetNames[0];
DestroySlaveDatabase();
bool b_exists = FileExists(dataset_name);
ASSERT_TRUE( false == b_exists );
SDKResult res;
ClassCode code = s101::kFCC_BCNCAR;
SDKUInt32 attr_code = s101::kFAC_BOYSHP;
SDKUInt16 attr_val = 1;
FOID foid_added = { 0 };
ScopedAny dt_full(0);
ANY_TYPE(&dt_full) = kSDKAnyType_SDKTimePacked;
ANY_TIME_PACKED_YEAR(&dt_full) = 1941;
ANY_TIME_PACKED_MONTH(&dt_full) = 6;
ANY_TIME_PACKED_MDAY(&dt_full) = 22;
ANY_TIME_PACKED_HOUR(&dt_full) = 4;
const ClassCode dt_full_code = s101::kFAC_DATSTA;
const std::wstring dt_full_str = L"19410622T040000";
ScopedAny dt_md(0);
ANY_TYPE(&dt_md) = kSDKAnyType_SDKTimePacked;
ANY_TIME_PACKED_MONTH(&dt_md) = 6;
ANY_TIME_PACKED_MDAY(&dt_md) = 22;
ANY_TIME_PACKED_HOUR(&dt_md) = kSDK_PACKED_TIME_INVALID_HOUR;
const ClassCode dt_md_code = s101::kFAC_PERSTA;
const std::wstring dt_md_str = L"--0622";
ScopedAny dt_m(0);
ANY_TYPE(&dt_m) = kSDKAnyType_SDKTimePacked;
ANY_TIME_PACKED_MONTH(&dt_m) = 6;
ANY_TIME_PACKED_HOUR(&dt_m) = kSDK_PACKED_TIME_INVALID_HOUR;
const ClassCode dt_m_code = s101::kFAC_PEREND;
const std::wstring dt_m_str = L"--06";
ScopedAny dt_invalid(0);
ANY_TYPE(&dt_invalid) = kSDKAnyType_SDKTimePacked;
ANY_TIME_PACKED_YEAR(&dt_invalid) = kSDK_PACKED_TIME_INVALID_YEAR;
ANY_TIME_PACKED_MONTH(&dt_invalid) = kSDK_PACKED_TIME_INVALID_MONTH;
ANY_TIME_PACKED_MDAY(&dt_invalid) = kSDK_PACKED_TIME_INVALID_MDAY;
ANY_TIME_PACKED_HOUR(&dt_invalid) = kSDK_PACKED_TIME_INVALID_HOUR;
ANY_TIME_PACKED_MINUTE(&dt_invalid) = kSDK_PACKED_TIME_INVALID_MINUTE;
ANY_TIME_PACKED_SECOND(&dt_invalid) = kSDK_PACKED_TIME_INVALID_SECOND;
const ClassCode dt_invalid_code = s101::kFAC_DATEND;
ScopedAny dt_only_time_valid(0);
ANY_TYPE(&dt_only_time_valid) = kSDKAnyType_SDKTimePacked;
ANY_TIME_PACKED_YEAR(&dt_only_time_valid) = kSDK_PACKED_TIME_INVALID_YEAR;
ANY_TIME_PACKED_MONTH(&dt_only_time_valid) = kSDK_PACKED_TIME_INVALID_MONTH;
ANY_TIME_PACKED_MDAY(&dt_only_time_valid) = kSDK_PACKED_TIME_INVALID_MDAY;
ANY_TIME_PACKED_HOUR(&dt_only_time_valid) = 01;
ANY_TIME_PACKED_MINUTE(&dt_only_time_valid) = 02;
ANY_TIME_PACKED_SECOND(&dt_only_time_valid) = 03;
const ClassCode dt_only_time_valid_code = s101::kFAC_SURSTA;
ScopedAny dt_only_date_valid(0);
ANY_TYPE(&dt_only_date_valid) = kSDKAnyType_SDKTimePacked;
ANY_TIME_PACKED_YEAR(&dt_only_date_valid) = 2014;
ANY_TIME_PACKED_MONTH(&dt_only_date_valid) = 05;
ANY_TIME_PACKED_MDAY(&dt_only_date_valid) = 14;
ANY_TIME_PACKED_HOUR(&dt_only_date_valid) = kSDK_PACKED_TIME_INVALID_HOUR;
ANY_TIME_PACKED_MINUTE(&dt_only_date_valid) = kSDK_PACKED_TIME_INVALID_MINUTE;
ANY_TIME_PACKED_SECOND(&dt_only_date_valid) = kSDK_PACKED_TIME_INVALID_SECOND;
const ClassCode dt_only_date_valid_code = s101::kFAC_SUREND;
GeoPoint gp;
{
IFeatureDatasetSP dataset_master;
OpenMasterDataset(dataset_master, m_wks_factory, m_config,
senc_dataset_name);
ASSERT_TRUE(dataset_master != NULL);
geometry::IEnvelopeSP envelope;
res = dataset_master->GetBounds(&envelope);
ASSERT_EQ(kSDKResult_Succeeded, res);
ASSERT_TRUE(NULL != envelope);
double x_min = 360, y_min = 360, x_max = 360, y_max = 360;
res = envelope->GetCoordinates(kSDKAnyType_Double,
&x_min, &y_min, &x_max, &y_max);
ASSERT_EQ(kSDKResult_Succeeded, res);
gp = GeoPoint(x_min + (x_max - x_min) / 2.,y_min + (y_max - y_min) / 2.);
IFeatureEditSP feature_editor;
res = m_mu->CreateFeature(dataset_master,
kGMT_Point, kGMPD_2, feature_editor);
ASSERT_EQ(kSDKResult_Succeeded, res);
ASSERT_TRUE(NULL != feature_editor);
res = feature_editor->StartEditing();
ASSERT_EQ(kSDKResult_Succeeded, res);
res = feature_editor->SetObjectClassCode(code);
ASSERT_EQ(kSDKResult_Succeeded, res);
{
ScopedFeatureEdit fe(feature_editor);
fe.SetAttribute(attr_code, attr_val);
fe.SetAttributeValue(dt_full_code, dt_full);
fe.SetAttributeValue(dt_md_code, dt_md);
fe.SetAttributeValue(dt_m_code, dt_m);
fe.SetAttributeValue(dt_invalid_code, dt_invalid);
fe.SetAttributeValue(dt_only_time_valid_code, dt_only_time_valid);
fe.SetAttributeValue(dt_only_date_valid_code, dt_only_date_valid);
}
IGeometryEditSP geom_edit =
feature_editor.GetInterface();
ASSERT_TRUE(NULL != geom_edit);
res = geom_edit->AddPoints(geometry::kGMPT_GeoPoint, &gp, 1, -1, 0);
ASSERT_EQ(kSDKResult_Succeeded, res);
res = feature_editor->StopEditing(true, NULL);
ASSERT_EQ(kSDKResult_Succeeded, res);
IFeatureSP f = feature_editor.GetInterface();
ASSERT_TRUE(NULL != f);
ScopedAny foid_any;
res = f->GetFOID(foid_any);
ASSERT_EQ(kSDKResult_Succeeded, res);
foid_added.foid = GetAnyValue(foid_any);
ASSERT_TRUE(0 != foid_added.foid);
}
{
IFeatureDatasetSP dataset_master;
OpenMasterDataset(dataset_master, m_wks_factory, m_config,
senc_dataset_name);
ASSERT_TRUE(NULL != dataset_master);
IEnumFeatureSP enum_fea;
res = dataset_master->GetFeatures(NULL, NULL, NULL, &enum_fea);
ASSERT_EQ(kSDKResult_Succeeded, res);
ASSERT_TRUE(NULL != enum_fea);
bool is_found = false;
for (IFeatureSP fea; SDK_OK(enum_fea->Next(&fea)); fea.Release())
{
ScopedAny foid_any;
res = fea->GetFOID(foid_any);
if (SDK_OK(res) && GetAnyValue(foid_any) == foid_added.foid)
{
SDKUInt64 flags;
ASSERT_TRUE(SDK_OK(fea->GetFlags(flags)));
senc::FEATS_TRP_FLAGS feature_flags;
feature_flags.m_RAWF = static_cast(flags);
ASSERT_TRUE(feature_flags.m_UPDATE_TYPE ==
senc::kUpdateType_NonIntegratedUpdate);
std::wstring dt_str;
{
IAttributeCollectionSP attributes;
ASSERT_TRUE(SDK_OK(fea->GetAttributes(&attributes)));
ScopedAny dt_full_returned;
ASSERT_TRUE(SDK_OK(attributes->GetAttributeValue(dt_full_code,
dt_full_returned)));
ASSERT_TRUE(dt_full == dt_full_returned);
ScopedAny dt_md_returned;
ASSERT_TRUE(SDK_OK(attributes->GetAttributeValue(dt_md_code,
dt_md_returned)));
ASSERT_TRUE(dt_md == dt_md_returned);
ScopedAny dt_m_returned;
ASSERT_TRUE(SDK_OK(attributes->GetAttributeValue(dt_m_code,
dt_m_returned)));
ASSERT_TRUE(dt_m == dt_m_returned);
dt_m_returned.Clear();
ASSERT_TRUE(SDK_OK(attributes->GetAttributeValue(dt_invalid_code,
dt_m_returned)));
{
IAttributeSP attr;
ASSERT_TRUE(SDK_OK(attributes->FindAttribute(dt_invalid_code,
&attr)));
ScopedAny returned_value;
ASSERT_TRUE(SDK_OK(attr->GetValue(returned_value)));
SDKUInt64 flags = 0;
ASSERT_TRUE(SDK_OK(attr->GetFlags(flags)));
ASSERT_TRUE(ANY_IS_TIME(&returned_value));
ScopedAny time_packed;
ASSERT_TRUE(SDK_OK(SDKTimeToSDKTimePacked(ANY_TIME(&returned_value),
flags, time_packed)));
ASSERT_TRUE(dt_invalid == time_packed);
}
{
IAttributeSP attr;
ASSERT_TRUE(SDK_OK(attributes->FindAttribute(dt_only_time_valid_code,
&attr)));
ScopedAny returned_value;
ASSERT_TRUE(SDK_OK(attr->GetValue(returned_value)));
SDKUInt64 flags = 0;
ASSERT_TRUE(SDK_OK(attr->GetFlags(flags)));
ASSERT_TRUE(ANY_IS_TIME(&returned_value));
ScopedAny time_packed;
ASSERT_TRUE(SDK_OK(SDKTimeToSDKTimePacked(ANY_TIME(&returned_value),
flags, time_packed)));
ASSERT_TRUE(dt_only_time_valid == time_packed);
}
{
IAttributeSP attr;
ASSERT_TRUE(SDK_OK(attributes->FindAttribute(dt_only_date_valid_code,
&attr)));
ScopedAny returned_value;
ASSERT_TRUE(SDK_OK(attr->GetValue(returned_value)));
SDKUInt64 flags = 0;
ASSERT_TRUE(SDK_OK(attr->GetFlags(flags)));
ASSERT_TRUE(ANY_IS_TIME(&returned_value));
ScopedAny time_packed;
ASSERT_TRUE(SDK_OK(SDKTimeToSDKTimePacked(ANY_TIME(&returned_value),
flags, time_packed)));
ASSERT_TRUE(dt_only_date_valid == time_packed);
}
}
is_found = true;
break;
}
}
ASSERT_TRUE(is_found == true);
}
}
The SDK provides a manual update catalogue to help developers to create a manual update editor. The catalogue is a simple XML file consisting of a list of features grouped in a hierarchical structure where root features are themes. There is no additional service on top of the catalogue. Applications can use it as it is.