In Objective C, How to do Clustering with pagination using CATileLayer - ios

I have one scenario as do cluster for the nearest CGPoint in UIView. So i have set of CGPoint NSArray, I trying to get the nearest value and do cluster but i could not get the logic :
// my code
//total CGpointArray ex: cgPointGroupArray, i try to get each obj closest obj
for (CGPoint firstObjOfCGPoint in cgPointGroupArray) {
for (CGPoint nextPoint in cgPointGroupArray) {
//ex: 30 -distance b/w two point
if (30>[self distanceBetween: firstObjOfCGPoint and:nextPoint]){
[shortestClusterArr addObject:nextPoint];
}
else{
[longestClusterArr addObject:nextPoint];
}
}
//if array hold more than 2 value it will cluster otherwise mark single obj
if(shortestClusterArr.count>2){
//clustered marker obj
[self addClusterMarker:shortestClusterArr];
}
else{
//no cluster marker obj
}
}
Above code, looping time getting duplicate points as well override on the same object so if anyone knows the logic comment here,.. But I want such as clustering concepts like Geo-map clustering with pagination.

xTotalCount=pow( 2, self.mapScrollView.zoomLevel );
for ( int i = 0; i < xTotalCount ; i++) {
// ex : 0 < 2, it will execute 2 times depends on zoom level(pow(2,0),pow(2,1),pow(2,2),.. )
xISet = [[ NSMutableArray alloc ] init];
//set the cordination value to the a and b according to the zoom level
ax=( i*zoomLevelTicketSpacing ) / xTotalCount; // ex : a = 0
bx=((i + 1) *zoomLevelTicketSpacing ) / xTotalCount; // b = 256
for (EDCTicketMarker *ticketMarker in weakSelf.activeTicketMarkers) {
// group with zoom scale
nextPointX = ticketMarker.location.x;
if(nextPointX > ax && nextPointX < bx){
[xISet addObject:ticketMarker];
}
}
[xMatrixSet setValue:xISet forKey:[#(i)stringValue]];
// Y cordination ( 00, 01, 10, 11 )
yTotalCount=pow ( 2, self.mapScrollView.zoomLevel );
for (int j=0; j< yTotalCount ; j++) {
yISet = [[ NSMutableArray alloc ] init];
ay=( j*zoomLevelTicketSpacing ) / yTotalCount; // ex : a = 0
by=(( j+1 ) *zoomLevelTicketSpacing) / yTotalCount; // b = 256
for (EDCTicketMarker *ticketMarker in weakSelf.activeTicketMarkers) {
// group with zoom scale
nextPointY = ticketMarker.location.y;
if( nextPointY > ay && nextPointY < by ){
[yISet addObject:ticketMarker];
}
}
[yMatrixSet setValue:yISet forKey:[#(i)stringValue]];
// Intersect the X and Y matrix array
NSMutableSet *matrixSetX = [ NSMutableSet setWithArray:xISet ];
NSMutableSet *matrixSetY = [ NSMutableSet setWithArray:yISet ];
[matrixSetX intersectSet:matrixSetY];
NSArray *resultMatrix = [matrixSetX allObjects];
NSLog(resultMatrix) // it will print according to the x and y position (00,01,10,11)

Related

Looking for an more efficient way to create a 4 directional linked-list

I am trying to create a method that will link all Cell objects set up in a 2D array named CellGrid[,]
My question is: Since most of the code in SetDirection() is so similar, it seem there is a better way to achieve my goal.
(Side note: This is functional but the execution feels "off" )
private void SetDirection()
{
int x = 0, y = 0;
for ( int i = 0 ; i < Size * (Size - 1);)//setting all UP pointers
{
if ( i == 0 ) { x = 0; y = 1;}//initial setup
for ( x = 0 ; x < Size ; x++ )
{
CellGrid[x,y].SetPointer(CellGrid[x,y-1] , Direction.Up );
i++;
}
y++;
}
for ( int i = 0 ; i < Size * (Size - 1);) //setting all DOWN pointers
{
if ( i == 0 ) { x = 0; y = 0;}//initial setup
for ( x = 0 ; x < Size ; x++ )
{
CellGrid[x,y].SetPointer(CellGrid[x,y+1], Direction.Down);
i++;
}
y++;
}
for ( int i = 0 ; i < Size * (Size - 1);)//setting all LEFT pointers
{
if ( i == 0 ) { x = 1; y = 0;}//initial setup
for ( y = 0 ; y < Size ; y++ )
{
CellGrid[x, y].SetPointer( CellGrid[x-1,y], Direction.Left);
i++;
}
x++;
}
for ( int i = 0 ; i < Size * (Size - 1);) //setting all RIGHT pointers
{
if ( i == 0 ) { x = 0; y = 0;}//initial setup
for ( y = 0 ; y < Size ; y++ )
{
CellGrid[x, y].SetPointer( CellGrid[x+1,y], Direction.Right);
i++;
}
x++;
}
}
public void SetPointer( Cell cellRef ,GridBuilder.Direction dir)
{
switch ( dir )
{
case GridBuilder.Direction.Up:
this.Up = cellRef;
break;
case GridBuilder.Direction.Down:
this.Down = cellRef;
break;
case GridBuilder.Direction.Left:
this.Left = cellRef;
break;
case GridBuilder.Direction.Right:
this.Right = cellRef;
break;
}
}
You can indeed use one set of loops to make the links in all four directions. This is based on two ideas:
When setting a link, immediately set the link in the opposite direction between the same two cells.
When setting a link, immediately set the link between the two cells that are located in the mirrored positions -- mirrored by the main diagonal (x <--> y).
private void SetDirection() {
for (int i = 1; i < Size; i++) {
for (int j = 0; j < Size; j++) {
CellGrid[i, j].SetPointer(CellGrid[i-1, j], Direction.Left);
CellGrid[i-1, j].SetPointer(CellGrid[i, j], Direction.Right);
CellGrid[j, i].SetPointer(CellGrid[j, i-1], Direction.Up);
CellGrid[j, i-1].SetPointer(CellGrid[j, i], Direction.Down);
}
}
}

Network Delay Problem - Complexity Analysis

Below is a solution Network delay problem of leetcode. I have written a all test case success solution. But not able to analyse the time complexity. I believe its O(V^2 + E) where V is the number of nodes and E edges.
In this solution though I am adding all adjacents of each node every time, but not processing them further if there exists a min distance for that node already.
Leetcode question link https://leetcode.com/problems/network-delay-time
public int networkDelayTime(int[][] times, int n, int k) {
int[] distances = new int[n+1];
Arrays.fill(distances , -1);
if(n > 0){
List<List<int[]>> edges = new ArrayList<List<int[]>>();
for(int i = 0 ; i <= n ; i++){
edges.add(new ArrayList<int[]>());
}
for(int[] time : times){
edges.get(time[0]).add(new int[]{time[1] , time[2]});
}
Queue<Vertex> queue = new LinkedList<>();
queue.add(new Vertex(k , 0));
while(!queue.isEmpty()){
Vertex cx = queue.poll();
int index = cx.index;
int distance = cx.distance;
//process adjacents only if distance is updated
if(distances[index] == -1 || distances[index] > distance){
distances[index] = distance;
List<int[]> adjacents = edges.get(index);
for(int[] adjacent : adjacents){
queue.add(new Vertex(adjacent[0] , adjacent[1]+distance));
}
}
}
}
int sum = 0;
for(int i = 1 ; i <= n; i++){
int distance = distances[i];
if(distance == -1){
return -1;
}
sum = Math.max(sum , distance);
}
return sum;
}
public static class Vertex{
int index;
int distance;
public Vertex(int i , int d){
index = i;
distance = d;
}
}
You should use PriorityQueue instead of LinkedList

How to create random numbers for multiple images to show randomly in Grid without repetition in iOS?

I create GridView in SpriteKit.my requirement is to shuffle images randomly in Grid View.
Here is my code to show images randomly without repetition.but this code is working for only two images.for multiple images this code is not working.
int RandomRowMainImage = arc4random_uniform(3);
int RandomColumnMainImage = arc4random_uniform(3);
//
int RandomRowOtherImage = arc4random_uniform(3);
int RandomColumnOtherImage = arc4random_uniform(3);
NSLog(#"RandomRowMain:%d \n Random Column :%d \n RandomRow1:%d \n randomColumn1 :%d",RandomRowMainImage,RandomColumnMainImage,RandomRowOtherImage,RandomColumnOtherImage);
//
BOOL checkStatus = [self checkRandomNumberColumRowLogic:RandomRowMainImage withMainRow:RandomColumnMainImage withOtherColumn:RandomColumnOtherImage withOtherRow:RandomRowOtherImage];
if (checkStatus) {
imgIcons.position = [self GridPosition:MainRowCount Column:MainColumnCount];
imgOtherImage.position = [self GridPosition:otherRowCount Column:otherColumnCount];
}
than Code for Position of Images
//Grid Position
-(CGPoint)GridPosition:(int)Row Column:(int)Column
{
CGFloat offset = SizeOfGrid / 2.0 + 0.5;
CGFloat x = Column * SizeOfGrid - (SizeOfGrid*TotalCol)/2.0 + offset;
CGFloat y = (TotalRows-Row-1) * SizeOfGrid -(SizeOfGrid*TotalRows)/2.0 + offset;
return CGPointMake(x, y);}
//Code to check prevent duplication of repeat random number for Two Images.
- (BOOL)checkRandomNumberColumRowLogic:(int)MainColumn withMainRow:(int)mainRow withOtherColumn:(int)otherColumn withOtherRow:(int)otherRow {
BOOL CompareRow = false;
BOOL CompareColumn = false;
if (mainRow == otherRow) {
int otherRow = 0;
for (int i = 0; i < TotalCol; i++ ) {
otherRow = [self checkRandomNumberCompare:otherRow];
if (MainColumn == otherRow) {
CompareRow = true;
break;
}
}
MainColumnCount = mainRow;
otherColumnCount = otherRow;
}
else {
CompareRow = true;
MainRowCount = mainRow;
otherRowCount = otherRow;
}
if (MainColumn == otherColumn) {
int otherCol = 0;
for (int i = 0; i < TotalCol; i++ ) {
otherCol = [self checkRandomNumberCompare:otherColumn];
if (MainColumn == otherCol) {
CompareColumn = true;
break;
}
}
MainColumnCount = MainColumn;
otherColumnCount = otherCol;
}
else {
CompareColumn = true;
MainColumnCount = MainColumn;
otherColumnCount = otherColumn;
}
if(CompareRow == CompareColumn) {
return true;
} else {
return false;
}
}
-(int)checkRandomNumberCompare:(int)compareRow {
int compareDiff = arc4random_uniform(TotalRows);
return compareDiff;
}
can you please help to display multiple images without repeat? like one time one image in Node
Sorry, but the logic of your checkRandomNumberColumRowLogic: method baffles me. Given two coordinates (x1, y1) and (x2, y2) then they represent the same point if and only if x1 == x2 and y1 == y2, and if this is not fall then they represent different points.
Here is the outline of a possible algorithm to solve your problem. First consider that given a rectangular grid of cells where the rows and columns are numbered starting from 0 then each cell can be assigned a unique number by multiplying its row index by the number of columns and adding in its column index. A diagram is worth a thousand words, given a 3 x 3 grid you get the numbering:
0 1 2
3 4 5
6 7 8
Note that given a cell number the row & column it represents can be calculated using integer division and remainder.
Doing the above reduces your problem to producing the numbers from 0 to rowCount x colCount - 1 in some random order.
There are a number of ways in which you can do this, here is one:
Set upperLimit to rowCount x colCount - 1
Generate a random number r between 0 and upperLimit
Check if cell r is occupied, if it is add 1 to r and repeat this step
Place next image into cell r
Subtract 1 from upperLimit and goto step 2 if the result is greater than 0 (of course "goto" here translates to a "while" in code)
They key to avoiding duplicates is step 3, and the algorithm guarantees that step 3 will always find an unoccupied cell – proving that is left as an exercise.
HTH
I'd agree with the answer above that your logic is overly complicated. If you give an index to each image as suggested, e.g. for a 3x4 grid:
0 1 2
3 4 5
6 7 8
9 10 11
You could then randomise the grid and exchange those images. The following code would achieve this:
-(void)createRandomGridArrays
{
NSInteger columnLength = 3;
NSInteger rowLength = 4;
// Create an array of NSNumbers up to the max then randomise
NSMutableArray *indexes = [NSMutableArray new];
for (NSInteger i=0; i<columnLength*rowLength; i++) {
[indexes addObject:#(i)];
}
NSArray *randomIndexes = [self shuffleArray:indexes];
NSLog(#"%# -> %#", indexes, randomIndexes);
// (0,1,2,3,4,5,6,7,8,9,10,11) -> (1,0,6,10,4,2,7,11,9,5,8,3)
// Convert indexes back to row/columns
for (NSNumber *randomIndex in randomIndexes) {
NSInteger index = [randomIndex integerValue];
NSInteger row = index % rowLength;
NSInteger column = index % columnLength;
NSLog(#"%ld row:%ld, column:%ld", index, row, column);
}
}
-(NSArray*)shuffleArray:(NSArray*)array
{
NSMutableArray *shuffledArray = [array mutableCopy];
for (NSInteger i=shuffledArray.count-1; i>0; i--) {
[shuffledArray exchangeObjectAtIndex:i withObjectAtIndex:arc4random_uniform(i+1)];
}
return shuffledArray;
}
If you had an NSMutableArray of images you would then just exchange the image at index with the image at [randomIndexes[index] integerValue].

Find closest point on line from a particular point

I'm using Google Maps iOS to set up Geofencing around a building complex. I've created a polyline around the complex and if the user taps outside of the polyline it will move the marker to the closest point that's on the polyline, otherwise it will just place the marker. This seems to work relatively well using this method.
However I've noticed that this method only seems to work when the point in question is perpendicular to a point on the line, otherwise it comes up with strange results. I've posted my code and some screenshots below.
-(CLLocationCoordinate2D) findClosestPointWithinFence:(CLLocationCoordinate2D) pointToTest {
CLLocationDistance smallestDistance = 0;
CLLocationCoordinate2D closestPoint = pointToTest;
for(int i = 0; i < [geoFencePoints count] - 1; i++) {
CGPoint point = [[geoFencePoints objectAtIndex:i] CGPointValue];
CGPoint point2 = [[geoFencePoints objectAtIndex:i + 1] CGPointValue];
CLLocationCoordinate2D locationA = CLLocationCoordinate2DMake(point.x, point.y);
CLLocationCoordinate2D locationB = CLLocationCoordinate2DMake(point2.x, point2.y);
CLLocationCoordinate2D myLoc = [self findClosestPointOnLine:locationA secondPoint:locationB fromPoint:pointToTest];
if(GMSGeometryIsLocationOnPath(myLoc, dealershipParameters.path, YES)) {
if(smallestDistance == 0) {
smallestDistance = GMSGeometryDistance(myLoc, pointToTest);
closestPoint = myLoc;
} else {
if(smallestDistance > GMSGeometryDistance(myLoc, pointToTest)) {
smallestDistance = GMSGeometryDistance(myLoc, pointToTest);
closestPoint = myLoc;
}
}
}
}
return closestPoint;
}
-(CLLocationCoordinate2D) findClosestPointOnLine:(CLLocationCoordinate2D)locationA secondPoint:(CLLocationCoordinate2D)locationB fromPoint:(CLLocationCoordinate2D) pointToTest {
CGPoint aToP = CGPointMake(pointToTest.latitude - locationA.latitude, pointToTest.longitude - locationA.longitude);
CGPoint aToB = CGPointMake(locationB.latitude - locationA.latitude, locationB.longitude - locationA.longitude);
float atb2 = (aToB.x * aToB.x) + (aToB.y * aToB.y);
float atp_dot_atb = (aToP.x * aToB.x) + (aToP.y * aToB.y);
float t = atp_dot_atb / atb2;
CLLocationCoordinate2D myLoc = CLLocationCoordinate2DMake(locationA.latitude + aToB.x * t, locationA.longitude + aToB.y * t);
return myLoc;
}
-(BOOL)testIfInsideGeoFence:(CLLocationCoordinate2D) pointToTest {
return GMSGeometryContainsLocation(pointToTest, dealershipParameters.path, YES) || GMSGeometryIsLocationOnPath(pointToTest, dealershipParameters.path, YES);
}
Below the first screenshot shows the marker successfully finding the closest point, the marker off the blue line is where I initially tapped, and the marker on the blue line is the point it found. The second shows the marker failing to find the closest point. The marker on the screen is where I initially tapped, since it is unable to find a proper solution it doesn't place a second marker.
Screenshot 1
Screenshot 2
I ran into a similar issue. I think what is happening is that you are treating the line segment as a line. Since the segment does not extend to a point that would be perpendicular to the point, the closest point on the segment would be one of it endpoints, not an extension of the segment.
Here is a method I am using. It takes the endpoint of the segment and returns a struct containing the nearest point on the segment and the distance from the giving point. The key difference being the if-else statements that check whether the solution is on the segment or not. You may need to rework a few things for your purposes.
The other thing to note is that I have had more accurate results performing the math on MKMapPoints rather than CLLocationCoordinate2D objects. I think it has something to do with the earth being round or some such nonsense.
+ (struct TGShortestDistanceAndNearestCoordinate)distanceFromPoint:(CLLocationCoordinate2D)p
toLineSegmentBetween:(CLLocationCoordinate2D)l1
and:(CLLocationCoordinate2D)l2 {
return [[self class] distanceFromMapPoint:MKMapPointForCoordinate(p)
toLineSegmentBetween:MKMapPointForCoordinate(l1)
and:MKMapPointForCoordinate(l2)];
}
+ (struct TGShortestDistanceAndNearestCoordinate)distanceFromMapPoint:(MKMapPoint)p
toLineSegmentBetween:(MKMapPoint)l1
and:(MKMapPoint)l2 {
double A = p.x - l1.x;
double B = p.y - l1.y;
double C = l2.x - l1.x;
double D = l2.y - l1.y;
double dot = A * C + B * D;
double len_sq = C * C + D * D;
double param = dot / len_sq;
double xx, yy;
if (param < 0 || (l1.x == l2.x && l1.y == l2.y)) {
xx = l1.x;
yy = l1.y;
}
else if (param > 1) {
xx = l2.x;
yy = l2.y;
}
else {
xx = l1.x + param * C;
yy = l1.y + param * D;
}
struct TGShortestDistanceAndNearestCoordinate result;
MKMapPoint nearestPoint = MKMapPointMake(xx, yy);
result.shortestDistance = MKMetersBetweenMapPoints(p, nearestPoint);
result.nearestCoordinate = MKCoordinateForMapPoint(nearestPoint);
return result;
}
A very elegant solution. But I'm not sure about your test in the line "if param < 0 ... ". l1.x == l2.x iff the segment is vertical, and l1.y == l2.y iff it is horizontal. So how can this conjunction ever be true? (except when l1, l2 are identical)

c style 2d array not retaining value between functions

Ok so I'm creating a map using a c-style 2d array containing position structs:
typedef struct{
int x;
int y;
} posn;
I upload the values fine and print them out to make sure the values are correct. The 2d array is stored as an instance variable in my class.
In my next function I start by printing the array to make sure it's the same but it's not. The values are totally different and the array is even shortened. Can anyone tell me why I'm getting this issue. I'm using structs and c style arrays because I'm designing a game and I figured using them would be faster than NSMutableArray.
this is how I fill the array
mapa_camino = (posn *)malloc(w * h * sizeof(posn));
int i, j = 0;
for (i = 0; i < w; i++){
for (j = 0; j < h; j++){
SKNode *act;
act = [self.main_view nodeAtPoint:CGPointMake(i-algorimo_compensado.x, j-algorimo_compensado.y)];
if([act isKindOfClass:[BasicActor class]] && ![act isKindOfClass:[CMActor class]]){
//crea pt
posn pt = {.x = i,
.y = j,
.ocupado = YES,
.visitado = NO};
//fija posicion actual como pt
*(mapa_camino + i*h + j) = pt;
}else{
posn pt = {.x = i,
.y = j,
.ocupado = NO,
.visitado = NO};
*(mapa_camino + i*h + j) = pt;
}
}
}
this is how I print it:
- (NSMutableArray*) printtwodarray:(posn*)matriz{
int array_w = self.frame.size.width;
int array_h = self.frame.size.height;
NSMutableArray* regresa_matriz = [[NSMutableArray alloc] initWithCapacity:array_w];
for(int i=0;i<array_w;i++){
[regresa_matriz addObject:[[NSMutableArray alloc] initWithCapacity:array_h]];
for(int j=0;j<array_h;j++){
posn *pt = (matriz + i*array_h + j);
[[regresa_matriz objectAtIndex:i] insertObject:[[Posn alloc] initWithX:pt->x Y:pt->y H:pt->h G:pt->g Ocupado:pt->ocupado Goal:pt->is_goal] atIndex:j];
}
}
return regresa_matriz;
}
In order to store a 2D array in an instance variable from one function and use it in another function you need to declare the variable as an array, not as a pointer. Assignment would not work, so you would need to initialize the data with memcpy:
#interface Foo : NSObject {
posn p[20][30];
}
#end
...
-(void)bar {
posn d[20][30] = {{...}, {...},...,{...}};
memcpy(p, d, sizeof(p));
}

Resources