Fix for Issue 54: Bug when a non-shared vertex is marked for remove

This commit is contained in:
Mikko Mononen 2010-03-18 08:42:45 +00:00
parent 70c17e8212
commit 8291ceace2
6 changed files with 155 additions and 52 deletions

View File

@ -297,7 +297,7 @@ public:
// startRef - (in) ref to the polygon where the start lies. // startRef - (in) ref to the polygon where the start lies.
// startPos[3] - (in) start position of the query. // startPos[3] - (in) start position of the query.
// endPos[3] - (in) end position of the query. // endPos[3] - (in) end position of the query.
// t - (out) hit parameter along the segment, 0 if no hit. // t - (out) hit parameter along the segment, FLT_MAX if no hit.
// hitNormal[3] - (out) normal of the nearest hit. // hitNormal[3] - (out) normal of the nearest hit.
// filter - (in) path polygon filter. // filter - (in) path polygon filter.
// path - (out) visited path polygons. // path - (out) visited path polygons.

View File

@ -1826,8 +1826,16 @@ int dtNavMesh::raycast(dtPolyRef centerRef, const float* startPos, const float*
if (tmax > t) if (tmax > t)
t = tmax; t = tmax;
// Store visited polygons.
if (n < pathSize) if (n < pathSize)
path[n++] = curRef; path[n++] = curRef;
// Ray end is completely inside the polygon.
if (segMax == -1)
{
t = FLT_MAX;
return n;
}
// Follow neighbours. // Follow neighbours.
dtPolyRef nextRef = 0; dtPolyRef nextRef = 0;

View File

@ -483,53 +483,70 @@ static void pushBack(int v, int* arr, int& an)
an++; an++;
} }
static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int maxTris)
static int removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int maxTris)
{ {
const int nvp = mesh.nvp; const int nvp = mesh.nvp;
// Count number of polygons to remove. // Count number of polygons to remove.
int nrem = 0; int numRemovedVerts = 0;
int numRemainingEdges = 0;
for (int i = 0; i < mesh.npolys; ++i) for (int i = 0; i < mesh.npolys; ++i)
{ {
unsigned short* p = &mesh.polys[i*nvp*2]; unsigned short* p = &mesh.polys[i*nvp*2];
for (int j = 0; j < nvp; ++j) for (int j = 0; j < nvp; ++j)
if (p[j] == rem) { nrem++; break; } {
if (p[j] == RC_MESH_NULL_IDX) break;
numRemainingEdges++;
if (p[j] == rem)
{
numRemovedVerts++;
numRemainingEdges -= 2;
}
}
} }
// There would be too few edges remaining to create a polygon.
// This can happen for example when a tip of a triangle is marked
// as deletion, but there are no other polys that share the vertex.
// In this case, the vertex should not be removed.
if (numRemainingEdges <= 2)
return -1;
int nedges = 0; int nedges = 0;
rcScopedDelete<int> edges = new int[nrem*nvp*4]; rcScopedDelete<int> edges = new int[numRemovedVerts*nvp*4];
if (!edges) if (!edges)
{ {
if (rcGetLog()) if (rcGetLog())
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'edges' (%d).", nrem*nvp*4); rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'edges' (%d).", numRemovedVerts*nvp*4);
return false; return 0;
} }
int nhole = 0; int nhole = 0;
rcScopedDelete<int> hole = new int[nrem*nvp]; rcScopedDelete<int> hole = new int[numRemovedVerts*nvp];
if (!hole) if (!hole)
{ {
if (rcGetLog()) if (rcGetLog())
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hole' (%d).", nrem*nvp); rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hole' (%d).", numRemovedVerts*nvp);
return false; return 0;
} }
int nhreg = 0; int nhreg = 0;
rcScopedDelete<int> hreg = new int[nrem*nvp]; rcScopedDelete<int> hreg = new int[numRemovedVerts*nvp];
if (!hreg) if (!hreg)
{ {
if (rcGetLog()) if (rcGetLog())
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hreg' (%d).", nrem*nvp); rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hreg' (%d).", numRemovedVerts*nvp);
return false; return 0;
} }
int nharea = 0; int nharea = 0;
rcScopedDelete<int> harea = new int[nrem*nvp]; rcScopedDelete<int> harea = new int[numRemovedVerts*nvp];
if (!harea) if (!harea)
{ {
if (rcGetLog()) if (rcGetLog())
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'harea' (%d).", nrem*nvp); rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'harea' (%d).", numRemovedVerts*nvp);
return false; return 0;
} }
for (int i = 0; i < mesh.npolys; ++i) for (int i = 0; i < mesh.npolys; ++i)
@ -588,7 +605,7 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
} }
if (nedges == 0) if (nedges == 0)
return true; return 1;
// Start with one vertex, keep appending connected // Start with one vertex, keep appending connected
// segments to the start and end of the hole. // segments to the start and end of the hole.
@ -645,7 +662,7 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
{ {
if (rcGetLog()) if (rcGetLog())
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tris' (%d).", nhole*3); rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tris' (%d).", nhole*3);
return false; return 0;
} }
rcScopedDelete<int> tverts = new int[nhole*4]; rcScopedDelete<int> tverts = new int[nhole*4];
@ -653,7 +670,7 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
{ {
if (rcGetLog()) if (rcGetLog())
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tverts' (%d).", nhole*4); rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tverts' (%d).", nhole*4);
return false; return 0;
} }
rcScopedDelete<int> thole = new int[nhole]; rcScopedDelete<int> thole = new int[nhole];
@ -661,7 +678,7 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
{ {
if (rcGetLog()) if (rcGetLog())
rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'thole' (%d).", nhole); rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'thole' (%d).", nhole);
return false; return 0;
} }
// Generate temp vertex array for triangulation. // Generate temp vertex array for triangulation.
@ -690,21 +707,21 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
{ {
if (rcGetLog()) if (rcGetLog())
rcGetLog()->log(RC_LOG_ERROR, "removeVertex: Out of memory 'polys' (%d).", (ntris+1)*nvp); rcGetLog()->log(RC_LOG_ERROR, "removeVertex: Out of memory 'polys' (%d).", (ntris+1)*nvp);
return false; return 0;
} }
rcScopedDelete<unsigned short> pregs = new unsigned short[ntris]; rcScopedDelete<unsigned short> pregs = new unsigned short[ntris];
if (!pregs) if (!pregs)
{ {
if (rcGetLog()) if (rcGetLog())
rcGetLog()->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pregs' (%d).", ntris); rcGetLog()->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pregs' (%d).", ntris);
return false; return 0;
} }
rcScopedDelete<unsigned char> pareas = new unsigned char[ntris]; rcScopedDelete<unsigned char> pareas = new unsigned char[ntris];
if (!pregs) if (!pregs)
{ {
if (rcGetLog()) if (rcGetLog())
rcGetLog()->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pareas' (%d).", ntris); rcGetLog()->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pareas' (%d).", ntris);
return false; return 0;
} }
unsigned short* tmpPoly = &polys[ntris*nvp]; unsigned short* tmpPoly = &polys[ntris*nvp];
@ -726,7 +743,7 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
} }
} }
if (!npolys) if (!npolys)
return true; return 1;
// Merge polygons. // Merge polygons.
if (nvp > 3) if (nvp > 3)
@ -790,11 +807,11 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m
{ {
if (rcGetLog()) if (rcGetLog())
rcGetLog()->log(RC_LOG_ERROR, "removeVertex: Too many polygons %d (max:%d).", mesh.npolys, maxTris); rcGetLog()->log(RC_LOG_ERROR, "removeVertex: Too many polygons %d (max:%d).", mesh.npolys, maxTris);
return false; return 0;
} }
} }
return true; return 1;
} }
@ -1046,16 +1063,27 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh)
{ {
if (vflags[i]) if (vflags[i])
{ {
if (!removeVertex(mesh, i, maxTris)) int res = removeVertex(mesh, i, maxTris);
if (!res)
{ {
// Failed to remove vertex
if (rcGetLog()) if (rcGetLog())
rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Failed to remove edge vertex %d.", i); rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Failed to remove edge vertex %d.", i);
return false; return false;
} }
// Note: mesh.nverts is already decremented inside removeVertex()! else if (res == -1)
for (int j = i; j < mesh.nverts; ++j) {
vflags[j] = vflags[j+1]; // Vertex should not be removed.
--i; continue;
}
else
{
// Remove vertex
// Note: mesh.nverts is already decremented inside removeVertex()!
for (int j = i; j < mesh.nverts; ++j)
vflags[j] = vflags[j+1];
--i;
}
} }
} }

View File

@ -16,8 +16,8 @@
8D1107260486CEB800E47090 /* Recast */, 8D1107260486CEB800E47090 /* Recast */,
); );
breakpoints = ( breakpoints = (
6B8037A6113D1788005ED67B /* RecastMesh.cpp:504 */, 6B8037A6113D1788005ED67B /* RecastMesh.cpp:521 */,
6B8037B4113D193D005ED67B /* RecastMesh.cpp:532 */, 6B8037B4113D193D005ED67B /* RecastMesh.cpp:549 */,
6B904B781144F2B000A12E63 /* Sample_Debug.cpp:87 */, 6B904B781144F2B000A12E63 /* Sample_Debug.cpp:87 */,
6B904B941144F35E00A12E63 /* Sample_Debug.cpp:120 */, 6B904B941144F35E00A12E63 /* Sample_Debug.cpp:120 */,
); );
@ -310,6 +310,12 @@
6B904C6B1152164400A12E63 /* PBXTextBookmark */ = 6B904C6B1152164400A12E63 /* PBXTextBookmark */; 6B904C6B1152164400A12E63 /* PBXTextBookmark */ = 6B904C6B1152164400A12E63 /* PBXTextBookmark */;
6B904C6C1152164400A12E63 /* PBXTextBookmark */ = 6B904C6C1152164400A12E63 /* PBXTextBookmark */; 6B904C6C1152164400A12E63 /* PBXTextBookmark */ = 6B904C6C1152164400A12E63 /* PBXTextBookmark */;
6B904C6D1152164400A12E63 /* PBXTextBookmark */ = 6B904C6D1152164400A12E63 /* PBXTextBookmark */; 6B904C6D1152164400A12E63 /* PBXTextBookmark */ = 6B904C6D1152164400A12E63 /* PBXTextBookmark */;
6B904C6F115218D800A12E63 /* PBXTextBookmark */ = 6B904C6F115218D800A12E63 /* PBXTextBookmark */;
6B904C70115218D800A12E63 /* PBXTextBookmark */ = 6B904C70115218D800A12E63 /* PBXTextBookmark */;
6B904C71115218D800A12E63 /* PBXTextBookmark */ = 6B904C71115218D800A12E63 /* PBXTextBookmark */;
6B904C72115218D800A12E63 /* PBXTextBookmark */ = 6B904C72115218D800A12E63 /* PBXTextBookmark */;
6B904C7411521CEA00A12E63 /* PBXTextBookmark */ = 6B904C7411521CEA00A12E63 /* PBXTextBookmark */;
6B904C7611521D4400A12E63 /* PBXTextBookmark */ = 6B904C7611521D4400A12E63 /* PBXTextBookmark */;
6B92D9121140F58200E82EC3 = 6B92D9121140F58200E82EC3 /* PBXTextBookmark */; 6B92D9121140F58200E82EC3 = 6B92D9121140F58200E82EC3 /* PBXTextBookmark */;
6B92D91C1140F5F800E82EC3 = 6B92D91C1140F5F800E82EC3 /* PBXTextBookmark */; 6B92D91C1140F5F800E82EC3 = 6B92D91C1140F5F800E82EC3 /* PBXTextBookmark */;
6B92D9411140F84100E82EC3 = 6B92D9411140F84100E82EC3 /* PBXTextBookmark */; 6B92D9411140F84100E82EC3 = 6B92D9411140F84100E82EC3 /* PBXTextBookmark */;
@ -522,9 +528,9 @@
}; };
6B137C870F7FCC1100459200 /* RecastMesh.cpp */ = { 6B137C870F7FCC1100459200 /* RecastMesh.cpp */ = {
uiCtxt = { uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {815, 19904}}"; sepNavIntBoundsRect = "{{0, 0}, {815, 20224}}";
sepNavSelRange = "{14617, 0}"; sepNavSelRange = "{13330, 0}";
sepNavVisRange = "{10934, 788}"; sepNavVisRange = "{12592, 895}";
}; };
}; };
6B137C880F7FCC1100459200 /* RecastRasterization.cpp */ = { 6B137C880F7FCC1100459200 /* RecastRasterization.cpp */ = {
@ -1072,7 +1078,7 @@
vrLen = 868; vrLen = 868;
vrLoc = 21829; vrLoc = 21829;
}; };
6B8037A6113D1788005ED67B /* RecastMesh.cpp:504 */ = { 6B8037A6113D1788005ED67B /* RecastMesh.cpp:521 */ = {
isa = PBXFileBreakpoint; isa = PBXFileBreakpoint;
actions = ( actions = (
); );
@ -1084,12 +1090,12 @@
functionName = "checkNullPolys(rcPolyMesh& mesh)"; functionName = "checkNullPolys(rcPolyMesh& mesh)";
hitCount = 0; hitCount = 0;
ignoreCount = 0; ignoreCount = 0;
lineNumber = 504; lineNumber = 521;
location = Recast; location = Recast;
modificationTime = 290591670.511081; modificationTime = 290591670.511081;
state = 1; state = 1;
}; };
6B8037B4113D193D005ED67B /* RecastMesh.cpp:532 */ = { 6B8037B4113D193D005ED67B /* RecastMesh.cpp:549 */ = {
isa = PBXFileBreakpoint; isa = PBXFileBreakpoint;
actions = ( actions = (
); );
@ -1101,7 +1107,7 @@
functionName = "removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int maxTris)"; functionName = "removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int maxTris)";
hitCount = 0; hitCount = 0;
ignoreCount = 0; ignoreCount = 0;
lineNumber = 532; lineNumber = 549;
location = Recast; location = Recast;
modificationTime = 290591670.511272; modificationTime = 290591670.511272;
state = 1; state = 1;
@ -2642,6 +2648,66 @@
vrLen = 1021; vrLen = 1021;
vrLoc = 16495; vrLoc = 16495;
}; };
6B904C6F115218D800A12E63 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 6BB7FC0A10EBB6AA006DA0A6 /* NavMeshTesterTool.cpp */;
name = "NavMeshTesterTool.cpp: 633";
rLen = 0;
rLoc = 17051;
rType = 0;
vrLen = 1021;
vrLoc = 16495;
};
6B904C70115218D800A12E63 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 6B137C870F7FCC1100459200 /* RecastMesh.cpp */;
name = "RecastMesh.cpp: 568";
rLen = 0;
rLoc = 15139;
rType = 0;
vrLen = 723;
vrLoc = 10999;
};
6B904C71115218D800A12E63 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 6BB7FC0A10EBB6AA006DA0A6 /* NavMeshTesterTool.cpp */;
name = "NavMeshTesterTool.cpp: 633";
rLen = 0;
rLoc = 17051;
rType = 0;
vrLen = 1021;
vrLoc = 16495;
};
6B904C72115218D800A12E63 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 6B137C870F7FCC1100459200 /* RecastMesh.cpp */;
name = "RecastMesh.cpp: 498";
rLen = 0;
rLoc = 13375;
rType = 0;
vrLen = 758;
vrLoc = 12451;
};
6B904C7411521CEA00A12E63 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 6B137C870F7FCC1100459200 /* RecastMesh.cpp */;
name = "RecastMesh.cpp: 1072";
rLen = 0;
rLoc = 27474;
rType = 0;
vrLen = 707;
vrLoc = 26829;
};
6B904C7611521D4400A12E63 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 6B137C870F7FCC1100459200 /* RecastMesh.cpp */;
name = "RecastMesh.cpp: 512";
rLen = 0;
rLoc = 13330;
rType = 0;
vrLen = 895;
vrLoc = 12592;
};
6B92D9121140F58200E82EC3 /* PBXTextBookmark */ = { 6B92D9121140F58200E82EC3 /* PBXTextBookmark */ = {
isa = PBXTextBookmark; isa = PBXTextBookmark;
fRef = 6B137C830F7FCC1100459200 /* RecastContour.cpp */; fRef = 6B137C830F7FCC1100459200 /* RecastContour.cpp */;
@ -2881,7 +2947,7 @@
6BB7FC0A10EBB6AA006DA0A6 /* NavMeshTesterTool.cpp */ = { 6BB7FC0A10EBB6AA006DA0A6 /* NavMeshTesterTool.cpp */ = {
uiCtxt = { uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {831, 15024}}"; sepNavIntBoundsRect = "{{0, 0}, {831, 15024}}";
sepNavSelRange = "{16816, 0}"; sepNavSelRange = "{17051, 0}";
sepNavVisRange = "{16495, 1021}"; sepNavVisRange = "{16495, 1021}";
}; };
}; };
@ -3041,7 +3107,7 @@
fRef = 6B137C870F7FCC1100459200 /* RecastMesh.cpp */; fRef = 6B137C870F7FCC1100459200 /* RecastMesh.cpp */;
name = "RecastMesh.cpp: 568"; name = "RecastMesh.cpp: 568";
rLen = 0; rLen = 0;
rLoc = 14617; rLoc = 15139;
rType = 0; rType = 0;
vrLen = 788; vrLen = 788;
vrLoc = 10934; vrLoc = 10934;
@ -3051,7 +3117,7 @@
fRef = 6B137C870F7FCC1100459200 /* RecastMesh.cpp */; fRef = 6B137C870F7FCC1100459200 /* RecastMesh.cpp */;
name = "RecastMesh.cpp: 568"; name = "RecastMesh.cpp: 568";
rLen = 0; rLen = 0;
rLoc = 14617; rLoc = 15139;
rType = 0; rType = 0;
vrLen = 788; vrLen = 788;
vrLoc = 10934; vrLoc = 10934;

View File

@ -281,14 +281,14 @@
<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key> <key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
<array> <array>
<array> <array>
<integer>52</integer> <integer>33</integer>
<integer>46</integer> <integer>21</integer>
<integer>1</integer> <integer>1</integer>
<integer>0</integer> <integer>0</integer>
</array> </array>
</array> </array>
<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key> <key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
<string>{{0, 429}, {358, 643}}</string> <string>{{0, 347}, {358, 643}}</string>
</dict> </dict>
<key>PBXTopSmartGroupGIDs</key> <key>PBXTopSmartGroupGIDs</key>
<array/> <array/>
@ -323,7 +323,7 @@
<key>PBXProjectModuleGUID</key> <key>PBXProjectModuleGUID</key>
<string>6B8632A30F78115100E2684A</string> <string>6B8632A30F78115100E2684A</string>
<key>PBXProjectModuleLabel</key> <key>PBXProjectModuleLabel</key>
<string>NavMeshTesterTool.cpp</string> <string>RecastMesh.cpp</string>
<key>PBXSplitModuleInNavigatorKey</key> <key>PBXSplitModuleInNavigatorKey</key>
<dict> <dict>
<key>Split0</key> <key>Split0</key>
@ -331,11 +331,11 @@
<key>PBXProjectModuleGUID</key> <key>PBXProjectModuleGUID</key>
<string>6B8632A40F78115100E2684A</string> <string>6B8632A40F78115100E2684A</string>
<key>PBXProjectModuleLabel</key> <key>PBXProjectModuleLabel</key>
<string>NavMeshTesterTool.cpp</string> <string>RecastMesh.cpp</string>
<key>_historyCapacity</key> <key>_historyCapacity</key>
<integer>0</integer> <integer>0</integer>
<key>bookmark</key> <key>bookmark</key>
<string>6B904C6D1152164400A12E63</string> <string>6B904C7611521D4400A12E63</string>
<key>history</key> <key>history</key>
<array> <array>
<string>6B8DE70D10B01BBF00DF20FB</string> <string>6B8DE70D10B01BBF00DF20FB</string>
@ -372,7 +372,6 @@
<string>6B8036D0113BAF79005ED67B</string> <string>6B8036D0113BAF79005ED67B</string>
<string>6B8036F7113BB746005ED67B</string> <string>6B8036F7113BB746005ED67B</string>
<string>6B803729113D1079005ED67B</string> <string>6B803729113D1079005ED67B</string>
<string>6BC8BE261140ED5F00555B22</string>
<string>6B92D96A1140FBDA00E82EC3</string> <string>6B92D96A1140FBDA00E82EC3</string>
<string>6B92D97A1140FE6000E82EC3</string> <string>6B92D97A1140FE6000E82EC3</string>
<string>6B92D97D1140FE6000E82EC3</string> <string>6B92D97D1140FE6000E82EC3</string>
@ -401,7 +400,8 @@
<string>6B904C591152139200A12E63</string> <string>6B904C591152139200A12E63</string>
<string>6B904C631152164400A12E63</string> <string>6B904C631152164400A12E63</string>
<string>6B904C641152164400A12E63</string> <string>6B904C641152164400A12E63</string>
<string>6B904C651152164400A12E63</string> <string>6B904C6F115218D800A12E63</string>
<string>6B904C70115218D800A12E63</string>
</array> </array>
<key>prevStack</key> <key>prevStack</key>
<array> <array>
@ -487,6 +487,7 @@
<string>6B904C6A1152164400A12E63</string> <string>6B904C6A1152164400A12E63</string>
<string>6B904C6B1152164400A12E63</string> <string>6B904C6B1152164400A12E63</string>
<string>6B904C6C1152164400A12E63</string> <string>6B904C6C1152164400A12E63</string>
<string>6B904C71115218D800A12E63</string>
</array> </array>
</dict> </dict>
<key>SplitCount</key> <key>SplitCount</key>