1

I am trying to replicate a Voronoi treemap in R. Thankfully, Paul Murrell did already a great bunch of work providing open source code to generate such a visual: https://www.stat.auckland.ac.nz/~paul/Reports/VoronoiTreemap/voronoiTreeMap.html and https://www.stat.auckland.ac.nz/~paul/Reports/pricekaleidoscope/pricekaleidoscope.html

However, I ran into problems - mainly because part of the code is based on c++. And Murrell does not provide any information of how to make this piece compatible with R. So let me describe what I did so far.

I copied and run the R code from Murrell which worked out fine until the c++ program comes into place. My current R code looks like this (you'll find all the sources if you open the first link mentioned above):

assign("scale", 1000, envir=.GlobalEnv)
source("VoronoiCode/util.R")
source("VoronoiCode/voronoi.R")
source("VoronoiCode/kaleidescope.R")
source("VoronoiCode/draw.R")
source("VoronoiCode/debug.R")

library("gpclib")
t <- seq(0, 2*pi, length=100)[-1]
circle <- as(list(x=1000*cos(t), y=1000*sin(t)),
             "gpc.poly")
siteX <- c(-500, -500, 500, 500)
siteY <- c(-500, 500, 500, -500)
weights <- seq(10, 40, 10)
target <- weights/sum(weights)

At this point the R code has to make use of a certain c++ program called the 'voronoiDiagram' that Murrell makes available on his webpage; you'll find the code if you click on the first link I mentioned above, but I also copy it here:

/*
 *  Copyright (C) 2012 Paul Murrell
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, a copy is available at
 *  http://www.gnu.org/licenses/gpl.txt
 */

// This code is based on a CGAL example 
// examples/Apollonius_graph_2/ag2_exact_traits.cpp

// standard includes
#include <iostream>
#include <fstream>
#include <cassert>

// the number type
#include <CGAL/MP_Float.h>


// example that uses an exact number type

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Delaunay_triangulation_2.h>
#include <iterator>

typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::Point_2 Point_2;
typedef K::Iso_rectangle_2 Iso_rectangle_2;
typedef K::Segment_2 Segment_2;
typedef K::Ray_2 Ray_2;
typedef K::Line_2 Line_2;

// typedefs for the traits and the algorithm

#include <CGAL/Apollonius_graph_2.h>
#include <CGAL/Apollonius_graph_traits_2.h>

typedef CGAL::Apollonius_graph_traits_2<K>   Traits;
typedef CGAL::Apollonius_graph_2<Traits>     Apollonius_graph;


//A class to recover Voronoi diagram from stream.
struct Cropped_voronoi_from_apollonius{
    std::list<Segment_2> m_cropped_vd;
    Iso_rectangle_2 m_bbox;

    Cropped_voronoi_from_apollonius(const Iso_rectangle_2& bbox):m_bbox(bbox){}

    template <class RSL>
    void crop_and_extract_segment(const RSL& rsl){
        CGAL::Object obj = CGAL::intersection(rsl,m_bbox);
        const Segment_2* s=CGAL::object_cast<Segment_2>(&obj);
        if (s) m_cropped_vd.push_back(*s);
    }

    void operator<<(const Ray_2& ray)    { crop_and_extract_segment(ray); }
    void operator<<(const Line_2& line)  { crop_and_extract_segment(line); }
    void operator<<(const Segment_2& seg){ crop_and_extract_segment(seg); }

    void reset() {
        m_cropped_vd.erase(m_cropped_vd.begin(), m_cropped_vd.end());
    }
};

int main()
{
  std::ifstream ifs("sites.cin");
  assert( ifs );

  Apollonius_graph ag;
  Apollonius_graph::Site_2 site;

  // read the sites and insert them in the Apollonius graph
  while ( ifs >> site ) {
    ag.insert(site);
  }

  //construct a rectangle
  // This is set up to be well outside the range of the sites
  // This means that we should be able to just join up the end
  // points for any open cells, without fear of crossing the 
  // area that contains the sites (EXCEPT for pretty pathological
  // cases, e.g., where there are only two sites)
  Iso_rectangle_2 bbox(-2000,-2000,2000,2000);

  Cropped_voronoi_from_apollonius vor(bbox);

  // iterate to extract Voronoi diagram edges around each vertex
  Apollonius_graph::Finite_vertices_iterator vit;
  for (vit = ag.finite_vertices_begin(); 
       vit != ag.finite_vertices_end(); 
       ++vit) {
      std::cout << "Vertex ";
      std::cout << vit->site().point();
      std::cout << "\n";
      Apollonius_graph::Edge_circulator ec = ag.incident_edges(vit), done(ec);
      if (ec != 0) {
          do { 
              ag.draw_dual_edge(*ec, vor);
              // std::cout << "Edge\n";
          } while(++ec != done); 
      }
      //print the cropped Voronoi diagram edges as segments
      std::copy(vor.m_cropped_vd.begin(),vor.m_cropped_vd.end(),
                std::ostream_iterator<Segment_2>(std::cout,"\n"));
      vor.reset();
  }

  //extract the entire cropped Voronoi diagram
  // ag.draw_dual(vor);

  return 0;
}

Since the c++ code is based on the CGAL library I downloaded it, however, I wasn't able to integrate the c++ code with R. My first thought was to use the rcpp package and the inline command. But I don't know how I can practically do this. I specifically don't know what to put into the cxxfunction() command guessing I have to use it.

If the c++ code was perfectly working, the R script would continue with:

regions <- allocate(letters[1:4], 
                    list(x=siteX, y=siteY),
                    weights, circle, target)

drawRegions(regions, label=TRUE)

It would be really amazing if you had some hints for me...

Anna Blume
  • 11
  • 1
  • The way Murrell seems to be using it is just by compiling the c++ code into it's own executable, independent of R. Are you not satisfied with that solution or have you simply not tried it? What OS are you running? Do you have access to a compiler like `g++`? – MrFlick Aug 22 '14 at 20:36
  • @MrFlick I thought it would be easier and neater to have everything running from R. Don't you think? Also, I am using Windows 8.1, whereas Murrell used Ubuntu. And I havn't downloaded the g++ compiler yet. However, in the end I want the code to be running, so maybe I have to dig deeper into compiling c++ code into its own executable. – Anna Blume Aug 23 '14 at 09:34
  • To me it's more important that it works rather than how it works. Admittedly it is more annoying to compile stuff on Windows usually, but i'm guessing the translation to Rcpp might be non-trivial. – MrFlick Aug 23 '14 at 18:23

1 Answers1

1

As MrFlick suggests, the first thing to do is get the C++ code up and working in standard C++, using gcc/g++ (perhaps via some/any IDE that uses gcc/g++ - assuming you are using windows and new to C++). Ultimately, an understanding of using g++ at the command line will be of greatest benefit to you, when using C++ via Rcpp and R. You will need to do this to:

  1. understand the code and how to include the external library
  2. have something to compare any Rcpp output to - as otherwise how will you know your port will not introduce bugs, etc?

You could probably follow the (many, many) examples of using Boost library with Rcpp (before the boost headers in R became available), and is covered here, and in the links in that question.

I personally have performed a number of similar tasks to what you are trying to achieve, and it certainly requires an understanding of the program, and how the various parts (external libraries, headers, etc) work.

Community
  • 1
  • 1
Rusan Kax
  • 1,894
  • 2
  • 13
  • 17