File indexing completed on 2024-05-12 03:50:19

0001 <html>
0002 <head>
0003     <title>GeoData API - Internal programming documentation</title>
0004 </head>
0005 <body>
0006 <h1>GeoData API - Internal programming documentation</h1>
0007 <a name="topics"><h2>Topics</h2></a>
0008 <ol>
0009 <a href="#topics"><li>Topics</li></a>
0010 <a href="#Introduction"><li>Introduction</li></a>
0011 <a href="#implicit sharing"><li>"implicit sharing"</li></a>
0012 <a href="#How implicit sharing and derivation can work together"><li>How "implicit sharing" and derivation can work together</li></a>
0013 <a href="#serialization and deserialization"><li>serialization and deserialization</li></a>
0014 </ol>
0015 <a name="Introduction"><h2>Introduction</h2></a>
0016 <p>The geodata-API should be used to contain easy and complex geographical data.
0017 It consists currently of three main types:
0018 <ul>
0019 <li>GeoDataFeature</li>
0020 <li>GeoDataGeometry</li>
0021 <li>GeoDataColorStyle</li>
0022 </ul>
0023 From each of those three multiple classes are derived. The first two are most 
0024 interesting because of a feature seldom found in APIs. Each derived class can
0025 be stored in its base class and can later be transformed back again. This means
0026 that the following code is possible:
0027 <pre><code>
0028 GeoDataPlacemark placemark;
0029 GeoDataFeature placemarkAsFeature = placemark;
0030 GeoDataPlacemark other = placemarkAsFeature;
0031 
0032 return (placemark == other); // should return true
0033 </code></pre>
0034 This feature is useful so that you can easily store classes which inherit GeoDataFeature in a QVector&lt;GeoDataFeature&gt;
0035 which would only be possible with Vectors normally. This is roughly the same as storing a QString in a QVariant (there are no 
0036 GeoDataFeatures though that can be added at runtime). As an example:
0037 <pre><code>
0038 GeoDataPlacemark placemark;
0039 QVector&lt;GeoDataFeature&gt; m_vector;
0040 
0041 m_vector.append( placemark );
0042 GeoDataFeature placeMarkAsFeature = m_vector.last();
0043 GeoDataPlacemark other = placemarkAsFeature;
0044 
0045 return (placemark == other); // should return true
0046 </code></pre>
0047 This feature is the base for the GeoDataContainer classes and for the GeoDataMultiGeometry class.
0048 </p>
0049 <a name="implicit sharing"><h2>"implicit sharing"</h2></a>
0050 <p>The <code>GeoDataFeature</code> and <code>GeoDataGeometry</code> classes do use 
0051 implicit-sharing which means that after copying, only a shallow copy is done. Only 
0052 after a write access to the data of the object (calling a non-<code>const</code> function) a 
0053 copy of the whole data is done. This makes copying those data structures rather 
0054 cheap, even if they contain a lot of other <code>GeoDataObjects</code> (as without 
0055 writing there is not much more copying done than with a pointer.<p/>
0056 <p>As done already now, there is a private class which contains all the data members 
0057 and gets accessed from the main classes accessor functions. This way you can keep 
0058 binary compatibility over a long time without being restricted to the data members 
0059 you chose in the beginning. When copying a <code>d</code>-pointer'ed class, you must put a 
0060 new private class object on the stack though and copy the values from its origin.
0061 Implicit sharing now means, that in the moment of copying, you only copy the 
0062 address of the private d pointer but you increment the reference counter of that
0063 object. After that there are two objects with the same private class object. If 
0064 somebody tries to change something in one of those two objects, he must call 
0065 a non-const function which in return will call a function called 
0066 <code>void detach()</code>. This function copies the private object and decrements 
0067 the reference counter. If one of the base objects gets deleted, it decrements the 
0068 reference counter too as long as there are more objects connected to this private 
0069 object. If the counter reaches 0 again, the private object gets deleted too.
0070 This is mostly hidden by <code>QSharedData</code>/<code>QSharedDataPointer</code> 
0071 so that you don't have to worry about that.<p/>
0072 <p>The problems arise, when you try to derive from an implicitly shared 
0073 class. The <code>detach()</code> function is not virtual in the current implementation of 
0074 QVector and thus will not call the function from the derived class if 
0075 changes occur through the interface of the base class. This leads to both GeoDataContainer
0076 and GeoDataMultiGeometry not inheriting QVector but rather rebuilding the interface.</p>
0077 
0078 <a name="How implicit sharing and derivation can work together"><h2>How "implicit sharing" and derivation can work together</h2></a>
0079 <p>As described above, we can't use <code>QSharedData</code> directly if we want 
0080 to use implicit sharing and derivation. Instead we do this on our own.
0081 Our Private classes are all contained in a *_p.h header file. They are derived 
0082 from the private class of the base class (of the current class).
0083 Besides the data members, each private class contains a function <code>void *copy()
0084 </code> which returns a new copy of the private object. As needed an assignment 
0085 operator may occur. The private classes also do contain a function 
0086 <code>virtual EnumFeatureId featureId() const</code> / <code>virtual EnumGeometryId geometryId() const</code>
0087 but those are mostly a convenience solution to provide a way to check the type 
0088 of your data when it is contained in the base class.
0089 Each of the base classes contains a <code>void*</code> pointer which holds the address of the 
0090 private <code>d</code> pointer. Instead of having one <code>d</code> pointer per derivation step, we only 
0091 have one per object. With a function <code>p()</code> which is contained by each derived class
0092 a pointer casted to the Private class of the class is returned. All of the private 
0093 classes are derived from each other, in the same way as their connected classes.
0094 In the base class (in this case <code>GeoDataFeature</code> and <code>GeoDataGeometry</code>) a function 
0095 <code>void detach()</code> is implemented which calls the <code>void* copy()</code> function of the private class.
0096 This way a copy will always result in the same type as the original, even though 
0097 it might occur in a different wrapper (one of the type classes e.g.).
0098 Above mentioned reference counting is done in the detach function.
0099 </p>
0100 <a name="serialization and deserialization"><h2>serialization and deserialization</h2></a>
0101 <p>The idea of a full serialization of GeoData-API is to use that for saving and
0102 reloading binary representations of GeoData-objects. For this to happen you simply
0103 need to call the <code>pack()</code> or <code>unpack()</code> function for the base
0104 <code>GeoDataDocument</code> providing a <code>QDataStream</code>. As the saved
0105 amount in space, is very small, Marble itself still uses a lossy implementation
0106 for that.</p>
0107 </body>
0108 </html>