@@ -566,9 +566,7 @@ PyObject* QuadContourGenerator::create_contour(const double& level)
566
566
if (EXISTS_NONE (quad) || VISITED (quad,1 ))
567
567
continue ;
568
568
569
- Edge start_edge =
570
- (EXISTS_ANY_CORNER (quad) ? get_corner_start_edge (quad, 1 )
571
- : get_quad_start_edge (quad, 1 ));
569
+ Edge start_edge = get_start_edge (quad, 1 );
572
570
if (start_edge == Edge_None)
573
571
continue ;
574
572
@@ -701,7 +699,7 @@ unsigned int QuadContourGenerator::follow_boundary(
701
699
702
700
if (level_index == 1 ) {
703
701
if (start_level <= level_index && end_level == 2 ) {
704
- // Increasing z, switching levels.
702
+ // Increasing z, switching levels from 1 to 2 .
705
703
level_index = 2 ;
706
704
stop = true ;
707
705
}
@@ -716,7 +714,7 @@ unsigned int QuadContourGenerator::follow_boundary(
716
714
stop = true ;
717
715
}
718
716
else if (start_level >= 1 && end_level == 0 ) {
719
- // Decreasing z, switching levels.
717
+ // Decreasing z, switching levels from 2 to 1 .
720
718
level_index = 1 ;
721
719
stop = true ;
722
720
}
@@ -834,13 +832,19 @@ void QuadContourGenerator::follow_interior(ContourLine& contour_line,
834
832
assert (!EXISTS_NONE (quad) && " Quad does not exist" );
835
833
assert (!(_cache[quad] & visited_mask) && " Quad already visited" );
836
834
837
- // Determine direction to move to next quad.
835
+ // Determine direction to move to next quad. If the quad is already
836
+ // labelled as a saddle quad then the direction is easily read from
837
+ // the cache. Otherwise the direction is determined differently
838
+ // depending on whether the quad is a corner quad or not.
839
+
838
840
if (_cache[quad] & saddle_mask) {
839
841
// Already identified as a saddle quad, so direction is easy.
840
842
dir = (SADDLE_LEFT (quad,level_index) ? Dir_Left : Dir_Right);
841
843
_cache[quad] |= visited_mask;
842
844
}
843
845
else if (EXISTS_ANY_CORNER (quad)) {
846
+ // Need z-level of point opposite the entry edge, as that
847
+ // determines whether contour turns left or right.
844
848
long point_opposite = -1 ;
845
849
switch (edge) {
846
850
case Edge_E:
@@ -867,6 +871,10 @@ void QuadContourGenerator::follow_interior(ContourLine& contour_line,
867
871
}
868
872
assert (point_opposite != -1 && " Failed to find opposite point" );
869
873
874
+ // Lower-level polygons (level_index == 1) always have higher
875
+ // values to the left of the contour. Upper-level contours
876
+ // (level_index == 2) are reversed, which is what the fancy XOR
877
+ // does below.
870
878
if ((Z_LEVEL (point_opposite) >= level_index) ^ (level_index == 2 ))
871
879
dir = Dir_Right;
872
880
else
@@ -891,7 +899,7 @@ void QuadContourGenerator::follow_interior(ContourLine& contour_line,
891
899
// lower level ones, i.e. higher values on the right rather than
892
900
// the left.
893
901
if (level_index == 2 )
894
- config = 3 - config;
902
+ config = 3 - config;
895
903
896
904
// Calculate turn direction to move to next quad along contour line.
897
905
if (config == 1 ) {
@@ -1018,7 +1026,7 @@ Edge QuadContourGenerator::get_corner_start_edge(long quad,
1018
1026
// Upper level (level_index == 2) polygons are reversed compared to lower
1019
1027
// level ones, i.e. higher values on the right rather than the left.
1020
1028
if (level_index == 2 )
1021
- config = 7 - config;
1029
+ config = 7 - config;
1022
1030
1023
1031
switch (config) {
1024
1032
case 0 : return Edge_None;
@@ -1040,6 +1048,20 @@ long QuadContourGenerator::get_edge_point_index(const QuadEdge& quad_edge,
1040
1048
" Quad index out of bounds" );
1041
1049
assert (quad_edge.edge != Edge_None && " Invalid edge" );
1042
1050
1051
+ // Edges are ordered anticlockwise around their quad, as indicated by
1052
+ // directions of arrows in diagrams below.
1053
+ // Full quad NW corner (others similar)
1054
+ //
1055
+ // POINT_NW Edge_N POINT_NE POINT_NW Edge_N POINT_NE
1056
+ // +----<-----+ +----<-----+
1057
+ // | | | /
1058
+ // | | | quad /
1059
+ // Edge_W V quad ^ Edge_E Edge_W V ^
1060
+ // | | | / Edge_SE
1061
+ // | | | /
1062
+ // +---->-----+ +
1063
+ // POINT_SW Edge_S POINT_SE POINT_SW
1064
+ //
1043
1065
const long & quad = quad_edge.quad ;
1044
1066
switch (quad_edge.edge ) {
1045
1067
case Edge_E: return (start ? POINT_SE : POINT_NE);
@@ -1064,6 +1086,9 @@ Edge QuadContourGenerator::get_exit_edge(const QuadEdge& quad_edge,
1064
1086
const long & quad = quad_edge.quad ;
1065
1087
const Edge& edge = quad_edge.edge ;
1066
1088
if (EXISTS_ANY_CORNER (quad)) {
1089
+ // Corner directions are always left or right. A corner is a triangle,
1090
+ // entered via one edge so the other two edges are the left and right
1091
+ // ones.
1067
1092
switch (edge) {
1068
1093
case Edge_E:
1069
1094
return (EXISTS_SE_CORNER (quad)
@@ -1089,6 +1114,8 @@ Edge QuadContourGenerator::get_exit_edge(const QuadEdge& quad_edge,
1089
1114
}
1090
1115
}
1091
1116
else {
1117
+ // A full quad has four edges, entered via one edge so that other three
1118
+ // edges correspond to left, straight and right directions.
1092
1119
switch (edge) {
1093
1120
case Edge_E:
1094
1121
return (dir == Dir_Left ? Edge_S :
@@ -1172,6 +1199,15 @@ Edge QuadContourGenerator::get_quad_start_edge(long quad,
1172
1199
}
1173
1200
}
1174
1201
1202
+ Edge QuadContourGenerator::get_start_edge (long quad,
1203
+ unsigned int level_index) const
1204
+ {
1205
+ if (EXISTS_ANY_CORNER (quad))
1206
+ return get_corner_start_edge (quad, level_index);
1207
+ else
1208
+ return get_quad_start_edge (quad, level_index);
1209
+ }
1210
+
1175
1211
void QuadContourGenerator::init_cache_grid (const MaskArray& mask)
1176
1212
{
1177
1213
long i, j, quad;
@@ -1230,9 +1266,11 @@ void QuadContourGenerator::init_cache_grid(const MaskArray& mask)
1230
1266
}
1231
1267
}
1232
1268
1233
- // Stage 2, calculate W and S boundaries. For each quad use data
1234
- // already calculated for quads to W and S, so must iterate through
1235
- // quads in correct order (increasing i and j indices).
1269
+ // Stage 2, calculate W and S boundaries. For each quad use boundary
1270
+ // data already calculated for quads to W and S, so must iterate
1271
+ // through quads in correct order (increasing i and j indices).
1272
+ // Cannot use boundary data for quads to E and N as have not yet
1273
+ // calculated it.
1236
1274
quad = 0 ;
1237
1275
for (j = 0 ; j < _ny; ++j) {
1238
1276
for (i = 0 ; i < _nx; ++i, ++quad) {
@@ -1445,6 +1483,8 @@ void QuadContourGenerator::move_to_next_quad(QuadEdge& quad_edge) const
1445
1483
" Quad index out of bounds" );
1446
1484
assert (quad_edge.edge != Edge_None && " Invalid edge" );
1447
1485
1486
+ // Move from quad_edge.quad to the neighbouring quad in the direction
1487
+ // specified by quad_edge.edge.
1448
1488
switch (quad_edge.edge ) {
1449
1489
case Edge_E: quad_edge.quad += 1 ; quad_edge.edge = Edge_W; break ;
1450
1490
case Edge_N: quad_edge.quad += _nx; quad_edge.edge = Edge_S; break ;
@@ -1626,6 +1666,13 @@ void QuadContourGenerator::single_quad_filled(Contour& contour,
1626
1666
(!SADDLE (quad,1 ) || !SADDLE_LEFT (quad,1 )))
1627
1667
contour.push_back (start_filled (quad, Edge_E, 1 , Hole, Interior,
1628
1668
lower_level, upper_level));
1669
+
1670
+ // All possible contours passing through the interior of this quad
1671
+ // should have already been created, so assert this.
1672
+ assert ((VISITED (quad,1 ) || get_start_edge (quad, 1 ) == Edge_None) &&
1673
+ " Found start of contour that should have already been created" );
1674
+ assert ((VISITED (quad,2 ) || get_start_edge (quad, 2 ) == Edge_None) &&
1675
+ " Found start of contour that should have already been created" );
1629
1676
}
1630
1677
1631
1678
// Lower-level start following N boundary from E to W, hole.
0 commit comments