void KdTreeNode::insert (LineSegment *l) { switch (splitType) { case 0: if (l->p0 != splitAt && l->p1 != splitAt && XOrder(l->p0, splitAt) == 1 && XOrder(l->p1, splitAt) == 1) { insertLeft(l); } else if (l->p0 != splitAt && l->p1 != splitAt && XOrder(splitAt, l->p0) == 1 && XOrder(splitAt, l->p1) == 1) { insertRight(l); } else { LineSegment *l0, *l1; splitLineSegment(l, splitAt, splitType, &l0, &l1); insertLeft(l0); insertRight(l1); } break; case 1: if (l->p0 != splitAt && l->p1 != splitAt && YOrder(l->p0, splitAt) == 1 && YOrder(l->p1, splitAt) == 1) { insertLeft(l); } else if (l->p0 != splitAt && l->p1 != splitAt && YOrder(splitAt, l->p0) == 1 && YOrder(splitAt, l->p1) == 1) { insertRight(l); } else { LineSegment *l0, *l1; splitLineSegment(l, splitAt, splitType, &l0, &l1); insertLeft(l0); insertRight(l1); } break; } }
bool KdTreeNode::intersects (LineSegment *l) { if (lineSegment != 0 && lineSegment->intersects(l)) return true; switch (splitType) { case 0: if (l->p0 != splitAt && l->p1 != splitAt && XOrder(l->p0, splitAt) == 1 && XOrder(l->p1, splitAt) == 1) { if (left == 0) return false; else return left->intersects(l); } else if (l->p0 != splitAt && l->p1 != splitAt && XOrder(splitAt, l->p0) == 1 && XOrder(splitAt, l->p1) == 1) { if (right == 0) return false; else return right->intersects(l); } else { LineSegment *l0, *l1; splitLineSegment(l, splitAt, splitType, &l0, &l1); if (left != 0) if (left->intersects(l0)) return true; if (right != 0) if (right->intersects(l1)) return true; return false; } break; case 1: if (l->p0 != splitAt && l->p1 != splitAt && YOrder(l->p0, splitAt) == 1 && YOrder(l->p1, splitAt) == 1) { if (left == 0) return false; else return left->intersects(l); } else if (l->p0 != splitAt && l->p1 != splitAt && YOrder(splitAt, l->p0) == 1 && YOrder(splitAt, l->p1) == 1) { if (right == 0) return false; else return right->intersects(l); } else { LineSegment *l0, *l1; splitLineSegment(l, splitAt, splitType, &l0, &l1); if (left != 0) if (left->intersects(l0)) return true; if (right != 0) if (right->intersects(l1)) return true; return false; } break; } }
/** * Split any overlapping line segments in the convex subspaces, creating new * line segments (and vertices) as required. A subspace may well include such * overlapping segments as if they do not break the convexity rule they won't * have been split during the partitioning process. * * @todo Perform the split in divideSpace() */ void splitOverlappingSegments() { for(ConvexSubspaceProxy const &subspace : subspaces) { /* * The subspace provides a specially ordered list of the segments to * simplify this task. The primary clockwise ordering (decreasing angle * relative to the center of the subspace) places overlapping segments * adjacently. The secondary anticlockwise ordering sorts the overlapping * segments enabling the use of single pass algorithm here. */ OrderedSegments convexSet = subspace.segments(); int const numSegments = convexSet.count(); for(int i = 0; i < numSegments - 1; ++i) { // Determine the indice range of the partially overlapping segments. int k = i; while(de::fequal(convexSet[k + 1].fromAngle, convexSet[i].fromAngle) && ++k < numSegments - 1) {} // Split each overlapping segment at the point defined by the end // vertex of each of the other overlapping segments. for(int l = i; l < k; ++l) { OrderedSegment &a = convexSet[l]; for(int m = l + 1; m <= k; ++m) { OrderedSegment &b = convexSet[m]; // Segments of the same length will not be split. if(de::fequal(b.segment->length(), a.segment->length())) continue; // Do not attempt to split at an existing vertex. /// @todo fixme: For this to happen we *must* be dealing with /// an invalid mapping construct such as a two-sided line in /// the void. These cannot be dealt with here as they require /// a detection algorithm ran prior to splitting overlaps (so /// that we can skip them here). Presently it is sufficient to /// simply not split if the would-be split point is equal to /// either of the segment's existing vertexes. Vector2d const &point = b.segment->to().origin(); if(point == a.segment->from().origin() || point == a.segment->to().origin()) continue; splitLineSegment(*a.segment, point, false /*don't update edge tips*/); } } i = k; } } }
/** * Take the given line segment @a lineSeg, compare it with the partition * plane and determine into which of the two sets it should be. If the * line segment is found to intersect the partition, the intercept point * is determined and the line segment then split in two at this point. * Each piece of the line segment is then added to the relevant set. * * If the line segment is collinear with, or intersects the partition then * a new intercept is added to the partitioning half-plane. * * @note Any existing @em twin of @a lineSeg is so too handled uniformly. * * @param seg Line segment to be "partitioned". * @param rights Set of line segments on the right side of the partition. * @param lefts Set of line segments on the left side of the partition. */ void divideOneSegment(LineSegmentSide &seg, LineSegmentBlockTreeNode &rights, LineSegmentBlockTreeNode &lefts) { coord_t fromDist, toDist; LineRelationship rel = hplane.relationship(seg, &fromDist, &toDist); switch(rel) { case Collinear: { interceptPartition(seg, LineSegment::From); interceptPartition(seg, LineSegment::To); // Direction (vs that of the partition plane) determines in which // subset this line segment belongs. if(seg.direction().dot(hplane.partition().direction) < 0) { linkLineSegmentInBlockTree(lefts, seg); } else { linkLineSegmentInBlockTree(rights, seg); } break; } case Right: case RightIntercept: if(rel == RightIntercept) { // Direction determines which edge of the line segment interfaces // with the new half-plane intercept. interceptPartition(seg, (fromDist < DIST_EPSILON? LineSegment::From : LineSegment::To)); } linkLineSegmentInBlockTree(rights, seg); break; case Left: case LeftIntercept: if(rel == LeftIntercept) { interceptPartition(seg, (fromDist > -DIST_EPSILON? LineSegment::From : LineSegment::To)); } linkLineSegmentInBlockTree(lefts, seg); break; case Intersects: { // Calculate the intersection point and split this line segment. Vector2d point = intersectPartition(seg, fromDist, toDist); LineSegmentSide &newFrontRight = splitLineSegment(seg, point); // Ensure the new back left segment is inserted into the same block as // the old back right segment. if(LineSegmentBlockTreeNode *backLeftBlock = (LineSegmentBlockTreeNode *)seg.back().blockTreeNodePtr()) { linkLineSegmentInBlockTree(*backLeftBlock, newFrontRight.back()); } interceptPartition(seg, LineSegment::To); // Direction determines which subset the line segments are added to. if(fromDist < 0) { linkLineSegmentInBlockTree(rights, newFrontRight); linkLineSegmentInBlockTree(lefts, seg); } else { linkLineSegmentInBlockTree(rights, seg); linkLineSegmentInBlockTree(lefts, newFrontRight); } break; } } }