提高RegionPlot的速度(或替代)

时间:2011-12-07 03:00:56

标签: wolfram-mathematica plot

我想在Manipulate结构中包含一些区域图,但渲染速度几乎非常慢。代码是

ClearAll[regions, rplot]
r:regions[n_Integer, o_Integer] := r = Apply[And, 
    Subsets[Table[(#1 - Cos[t])^2 + (#2 - Sin[t])^2 <= 1, {t, 2 Pi/n, 
       2 Pi, 2 Pi/n}], {o}], {1}] &
r:rplot[n_Integer, o_Integer] := r = Show[{RegionPlot[
     Evaluate[regions[n, o][x, y]], {x, -2, 2}, {y, -2, 2},
     PlotRange -> {{-2, 2}, {-2, 2}}, PlotRangePadding -> .1, 
     Frame -> False, PlotPoints -> 100], 
    Graphics[Table[Circle[{Cos[t], Sin[t]}, 1], {t, 2 Pi/n, 2 Pi, 2 Pi/n}]]}]

产生类似

的图形
GraphicsGrid[{{rplot[3, 2], rplot[5, 3]}, {rplot[7, 2], rplot[4, 1]}}]

circles from above!

以上大约需要40秒才能在我的计算机上进行计算和渲染。 任何人都可以建议一种方法来更快地获得类似质量的图形吗?


注1:我已经记住了图形对象,因此每次在我的演示中都不需要重新计算它 - 但即使是第一次它也太慢了。
注2:我对栅格化图像感到满意,因此洪水填充类型解决方案可能是一种选择...
注3:我需要Manipulate[ rplot[n, o], {n, 2, 10, 1, Appearance -> "Labeled"}, {{o, 1}, Range[1, (n + 1)/2], ControlType -> RadioButtonBar}]这样的东西才能使用。

4 个答案:

答案 0 :(得分:4)

你可以做这样的事情

rplot[n_Integer, o_Integer] :=  Module[{centres, masks, opacity = .3, 
   colours, region, img, createmask},
  centres = Table[Through[{Re, Im}[Exp[I t]]], {t, 2 Pi/n, 2 Pi, 2 Pi/n}];
  createmask[centres_] := Fold[ImageMultiply, #[[1]], Rest[#]] &@ 
     (ColorNegate[ Image[Graphics[Disk[#, 1], PlotRange -> {{-2, 2}, {-2, 2}}, 
          PlotRangePadding -> .1], ColorSpace -> "Grayscale"]] & /@ centres);
  masks = createmask /@ Subsets[centres, {o}];
  colours = PadRight[#, Length[masks], #] & @ (List @@@ ColorData[1, "ColorList"]);
  region[img_, col_] := 
   SetAlphaChannel[ColorCombine[ImageMultiply[img, #] & /@ col, "RGB"], 
    ImageMultiply[img, opacity]];
  img = Fold[ImageCompose, #[[1]], Rest[#]] &@(MapThread[region, {masks, colours}]);
  Overlay[{img, Graphics[Circle[#, 1] & /@ centres, PlotRangePadding -> .1, 
     PlotRange -> {{-2, 2}, {-2, 2}}]}]
 ]

然后GraphicsGrid[{{rplot[3, 2], rplot[5, 3]}, {rplot[7, 2], rplot[4, 1]}}]会产生类似

的内容

cross sections of circles

修改

将之前的修改移至单独的答案。

答案 1 :(得分:3)

先生。向导让我意识到虽然我有RegionPlot中可以使用的区域的分析形式,但如果我获得了边界的参数化形式,那么我可以使用ParametricPlot。那么,让我们这样做!

i th i=0,...,n-1)圆在复平面上被参数化 Exp[I t] + Exp[2 i Pi I / n]中的t [0, 2 Pi]。{/ p>

我们可以求解找到i th (i+o-1) th 圈子的交集,其中o是重叠次数,如问题的原始代码。这给出了

point[n_, o_, i_] := {Cos[(2 i Pi)/n] + Cos[(2 Pi (i + o - 1))/n], 
                      Sin[(2 i Pi)/n] + Sin[(2 Pi (i + o - 1))/n]}

现在我们可以将从原点到point[n,o,i]的弧参数化,并将它们反映在从原点到point[n,o,i]的整个线上。使用参数s对两者进行插值,得出参数化区域

area[n_, o_, i_, t_, s_] := With[{a = 2 Sin[((2 + n - 2 o) (1 - t) )/(2 n) Pi], 
   b = (2 - 4 i + 2 t + n t - 2 o (1 + t))/(2 n) Pi, 
   c = ((2 + n - 2 o) (1 - t) - 4 i)/(2 n) Pi}, 
   {a (s Cos[b] + (1 - s) Sin[c]) , -a (s Sin[b] - (1 - s) Cos[c])}]

然后我们可以定义

rplot[n_Integer, o_Integer] := ParametricPlot[Evaluate[
  Table[area[n, o, i, t, s], {i, 0, n - 1}]], {t, 0, 1}, {s, 0, 1},
  Mesh -> False, MaxRecursion -> 1, Frame -> False, Axes -> False, 
  PlotRange -> 2.1 {{-1, 1}, {-1, 1}},
  Epilog -> {Table[Circle[{Cos[t], Sin[t]}, 1], {t, 0, 2 Pi (n-1)/n, 2 Pi/n}],
    Red, Point[Table[point[n, o, i], {i, 1, n}]]}]

GraphicsGrid[{{rplot[3, 2], rplot[5, 3]}, {rplot[7, 2], rplot[4, 1]}}]生成

graphics grid

答案 2 :(得分:3)

我之前发布此内容作为我的其他答案的补充。它的灵感来自Simon的分析方法,并通过一些修改来加速提升

intersect[n_, o_] :=
  With[{a = Pi/2 - (o-1) Pi/n},
   If[o-1 >= n/2, Return[{}]]; (* intersection is {} *)
   Polygon[
    Join[Table[{Sin[a] + Sin[phi], (-Cos[a] + Cos[phi])}, {phi, -a, a-2 a/10, 2 a/10}], 
     Table[{Sin[a] + Sin[phi], (Cos[a] - Cos[phi])}, {phi, a, -a+2 a/10, -2 a/10}]]]]

rplot2[n_, o_] := With[{pl = intersect[n, o], opac = .3, col = ColorData[1]},
  Graphics[{{Opacity[opac], 
     Table[{col[k], Rotate[pl, Mod[o - 1, 2] Pi/n + 2 Pi k/n, {0, 0}]}, {k, n}]},
    {Black, Circle[Through[{Re, Im}[Exp[I #]]]] & /@ (Range[n] 2 Pi/n)}}]
 ]

首先,我使用no的给定值,i - 和i+o-1 - 圈之间的交叉区域是与第一个和第o个圆之间的交叉区域相同,除了在角度2 Pi (i-1)/n上旋转之外,因此只需计算一次区域并使用Rotate旋转该区域就足够了

此外,我没有使用ParametricPlot绘制交叉区域,而是使用Polygon,所以我只需要计算边界上的一些点,这样可以节省时间。

GraphicsGrid[{{rplot2[3, 2], rplot2[5, 2]}, {rplot2[7, 3], rplot2[4, 1]}}]的结果类似于

Intersecting circles revisited

我得到的时间是

rplot2[10, 3]; // Timing

(* ==> {0.0016, Null} *)

与Simon的解决方案相比

rplot[10, 3]; // Timing

(* ==> {0.16519, Null} *)

答案 3 :(得分:1)

分析方法

如果圆圈总是以如图所示的均匀环排列,则应该有一个圆圈交叉点的解析解。我将从环上布置的每个圆圈之间的度数开始。

我将在时间允许的情况下探索这种方法。

光栅方法

  1. 二进制光栅化一系列位于正确位置的磁盘

  2. 为每个栅格分配唯一的2次幂值而不是

  3. 添加数组

  4. 根据总数数组中每个点的值计算唯一的重叠集

  5. 将正确的颜色映射到结果数组并生成输出


  6. 光栅方法的第一次粗略传递,仅作为概念证明。您可以看到每个区域都有一个唯一的阴影,这只是该点栅格的总和。

    raster = 
      1 - First@Binarize@Rasterize@Graphics[#, PlotRange -> {{-2, 2}, {-2, 2}}] &;
    
    disks =
      Table[raster @ Disk[{Cos[t], Sin[t]}, 1], {t, 2 Pi/#, 2 Pi, 2 Pi/#}] &;
    
    n = 5;
    
    array = disks[n] * 2^Range[0, n - 1] //Total;
    
    ArrayPlot[array]
    

    enter image description here


    第二稿,添加颜色。它仍然相当笨重。

    n = 7; o = 2;
    
    sets = Table[
       NestList[RotateLeft, PadLeft[Table[1, {o + i}], n], n - 1],
       {i, 0, n - o}
       ];
    
    colors = NestList[
       Mean /@ Partition[#, 2, 1, 1] &,
       List @@@ Take[ColorData[4, "ColorList"], n],
       n - o
       ];
    
    rules = Append[Rule @@@ Flatten[{sets, colors}, {{2, 3}}], _ -> {1, 1, 1}];
    
    Replace[Transpose[disks[n], {3, 2, 1}], rules, {2}] // Image
    

    enter image description here