The DataSource object is the most commonly used object in GeoCalc. It represents a data source XML file that has been loaded into memory. In order to retrieve or modify any of the definitions in the data source file, you must interact with the DataSource.
In order to compile the code examples contained in this lesson, it will be necessary to include the WDataSource.h header file.
The DataSource object can be instantiated in the same way as any other object. The construction of the DataSource may throw a GeoCalcException if a valid license for GeoCalc cannot be found. For instructions on licensing, see Lesson 1. Here is how we will create a DataSource:
DataSource * dataSource = 0;
try
{
dataSource = DataSource::CreateDataSource();
}
catch(GeoCalcException & ex)
{
if(ex.get_ErrorCode() == GeoCalcException::Code::NoLicensedDataSource)
{
// Then you do not have a valid license to use GeoCalc
return;
}
}
Once we have created our DataSource, we must populate it with data by loading one of the data source XML files into it. This is accomplished by using the LoadFile method:
if(! dataSource->LoadFile(L"C:\\bmg\\GeoCalcPBW\\data\\geocalc.xml", false, L"c:\\bmg\\GeoCalcPBW\\data\custom.xml"))
{
// Then GeoCalc was unable to load the specified data source file
return;
}
We now have an instance of the DataSource object that is full of useful definitions and ready to be used. We also have a custom file to store any new systems and objects that we might need.
All objects that can be stored in the DataSource inherit from the Serializable object. For each kind of Serializable object, there are three methods on the DataSource for retrieving and modifying the object: a Get method, a Put method, and a Remove method.
For example, there is a GetProjectedCoordSys method that retrieves a ProjectedCoordSys from the DataSource, a PutProjectedCoordSys method that puts a ProjectedCoordSys into the DataSource, and a RemoveProjectedCoordSys method that removes a ProjectedCoordSys from the DataSource.
Let's now walk through using each of these methods with a ProjectedCoordSys. In order to retrieve a ProjectedCoordSys from the DataSource, we will need to know an identifier for the object. For more information about identifiers, see Lesson 3. If we did not know the identifier for an object, it would be possible to get the object by using the GeoCalc dialogs and browsing through the DataSource. These dialogs are covered in more depth in Lesson 5. Here we will work with the ProjectedCoordSys that corresponds to the UTM 19N coordinate system:
ProjectedCoordSys * pcs = 0;
try
{
pcs = dataSource->GetProjectedCoordSys(L"BMG", L"UTM-19N");
}
catch(GeoCalcException & ex)
{
if(ex.get_ErrorCode() == GeoCalcException::Code::IdentifierNotFound)
{
// Then there is not an object in the DataSource with the specified identifier
return;
}
}
Now we have an instance of a ProjectedCoordSys that we can work with and modify.
If we want to modify it and then save these modifications in the DataSource, then we would need to use the Put method to put the changes into the DataSource. This method can be used to either add a new object to the DataSource, or to change an existing object. *Note: If you load a base datasource as read-only, you cannot edit the base objects. As part of the LoadFile() call, you can also specify a custom datasource for any objects that you might want to add. The Put method takes two arguments, the first of which is the object to be put into the DataSource, and the second of which is a boolean value indicating whether this object should overwrite an existing object in the DataSource with the same identifier.
Let's make some changes to our ProjectedCoordSys, and then put the changes in the DataSource by using the PutProjectedCoordSys. In this case, we do not want to overwrite the existing definition for the UTM 19N system, so we will change the identifiers on our ProjectedCoordSys and add it as a new object:
HorizontalDatum * datum = 0;
datum = dataSource->GetHorizontalDatum(L"BMG", L"NAD27");
pcs->set_Datum(*datum);
pcs->get_Identifiers().set_Item(L"GC", L"UTM-19N-NAD27");
pcs->get_Identifiers().set_Item(L"BMG", L"UTM-19N-NAD27");
pcs->get_Identifiers().Remove(L"EPSG");
try
{
if(! dataSource->PutProjectedCoordSys(*pcs, false))
{
// Then the ProjectedCoordSys could not be added to the DataSource
return;
}
}
catch(GeoCalcException & ex)
{
if(ex.get_ErrorCode() == GeoCalcException::Code::GCIdentifierMissing)
{
// The ProjectedCoordSys could not be put in the DataSource because
// it did not have an identifier where issuer="GC".
return;
}
else if(ex.get_ErrorCode() == GeoCalcException::Code::FileReadOnly)
{
// The DataSource is not editable
return;
}
}
Now we have put our definition into the data source, without modifying the existing definition for the UTM 19N system. It is important to note that we have not yet made any changes to the XML file - we have just modified the in-memory DataSource. We will discuss saving these changes to a file later in this lesson.
We can remove existing definitions from the DataSource by using the Remove methods. Suppose we now want to remove the ProjectedCoordSys definition that we just added to the DataSource. We can accomplish this with the RemoveProjectedCoordSys method. In order to remove a ProjectedCoordSys from the DataSource, we will need to know an identifier for the object. For more information about identifiers, see Lesson 3. If we did not know the identifier for an object, it would be possible to remove the object by using the GeoCalc dialogs and browsing through the DataSource. These dialogs are covered in more depth in Lesson 5. However, we do know an identifier for this object, so here is how we will remove it:
try
{
// This will only work if our datasource is not read-only, or the system
// is in our custom datasource
if(! dataSource->RemoveProjectedCoordSys(L"MYCS", L"MYNAD27-CoordinateSystem"))
{
// Then the specified ProjectedCoordSys could not be removed from the DataSource
return;
}
}
catch(GeoCalcException & ex)
{
if(ex.get_ErrorCode() == GeoCalcException::Code::IdentifierNotFound)
{
// Then the specified identifier could not be found in the DataSource
return;
}
else if(ex.get_ErrorCode() == GeoCalcException::Code::FileReadOnly)
{
// The DataSource is not editable
return;
}
}
Now we have removed our new definition, and our DataSource is back to the state it was in when we first loaded it.
It is possible to import some kinds of external coordinate system definitions into GeoCalc. This is accomplished with the ImportCoordSysFromFile, ImportCoordSysFromString, and ImportFile methods. Currently, GeoCalc has the ability to import definitions in the form of Well-Known Text (WKT), ESRI PRJ files, MapInfo MAP files, and MapInfo TAB files. If these coordinate systems do not match systems that are currently in our datasource, they will be added to our custom datasource file.
For this lesson, let's assume we have a PRJ file located on our C drive called "MyCoordSys.prj". We can import this into GeoCalc like this:
CoordSys * importedCS = 0;
try
{
importedCS = dataSource->ImportCoordSysFromFile(L"C:\\MyCoordSys.prj");
}
catch(GeoCalcException & ex)
{
if(ex.get_ErrorCode() == GeoCalcException::Code::FileNotFound)
{
// Then the specified file could not be found
return;
}
if(ex.get_ErrorCode() == GeoCalcException::Code::CannotImportCoordinateSystem)
{
// Failed to import the CoordSys
return;
}
}
We now have a CoordSys object that contains the coordinate system definition given by the PRJ file.
GeoCalc also provides the ability to export CoordSys definitions, but there are fewer supported export formats than there are import formats. The methods ExportCoordSysToFile and ExportCoordSysToString will export CoordSys definitions as Well-Known Text (WKT). Here we export the CoordSys we just imported to a WKT string:
wchar_t * wktString = 0;
try
{
wktString = dataSource->ExportCoordSysToString(*importedCS);
}
catch(GeoCalcException & ex)
{
if(ex.get_ErrorCode() == GeoCalcException::Code::CannotExportCoordinateSystem)
{
// Failed to export CoordSys
return;
}
}
When changes are made to the DataSource, they are not automatically made to the XML file. It is necessary to use the CommitToFile method to save the DataSource to an XML file, such that the modifications made in one instance of the DataSource can be accessed by another instance. There are two signatures for the CommitToFile method, one of which takes no arguments and saves the DataSource to the file from which it was loaded, and one of which takes a string argument that specifies where to save the DataSource. This is how you save the DataSource:
if(! dataSource->CommitToFile())
{
// Failed to save the contents of the DataSource to the source file
return;
}
*Note: If we are using a read-only base datasource, and a custom datasource, only the custom file will be updated.
Finally, we must clean up after ourselves and free the memory that we have allocated in this lesson using the Disposal::Dispose method:
if(pcs) Disposal::Dispose(pcs);
if(datum) Disposal::Dispose(datum);
if(importedCS) Disposal::Dispose(importedCS);
if(wktString) Disposal::Dispose(wktString);
if(dataSource) Disposal::Dispose(dataSource);