Skip to content

Commit

Permalink
Cleaned up the interface slightly. Switched over to a protocol for th…
Browse files Browse the repository at this point in the history
…e range.
  • Loading branch information
heardrwt committed Apr 1, 2013
1 parent 343c87a commit 47ce405
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 82 deletions.
35 changes: 32 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@ They can also be used for windowing queries, for instance, to find all roads on

## Classes
* RHIntervalTree - main interface to the Interval Tree.
* RHInterval - container class for objects passed into the Interval Tree.
* RHInterval - convenience container class for objects passed into the Interval Tree.
* RHIntervalProtocol - RHInterval implements this protocol, so can you.


## Getting Started
Include RHIntervalTree.h in your project. (RHIntervalTree.mm is a Objective-C++ file hence its extension)


```objectivec
#import <RHIntervalTree.h>
```


Setting up a tree.

```objectivec
Expand All @@ -36,15 +39,41 @@ Setting up a tree.
[RHInterval intervalWithRange:NSMakeRange(2, 8) object:@"four"],
nil];

RHIntervalTree *tree = [[RHIntervalTree alloc] initWithIntervals:intervals];
RHIntervalTree *tree = [[RHIntervalTree alloc] initWithIntervalObjects:intervals];
```
Performing a query
```objectivec
NSArray *overlappingObjects = [tree overlappingObjectsBetweenStart:77 andStop:220];
NSArray *overlappingObjects = [tree overlappingObjectsBetweenStart:77 andStop:220];
```

## Interface

```objectivec

@interface RHIntervalTree : NSObject

-(id)initWithIntervalObjects:(NSArray*)intervals; //all added objects should implement the RHIntervalProtocol

-(NSInteger)minStart;
-(NSInteger)maxStop;

-(NSArray*)allObjects;

//Contained methods return objects fully contained within the start and stop(inclusive) coordinates.
-(NSArray*)containedObjectsInRange:(NSRange)range;
-(NSArray*)containedObjectsBetweenStart:(NSInteger)start andStop:(NSInteger)stop;

//Overlapping methods return objects which are contained or partially overlap the start and stop(inclusive) coordinates.
-(NSArray*)overlappingObjectsInRange:(NSRange)range;
-(NSArray*)overlappingObjectsBetweenStart:(NSInteger)start andStop:(NSInteger)stop;

@end

```
## Licence
Expand Down
32 changes: 15 additions & 17 deletions RHIntervalTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,48 +37,46 @@

#import <Foundation/Foundation.h>

@class RHInterval;

@protocol RHIntervalProtocol <NSObject>

@required
-(NSInteger)start;
-(NSInteger)stop;

@end


@interface RHIntervalTree : NSObject

-(id)initWithIntervals:(NSArray*)intervals;
-(id)initWithIntervalObjects:(NSArray*)intervals; //all added objects should implement the RHIntervalProtocol

-(NSInteger)minStart;
-(NSInteger)maxStop;

-(NSArray*)allObjects;

//Contained methods return objects contained within the start and stop(inclusive) coordinates.
//Contained methods return objects fully contained within the start and stop(inclusive) coordinates.
-(NSArray*)containedObjectsInRange:(NSRange)range;
-(NSArray*)containedObjectsBetweenStart:(NSInteger)start andStop:(NSInteger)stop;

//Overlapping methods return objects which are contained or partially overlap the start and stop(inclusive) coordinates.
-(NSArray*)overlappingObjectsInRange:(NSRange)range;
-(NSArray*)overlappingObjectsBetweenStart:(NSInteger)start andStop:(NSInteger)stop;


//all the below methods return RHInterval objects
-(NSArray*)allIntervalObjects;

-(NSArray*)containedIntervalObjectsInRange:(NSRange)range;
-(NSArray*)containedIntervalObjectsBetweenStart:(NSInteger)start andStop:(NSInteger)stop;

-(NSArray*)overlappingIntervalObjectsInRange:(NSRange)range;
-(NSArray*)overlappingIntervalObjectsBetweenStart:(NSInteger)start andStop:(NSInteger)stop;

@end

@interface RHInterval : NSObject

@property (nonatomic, readonly) NSInteger start;
@property (nonatomic, readonly) NSInteger stop;
@property (nonatomic, readonly) NSRange range;
//convenience object that implements the RHIntervalProtocol
@interface RHInterval : NSObject <RHIntervalProtocol>

@property (nonatomic, readonly) id<NSObject> object;
@property (nonatomic, readonly) NSRange range;

+(id)intervalWithRange:(NSRange)range object:(id<NSObject>)object;
+(id)intervalWithStart:(NSInteger)start stop:(NSInteger)stop object:(id<NSObject>)object;

-(id)initWithStart:(NSInteger)start stop:(NSInteger)stop object:(id<NSObject>)object;

@end

60 changes: 23 additions & 37 deletions RHIntervalTree.mm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// RHIntervalTree.m
// RHIntervalTree.mm
// RHIntervalTree
//
// Created by Richard Heard on 28/02/13.
Expand Down Expand Up @@ -35,12 +35,12 @@
@implementation RHIntervalTree{
NSInteger _min;
NSInteger _max;

NSArray *_intervals;
IntervalTree<RHInterval*> *_intervalTree;
}

-(id)initWithIntervals:(NSArray *)intervals{
-(id)initWithIntervalObjects:(NSArray *)intervals{
if (!intervals) [NSException raise:NSInvalidArgumentException format:@"intervals must not be nil"];

self = [super init];
Expand All @@ -50,7 +50,7 @@ -(id)initWithIntervals:(NSArray *)intervals{
_min = NSIntegerMax;
_max = NSIntegerMin;

//hold onto the array until we are dealloc'd
//hold onto the array until we are dealloc'd
_intervals = [intervals copy];

//setup the interval tree
Expand Down Expand Up @@ -83,8 +83,7 @@ -(NSInteger)maxStop{
}


#pragma mark - objects

#pragma mark - interval objects
-(NSArray*)allObjects{
return _intervals;
}
Expand All @@ -94,36 +93,11 @@ -(NSArray*)containedObjectsInRange:(NSRange)range{
}

-(NSArray*)containedObjectsBetweenStart:(NSInteger)start andStop:(NSInteger)stop{
return [[self containedIntervalObjectsBetweenStart:start andStop:stop] valueForKey:@"object"];
}


#pragma mark - overlapping objects

-(NSArray*)overlappingObjectsInRange:(NSRange)range{
return [self overlappingObjectsBetweenStart:range.location andStop:range.location + range.length];
}

-(NSArray*)overlappingObjectsBetweenStart:(NSInteger)start andStop:(NSInteger)stop{
return [[self overlappingIntervalObjectsBetweenStart:start andStop:stop] valueForKey:@"object"];
}


#pragma mark - interval objects
-(NSArray*)allIntervalObjects{
return _intervals;
}

-(NSArray*)containedIntervalObjectsInRange:(NSRange)range{
return [self containedIntervalObjectsBetweenStart:range.location andStop:range.location + range.length];
}

-(NSArray*)containedIntervalObjectsBetweenStart:(NSInteger)start andStop:(NSInteger)stop{
vector<Interval<RHInterval*> > resultsVector;
_intervalTree->findContained(start, stop, resultsVector);

NSMutableArray *mutableResults = [NSMutableArray arrayWithCapacity:resultsVector.size()];

for (typename vector<Interval<RHInterval*> >::iterator i = resultsVector.begin(); i != resultsVector.end(); ++i) {
Interval<RHInterval*> interval = *i;
[mutableResults addObject:interval.value];
Expand All @@ -135,11 +109,11 @@ -(NSArray*)containedIntervalObjectsBetweenStart:(NSInteger)start andStop:(NSInte

#pragma mark - interval overlapping objects

-(NSArray*)overlappingIntervalObjectsInRange:(NSRange)range{
return [self overlappingIntervalObjectsBetweenStart:range.location andStop:range.location + range.length];
-(NSArray*)overlappingObjectsInRange:(NSRange)range{
return [self overlappingObjectsBetweenStart:range.location andStop:range.location + range.length];
}

-(NSArray*)overlappingIntervalObjectsBetweenStart:(NSInteger)start andStop:(NSInteger)stop{
-(NSArray*)overlappingObjectsBetweenStart:(NSInteger)start andStop:(NSInteger)stop{
vector<Interval<RHInterval*> > resultsVector;
_intervalTree->findOverlapping(start, stop, resultsVector);

Expand Down Expand Up @@ -175,7 +149,7 @@ +(id)intervalWithStart:(NSInteger)start stop:(NSInteger)stop object:(id)object{
-(id)initWithStart:(NSInteger)start stop:(NSInteger)stop object:(id)object{
if (start > stop) [NSException raise:NSInvalidArgumentException format:@"start must be greater than stop"];
if (!object) [NSException raise:NSInvalidArgumentException format:@"object can not be nil"];

self = [super init];
if (self){
_start = start;
Expand All @@ -185,8 +159,20 @@ -(id)initWithStart:(NSInteger)start stop:(NSInteger)stop object:(id)object{
return self;
}

-(NSInteger)start{
return _start;
}

-(NSInteger)stop{
return _stop;
}

-(id<NSObject>)object{
return _object;
}

-(NSRange)range{
//5, 10 should be (5, 6)
//5, 10 should be (5, 6)
NSRange range = NSMakeRange(_start, (_stop - _start) + 1);
return range;
}
Expand Down
48 changes: 23 additions & 25 deletions RHIntervalTreeUnitTests/RHIntervalTreeUnitTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ -(void)testRHIntervalTreePerformanceAndAccuracy{


// using the interval tree (contained)
RHIntervalTree *tree = [[RHIntervalTree alloc] initWithIntervals:intervals];
RHIntervalTree *tree = [[RHIntervalTree alloc] initWithIntervalObjects:intervals];
NSMutableArray *treeCounts = [NSMutableArray array];
t0 = clock() / (CLOCKS_PER_SEC / 1000);

Expand Down Expand Up @@ -122,7 +122,7 @@ -(void)testRHIntervalTreeMinMax{
[RHInterval intervalWithRange:NSMakeRange(5, 5) object:testObject],
nil];

RHIntervalTree *tree = [[RHIntervalTree alloc] initWithIntervals:intervals];
RHIntervalTree *tree = [[RHIntervalTree alloc] initWithIntervalObjects:intervals];


STAssertTrue(tree.minStart == 2, @"minStart is not right");
Expand All @@ -131,7 +131,7 @@ -(void)testRHIntervalTreeMinMax{
}


-(void)testRHIntervalTreeOverlapping{
-(void)testRHIntervalTreeContained{
NSString *testObject = @"test";
NSString *overlappingObject = @"overlap";

Expand All @@ -143,26 +143,24 @@ -(void)testRHIntervalTreeOverlapping{
[RHInterval intervalWithRange:NSMakeRange(9, 1) object:testObject],
[RHInterval intervalWithRange:NSMakeRange(11,1) object:overlappingObject],
[RHInterval intervalWithRange:NSMakeRange(13,1) object:overlappingObject],
[RHInterval intervalWithRange:NSMakeRange(15,1) object:testObject],
[RHInterval intervalWithRange:NSMakeRange(15,2) object:testObject],
[RHInterval intervalWithRange:NSMakeRange(12,2) object:overlappingObject],
nil];

RHIntervalTree *tree = [[RHIntervalTree alloc] initWithIntervals:intervals];
RHIntervalTree *tree = [[RHIntervalTree alloc] initWithIntervalObjects:intervals];


//TODO:
//
// NSArray *results = [tree overlappingIntervalObjects];
// STAssertTrue(results.count == 3, @"count is not right");
//
// for (NSString *obj in results) {
// STAssertEqualObjects(overlappingObject, obj, @"overlapping object was not right");
// }
//
NSArray *results = [tree containedObjectsBetweenStart:10 andStop:15];
STAssertTrue(results.count == 3, @"count is not right");

for (RHInterval *obj in results) {
STAssertEqualObjects(overlappingObject, [obj object], @"contained object was not right");
}

[tree release];
}

-(void)testRHIntervalTreeContained{
-(void)testRHIntervalTreeOverlapping{
NSString *testObject = @"test";
NSString *overlappingObject = @"overlap";

Expand All @@ -174,21 +172,21 @@ -(void)testRHIntervalTreeContained{
[RHInterval intervalWithRange:NSMakeRange(9, 1) object:testObject],
[RHInterval intervalWithRange:NSMakeRange(11,1) object:overlappingObject],
[RHInterval intervalWithRange:NSMakeRange(13,1) object:overlappingObject],
[RHInterval intervalWithRange:NSMakeRange(15,1) object:testObject],
[RHInterval intervalWithRange:NSMakeRange(15,2) object:overlappingObject],
[RHInterval intervalWithRange:NSMakeRange(12,2) object:overlappingObject],
nil];

RHIntervalTree *tree = [[RHIntervalTree alloc] initWithIntervals:intervals];
RHIntervalTree *tree = [[RHIntervalTree alloc] initWithIntervalObjects:intervals];


//TODO:
// NSArray *results = [tree overlappingIntervalObjects];
// STAssertTrue(results.count == 3, @"count is not right");
//
// for (NSString *obj in results) {
// STAssertEqualObjects(overlappingObject, obj, @"overlapping object was not right");
// }
//

NSArray *results = [tree overlappingObjectsBetweenStart:10 andStop:15];
STAssertTrue(results.count == 4, @"overlapping count is not right");

for (RHInterval *obj in results) {
STAssertEqualObjects(overlappingObject, [obj object], @"overlapping object was not right");
}

[tree release];
}

Expand Down

0 comments on commit 47ce405

Please sign in to comment.