如何在R中实现一个生成Voronoi树图的c++程序

How to implement a C++ program in R for the purpose of generating a Voronoi Treemap?

本文关键字:Voronoi 程序 c++ 一个 实现      更新时间:2023-10-16

我正在尝试在r中复制Voronoi树状图。谢天谢地,Paul Murrell已经做了大量的工作,提供了生成这种视觉效果的开源代码:https://www.stat.auckland.ac.nz/~paul/Reports/VoronoiTreemap/voronoiTreeMap.html和https://www.stat.auckland.ac.nz/~paul/Reports/pricekaleidoscope/pricekaleidoscope.html

然而,我遇到了问题——主要是因为部分代码是基于c++的。Murrell没有提供任何关于如何使这部分与r兼容的信息,所以让我描述一下我目前所做的。

我从Murrell那里复制并运行R代码,直到c++程序到位。我当前的R代码是这样的(如果你打开上面提到的第一个链接,你会发现所有的源代码):

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)
在这一点上,R代码必须使用一个叫做"voronoiDiagram"的c++程序,Murrell在他的网页上提供了这个程序;如果你点击我上面提到的第一个链接,你会发现代码,但我也把它复制到这里:
/*
 *  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 << "Edgen";
          } 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;
}

由于c++代码是基于我下载的CGAL库,然而,我无法将c++代码与r集成。我的第一个想法是使用rcpp包和内联命令。但我不知道该怎么做。我特别不知道在cxxfunction()命令中放入什么,猜测我必须使用它。

如果c++代码正常工作,R脚本将继续:

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

正如MrFlick建议的那样,首先要做的是使用gcc/g++(可能通过一些/任何使用gcc/g++的IDE—假设您正在使用windows并且是c++的新手),使c++代码在标准c++中工作。最后,当您通过Rcpp和r使用c++时,了解在命令行中使用c++将对您大有裨益。您需要这样做:

  1. 理解代码以及如何包含外部库
  2. 有东西来比较任何Rcpp输出-否则你怎么知道你的端口不会引入bug,等等?

您可以参考(很多很多)在Rcpp中使用Boost库的示例(在R中的Boost头文件可用之前),这些示例在这里和该问题的链接中都有介绍。

我个人已经执行了许多与您正在尝试实现的类似的任务,并且它当然需要了解程序,以及各个部分(外部库,头文件等)如何工作。