Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vectorize calculation of cell number in a hexagonal grid

I know the use of for-loop in R is often unnecessary, because it supports vectorization. I want to program as efficient as possible, there for my question concerning the following example code.

I have a hexagonal grid, and I am calculating the number of the cell, this counts from 1 to 225 in my example starting in the left lower corner, going to the right. So cell 16 is placed a bit offset right above cell 1. see snapshot: example of grid I'm working with

Therefor, if I have the Y coordinate, the X coordinate has to be either rounded, or ceiling. In my application the user points out cells, I save this and in a for loop go through the cells to determine the cells he chose as follows, with toy input values for Xcells and Ycells the user would have chosen:

gridsize <- 15 

 Xcells <-c(0.8066765, 1.8209879, 3.0526517, 0.5893240)
 Ycells <-c(0.4577802, 0.4577802, 0.5302311, 1.5445425)

 clicks <- length(Xcells)
 cells <-vector('list', clicks)

This corresponds to cell 1 2 3 and 16. 4 clicks. Now to determine the cell numbers:

  Y <- ceiling(Ycells)
      for(i in 1:clicks){
        if(Y[i]%%2==1){
           X[i] <- round(Xcells[i])
        }
      else{
         X[i]<- ceiling(Xcells[i])
         }

      #determine the cell numbers and store in predefined list
      cells[[i]] <- (Y[i]-1)*gridsize + X[i]
       }

So if the Y is 'even' the X has to be rounded, and if the Y is 'un-even' it has to be the ceiling value.

Is there a way to do this without the for loop, by using the vectorization?

like image 401
Piet93 Avatar asked Oct 29 '22 19:10

Piet93


1 Answers

You can vectorize this as follows

(Y - 1) * gridsize + ifelse(Y %% 2 == 1, round(Xcells), ceiling(Xcells))
# [1]  1  2  3 16

(I'm not sure pre-calculating round(Xcells) and ceiling(Xcells) will improve this a bit more - you could try)


Another option (if you want to avoid ifelse) could be

(Y - 1) * gridsize + cbind(ceiling(Xcells), round(Xcells))[cbind(1:length(Xcells), Y %% 2 + 1)]
# [1]  1  2  3 16
like image 186
David Arenburg Avatar answered Nov 15 '22 06:11

David Arenburg