Absolute wall positions in IFC - c++

Because I want to associate windows with walls, I am trying to find the endpoints of a wall using IFCOpenShell.
#include <ifcgeom/IfcGeom.h>
#include <ifcparse/IfcFile.h>
using namespace Ifc2x3;
using namespace IfcSchema;
using namespace IfcParse;
using namespace IfcUtil;
using namespace IfcGeom;
std::string tostr(gp_XYZ a) {
std::stringstream ss;
ss << a.X() << "," << a.Y() << "," << a.Z();
return ss.str();
}
int main(int argc, char** argv) {
IfcFile file;
if (!file.Init(argc > 1 ? argv[1] : "windows connected to walls Archicad.ifc")) abort();
Kernel k;
gp_Pnt start;
gp_Pnt end;
auto list = file.entitiesByType<IfcWall>();
for ( auto it = list->begin(); it != list->end(); ++it) {
auto w1 = *it;
std::cout << "wall " << w1->entity->id() << std::endl;
bool suc = k.find_wall_end_points(w1, start, end);
std::cout << suc << std::endl;
std::cout << tostr(start.XYZ()) << std::endl;
std::cout << tostr(end.XYZ()) << std::endl;
}
}
This currently yields 10.1596,0,0 and 9.08038,0,0 as endpoints for two walls, and 0 as the starting point for both. This means they are parallel. But when I open the IFC file in Archicad, they are orthogonal. There is even an IFC tag in the file specifying that one wall connects to the other ATSTART/ATEND. How can I derive the correct coordinates?
Compilation command line: g++ -I/usr/include/oce wallpoints.cpp -l IfcGeom -l IfcParse $(for i in $(cd /usr/lib/x86_64-linux-gnu/; ls libTK*.so | cut -d. -f1 | cut -c4-); do echo "-l $i"; done) $(icu-config --ldflags) -ggdb3
IFC file: https://hushfile.it/592c22c69af2a#AwrpRI2O3ecDuAmP_pIjNmCAV3BWvwr30tfrazqJ

As stated in the standard, the placement is relative, so I have to multiply this with a couple of matrices.

Related

Trouble when using Efficient_Ransac in CGAL

I want to use the Efficient Ransac implementation of CGAL, but whenever I try to set my own parameters, the algorithm doesn't detect any shape anymore.
This work is related to the Polyfit implementation in CGAL. I want to fine tune the plane detection to see the influence it has on the algorithm. When I use the standard call to ransac.detect(), it works perfectly. However, when I want to set my own parameters it just doesn't find any plane, even if I set them manually to the default values.
Here is my code, strongly related to this example
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/IO/read_xyz_points.h>
#include <CGAL/IO/Writer_OFF.h>
#include <CGAL/property_map.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Shape_detection/Efficient_RANSAC.h>
#include <CGAL/Polygonal_surface_reconstruction.h>
#ifdef CGAL_USE_SCIP
#include <CGAL/SCIP_mixed_integer_program_traits.h>
typedef CGAL::SCIP_mixed_integer_program_traits<double> MIP_Solver;
#elif defined(CGAL_USE_GLPK)
#include <CGAL/GLPK_mixed_integer_program_traits.h>
typedef CGAL::GLPK_mixed_integer_program_traits<double> MIP_Solver;
#endif
#if defined(CGAL_USE_GLPK) || defined(CGAL_USE_SCIP)
#include <CGAL/Timer.h>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
// Point with normal, and plane index
typedef boost::tuple<Point, Vector, int> PNI;
typedef std::vector<PNI> Point_vector;
typedef CGAL::Nth_of_tuple_property_map<0, PNI> Point_map;
typedef CGAL::Nth_of_tuple_property_map<1, PNI> Normal_map;
typedef CGAL::Nth_of_tuple_property_map<2, PNI> Plane_index_map;
typedef CGAL::Shape_detection::Efficient_RANSAC_traits<Kernel, Point_vector, Point_map, Normal_map> Traits;
typedef CGAL::Shape_detection::Efficient_RANSAC<Traits> Efficient_ransac;
typedef CGAL::Shape_detection::Plane<Traits> Plane;
typedef CGAL::Shape_detection::Point_to_shape_index_map<Traits> Point_to_shape_index_map;
typedef CGAL::Polygonal_surface_reconstruction<Kernel> Polygonal_surface_reconstruction;
typedef CGAL::Surface_mesh<Point> Surface_mesh;
int main(int argc, char ** argv)
{
Point_vector points;
// Loads point set from a file.
const std::string &input_file = argv[1];
//const std::string input_file(input);
std::ifstream input_stream(input_file.c_str());
if (input_stream.fail()) {
std::cerr << "failed open file \'" <<input_file << "\'" << std::endl;
return EXIT_FAILURE;
}
std::cout << "Loading point cloud: " << input_file << "...";
CGAL::Timer t;
t.start();
if (!input_stream ||
!CGAL::read_xyz_points(input_stream,
std::back_inserter(points),
CGAL::parameters::point_map(Point_map()).normal_map(Normal_map())))
{
std::cerr << "Error: cannot read file " << input_file << std::endl;
return EXIT_FAILURE;
}
else
std::cout << " Done. " << points.size() << " points. Time: " << t.time() << " sec." << std::endl;
// Shape detection
Efficient_ransac ransac;
ransac.set_input(points);
ransac.add_shape_factory<Plane>();
std::cout << "Extracting planes...";
t.reset();
// Set parameters for shape detection.
Efficient_ransac::Parameters parameters;
// Set probability to miss the largest primitive at each iteration.
parameters.probability = 0.05;
// Detect shapes with at least 500 points.
parameters.min_points = 100;
// Set maximum Euclidean distance between a point and a shape.
parameters.epsilon = 0.01;
// Set maximum Euclidean distance between points to be clustered.
parameters.cluster_epsilon = 0.01;
// Set maximum normal deviation.
// 0.9 < dot(surface_normal, point_normal);
parameters.normal_threshold = 0.9;
// Detect shapes.
ransac.detect(parameters);
//ransac.detect();
Efficient_ransac::Plane_range planes = ransac.planes();
std::size_t num_planes = planes.size();
std::cout << " Done. " << num_planes << " planes extracted. Time: " << t.time() << " sec." << std::endl;
// Stores the plane index of each point as the third element of the tuple.
Point_to_shape_index_map shape_index_map(points, planes);
for (std::size_t i = 0; i < points.size(); ++i) {
// Uses the get function from the property map that accesses the 3rd element of the tuple.
int plane_index = get(shape_index_map, i);
points[i].get<2>() = plane_index;
}
//////////////////////////////////////////////////////////////////////////
std::cout << "Generating candidate faces...";
t.reset();
Polygonal_surface_reconstruction algo(
points,
Point_map(),
Normal_map(),
Plane_index_map()
);
std::cout << " Done. Time: " << t.time() << " sec." << std::endl;
//////////////////////////////////////////////////////////////////////////
Surface_mesh model;
std::cout << "Reconstructing...";
t.reset();
if (!algo.reconstruct<MIP_Solver>(model)) {
std::cerr << " Failed: " << algo.error_message() << std::endl;
return EXIT_FAILURE;
}
const std::string& output_file(input_file+"_result.off");
std::ofstream output_stream(output_file.c_str());
if (output_stream && CGAL::write_off(output_stream, model))
std::cout << " Done. Saved to " << output_file << ". Time: " << t.time() << " sec." << std::endl;
else {
std::cerr << " Failed saving file." << std::endl;
return EXIT_FAILURE;
}
//////////////////////////////////////////////////////////////////////////
// Also stores the candidate faces as a surface mesh to a file
Surface_mesh candidate_faces;
algo.output_candidate_faces(candidate_faces);
const std::string& candidate_faces_file(input_file+"_candidate_faces.off");
std::ofstream candidate_stream(candidate_faces_file.c_str());
if (candidate_stream && CGAL::write_off(candidate_stream, candidate_faces))
std::cout << "Candidate faces saved to " << candidate_faces_file << "." << std::endl;
return EXIT_SUCCESS;
}
#else
int main(int, char**)
{
std::cerr << "This test requires either GLPK or SCIP.\n";
return EXIT_SUCCESS;
}
#endif // defined(CGAL_USE_GLPK) || defined(CGAL_USE_SCIP)
When launched, I have the following message:
Loading point cloud: Scene1/test.xyz... Done. 169064 points. Time: 0.428 sec.
Extracting planes... Done. 0 planes extracted. Time: 8.328 sec.
Generating candidate faces... Done. Time: 0.028 sec.
Reconstructing... Failed: at least 4 planes required to reconstruct a closed surface mesh (only 1 provided)
While I have this when launching the code the ransac detection function without parameters:
Loading point cloud: Scene1/test.xyz... Done. 169064 points. Time: 0.448 sec.
Extracting planes... Done. 18 planes extracted. Time: 3.088 sec.
Generating candidate faces... Done. Time: 94.536 sec.
Reconstructing... Done. Saved to Scene1/test.xyz_result.off. Time: 30.28 sec.
Can someone help me setting my own parameters for the ransac shape detection?
However, when I want to set my own parameters it just doesn't find any
plane, even if I set them manually to the default values.
Just to be sure: "setting them manually to the default values" is not what you are doing in the code you shared.
Default values are documented as:
1% of the total number of points for min_points, which should be around 1700 points in your case, not 100
1% of the bounding box diagonal for epsilon and cluster_epsilon. For that obviously I don't know if that is what you used (0.01) as I don't have access to your point set, but if you want to reproduce default values, you should use the CGAL::Bbox_3 object at some point
If you use these values, there's no reason why it should behave differently than with no parameters given (if it does not work, then please let me know because there may be a bug).

Way containing NodeRefs with invalid location

I'm parsing the mayotte pbf with osmium, and my handler is looking for ways. When I find one I process its barycentre and print it. The issue I ran into is that all of the ways I process have invalid location. And if print the location I get undefined for both latitude and longitude.
Is there an issue with my PBF file, or with my understanding of the osmium library?
Here is a mcve:
/**
* To compile this script, you should first install `libosmium` and its
* dependencies. Then:
* g++ -std=c++11 -lz -lexpat -lbz2 mcve.cpp -o mcve
*/
#include <iostream>
#include <osmium/handler.hpp>
#include <osmium/io/any_input.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/visitor.hpp>
class ParkingAndCarpoolingAreasHandler : public osmium::handler::Handler {
public:
void way(const osmium::Way& way) {
double lng;
double lat;
double count = 0.0;
for (const osmium::NodeRef& nr : way.nodes()) {
if (!nr.location().valid()) {
std::cerr << "Way (id=" << way.id()
<< " version=" << way.version()
<< " timestamp=" << way.timestamp()
<< " visible=" << (way.visible() ? "true" : "false")
<< " changeset=" << way.changeset()
<< " uid=" << way.uid()
<< " user=" << way.user() << ")\n";
std::cerr << "NodeRef (ref=" << nr.ref() << " location=" << nr.location() << ")\n";
std::cerr << std::endl;
return;
}
count++;
lng += nr.location().lon();
lat += nr.location().lat();
}
lng /= count;
lat /= count;
std::cout << "POINT(" << lat << ' ' << lng << ")\n";
}
};
int main() {
auto otypes = osmium::osm_entity_bits::node | osmium::osm_entity_bits::way;
osmium::io::Reader reader{"tmp/mayotte-latest.osm.pbf", otypes};
ParkingAndCarpoolingAreasHandler handler;
osmium::apply(reader, handler);
reader.close();
}
In OSM a way typically stores only references to the node it consists of. These references just contain the node ID but no additional information (such as coordinates and tags). To obtain node coordinates you have to look at the actual nodes, not just at their reference.
See OSM XML and PBF Format for more information.
Since I have no experience with osmium I can't tell you how to retrieve the corresponding nodes by their IDs. However according to the Osmium Concepts Manual you can use a NodeLocationsForWays handler to populate your NodeRef objects with locations. examples/osmium_road_length.cpp contains an example.

C++ backward regex search

I need to build an ultra-efficient log parser (~1GB/s). I implemented Hyperscan library (https://www.hyperscan.io) from Intel, and it works well to:
count a number of occurence of specified events
give the end position of the matches
One of the limitation is that no capture groups can be reported, only end offsets. For most matches, I only use the count, but for 10% of them, the match must be parsed to compute further statistics.
The challenge is to efficiently run a regex to get the Hyperscan match, knowing only the end offset. Currently, I tried:
string data(const string * block) const {
std::regex nlexpr("\n(.*)\n$");
std::smatch match;
std::regex_search((*block).begin(), (*block).begin() + end, match, nlexpr);
return match[1];
}
block points to the file loaded in memory (2GB, so no copy possible).
end is the known offset matching the regex.
But it is extremely inefficient when the string to match is far in the block. I would have expected the "$" to make the operation very quick as the offset is given as end position, but it is definitely not. The operation take ~1s if end = 100000000.
It is possible to get the start of the matches from Hyperscan, however performance impact is very high (approximately divided per 2 after testing), so that is not an option.
Any idea how to achieve this ? I am using C++ 11 (so std implements the boost regex).
Best regards
Edit :
As the question came in the comments, I do not have any control over the regexs to be used.
I have not enough reputation to comment XD. I don't see the following as an answer, its more an alternative, nevertheless I have to make an answer, else I won't reach you.
I guess you won't find a trick to make performance independent of the position (guess its going linear for such simple regex or whatever).
A very simple solution is to replace this horrible regex lib with e.g. the posix regex.h (old but gold ;) or boost regex.
Here is an example:
#include <iostream>
#include <regex>
#include <regex.h>
#include <chrono>
#include <boost/regex.hpp>
inline auto now = std::chrono::steady_clock::now;
inline auto toMs = [](auto &&x){
return std::chrono::duration_cast<std::chrono::milliseconds>(x).count();
};
void cregex(std::string const&s, std::string const&p)
{
auto start = now();
regex_t r;
regcomp(&r,p.data(),REG_EXTENDED);
std::vector<regmatch_t> m(r.re_nsub+1);
regexec(&r,s.data(),m.size(),m.data(),0);
regfree(&r);
std::cout << toMs(now()-start) << "ms " << std::string{s.cbegin()+m[1].rm_so,s.cbegin()+m[1].rm_eo} << std::endl;
}
void cxxregex(std::string const&s, std::string const&p)
{
using namespace std;
auto start = now();
regex r(p.data(),regex::extended);
smatch m;
regex_search(s.begin(),s.end(),m,r);
std::cout << toMs(now()-start) << "ms " << m[1] << std::endl;
}
void boostregex(std::string const&s, std::string const&p)
{
using namespace boost;
auto start = now();
regex r(p.data(),regex::extended);
smatch m;
regex_search(s.begin(),s.end(),m,r);
std::cout << toMs(now()-start) << "ms " << m[1] << std::endl;
}
int main()
{
std::string s(100000000,'x');
std::string s1 = "yolo" + s;
std::string s2 = s + "yolo";
std::cout << "yolo + ... -> cregex "; cregex(s1,"^(yolo)");
std::cout << "yolo + ... -> cxxregex "; cxxregex(s1,"^(yolo)");
std::cout << "yolo + ... -> boostregex "; boostregex(s1,"^(yolo)");
std::cout << "... + yolo -> cregex "; cregex(s2,"(yolo)$");
std::cout << "... + yolo -> cxxregex "; cxxregex(s2,"(yolo)$");
std::cout << "... + yolo -> boostregex "; boostregex(s2,"(yolo)$");
}
Gives:
yolo + ... -> cregex 5ms yolo
yolo + ... -> cxxregex 0ms yolo
yolo + ... -> boostregex 0ms yolo
... + yolo -> cregex 69ms yolo
... + yolo -> cxxregex 2594ms yolo
... + yolo -> boostregex 62ms yolo
I just realized...
That my solutions proposed below does not work. Well, at least if there are multiple "yolo" in the text. It does not return the "first instance found in the string", but it returns the "first instance found in a substring of the string". So if you have 4 CPUs, the string is split into 4 substrings. The first to return "yolo" 'wins'. This might be OK if you only want to see if "yolo" is anywhere in the text, but not if you want to get the position of the first instance.
Old answer
Building on OZ's answer, I've written a parallel version. edit: now using semaphores to finish early.
#include <mutex>
#include <condition_variable>
std::mutex g_mtx;
std::condition_variable g_cv;
int g_found_at = -1;
void thread(
int id,
std::string::const_iterator begin,
std::string::const_iterator end,
const boost::regex& r,
boost::smatch* const m)
{
boost::smatch m_i;
if (regex_search(begin, end, m_i, r))
{
*m = m_i;
std::unique_lock<std::mutex> lk(g_mtx);
g_found_at = id;
lk.unlock();
g_cv.notify_one();
}
}
#include <thread>
#include <vector>
#include <memory>
#include <algorithm>
#include <chrono>
using namespace std::chrono_literals;
void boostparregex(std::string const &s, std::string const &p)
{
{
std::unique_lock<std::mutex> lk(g_mtx);
g_found_at = -1;
}
auto nrOfCpus = std::thread::hardware_concurrency() / 2;
std::cout << "(Nr of CPUs: " << nrOfCpus << ") ";
auto start = steady_clock::now();
boost::regex r(p.data(), boost::regex::extended);
std::vector<std::shared_ptr<boost::smatch>> m; m.reserve(nrOfCpus);
std::generate_n(std::back_inserter(m), nrOfCpus, []() { return std::make_shared<boost::smatch>(); });
std::vector<std::thread> t; t.reserve(nrOfCpus);
auto sizePerThread = s.length() / nrOfCpus;
for (size_t tId = 0; tId < nrOfCpus; tId++) {
auto begin = s.begin() + (tId * sizePerThread);
auto end = tId == nrOfCpus - 1 ? s.end() : s.begin() + ((tId + 1) * sizePerThread) - 1;
t.push_back(std::thread(thread, (int)tId, begin, end, r, m[tId].get()));
}
{
std::unique_lock<std::mutex> lk(g_mtx);
g_cv.wait_for(lk, 10s, []() { return g_found_at >= 0; });
}
{
std::unique_lock<std::mutex> lk(g_mtx);
if (g_found_at < 0) std::cout << "Not found! "; else std::cout << m[g_found_at]->str() << " ";
}
std::cout << toMs(steady_clock::now() - start) << "ms " << std::endl;
for (auto& thr : t) thr.join();
}
Which gives me this output (don't have posix under vs2017)
yolo + ... -> cxxregex 0ms yolo
yolo + ... -> boostregex 1ms yolo
yolo + ... -> boostparregex (Nr of CPUs: 4) yolo 13ms
... + yolo -> cxxregex 5014ms yolo
... + yolo -> boostregex 837ms yolo
... + yolo -> boostparregex (Nr of CPUs: 4) yolo 222ms
I get an up to 4 times speedup on 4 CPUs. There is some overhead for starting up the threads
p.s. this is my first C++ thread program and first regex, so there could be some optimizations possible.

How to get file permissions with c++ boost library?

I am working on a project to make a database of the files I have on current directory. And one of the details I want about my files is the file permissions that are set with chmod in ubuntu. (just a note: I will be needing the group and owner info too - like chown- and if you could let me know if boost can retrieve the ownership info too that'd be great.)
I am using boost filesystem library and I have checked the documentation for numerous times but couldn't find how to get the permissions.
In this page it shows that there's enum perms that has the file permission strings which doesn't show up on my own filesystem.hpp. (And I have checked that i've got the 1.49 version, also built from the source just to be sure). Also on the same page here it shows that it can get the permissions like:
perms permissions() const noexcept;
//Returns: The value of
//permissions() specified by the postconditions of the most recent call
//to a constructor, operator=, or permissions(perms) function.
I haven't been able to find the permissions function nor the place where it stores the perms list.
This is the code I have so far (which is actually from boost tutorials, but I modified it to be recursive), if you could tell me how to get the file permissions/ownerships or suggest another library than boost I would appreciate it.
EDIT: I have added the s.permissions() as ethan_liou suggested however the output was not as expected. Here's the updated code and the output.
// filesystem tut4.cpp ---------------------------------------------------------------//
// Copyright Beman Dawes 2009
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
// Library home page: http://www.boost.org/libs/filesystem
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <boost/filesystem.hpp>
#include <stdio.h>
using namespace std;
using namespace boost::filesystem;
int read(path p);
int main(int argc, char* argv[])
{
if (argc < 2)
{
cout << "Usage: tut4 path\n";
return 1;
}
path p (argv[1]); // p reads clearer than argv[1] in the following code
read(p);
return 0;
}
int read(path p) {
try
{
if (exists(p)) // does p actually exist?
{
if (is_symlink(p)) {
cout << p << " is a link\n";
}
else if (is_regular_file(p)) {
// is p a regular file?
file_status s = status(p);
cout << p << " size is " << file_size(p) << " perms " << "" ;
printf("%o\n",s.permissions());
}
else if (is_directory(p)) // is p a directory?
{
cout << p << " is a directory containing:\n";
typedef vector<path> vec; // store paths,
vec v; // so we can sort them later
copy(directory_iterator(p), directory_iterator(), back_inserter(v));
sort(v.begin(), v.end()); // sort, since directory iteration
// is not ordered on some file systems
for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it)
{
//cout << " " << *it << '\n';
read(*it);
}
}
else
cout << p << " exists, but is neither a regular file nor a directory\n";
}
else
cout << p << " does not exist\n";
}
catch (const filesystem_error& ex)
{
cout << ex.what() << '\n';
}
return 0;
}
Output:
$ ./a.out ~/Desktop/test
"/home/usr/Desktop/test" is a directory containing:
"/home/usr/Desktop/test/a.out" size is 69446 perms 27746424350
"/home/usr/Desktop/test/la" is a directory containing:
"/home/usr/Desktop/test/la/Untitled Document" size is 0 perms 27746424170
"/home/usr/Desktop/test/la/lala" is a directory containing:
"/home/usr/Desktop/test/la/lala/Link to lalalala" is a link
"/home/usr/Desktop/test/la/lala/Untitled Folder" is a directory containing:
"/home/usr/Desktop/test/la/lala/lalalala" size is 0 perms 0
"/home/usr/Desktop/test/test.cpp" size is 2234 perms 0
"/home/usr/Desktop/test/test.cpp~" size is 2234 perms 0
Note: Those numbers that are like 27746424350 change each time the program is executed.
perms permissions() const { return m_perms; }
defined in boost/filesystem/v3/operations.hpp
Add an easy sample code
#include <boost/filesystem.hpp>
#include <stdio.h>
namespace fs=boost::filesystem;
int main(int argc,char * argv[]){
fs::path p(argv[1]);
fs::file_status s = status(p);
printf("%o\n",s.permissions());
}
File permissions example for windows:
unsigned long attributes = ::GetFileAttributes( filePath.file_string().c_str());
if ( attributes != 0xFFFFFFFF && ( attributes & FILE_ATTRIBUTE_READONLY ))
{
attributes &= ~FILE_ATTRIBUTE_READONLY;
::SetFileAttributes( filePath.file_string().c_str(), attributes );
}

forecast.HoltWinters is not getting mapped into C++

Based on the example code I was trying to run forecast method using c++ and RInside , but I am getting Read 100 items
Exception caught: not a matrix
Can somebody please take a look at my code.
#include <RInside.h>
int main ( int argc, char **argv) {
try {
// create an embedded R instance
RInside R ( argc, argv);
std::string txt =
"rain <- scan(\"http://robjhyndman.com/tsdldata/hurst/precip1.dat\",skip=1);"
"rainseries <- ts(rain,start=c(1813));"
"rainseriesforecasts <- HoltWinters(rainseries, beta=FALSE, gamma=FALSE);"
"suppressMessages(require(forecast));";
R.parseEvalQ(txt); // eval command, no return
Rcpp::NumericMatrix M((SEXP)R.parseEval("rainseriesforecasts2 <- forecast.HoltWinters(rainseriesforecasts, h=8)"));
Rcpp::StringVector cnames( (SEXP) R.parseEval("colnames(rainseriesforecasts2)"));
Rcpp::StringVector rnames( (SEXP) R.parseEval("rownames(rainseriesforecasts2)"));
std::cout << "\n\nAnd now from C++\n\n\t\t\t";
for (int i=0; i<cnames.size(); i++) {
std::cout << std::setw(11) << cnames[i] << "\t";
}
std::cout << std::endl;
for (int i=0; i<rnames.size(); i++) {
std::cout << std::setw(16) << rnames[i] << "\t";
for (int j=0; j<cnames.size(); j++) {
std::cout << std::setw(11) << M(i,j) << "\t";
}
std::cout << std::endl;
}
std::cout << std::endl;
} catch(std::exception& ex) {
std::cerr << "Exception caught: " << ex.what() << std::endl;
} catch(...) {
std::cerr << "Unknown exception caught" << std::endl;
}
}
This looks like a straight-up adaptation of one of the over a dozen examples I have included in the RInside sources -- so that is a good starting point.
The error you quote is an R error, not a C++ error so I would start by trying the few lines of R code by themselves in R. Pay particular attention to the class() of the returns you want to assign to make sure you do cast it to the right C++ types.
Edit: Ok, had some time to look at it. You were close, but as I suspected the types from the forecast package get in the way. Try this:
R.parseEvalQ(txt); // eval command, no return
Rcpp::NumericMatrix M((SEXP)R.parseEval("rainseriesforecasts2 <- as.matrix(as.data.frame(forecast.HoltWinters(rainseriesforecasts, h=8)))"));
Rcpp::StringVector cnames( (SEXP) R.parseEval("colnames(as.data.frame(rainseriesforecasts2))"));
Rcpp::StringVector rnames( (SEXP) R.parseEval("rownames(as.data.frame(rainseriesforecasts2))"));
and with that it works for me:
edd#dexter:~/svn/rinside/pkg/inst/examples/standard$ ./rinside_sample12
Read 100 items
And now from C++
Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
1913 24.6782 19.1749 30.1815 16.2617 33.0947
1914 24.6782 19.1733 30.1831 16.2592 33.0972
1915 24.6782 19.1717 30.1847 16.2568 33.0996
1916 24.6782 19.1701 30.1863 16.2543 33.102
1917 24.6782 19.1685 30.1879 16.2519 33.1045
1918 24.6782 19.1669 30.1895 16.2495 33.1069
1919 24.6782 19.1653 30.1911 16.247 33.1094
1920 24.6782 19.1637 30.1926 16.2446 33.1118
edd#dexter:~/svn/rinside/pkg/inst/examples/standard$