Create a GTFS realtime (vehicle positions) with R - r

I work on turning a dataframe into a GTFS realtime, and am struggling on the vehicle position part.
My data looks like that (stored in a dataframe called "vehicle"):
## Input data looks that way, one line per on-going vehicle
vehicle_id trip_id lat lon bear speed stop_time
52108 4.264930e+05 45.40 -71.92 1 9 2017-05-02 15:19:05
60105 4.273610e+05 45.40 -71.90 246 6 2017-05-02 15:18:59
59104 4.270150e+05 45.40 -71.87 81 7 2017-05-02 15:18:54
The details of my code is:
library(dplyr)
library(XML)
library(stringr)
library(RProtoBuf)
library(RODBC)
## Read the google gtfs proto file
readProtoFiles("gtfs-realtime.proto")
## List of current vehicles
current_vehicles <- unique(vehicle$vehicle_id)
## Create an empty list, 1 entry for each vehicle
protobuf_list <- vector(mode = "list", length = length(current_vehicles))
## Loop over all current vehicles
for(i in 1:length(current_vehicles)) {
## protobuf object
vehicle_position_update <- new(transit_realtime.VehiclePosition,
vehicle = vehicle$vehicle_id[i],
stop_id = vehicle$stop_id[i],
trip = vehicle$trip_id[i],
latitude = vehicle$lat[i],
longitude = vehicle$lon[i],
bearing = vehicle$bear[i],
speed = vehicle$speed[i])
## protobuf feed entity
e <- new(transit_realtime.FeedEntity,
id = as.character(vehicle$vehicle_id[i]),
vehicle = new(transit_realtime.VehiclePosition,
trip = new(transit_realtime.VehicleDescriptor,
id = vehicle$vehicle_id[i]),
VehiclePosition = vehicle_position_update))
## Fill the list
protobuf_list[[i]] <- e
}# Loop over vehicles
## GTFS header
header_object <- new(transit_realtime.FeedHeader,
gtfs_realtime_version = "1.0",
incrementality = "FULL_DATASET",
timestamp = as.numeric(as.POSIXlt(Sys.time())))
## Build the full GTFS
m <- new(transit_realtime.FeedMessage,
header = header_object,
entity = protobuf_list) # use entity_list
## Write the GTFS
writeLines(as.character(m))
## Turn it into binary
serialize(m, "vehiclePositions.pb")
When creating the protobuffer object vehicle_position_update, it crashes with the message:
type mismatch, expecting a 'Message' object
I went through the gtfs-realtime.proto, and my understanding of the different messages to include seems fine (well, obviously it'nt..).
Does anyone see why this protobuffer file cannot be created?
ADDED FOR A CLEAR SOLUTION:
My issue was that I was'nt following exactly the gtfs proto descriptions of the different messages. Once this point corrected, the loop over the vehicles becomes:
## Loop over all current vehicles
for(i in 1:length(current_vehicles)) {
## protobuf object
vehicle_position_update <- new(transit_realtime.Position,
latitude = vehicle$lat[i],
longitude = vehicle$lon[i],
bearing = vehicle$bear[i],
speed = vehicle$speed[i])
## protobuf feed entity
e <- new(transit_realtime.FeedEntity,
id = as.character(vehicle$vehicle_id[i]),
vehicle = new(transit_realtime.VehiclePosition,
trip = new(transit_realtime.TripDescriptor,
trip_id = vehicle$trip_id[i],
route_id = vehicle$route_id[i]),
stop_id = vehicle$stop_id[i],
position = vehicle_position_update))
## Fill the list
protobuf_list[[i]] <- e
}# Loop over vehicles
and it works

The message definition tells you what fields it requires, for example
writeLines(as.character(RProtoBuf::fileDescriptor(transit_realtime.FeedMessage)))
message FeedMessage {
required .transit_realtime.FeedHeader header = 1;
repeated .transit_realtime.FeedEntity entity = 2;
extensions 1000 to 1999;
}
message FeedHeader {
enum Incrementality {
FULL_DATASET = 0;
DIFFERENTIAL = 1;
}
required string gtfs_realtime_version = 1;
optional .transit_realtime.FeedHeader.Incrementality incrementality = 2 [default = FULL_DATASET];
optional uint64 timestamp = 3;
extensions 1000 to 1999;
}
message FeedEntity {
required string id = 1;
optional bool is_deleted = 2 [default = false];
optional .transit_realtime.TripUpdate trip_update = 3;
optional .transit_realtime.VehiclePosition vehicle = 4;
optional .transit_realtime.Alert alert = 5;
extensions 1000 to 1999;
}
... etc
Then, if you take a look at the Position message, you see the fields
message Position {
required float latitude = 1;
required float longitude = 2;
optional float bearing = 3;
optional double odometer = 4;
optional float speed = 5;
extensions 1000 to 1999;
}
So you define the Position using those values, e.g.
RProtoBuf::new(transit_realtime.Position, latitude = 0, longitude = 0)
And the VehiclePosition message is
message VehiclePosition {
enum VehicleStopStatus {
INCOMING_AT = 0;
STOPPED_AT = 1;
IN_TRANSIT_TO = 2;
}
enum CongestionLevel {
UNKNOWN_CONGESTION_LEVEL = 0;
RUNNING_SMOOTHLY = 1;
STOP_AND_GO = 2;
CONGESTION = 3;
SEVERE_CONGESTION = 4;
}
enum OccupancyStatus {
EMPTY = 0;
MANY_SEATS_AVAILABLE = 1;
FEW_SEATS_AVAILABLE = 2;
STANDING_ROOM_ONLY = 3;
CRUSHED_STANDING_ROOM_ONLY = 4;
FULL = 5;
NOT_ACCEPTING_PASSENGERS = 6;
}
optional .transit_realtime.TripDescriptor trip = 1;
optional .transit_realtime.VehicleDescriptor vehicle = 8;
optional .transit_realtime.Position position = 2;
optional uint32 current_stop_sequence = 3;
optional string stop_id = 7;
optional .transit_realtime.VehiclePosition.VehicleStopStatus current_status = 4 [default = IN_TRANSIT_TO];
optional uint64 timestamp = 5;
optional .transit_realtime.VehiclePosition.CongestionLevel congestion_level = 6;
optional .transit_realtime.VehiclePosition.OccupancyStatus occupancy_status = 9;
extensions 1000 to 1999;
}
So the message will be like
RProtoBuf::new(transit_realtime.VehiclePosition,
current_status = 1,
congestion_level = 0,
stop_id = "7",
current_stop_sequence = 1)

Related

netcdf file, delete first 1 and last 2 rows of lat and lon

I have a netcdf input file of following header:
`netcdf file:/Volumes/NSF12KP3CTL_CLM45_surface.nc {
dimensions:
jx = 180;
iy = 165;
kz = 19;
nmon = 12;
lsmpft = 17;
nlevsoi = 10;
gridcell = 12194;
numurbl = 3;
nlevurb = 5;
numrad = 2;`
And I have another output file that has header:
`dimensions:
gridcell = 12194 ;
landunit = 24398 ;
column = 36632 ;
pft = 207348 ;
jx = 177 ;
iy = 162 ;
levgrnd = 15 ;
levurb = 5 ;
levlak = 10 ;
numrad = 2 ;
string_length = 8 ;
levdcmp = 1 ;
hist_interval = 2 ;
time = UNLIMITED ; // (30 currently)`
All I want is to cut the first 1 and last 2 rows of both jx and iy from input file so that I can merge it into the output file to convert together into 2d lat-lon grid.
Thank you,
Y
I tried with cdo, nco. I have a model executable to convert it into 2d.

C5.0 package: Error in paste(apply(x, 1, paste, collapse = ","), collapse = "\n") : result would exceed 2^31-1 bytes

When trying to train a model with a dataset of around 3 million rows and 600 columns using the C5.0 CRAN package I get the following error:
Error in paste(apply(x, 1, paste, collapse = ","), collapse = "\n") : result would exceed 2^31-1 bytes
From what the owner of the repository answered to a similar issue, it is due to an R limitation in the number of bytes in a character string, which is limited to 2^31 - 1.
Long answer ahead:
So, as stated in the question, the error occurs in the last line of the makeDataFile function from the Cubist package, used in C5.0, which concatenates all rows into one string. As this string is needed to pass the data to the C5.0 function in C, but is not needed to make any operations in R, and C has no memory limitation aside from those of the machine itself, the approach I have taken is to create such string in C instead. In order to do this, the R code will pass the information in a character vector containing various strings that don’t surpass the length limit, instead of one, so that once in C these elements can be concatenated.
However, instead of leaving all rows as separate elements in the character vector to be concatenated in C using strcat in a loop, I have found that the strcat function is quite slow, so I have chosen to create another R function (create_max_len_strings) in order to concatenate the rows into the longest (~or close~) strings possible without reaching the memory limit so that strcat only needs to be applied a few times to concatenate these longer strings.
So, the last line of the original makeDataFile() function will be replaced so that each row is left separately as an element of a character vector, only adding a line break at the end of each string row so that when concatenating some of these elements into longer strings, using create_max_len_strings(), they will be differentiated:
makeDataFile.R:
create_max_len_strings <- function(original_vector) {
vector_length = length(original_vector)
nchars = sum(nchar(original_vector, type = "chars"))
## Check if the length of the string would reach 1900000000, which is close to the memory limitation
if(nchars >= 1900000000){
## Calculate how many strings we could create of the maximum length
nchunks = 0
while(nchars > 0){
nchars = nchars - 1900000000
nchunks = nchunks + 1
}
## Get the number of rows that would be contained in each string
chunk_size = vector_length/nchunks
## Get the rounded number of rows in each string
chunk_size = floor(chunk_size)
index = chunk_size
## Create a vector with the indexes of the rows that delimit each string
indexes_vector = c()
indexes_vector = append(indexes_vector, 0)
n = nchunks
while(n > 0){
indexes_vector = append(indexes_vector, index)
index = index + chunk_size
n = n - 1
}
## Get the last few rows if the division had remainder
remainder = vector_length %% nchunks
if (remainder != 0){
indexes_vector = append(indexes_vector, vector_length)
nchunks = nchunks + 1
}
## Create the strings pasting together the rows from the indexes in the indexes vector
strings_vector = c()
i = 2
while (i <= length(indexes_vector)){
## Sum 1 to the index_init so that the next string does not contain the last row of the previous string
index_init = indexes_vector[i-1] + 1
index_end = indexes_vector[i]
## Paste the rows from the vector from index_init to index_end
string <- paste0(original_vector[index_init:index_end], collapse="")
## Create vector containing the strings that were created
strings_vector <- append(strings_vector, string)
i = i + 1
}
}else {
strings_vector = paste0(original_vector, collapse="")
}
strings_vector
}
makeDataFile <- function(x, y, w = NULL) {
## Previous code stays the same
...
x = apply(x, 1, paste, collapse = ",")
x = paste(x, "\n", sep="")
char_vec = create_max_len_strings(x)
}
CALLING C5.0
Now, in order to create the final string to pass to the c50() function in C, an intermediate function is created and called instead. In order to do this, the .C() statement that calls c50() in R is replaced with a .Call() statement calling this function, as .Call() allows for complex objects such as vectors to be passed to C. Also, it allows for the result to be returned in the variable result instead of having to pass back the variables tree, rules and output by reference. The result of calling C5.0 will be received in the character vector result containing the strings corresponding to the tree, rules and output in the first three positions:
C5.0.R:
C5.0.default <- function(x,
y,
trials = 1,
rules = FALSE,
weights = NULL,
control = C5.0Control(),
costs = NULL,
...) {
## Previous code stays the same
...
dataString <- makeDataFile(x, y, weights)
num_chars = sum(nchar(dataString, type = "chars"))
result <- .Call(
"call_C50",
as.character(namesString),
dataString,
as.character(num_chars), ## The length of the resulting string is passed as character because it is too long for an integer
as.character(costString),
as.logical(control$subset),
# -s "use the Subset option" var name: SUBSET
as.logical(rules),
# -r "use the Ruleset option" var name: RULES
## for the bands option, I'm not sure what the default should be.
as.integer(control$bands),
# -u "sort rules by their utility into bands" var name: UTILITY
## The documentation has two options for boosting:
## -b use the Boosting option with 10 trials
## -t trials ditto with specified number of trial
## I think we should use -t
as.integer(trials),
# -t : " ditto with specified number of trial", var name: TRIALS
as.logical(control$winnow),
# -w "winnow attributes before constructing a classifier" var name: WINNOW
as.double(control$sample),
# -S : use a sample of x% for training
# and a disjoint sample for testing var name: SAMPLE
as.integer(control$seed),
# -I : set the sampling seed value
as.integer(control$noGlobalPruning),
# -g: "turn off the global tree pruning stage" var name: GLOBAL
as.double(control$CF),
# -c: "set the Pruning CF value" var name: CF
## Also, for the number of minimum cases, I'm not sure what the
## default should be. The code looks like it dynamically sets the
## value (as opposed to a static, universal integer
as.integer(control$minCases),
# -m : "set the Minimum cases" var name: MINITEMS
as.logical(control$fuzzyThreshold),
# -p "use the Fuzzy thresholds option" var name: PROBTHRESH
as.logical(control$earlyStopping)
)
## Get the first three positions of the character vector that contain the tree, rules and output returned by C5.0 in C
result_tree = result[1]
result_rules = result[2]
result_output = result[3]
modelContent <- strsplit(
if (rules)
result_rules
else
result_tree, "\n"
)[[1]]
entries <- grep("^entries", modelContent, value = TRUE)
if (length(entries) > 0) {
actual <- as.numeric(substring(entries, 10, nchar(entries) - 1))
} else
actual <- trials
if (trials > 1) {
boostResults <- getBoostResults(result_output)
## This next line is here to avoid a false positive warning in R
## CMD check:
## * checking R code for possible problems ... NOTE
## C5.0.default: no visible binding for global variable 'Data'
Data <- NULL
size <-
if (!is.null(boostResults))
subset(boostResults, Data == "Training Set")$Size
else
NA
} else {
boostResults <- NULL
size <- length(grep("[0-9])$", strsplit(result_output, "\n")[[1]]))
}
out <- list(
names = namesString,
cost = costString,
costMatrix = costs,
caseWeights = !is.null(weights),
control = control,
trials = c(Requested = trials, Actual = actual),
rbm = rules,
boostResults = boostResults,
size = size,
dims = dim(x),
call = funcCall,
levels = levels(y),
output = result_output,
tree = result_tree,
predictors = colnames(x),
rules = result_rules
)
class(out) <- "C5.0"
out
}
Now onto the C code, the function call_c50() basically acts as an intermediate between the R code and the C code, concatenating the elements in the dataString array to obtain the string needed by the C function c50(), by accessing each position of the array using CHAR(STRING_ELT(x, i)) and concatenating (strcat) them together. Then the rest of the variables are casted to their respective types and the c50() function in file top.c (where this function should also be placed) is called. The result of calling c50() will be returned to the R routine by creating a character vector and placing the strings corresponding to the tree, rules and output in each position.
Lastly, the c50() function is basically left as is, except for the variables treev, rulesv and outputv, as these are the values that are going to be returned by .Call() instead of being passed by reference, they no longer need to be in the arguments of the function. As they are all strings they can be returned in a single array, by setting each string to a position in the array c50_return.
top.c:
SEXP call_C50(SEXP namesString, SEXP data_vec, SEXP datavec_len, SEXP costString, SEXP subset, SEXP rules, SEXP bands, SEXP trials, SEXP winnow, SEXP sample,
SEXP seed, SEXP noGlobalPruning, SEXP CF, SEXP minCases, SEXP fuzzyThreshold, SEXP earlyStopping){
char* string;
char* concat;
long n = 0;
long size;
int i;
char* eptr;
// Get the length of the data vector
n = length(data_vec);
// Get the string indicating the length of the final string
char* size_str = malloc((strlen(CHAR(STRING_ELT(datavec_len, 0)))+1)*sizeof(char));
strcpy(size_str, CHAR(STRING_ELT(datavec_len, 0)));
// Turn the string to long
size = strtol(size_str, &eptr, 10);
// Allocate memory for the number of characters indicated by datavec_len
string = malloc((size+1)*sizeof(char));
// Copy the first element of data_vec into the string variable
strcpy(string, CHAR(STRING_ELT(data_vec, 0)));
// Loop over the data vector until all elements are concatenated in the string variable
for (i = 1; i < n; i++) {
strcat(string, CHAR(STRING_ELT(data_vec, i)));
}
// Copy the value of namesString into a char*
char* namesv = malloc((strlen(CHAR(STRING_ELT(namesString, 0)))+1)*sizeof(char));
strcpy(namesv, CHAR(STRING_ELT(namesString, 0)));
// Copy the value of costString into a char*
char* costv = malloc((strlen(CHAR(STRING_ELT(costString, 0)))+1)*sizeof(char));
strcpy(costv, CHAR(STRING_ELT(costString, 0)));
// Call c50() function casting the rest of arguments into their respective C types
char** c50_return = c50(namesv, string, costv, asLogical(subset), asLogical(rules), asInteger(bands), asInteger(trials), asLogical(winnow), asReal(sample), asInteger(seed), asInteger(noGlobalPruning), asReal(CF), asInteger(minCases), asLogical(fuzzyThreshold), asLogical(earlyStopping));
free(string);
free(namesv);
free(costv);
// Create a character vector to be returned to the C5.0 R function
SEXP out = PROTECT(allocVector(STRSXP, 3));
SET_STRING_ELT(out, 0, mkChar(c50_return[0]));
SET_STRING_ELT(out, 1, mkChar(c50_return[1]));
SET_STRING_ELT(out, 2, mkChar(c50_return[2]));
UNPROTECT(1);
return out;
}
static char** c50(char *namesv, char *datav, char *costv, int subset,
int rules, int utility, int trials, int winnow,
double sample, int seed, int noGlobalPruning, double CF,
int minCases, int fuzzyThreshold, int earlyStopping) {
int val; /* Used by setjmp/longjmp for implementing rbm_exit */
char ** c50_return = malloc(3 * sizeof(char*));
// Initialize the globals to the values that the c50
// program would have at the start of execution
initglobals();
// Set globals based on the arguments. This is analogous
// to parsing the command line in the c50 program.
setglobals(subset, rules, utility, trials, winnow, sample, seed,
noGlobalPruning, CF, minCases, fuzzyThreshold, earlyStopping,
costv);
// Handles the strbufv data structure
rbm_removeall();
// Deallocates memory allocated by NewCase.
// Not necessary since it's also called at the end of this function,
// but it doesn't hurt, and I'm feeling paranoid.
FreeCases();
// XXX Should this be controlled via an option?
// Rprintf("Calling setOf\n");
setOf();
// Create a strbuf using *namesv as the buffer.
// Note that this is a readonly strbuf since we can't
// extend *namesv.
STRBUF *sb_names = strbuf_create_full(namesv, strlen(namesv))
// Register this strbuf using the name "undefined.names"
if (rbm_register(sb_names, "undefined.names", 0) < 0) {
error("undefined.names already exists");
}
// Create a strbuf using *datav and register it as "undefined.data"
STRBUF *sb_datav = strbuf_create_full(datav, strlen(datav));
// XXX why is sb_datav copied? was that part of my debugging?
// XXX or is this the cause of the leak?
if (rbm_register(strbuf_copy(sb_datav), "undefined.data", 0) < 0) {
error("undefined data already exists");
}
// Create a strbuf using *costv and register it as "undefined.costs"
if (strlen(costv) > 0) {
// Rprintf("registering cost matrix: %s", *costv);
STRBUF *sb_costv = strbuf_create_full(costv, strlen(costv));
// XXX should sb_costv be copied?
if (rbm_register(sb_costv, "undefined.costs", 0) < 0) {
error("undefined.cost already exists");
}
} else {
// Rprintf("no cost matrix to register\n");
}
/*
* We need to initialize rbm_buf before calling any code that
* might call exit/rbm_exit.
*/
if ((val = setjmp(rbm_buf)) == 0) {
// Real work is done here
c50main();
if (rules == 0) {
// Get the contents of the the tree file
STRBUF *treebuf = rbm_lookup("undefined.tree");
if (treebuf != NULL) {
char *treeString = strbuf_getall(treebuf);
c50_return[0] = R_alloc(strlen(treeString) + 1, 1);
strcpy(c50_return[0], treeString);
c50_return[1] = "";
} else {
// XXX Should *treev be assigned something in this case?
// XXX Throw an error?
}
} else {
// Get the contents of the the rules file
STRBUF *rulesbuf = rbm_lookup("undefined.rules");
if (rulesbuf != NULL) {
char *rulesString = strbuf_getall(rulesbuf);
c50_return[1] = R_alloc(strlen(rulesString) + 1, 1);
strcpy(c50_return[1], rulesString);
c50_return[0] = "";
} else {
// XXX Should *rulesv be assigned something in this case?
// XXX Throw an error?
}
}
} else {
Rprintf("c50 code called exit with value %d\n", val - JMP_OFFSET);
}
// Close file object "Of", and return its contents via argument outputv
char *outputString = closeOf();
c50_return[2] = R_alloc(strlen(outputString) + 1, 1);
strcpy(c50_return[2], outputString);
// Deallocates memory allocated by NewCase
FreeCases();
// We reinitialize the globals on exit out of general paranoia
initglobals();
return c50_return;
}
***IMPORTANT: if the string created is longer than 2147483647, you also will need to change the definition of the variables i and j in the function strbuf_gets() in strbuf.c. This function basically iterates through each position of the string, so trying to increase their value above the INT limit to access those positions in the array will cause a segmentation fault. I suggest changing the declaration type to long in order to avoid this issue.
C5.0 PREDICTIONS
However, as the makeDataFile function is not only used to create the model but also to pass the data to the predictions() function, this function will also have to be modified. Just like previously, the .C() statement in predict.C5.0() used to call predictions() will be replaced with a .Call() statement in order to be able to pass the character vector to C, and the result will be returned in the result variable instead of being passed by reference:
predict.C5.0.R:
predict.C5.0 <- function (object,
newdata = NULL,
trials = object$trials["Actual"],
type = "class",
na.action = na.pass,
...) {
## Previous code stays the same
...
caseString <- makeDataFile(x = newdata, y = NULL)
num_chars = sum(nchar(caseString, type = "chars"))
## When passing trials to the C code, convert to
## zero if the original version of trials is used
if (trials <= 0)
stop("'trials should be a positive integer", call. = FALSE)
if (trials == object$trials["Actual"])
trials <- 0
## Add trials (not object$trials) as an argument
results <- .Call(
"call_predictions",
caseString,
as.character(num_chars),
as.character(object$names),
as.character(object$tree),
as.character(object$rules),
as.character(object$cost),
pred = integer(nrow(newdata)),
confidence = double(length(object$levels) * nrow(newdata)),
trials = as.integer(trials)
)
predictions = as.numeric(unlist(results[1]))
confidence = as.numeric(unlist(results[2]))
output = as.character(results[3])
if(any(grepl("Error limit exceeded", output)))
stop(output, call. = FALSE)
if (type == "class") {
out <- factor(object$levels[predictions], levels = object$levels)
} else {
out <-
matrix(confidence,
ncol = length(object$levels),
byrow = TRUE)
if (!is.null(rownames(newdata)))
rownames(out) <- rownames(newdata)
colnames(out) <- object$levels
}
out
}
In the file top.c, the predictions() function will be modified to receive the variables passed by the .Call() statement, so that just like previously, the caseString array will be concatenated into a single string and the rest of the variables casted to their respective types. In this case the variables pred and confidence will be also received as vectors of integer and double types and so they will need to be casted to int* and double*. The rest of the function is left as it was in order to create the predictions and the resulting variables predv, confidencev and output variables will be placed in the first three positions of a vector respectively.
top.c:
SEXP call_predictions(SEXP caseString, SEXP case_len, SEXP names, SEXP tree, SEXP rules, SEXP cost, SEXP pred, SEXP confidence, SEXP trials){
char* casev;
char* outputv = "";
char* eptr;
char* size_str = malloc((strlen(CHAR(STRING_ELT(case_len, 0)))+1)*sizeof(char));
strcpy(size_str, CHAR(STRING_ELT(case_len, 0)));
long size = strtol(size_str, &eptr, 10);
casev = malloc((size+1)*sizeof(char));
strcpy(casev, CHAR(STRING_ELT(caseString, 0)));
int n = length(caseString);
for (int i = 1; i < n; i++) {
strcat(casev, CHAR(STRING_ELT(caseString, i)));
}
char* namesv = malloc((strlen(CHAR(STRING_ELT(names, 0)))+1)*sizeof(char));
strcpy(namesv, CHAR(STRING_ELT(names, 0)));
char* treev = malloc((strlen(CHAR(STRING_ELT(tree, 0)))+1)*sizeof(char));
strcpy(treev, CHAR(STRING_ELT(tree, 0)));
char* rulesv = malloc((strlen(CHAR(STRING_ELT(rules, 0)))+1)*sizeof(char));
strcpy(rulesv, CHAR(STRING_ELT(rules, 0)));
char* costv = malloc((strlen(CHAR(STRING_ELT(cost, 0)))+1)*sizeof(char));
strcpy(costv, CHAR(STRING_ELT(cost, 0)));
int variable;
int* predv = &variable;
int npred = length(pred);
predv = malloc((npred+1)*sizeof(int));
for (int i = 0; i < npred; i++) {
predv[i] = INTEGER(pred)[i];
}
double variable1;
double* confidencev = &variable1;
int nconf = length(confidence);
confidencev = malloc((nconf+1)*sizeof(double));
for (int i = 0; i < nconf; i++) {
confidencev[i] = REAL(confidence)[i];
}
int* trialsv = &variable;
*trialsv = asInteger(trials);
/* Original code for predictions starts */
int val;
// Announce ourselves for testing
// Rprintf("predictions called\n");
// Initialize the globals
initglobals();
// Handles the strbufv data structure
rbm_removeall();
// XXX Should this be controlled via an option?
// Rprintf("Calling setOf\n");
setOf();
STRBUF *sb_cases = strbuf_create_full(casev, strlen(casev));
if (rbm_register(sb_cases, "undefined.cases", 0) < 0) {
error("undefined.cases already exists");
}
STRBUF *sb_names = strbuf_create_full(namesv, strlen(namesv));
if (rbm_register(sb_names, "undefined.names", 0) < 0) {
error("undefined.names already exists");
}
if (strlen(treev)) {
STRBUF *sb_treev = strbuf_create_full(treev, strlen(treev));
if (rbm_register(sb_treev, "undefined.tree", 0) < 0) {
error("undefined.tree already exists");
}
} else if (strlen(rulesv)) {
STRBUF *sb_rulesv = strbuf_create_full(rulesv, strlen(rulesv));
if (rbm_register(sb_rulesv, "undefined.rules", 0) < 0) {
error("undefined.rules already exists");
}
setrules(1);
} else {
error("either a tree or rules must be provided");
}
// Create a strbuf using *costv and register it as "undefined.costs"
if (strlen(costv) > 0) {
// Rprintf("registering cost matrix: %s", *costv);
STRBUF *sb_costv = strbuf_create_full(costv, strlen(costv));
// XXX should sb_costv be copied?
if (rbm_register(sb_costv, "undefined.costs", 0) < 0) {
error("undefined.cost already exists");
}
} else {
// Rprintf("no cost matrix to register\n");
}
if ((val = setjmp(rbm_buf)) == 0) {
// Real work is done here
// Rprintf("\n\nCalling rpredictmain\n");
rpredictmain(trialsv, predv, confidencev);
// Rprintf("predict finished\n\n");
} else {
// Rprintf("predict code called exit with value %d\n\n", val - JMP_OFFSET);
}
// Close file object "Of", and return its contents via argument outputv
char *outputString = closeOf();
char *output = R_alloc(strlen(outputString) + 1, 1);
strcpy(output, outputString);
// We reinitialize the globals on exit out of general paranoia
initglobals();
/* Original code for predictions ends */
free(namesv);
free(treev);
free(rulesv);
free(costv);
SEXP predx = PROTECT(allocVector(INTSXP, npred));
for (int i = 0; i < npred; i++) {
INTEGER(predx)[i] = predv[i];
}
SEXP confidencex = PROTECT(allocVector(REALSXP, nconf));
for (int i = 0; i < npred; i++) {
REAL(confidencex)[i] = confidencev[i];
}
SEXP outputx = PROTECT(allocVector(STRSXP, 1));
SET_STRING_ELT(outputx, 0, mkChar(output));
SEXP vector = PROTECT(allocVector(VECSXP, 3));
SET_VECTOR_ELT(vector, 0, predx);
SET_VECTOR_ELT(vector, 1, confidencex);
SET_VECTOR_ELT(vector, 2, outputx);
UNPROTECT(4);
free(predv);
free(confidencev);
return vector;
}

KsProperty () returns"The data area passed to a system call is too small" ERROR_INSUFFICIENT_BUFFER while setting camera Zoom value

HRESULT hr = S_OK;
KSPROPERTY ksprop;
ZeroMemory(&ksprop, sizeof(ksprop));
PVOID pData = NULL;
ULONG valueSize = 0;
ULONG dataLength = 0;
KSPROPERTY_CAMERACONTROL_S cameraControl;
ZeroMemory(&cameraControl, sizeof(cameraControl));
ksprop.Set = PROPSETID_VIDCAP_CAMERACONTROL;
ksprop.Id = KSPROPERTY_CAMERACONTROL_ZOOM;
ksprop.Flags = KSPROPERTY_TYPE_SET;
cameraControl.Property = ksprop;
cameraControl.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
cameraControl.Capabilities = KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
cameraControl.Value = 50;
pData = &cameraControl;
dataLength = sizeof(cameraControl);
hr = m_pKsControl->KsProperty(
&ksprop, sizeof(ksprop),
pData, dataLength, &valueSize);
here hr "The data area passed to a system call is too small. "
I am compiling on vs 2010 on windows 7 machine.
You are likely to provide a buffer which is too small in fourth parameter.
It's easy to check this out, see IKsControl::KsProperty docs:
To determine the buffer size that is required for a specific property
request, you can call this method with PropertyData set to NULL and
DataLength equal to zero. The method returns
HRESULT_FROM_WIN32(ERROR_MORE_DATA), and BytesReturned contains the
size of the required buffer.
In this KsProperty use case, you should pass KSPROPERTY_CAMERACONTROL_S structure variable to make this work.
For example
KSPROPERTY_CAMERACONTROL_S kspIn = { 0 };
KSPROPERTY_CAMERACONTROL_S kspOut = { 0 };
ULONG valueSize = 0;
kspIn.Property.Set = PROPSETID_VIDCAP_CAMERACONTROL;
kspIn.Property.Id = KSPROPERTY_CAMERACONTROL_ZOOM;
kspIn.Property.Flags = KSPROPERTY_TYPE_SET;
kspOut.Property.Set = PROPSETID_VIDCAP_CAMERACONTROL;
kspOut.Property.Id = KSPROPERTY_CAMERACONTROL_ZOOM;
kspOut.Property.Flags = KSPROPERTY_TYPE_SET;
kspOut.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
kspOut.Capabilities = KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
kspOut.Value = 50;
hr = m_pKsControl->KsProperty(
(PKSPROPERTY)&kspIn, sizeof(kspIn),
&kspOut, sizeof(kspOut), &valueSize);
Should work

Converting ISO 6709 Formatted GPS Coordinates to Decimal Degrees in R

We have a piece of equipment that outputs its GPS coordinates as numeric values to file in an ISO 6709 lat/lon format of Lat = ±DDMM.MMMM & Lon = ±DDDMM.MMMM
Are there any packages with functions (or custom functions) in R that will convert this to a Decimal degrees format? (ie: ±DD.DDDDDD & ±DDD.DDDDDD)
An example would be that lat & lon (2433.056, -8148.443) would be converted to (24.55094, -81.80739).
You could read in the values from the file using something like read.csv or read.delim.
Then to convert from DDMM.MMMM and DDDMM.MMMM you could use something like this (of course modify as needed for the form of your input/outputs):
convertISO6709 <- function( lat, lon ) {
# will just do lat and lon together, as the process is the same for both
# It's simpler to do the arithmetic on positive numbers, we'll add the signs
# back in at the end.
latlon <- c(lat,lon)
sgns <- sign(latlon)
latlon <- abs(latlon)
# grab the MM.MMMM bit, which is always <100. '%%' is modular arithmetic.
mm <- latlon %% 100
# grab the DD bit. Divide by 100 because of the MM.MMMM bit.
dd <- (latlon - mm)/100
# convert to decimal degrees, don't forget to add the signs back!
out_latlon <- (dd+mm/60) * sgns
return(out_latlon)
}
This may not be the most elegant PHP code, but it does work:
function convertISO6709($coord)
{
$abs_coord = abs($coord);
$sign = ($abs_coord == $coord) ? 1 : -1;
$m = 2;
$dlen = 2;
$s = 0;
$seconds = 0;
switch (strlen($abs_coord)) {
case 4 :
break;
case 5 :
$dlen = 3;
$m = 3;
break;
case 6 :
$s = 4;
break;
}
$degrees = substr($abs_coord, 0, $dlen);
$minutes = substr($abs_coord, $m, 2);
if ($s != 0) {
$seconds = substr($abs_coord, $s, 2);
}
return ($degrees + ($minutes / 60) + ($seconds / 3600)) * $sign;
}
I has a similar issue getting coordinates from FedEx WS. I used this function to get the values from a string like +19.467945-99.14357/:
function convertCoordISO6709($coord)
{
//$coord example
//$coord = +19.467945-99.14357/
$returnArray[0] = 1;//result non 0 means error
$returnArray[1] = 0;//Lat
$returnArray[2] = 0;//long
$coord = trim($coord,"/"); //Strip / sign
//look for + - sign
$lat_sign = substr($coord,0,1); //strip and save the first sign (latitude value)
$sub_coord = substr($coord,1,strlen($coord));
if(count(explode("+",$sub_coord)) == 2) //Second value is + for the longitude
{
$coords=explode("+",$sub_coord);
$returnArray[0] = 0;
$returnArray[1] = $lat_sign.$coords[0];
$returnArray[2] = "+".$coords[1];
}
else //Second value is - for the longitude
{
$coords=explode("-",$sub_coord);
$returnArray[0] = 0;
$returnArray[1] = $lat_sign.$coords[0];
$returnArray[2] = "-".$coords[1];
}
return $returnArray;
}

Converting a decimal to a mixed-radix (base) number

How do you convert a decimal number to mixed radix notation?
I guess that given an input of an array of each of the bases, and the decimal number, it should output an array of the values of each column.
Pseudocode:
bases = [24, 60, 60]
input = 86462 #One day, 1 minute, 2 seconds
output = []
for base in reverse(bases)
output.prepend(input mod base)
input = input div base #div is integer division (round down)
Number -> set:
factors = [52,7,24,60,60,1000]
value = 662321
for i in n-1..0
res[i] = value mod factors[i]
value = value div factors[i]
And the reverse:
If you have the number like 32(52), 5(7), 7(24), 45(60), 15(60), 500(1000) and you want this converted to decimal:
Take number n, multiply it with the factor of n-1, continue for n-1..n=0
values = [32,5,7,45,15,500]
factors = [52,7,24,60,60,1000]
res = 0;
for i in 0..n-1
res = res * factors[i] + values[i]
And you have the number.
In Java you could do
public static int[] Number2MixedRadix(int[] base, int number) throws Exception {
//NB if the max number you want # a position is say 3 then the base# tha position
//in your base array should be 4 not 3
int[] RadixFigures = new int[base.length];
int[] PositionPowers = new int[base.length];
PositionPowers[base.length-1] = 1;
for (int k = base.length-2,pow = 1; k >-1; k--){
pow*=base[k+1];
PositionPowers[k]=pow;
}for (int k = 0; k<base.length; k++){
RadixFigures[k]=number/PositionPowers[k];
if(RadixFigures[k]>base[k])throw new Exception("RadixFigure#["+k+"] => ("+RadixFigures[k]+") is > base#["+k+"] => ("+base[k]+") | ( number is Illegal )");
number=number%PositionPowers[k];
}return RadixFigures;
}
Example
//e.g. mixed-radix base for 1day
int[] base = new int[]{1, 24, 60, 60};//max-day,max-hours,max-minutes,max-seconds
int[] MixedRadix = Number2MixedRadix(base, 19263);//19263 seconds
//this would give [0,5,21,3] => as per 0days 5hrs 21mins 3secs
Reversal
public static int MixedRadix2Number(int[] RadixFigures,int[] base) throws Exception {
if(RadixFigures.length!=base.length)throw new Exception("RadixFigures.length must be = base.length");
int number=0;
int[] PositionPowers = new int[base.length];
PositionPowers[base.length-1] = 1;
for (int k = base.length-2,pow = 1; k >-1; k--){
pow*=base[k+1];
PositionPowers[k]=pow;
}for (int k = 0; k<base.length; k++){
number+=(RadixFigures[k]*PositionPowers[k]);
if(RadixFigures[k]>base[k])throw new Exception("RadixFigure#["+k+"] => ("+RadixFigures[k]+") is > base#["+k+"] => ("+base[k]+") | ( number is Illegal )");
}return number;
}
I came up with a slightly different, and probably not as good method as the other ones here, but I thought I'd share anyway:
var theNumber = 313732097;
// ms s m h d
var bases = [1000, 60, 60, 24, 365];
var placeValues = []; // initialise an array
var currPlaceValue = 1;
for (var i = 0, l = bases.length; i < l; ++i) {
placeValues.push(currPlaceValue);
currPlaceValue *= bases[i];
}
console.log(placeValues);
// this isn't relevant for this specific problem, but might
// be useful in related problems.
var maxNumber = currPlaceValue - 1;
var output = new Array(placeValues.length);
for (var v = placeValues.length - 1; v >= 0; --v) {
output[v] = Math.floor(theNumber / placeValues[v]);
theNumber %= placeValues[v];
}
console.log(output);
// [97, 52, 8, 15, 3] --> 3 days, 15 hours, 8 minutes, 52 seconds, 97 milliseconds
I tried a few of the examples before and found an edge case they didn't cover, if you max out your scale you need to prepend the result from the last step
def intToMix(number,radix=[10]):
mixNum=[]
radix.reverse()
for i in range(0,len(radix)):
mixNum.append(number%radix[i])
number//=radix[i]
mixNum.append(number)
mixNum.reverse()
radix.reverse()
return mixNum
num=60*60*24*7
radix=[7,24,60,60]
tmp1=intToMix(num,radix)

Resources