[mapguide-commits] r10218 - in branches/4.0/MgDev: Common/Stylization Server/src/UnitTesting
svn_mapguide at osgeo.org
svn_mapguide at osgeo.org
Tue Sep 22 04:16:06 PDT 2026
Author: jng
Date: 2026-09-22 04:16:06 -0700 (Tue, 22 Sep 2026)
New Revision: 10218
Modified:
branches/4.0/MgDev/Common/Stylization/DefaultStylizer.cpp
branches/4.0/MgDev/Common/Stylization/LineBuffer.cpp
branches/4.0/MgDev/Common/Stylization/LineBuffer.h
branches/4.0/MgDev/Server/src/UnitTesting/TestRenderingService.cpp
Log:
Implement missing support for rendering GeometryCollection instances
Fixes #2461
Modified: branches/4.0/MgDev/Common/Stylization/DefaultStylizer.cpp
===================================================================
--- branches/4.0/MgDev/Common/Stylization/DefaultStylizer.cpp 2026-09-21 12:56:43 UTC (rev 10217)
+++ branches/4.0/MgDev/Common/Stylization/DefaultStylizer.cpp 2026-09-22 11:16:06 UTC (rev 10218)
@@ -361,19 +361,61 @@
continue;
}
- // if we know how to stylize this type of geometry, then go ahead
- GeometryAdapter* adapter = FindGeomAdapter(lb->geom_type());
- if (adapter)
+ // A MultiGeometry (a.k.a. GeometryCollection) is a heterogeneous
+ // aggregate, so stylize each sub-geometry with the adapter matching
+ // its own geometry type.
+ if (lb->geom_type() == FdoGeometryType_MultiGeometry)
{
- // we need to stylize once for each FeatureTypeStyle that matches
- // the geometry type (Note: this may have to change to match
- // feature classes)
- for (int i=0; i<ftsc->GetCount(); ++i)
+ for (int g=0; g<lb->geom_count(); ++g)
{
- MdfModel::FeatureTypeStyle* fts = ftsc->GetAt(i);
- adapter->Stylize(renderer, features, initialPass, exec, lb, fts, lrTip, lrUrl, elevSettings);
+ int subType = lb->geom_type_of(g);
+
+ // TODO: Nested MultiGeometry sub-geometries are skipped here
+ // (FindGeomAdapter returns NULL for them). Nested geometry
+ // collections are extremely rare; if support is ever needed,
+ // iterate the nested geometry's own sub-geometries recursively.
+ GeometryAdapter* subAdapter = FindGeomAdapter(subType);
+ if (!subAdapter)
+ continue;
+
+ LineBuffer* subLb = LineBufferPool::NewLineBuffer(&m_lbPool, 8, lb->dimensionality(), lb->ignoreZ());
+ if (!subLb)
+ continue;
+
+ std::unique_ptr<LineBuffer> spSubLB(subLb);
+ lb->ExtractGeometry(g, subLb);
+
+ if (subLb->point_count() == 0)
+ {
+ LineBufferPool::FreeLineBuffer(&m_lbPool, spSubLB.release());
+ continue;
+ }
+
+ for (int i=0; i<ftsc->GetCount(); ++i)
+ {
+ MdfModel::FeatureTypeStyle* fts = ftsc->GetAt(i);
+ subAdapter->Stylize(renderer, features, initialPass, exec, subLb, fts, lrTip, lrUrl, elevSettings);
+ }
+
+ LineBufferPool::FreeLineBuffer(&m_lbPool, spSubLB.release());
}
}
+ else
+ {
+ // if we know how to stylize this type of geometry, then go ahead
+ GeometryAdapter* adapter = FindGeomAdapter(lb->geom_type());
+ if (adapter)
+ {
+ // we need to stylize once for each FeatureTypeStyle that matches
+ // the geometry type (Note: this may have to change to match
+ // feature classes)
+ for (int i=0; i<ftsc->GetCount(); ++i)
+ {
+ MdfModel::FeatureTypeStyle* fts = ftsc->GetAt(i);
+ adapter->Stylize(renderer, features, initialPass, exec, lb, fts, lrTip, lrUrl, elevSettings);
+ }
+ }
+ }
// free geometry when done stylizing
LineBufferPool::FreeLineBuffer(&m_lbPool, spLB.release());
Modified: branches/4.0/MgDev/Common/Stylization/LineBuffer.cpp
===================================================================
--- branches/4.0/MgDev/Common/Stylization/LineBuffer.cpp 2026-09-21 12:56:43 UTC (rev 10217)
+++ branches/4.0/MgDev/Common/Stylization/LineBuffer.cpp 2026-09-22 11:16:06 UTC (rev 10218)
@@ -70,6 +70,8 @@
m_num_geomcntrs_len = m_cntrs_len;
m_num_geomcntrs = new int[m_num_geomcntrs_len];
m_num_geomcntrs[0] = 0;
+ m_geom_types = new int[m_num_geomcntrs_len];
+ m_geom_types[0] = 0;
if (!m_bProcessZ)
m_bounds.minz = m_bounds.maxz = 0.0;
}
@@ -99,7 +101,8 @@
m_bProcessZ(false),
m_bTransform2DPoints(false),
m_num_geomcntrs_len(0),
- m_num_geomcntrs(NULL)
+ m_num_geomcntrs(NULL),
+ m_geom_types(NULL)
{
}
@@ -111,6 +114,7 @@
delete[] m_cntrs;
delete[] m_csp;
delete[] m_num_geomcntrs;
+ delete[] m_geom_types;
delete[] m_arcs_sp;
delete[] m_closeseg;
}
@@ -127,6 +131,7 @@
m_bTransform2DPoints = false;
m_cur_geom = -1;
m_num_geomcntrs[0] = 0;
+ m_geom_types[0] = 0;
m_drawingScale = 0.0;
m_cur_arcs_sp = -1;
@@ -190,12 +195,15 @@
if (m_num_geomcntrs_len <= src.m_cur_geom)
{
delete [] m_num_geomcntrs;
+ delete [] m_geom_types;
m_num_geomcntrs_len = src.m_num_geomcntrs_len;
m_num_geomcntrs = new int[m_num_geomcntrs_len];
+ m_geom_types = new int[m_num_geomcntrs_len];
}
m_cur_geom = src.m_cur_geom;
memcpy(m_num_geomcntrs, src.m_num_geomcntrs, sizeof(int)*(1+m_cur_geom));
+ memcpy(m_geom_types, src.m_geom_types, sizeof(int)*(1+m_cur_geom));
// arc start point indices
if (m_arcs_sp_len < src.m_arcs_sp_len)
@@ -236,6 +244,7 @@
if (m_cur_geom >= m_num_geomcntrs_len)
ResizeNumGeomContours(m_cur_geom * 2);
m_num_geomcntrs[m_cur_geom] = 0;
+ m_geom_types[m_cur_geom] = m_geom_type;
}
@@ -526,6 +535,7 @@
if (m_cur_geom + other.m_cur_geom + 2 > m_num_geomcntrs_len)
ResizeNumGeomContours(m_cur_geom + other.m_cur_geom + 2);
memcpy(m_num_geomcntrs + m_cur_geom + 1, other.m_num_geomcntrs, sizeof(int)*(1+other.m_cur_geom));
+ memcpy(m_geom_types + m_cur_geom + 1, other.m_geom_types, sizeof(int)*(1+other.m_cur_geom));
m_cur_geom += other.m_cur_geom + 1; // follows same pattern as contour
m_bounds.add_point(RS_F_Point(other.m_bounds.minx, other.m_bounds.miny));
@@ -538,10 +548,19 @@
void LineBuffer::ResizeNumGeomContours(int size)
{
_ASSERT(size > m_num_geomcntrs_len);
+
+ int old_len = m_num_geomcntrs_len;
+
int* tempCntrs = new int[size];
- memcpy(tempCntrs, m_num_geomcntrs, sizeof(int)*m_num_geomcntrs_len);
+ memcpy(tempCntrs, m_num_geomcntrs, sizeof(int)*old_len);
delete[] m_num_geomcntrs;
m_num_geomcntrs = tempCntrs;
+
+ int* tempTypes = new int[size];
+ memcpy(tempTypes, m_geom_types, sizeof(int)*old_len);
+ delete[] m_geom_types;
+ m_geom_types = tempTypes;
+
m_num_geomcntrs_len = size;
}
@@ -866,14 +885,23 @@
{
int* ireader = (int*)data;
- // the geometry type
- m_geom_type = (GeometryType)*ireader++;
-
double last_z = 0.0;
bool use_last_z = false;
bool have_bad_z = false;
- switch (m_geom_type)
+ // the geometry type
+ GeometryType geom_type = (GeometryType)*ireader++;
+
+ LoadAgfGeometry(geom_type, ireader, xformer, last_z, use_last_z, have_bad_z);
+}
+
+
+void LineBuffer::LoadAgfGeometry(GeometryType geomType, int*& ireader, CSysTransformer* xformer,
+ double& last_z, bool& use_last_z, bool& have_bad_z)
+{
+ m_geom_type = geomType;
+
+ switch (geomType)
{
// all the linear types...
case GeometryType_MultiLineString:
@@ -1162,7 +1190,34 @@
case GeometryType_MultiGeometry:
{
- // can't do that yet
+ // A MultiGeometry (a.k.a. GeometryCollection) is a heterogeneous
+ // aggregate of geometries. It is serialized as:
+ //
+ // [type = MultiGeometry][num geometries]
+ // [sub-geometry type][sub-geometry data]...
+ //
+ // Each sub-geometry is itself a complete AGF geometry, so parse
+ // each one recursively and separate them in the LineBuffer with
+ // NewGeometry().
+ int num_geoms = *ireader++;
+ for (int q=0; q<num_geoms; ++q)
+ {
+ // read the type of this sub-geometry
+ GeometryType sub_type = (GeometryType)*ireader++;
+
+ // mark the beginning of a new geometry and record its type
+ if (q > 0)
+ {
+ m_geom_type = sub_type;
+ NewGeometry();
+ }
+
+ // parse the sub-geometry
+ LoadAgfGeometry(sub_type, ireader, xformer, last_z, use_last_z, have_bad_z);
+ }
+
+ // restore the aggregate geometry type
+ m_geom_type = GeometryType_MultiGeometry;
break;
}
}
@@ -1169,6 +1224,37 @@
}
+void LineBuffer::ExtractGeometry(int geomIndex, LineBuffer* dst)
+{
+ _ASSERT(dst != NULL);
+
+ // locate the contour range belonging to this geometry
+ int contourStart = 0;
+ for (int g = 0; g < geomIndex; ++g)
+ contourStart += m_num_geomcntrs[g];
+
+ int contourCount = m_num_geomcntrs[geomIndex];
+ if (contourCount == 0)
+ return;
+
+ int ptStart = m_csp[contourStart];
+ int ptEnd = m_csp[contourStart + contourCount - 1] + m_cntrs[contourStart + contourCount - 1];
+
+ // make room for the extracted points up front
+ dst->EnsurePoints(ptEnd - ptStart);
+
+ for (int i = ptStart; i < ptEnd; ++i)
+ {
+ if (m_types[i] == (unsigned char)stMoveTo)
+ dst->MoveTo(m_pts[i][0], m_pts[i][1], m_pts[i][2]);
+ else
+ dst->LineTo(m_pts[i][0], m_pts[i][1], m_pts[i][2]);
+ }
+
+ dst->SetGeometryType(m_geom_types[geomIndex]);
+}
+
+
#define WRITE_INT(os, val) { \
int val2 = val; \
os->write(&val2, 4); } \
Modified: branches/4.0/MgDev/Common/Stylization/LineBuffer.h
===================================================================
--- branches/4.0/MgDev/Common/Stylization/LineBuffer.h 2026-09-21 12:56:43 UTC (rev 10217)
+++ branches/4.0/MgDev/Common/Stylization/LineBuffer.h 2026-09-22 11:16:06 UTC (rev 10218)
@@ -167,6 +167,9 @@
// start a new geometry
STYLIZATION_API void NewGeometry();
+ // extract a single geometry (by index) into a separate line buffer
+ STYLIZATION_API void ExtractGeometry(int geomIndex, LineBuffer* dst);
+
// checks for a point in any contour
STYLIZATION_API bool PointInPolygon(double& x, double& y) const;
STYLIZATION_API bool PointInPolygon(int cntr, double& x, double& y) const; // point in specific contour
@@ -190,6 +193,7 @@
inline int* geoms() const;
inline int geom_count() const;
inline int geom_size(int geom) const;
+ inline int geom_type_of(int geom) const;
inline const RS_Bounds& bounds() const;
inline void EnsurePoints(int n);
inline void EnsureContours(int n);
@@ -241,6 +245,7 @@
bool m_bTransform2DPoints;
Matrix3D m_T;
int* m_num_geomcntrs;
+ int* m_geom_types;
int m_num_geomcntrs_len;
int m_cur_geom;
bool m_bIgnoreZ;
@@ -287,6 +292,9 @@
void ResizeContours(int n);
void ResizeArcsSpArray(int n);
void ResizeCloseSegArray(int n);
+
+ void LoadAgfGeometry(GeometryType geomType, int*& ireader, CSysTransformer* xformer,
+ double& last_z, bool& use_last_z, bool& have_bad_z);
};
@@ -373,6 +381,12 @@
}
+int LineBuffer::geom_type_of(int geom) const
+{
+ return m_geom_types[geom];
+}
+
+
const RS_Bounds& LineBuffer::bounds() const
{
return m_bounds;
Modified: branches/4.0/MgDev/Server/src/UnitTesting/TestRenderingService.cpp
===================================================================
--- branches/4.0/MgDev/Server/src/UnitTesting/TestRenderingService.cpp 2026-09-21 12:56:43 UTC (rev 10217)
+++ branches/4.0/MgDev/Server/src/UnitTesting/TestRenderingService.cpp 2026-09-22 11:16:06 UTC (rev 10218)
@@ -18,6 +18,7 @@
#include "MapGuideCommon.h"
#include "ServiceManager.h"
#include "ServerSiteService.h"
+#include "Services/FeatureService.h"
#include "Fdo.h"
#include "StylizationDefs.h"
//#include "AGGRenderer.h"
@@ -1803,4 +1804,257 @@
{
throw;
}
+}
+
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// Renders a map whose single layer is backed by an SDF feature source that
+/// contains one GeometryCollection feature (a point, a linestring and a
+/// polygon). The resulting image is written to the test results directory for
+/// manual visual inspection. This test only asserts that rendering completes
+/// without throwing.
+///----------------------------------------------------------------------------
+TEST_CASE("RenderGeometryCollection", "[RenderingService]")
+{
+ try
+ {
+ // Set the user information for the current thread to be administrator.
+ Ptr<MgUserInformation> adminUserInfo = new MgUserInformation(MgUser::Administrator, L"");
+ MgUserInformation::SetCurrentUserInfo(adminUserInfo);
+
+ MgServiceManager* serviceManager = MgServiceManager::GetInstance();
+ if (serviceManager == NULL)
+ throw new MgException(MgExceptionCodes::MgNullReferenceException, L"TestRenderingService.RenderGeometryCollection", __LINE__, __WFILE__, NULL, L"", NULL);
+
+ Ptr<MgFeatureService> svcFeature = dynamic_cast<MgFeatureService*>(serviceManager->RequestService(MgServiceType::FeatureService));
+ if (svcFeature == NULL)
+ throw new MgException(MgExceptionCodes::MgServiceNotAvailableException, L"TestRenderingService.RenderGeometryCollection", __LINE__, __WFILE__, NULL, L"", NULL);
+
+ Ptr<MgResourceService> svcResource = TestServiceFactory::CreateResourceService();
+
+ // Use a well-known geographic coordinate system.
+ Ptr<MgCoordinateSystemFactory> csFactory = new MgCoordinateSystemFactory();
+ STRING csWkt = csFactory->ConvertCoordinateSystemCodeToWkt(L"LL84");
+ std::string csWktMb = MgUtil::WideCharToMultiByte(csWkt);
+
+ STRING scName = L"Default";
+
+ // Build a schema whose geometry property accepts geometry collections.
+ // MultiGeometry is only added to the specific geometry types when the
+ // full set of geometric categories (point|curve|surface|solid) is set.
+ Ptr<MgFeatureSchema> schema = new MgFeatureSchema(L"Default", L"GeometryCollection test schema");
+ Ptr<MgClassDefinition> klass = new MgClassDefinition();
+ klass->SetName(L"TestClass");
+
+ Ptr<MgPropertyDefinitionCollection> clsProps = klass->GetProperties();
+ Ptr<MgPropertyDefinitionCollection> clsIdProps = klass->GetIdentityProperties();
+
+ Ptr<MgDataPropertyDefinition> id = new MgDataPropertyDefinition(L"ID");
+ id->SetDataType(MgPropertyType::Int32);
+ id->SetAutoGeneration(true);
+ clsProps->Add(id);
+ clsIdProps->Add(id);
+
+ Ptr<MgGeometricPropertyDefinition> geom = new MgGeometricPropertyDefinition(L"Geom");
+ geom->SetGeometryTypes(MgFeatureGeometricType::Point | MgFeatureGeometricType::Curve | MgFeatureGeometricType::Surface | MgFeatureGeometricType::Solid);
+ geom->SetSpatialContextAssociation(scName);
+ clsProps->Add(geom);
+
+ klass->SetDefaultGeometryPropertyName(L"Geom");
+
+ Ptr<MgClassDefinitionCollection> classes = schema->GetClasses();
+ classes->Add(klass);
+
+ Ptr<MgResourceIdentifier> fsId = new MgResourceIdentifier(L"Library://UnitTests/Data/GeometryCollectionTest.FeatureSource");
+ Ptr<MgFileFeatureSourceParams> fsParams = new MgFileFeatureSourceParams(L"OSGeo.SDF", scName, csWkt, schema);
+ svcFeature->CreateFeatureSource(fsId, fsParams);
+
+ // Build a geometry collection containing a point, a linestring and a polygon.
+ MgGeometryFactory geomFactory;
+ Ptr<MgGeometryCollection> geoms = new MgGeometryCollection();
+
+ Ptr<MgCoordinate> ptCoord = geomFactory.CreateCoordinateXY(0.0, 0.0);
+ Ptr<MgGeometry> point = geomFactory.CreatePoint(ptCoord);
+ geoms->Add(point);
+
+ Ptr<MgCoordinateCollection> lineCoords = new MgCoordinateCollection();
+ Ptr<MgCoordinate> lineCoord1 = geomFactory.CreateCoordinateXY(0.1, 0.1);
+ Ptr<MgCoordinate> lineCoord2 = geomFactory.CreateCoordinateXY(0.3, 0.3);
+ lineCoords->Add(lineCoord1);
+ lineCoords->Add(lineCoord2);
+ Ptr<MgGeometry> line = geomFactory.CreateLineString(lineCoords);
+ geoms->Add(line);
+
+ Ptr<MgCoordinateCollection> ringCoords = new MgCoordinateCollection();
+ Ptr<MgCoordinate> ringCoord1 = geomFactory.CreateCoordinateXY(0.1, 0.2);
+ Ptr<MgCoordinate> ringCoord2 = geomFactory.CreateCoordinateXY(0.2, 0.2);
+ Ptr<MgCoordinate> ringCoord3 = geomFactory.CreateCoordinateXY(0.2, 0.3);
+ Ptr<MgCoordinate> ringCoord4 = geomFactory.CreateCoordinateXY(0.1, 0.3);
+ Ptr<MgCoordinate> ringCoord5 = geomFactory.CreateCoordinateXY(0.1, 0.2);
+ ringCoords->Add(ringCoord1);
+ ringCoords->Add(ringCoord2);
+ ringCoords->Add(ringCoord3);
+ ringCoords->Add(ringCoord4);
+ ringCoords->Add(ringCoord5);
+ Ptr<MgLinearRing> ring = geomFactory.CreateLinearRing(ringCoords);
+ Ptr<MgGeometry> polygon = geomFactory.CreatePolygon(ring, nullptr);
+ geoms->Add(polygon);
+
+ Ptr<MgGeometry> multiGeom = geomFactory.CreateMultiGeometry(geoms);
+
+ // Insert the geometry collection feature.
+ Ptr<MgAgfReaderWriter> agfRw = new MgAgfReaderWriter();
+ Ptr<MgByteReader> agf = agfRw->Write(multiGeom);
+
+ Ptr<MgPropertyCollection> propVals = new MgPropertyCollection();
+ Ptr<MgGeometryProperty> geomVal = new MgGeometryProperty(L"Geom", agf);
+ propVals->Add(geomVal);
+
+ Ptr<MgFeatureReader> fr = svcFeature->InsertFeatures(fsId, L"Default:TestClass", propVals);
+ fr->Close();
+
+ // Layer definition with a point, a line and an area style so that every
+ // part of the geometry collection has a matching style.
+ std::string ldfXml;
+ ldfXml += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+ ldfXml += "<LayerDefinition xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" version=\"1.2.0\" xsi:noNamespaceSchemaLocation=\"LayerDefinition-1.2.0.xsd\">";
+ ldfXml += "<VectorLayerDefinition>";
+ ldfXml += "<ResourceId>Library://UnitTests/Data/GeometryCollectionTest.FeatureSource</ResourceId>";
+ ldfXml += "<FeatureName>Default:TestClass</FeatureName>";
+ ldfXml += "<FeatureNameType>FeatureClass</FeatureNameType>";
+ ldfXml += "<Geometry>Geom</Geometry>";
+ ldfXml += "<VectorScaleRange>";
+ ldfXml += "<PointTypeStyle>";
+ ldfXml += "<DisplayAsText>false</DisplayAsText>";
+ ldfXml += "<AllowOverpost>false</AllowOverpost>";
+ ldfXml += "<PointRule>";
+ ldfXml += "<LegendLabel />";
+ ldfXml += "<PointSymbolization2D>";
+ ldfXml += "<Mark>";
+ ldfXml += "<Unit>Points</Unit>";
+ ldfXml += "<SizeContext>DeviceUnits</SizeContext>";
+ ldfXml += "<SizeX>10</SizeX>";
+ ldfXml += "<SizeY>10</SizeY>";
+ ldfXml += "<Rotation>0</Rotation>";
+ ldfXml += "<Shape>Square</Shape>";
+ ldfXml += "<Fill>";
+ ldfXml += "<FillPattern>Solid</FillPattern>";
+ ldfXml += "<ForegroundColor>ffff0000</ForegroundColor>";
+ ldfXml += "<BackgroundColor>ffff0000</BackgroundColor>";
+ ldfXml += "</Fill>";
+ ldfXml += "<Edge>";
+ ldfXml += "<LineStyle>Solid</LineStyle>";
+ ldfXml += "<Thickness>1</Thickness>";
+ ldfXml += "<Color>ff000000</Color>";
+ ldfXml += "<Unit>Points</Unit>";
+ ldfXml += "<SizeContext>DeviceUnits</SizeContext>";
+ ldfXml += "</Edge>";
+ ldfXml += "</Mark>";
+ ldfXml += "</PointSymbolization2D>";
+ ldfXml += "</PointRule>";
+ ldfXml += "</PointTypeStyle>";
+ ldfXml += "<LineTypeStyle>";
+ ldfXml += "<LineRule>";
+ ldfXml += "<LegendLabel />";
+ ldfXml += "<LineSymbolization2D>";
+ ldfXml += "<LineStyle>Solid</LineStyle>";
+ ldfXml += "<Thickness>2</Thickness>";
+ ldfXml += "<Color>ff00ff00</Color>";
+ ldfXml += "<Unit>Points</Unit>";
+ ldfXml += "<SizeContext>DeviceUnits</SizeContext>";
+ ldfXml += "</LineSymbolization2D>";
+ ldfXml += "</LineRule>";
+ ldfXml += "</LineTypeStyle>";
+ ldfXml += "<AreaTypeStyle>";
+ ldfXml += "<AreaRule>";
+ ldfXml += "<LegendLabel />";
+ ldfXml += "<AreaSymbolization2D>";
+ ldfXml += "<Fill>";
+ ldfXml += "<FillPattern>Solid</FillPattern>";
+ ldfXml += "<ForegroundColor>ff0000ff</ForegroundColor>";
+ ldfXml += "<BackgroundColor>ff0000ff</BackgroundColor>";
+ ldfXml += "</Fill>";
+ ldfXml += "<Stroke>";
+ ldfXml += "<LineStyle>Solid</LineStyle>";
+ ldfXml += "<Thickness>1</Thickness>";
+ ldfXml += "<Color>ff000000</Color>";
+ ldfXml += "<Unit>Points</Unit>";
+ ldfXml += "<SizeContext>DeviceUnits</SizeContext>";
+ ldfXml += "</Stroke>";
+ ldfXml += "</AreaSymbolization2D>";
+ ldfXml += "</AreaRule>";
+ ldfXml += "</AreaTypeStyle>";
+ ldfXml += "</VectorScaleRange>";
+ ldfXml += "</VectorLayerDefinition>";
+ ldfXml += "</LayerDefinition>";
+
+ Ptr<MgByteSource> ldfBs = new MgByteSource((BYTE_ARRAY_IN)ldfXml.c_str(), (INT32)ldfXml.length());
+ Ptr<MgByteReader> ldfContent = ldfBs->GetReader();
+ Ptr<MgResourceIdentifier> ldfId = new MgResourceIdentifier(L"Library://UnitTests/Layers/GeometryCollectionTest.LayerDefinition");
+ svcResource->SetResource(ldfId, ldfContent, nullptr);
+
+ // Map definition pointing at the layer definition.
+ std::string mdfXml;
+ mdfXml += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+ mdfXml += "<MapDefinition xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" version=\"3.0.0\" xsi:noNamespaceSchemaLocation=\"MapDefinition-3.0.0.xsd\">";
+ mdfXml += "<Name>GeometryCollectionTest</Name>";
+ mdfXml += "<CoordinateSystem>";
+ mdfXml += csWktMb;
+ mdfXml += "</CoordinateSystem>";
+ mdfXml += "<Extents><MinX>-0.1</MinX><MaxX>0.5</MaxX><MinY>-0.1</MinY><MaxY>0.5</MaxY></Extents>";
+ mdfXml += "<BackgroundColor>ffffffff</BackgroundColor>";
+ mdfXml += "<MapLayer>";
+ mdfXml += "<Name>GeometryCollection</Name>";
+ mdfXml += "<ResourceId>Library://UnitTests/Layers/GeometryCollectionTest.LayerDefinition</ResourceId>";
+ mdfXml += "<Selectable>true</Selectable>";
+ mdfXml += "<ShowInLegend>true</ShowInLegend>";
+ mdfXml += "<LegendLabel>GeometryCollection</LegendLabel>";
+ mdfXml += "<ExpandInLegend>true</ExpandInLegend>";
+ mdfXml += "<Visible>true</Visible>";
+ mdfXml += "<Group />";
+ mdfXml += "</MapLayer>";
+ mdfXml += "<Watermarks />";
+ mdfXml += "</MapDefinition>";
+
+ Ptr<MgByteSource> mdfBs = new MgByteSource((BYTE_ARRAY_IN)mdfXml.c_str(), (INT32)mdfXml.length());
+ Ptr<MgByteReader> mdfContent = mdfBs->GetReader();
+ Ptr<MgResourceIdentifier> mdfId = new MgResourceIdentifier(L"Library://UnitTests/Maps/GeometryCollectionTest.MapDefinition");
+ svcResource->SetResource(mdfId, mdfContent, nullptr);
+
+ // Render the map.
+ Ptr<MgServerSiteService> svcSite = TestServiceFactory::CreateSiteService();
+ Ptr<MgSiteConnection> siteConnection = TestServiceFactory::CreateSiteConnection(svcSite);
+
+ Ptr<MgMap> map = new MgMap(siteConnection);
+ map->Create(mdfId, mdfId->GetName());
+
+ Ptr<MgCoordinate> coordNewCenter = new MgCoordinateXY(0.2, 0.2);
+ Ptr<MgPoint> ptNewCenter = new MgPoint(coordNewCenter);
+ map->SetViewCenter(ptNewCenter);
+ map->SetViewScale(250000.0);
+ map->SetDisplayDpi(96);
+ map->SetDisplayWidth(1024);
+ map->SetDisplayHeight(1024);
+
+ Ptr<MgRenderingService> svcRendering = TestServiceFactory::CreateRenderingService();
+ Ptr<MgByteReader> image = svcRendering->RenderMap(map, nullptr, MgImageFormats::Png);
+ image->ToFile(L"../UnitTestFiles/Results/RenderGeometryCollection.png");
+ }
+ catch (MgException* e)
+ {
+ STRING message = e->GetDetails(TestServiceFactory::TEST_LOCALE);
+ SAFE_RELEASE(e);
+ FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+ }
+ catch (FdoException* e)
+ {
+ FDO_SAFE_RELEASE(e);
+ FAIL("FdoException occurred");
+ }
+ catch (...)
+ {
+ throw;
+ }
}
\ No newline at end of file
More information about the mapguide-commits
mailing list