Exemplo n.º 1
0
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;
  }
}
Exemplo n.º 2
0
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;
  }
}
Exemplo n.º 3
0
    /**
     * 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;
            }
        }
    }
Exemplo n.º 4
0
    /**
     * 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; }
        }
    }