用于绘制几何图的语言或包

时间:2010-10-23 16:48:05

标签: language-agnostic math programming-languages geometry diagram

我正在寻找一种适用于指定和绘制几何图形的语言或现有语言的包。

例如,我想绘制一个六边形网格,其上叠加双三角形网格。现在,我可以坐下来,用一些肘部油脂来手工制作三角形,然后拿出一些会显示这样一个网格的Postscript或SVG。但我想知道是否有任何语言或软件包可以帮助我解决这个问题;这样可以轻松指定六边形网格,找到中心,并在其上绘制三角形网格。

最简单的方法是什么?

代码示例,显示了创建这种几何指定图表是多么容易,我们将不胜感激。特别是,请说明绘制六边形网格是多么容易;虽然我可以通过手工绘制所有线条来用任何语言做到这一点,但我对语言或包装很感兴趣,这使得几何图形变得简单明了。

恩惠

由于这个问题已得到解答,但答案比我想要的要复杂得多,我将向能够以任何预先存在的语言生成最短和最简单的代码并使用任何预先存在的人提供奖励。包装,用于绘制六边形网格,其双三角形网格叠加在其上;如果您将每个六边形的中心连接到每个相邻六边形的中心,则双三角网格是您获得的三角形网格。例如,请参阅Antal S-Z's答案;他的例子完成了这项工作,但我一直在寻找一种能让这个问题更容易的语言。您可以生成一个大致为矩形的网格,如在他的示例中(奇数行对齐,偶数行对齐),或者一个Hex板样式的网格(每行向右移动半个十六进制) ,形成菱形);两者都可以接受。

程序可以采用函数或子程序的形式输入,该语言采用多行和多列,或者在命令行上传入指示行和列的输入。它应该以任何标准和通用图形格式生成输出,例如Postscript,PDF,SVG,PNG或PNM;输出应包含六角网格和三角形网格,以一些对比色,线宽或线条样式使图表清晰。

我正在寻找最简短,最简单的答案,作为一种找到最适合描述这些图表的语言或包的方法;赏金将用于解决问题的最短程序。这不是代码高尔夫,所以我不会计算字符数或代码行数。如果没有明显的最短答案,那么我将根据令牌数来衡量;用你的语言有多少令牌来表达这个问题?因此,使用库函数,注释,空格等的可读常量和变量名都可以,因为它们不会增加令牌数。它仍然不是一个完美的度量标准(Lisps会有更多的标记,因为你需要更多的括号来分隔你的算术表达式,我相信如果你过度优化这个指标,你仍然可以产生一些不可读的代码),但它是您的代码复杂程度的粗略指南。

因此,对于赏金来说,挑战是创建最短的程序,绘制带有叠加三角形网格的六边形网格。请发布您的代码,语言链接以及您使用过的所有软件包,如果可能,请提供粗略的令牌计数,以及示例输出图像。现有的答案是你必须击败才能获得资格的标准;它完成了这项工作,但我希望更短更简单。

为了给我足够的时间来查看答案并奖励赏金,所有答案必须在赏金截止日期前至少24小时提交。我可能会或可能不会在截止日期前24小时内考虑提交任何答案。

12 个答案:

答案 0 :(得分:10)

我还想推荐PGF / TikZ,但需要注意它是在TeX中。如果您不熟悉TeX编程,可能会有点头疼,因为有一些...特性。 (例如,处理杂散空间可能是一种冒险。)但是,如果您愿意进行TeX编程,我强烈推荐它;即使我不在TeX工作,我经常使用它来绘制数字。此外,its manual绝对是惊人的TeXample gallery有很多很好的例子。

绘制十六进制网格并对其进行三角测量的示例代码如下所示。我承认它很长,但我认为它真的不是那么糟糕。

\documentclass{article}

\usepackage{tikz}
\usepackage{ifthen}

\usetikzlibrary{calc}
\usetikzlibrary{shapes.geometric}

\tikzset{hexagon/.style={regular polygon, regular polygon sides = 6}}

\newif\ifHexgridTriangulate
\newif\ifHexgridStartShifted
\pgfqkeys{/hexgrid}
         { name/.store in       = \HexgridName
         , xpos/.store in       = \HexgridX
         , ypos/.store in       = \HexgridY
         , rows/.store in       = \HexgridRows
         , cols/.store in       = \HexgridCols
         , size/.code           = {\pgfmathsetmacro{\HexDiameter}{#1}}
         , triangulate/.is if   = HexgridTriangulate
         , start shifted/.is if = HexgridStartShifted }

\tikzset{ every hexgrid hex/.style 2 args   = {draw}
        , every hexgrid triangulator/.style = {}}

\newcommand{\hexgrid}[2][]{
  \pgfqkeys{/hexgrid}{ name  = hexgrid , size = 1cm
                     , xpos  = 0       , ypos = 0
                     , triangulate   = false
                     , start shifted = false
                     ,#2 }

  \ifHexgridStartShifted
    \def\HexShiftModCheck{0}
  \else
    \def\HexShiftModCheck{1}
  \fi

  \begin{scope}[xshift=\HexgridX, yshift=\HexgridY,#1]
    \pgfmathsetmacro{\HexRadius}{\HexDiameter/2}
    \pgfmathsetmacro{\HexSide}{sqrt(3)*\HexRadius/2}
    \pgfmathsetmacro{\HexWidth}{2*\HexSide}

    \tikzset{every node/.style={hexagon, minimum size=\HexDiameter}}

    \foreach \row in {1,...,\HexgridRows} {
      \foreach \col in {1,...,\HexgridCols} {
        \pgfmathsetmacro{\HexX}%
                        {\HexWidth*(  (\col-1)
                                    + (mod(\row,2) == \HexShiftModCheck
                                        ? 0 : .5))}
        \pgfmathsetmacro{\HexY}%
                        {-(\HexRadius + \HexSide/2 + 2*\pgflinewidth)*(\row-1)}
        \node [hexagon, rotate=90, every hexgrid hex = {\row}{\col}]
              (\HexgridName-\row-\col)
              at (\HexX pt ,\HexY pt)
              {} ;
      }
    }

    \ifHexgridTriangulate
      \begin{scope}[every path/.style={every hexgrid triangulator}]
        \foreach \row in {1,...,\HexgridRows} {
          \foreach \col in {1,...,\HexgridCols} {
            % Using \pgfmathsetmacro always includes a decimal point, which
            % breaks \ifnum.
            \pgfmathparse{int(\row-1)}\let\prow\pgfmathresult
            \pgfmathparse{int(\col-1)}\let\pcol\pgfmathresult

            \ifnum\prow>0
              \draw    (\HexgridName-\prow-\col.center)
                    -- (\HexgridName-\row-\col.center) ;
            \fi
            \ifnum\pcol>0
              \draw    (\HexgridName-\row-\pcol.center)
                    -- (\HexgridName-\row-\col.center) ;
            \fi
            \ifnum\prow>0\ifnum\pcol>0
              \pgfmathparse{mod(\prow,2) == \HexShiftModCheck}
              \ifnum\pgfmathresult=1
                \draw    (\HexgridName-\prow-\col.center)
                      -- (\HexgridName-\row-\pcol.center) ;
              \else
                \draw    (\HexgridName-\prow-\pcol.center)
                      -- (\HexgridName-\row-\col.center) ;
              \fi
            \fi\fi
          }
        }
      \end{scope}
    \fi
  \end{scope}
}

\begin{document}

\begin{center}\begin{tikzpicture}
  % Simplest case
  \hexgrid{rows = 5, cols = 5}

  % Every possible option at once
  \hexgrid[ every hexgrid hex/.style 2 args   = {ultra thick, draw=blue}
          , every hexgrid triangulator/.style = {color=black!75} ]
          { name = thg , size = 1.5cm
          , xpos = 0   , ypos = -5cm
          , rows = 5   , cols = 5
          , triangulate
          , start shifted}
  % Mark the center of that grid, just because we can.
  \filldraw [red] (thg-3-3) circle (2pt) ;
\end{tikzpicture}\end{center}

\end{document}

\newcommand{\hexgrid}之前的代码只包含所需的包并设置关键字参数:name设置用于引用六边形的名称,size设置角落到 - 每个六边形的边角大小,xposypos位于整个网格的左上角,rowscols确定六边形的数量,triangulate选项允许您选择对网格进行三角测量,start shifted选项将第一个行开始缩进而不是第二个行。我们还允许用户在\hexgrid的第一个可选参数中传递样式命令; every hexgrid hex/.style 2 args将允许它们设置单个六边形的样式(甚至可以查询该十六进制的位置,如果需要),every hexgrid triangulator/.style将允许它们设置三角形线的样式。

跳过一点,我们来到\pgfsetmacro行;指定六边形的直径,因此我们必须计算半径,边长,然后从一侧到另一侧计算宽度。以下两个\foreach循环是绘图代码的主要内容,应该非常清楚。请注意,在确定垂直放置时,我们必须考虑线条的粗细。在此之后会出现更长的代码块,介于\ifHexgridTriangulate\fi之间;如果需要这样的话,它负责对网格进行三角测量。

最后,我们看看它是什么样的:

Example hex grids.

答案 1 :(得分:4)

如果您有TeX,则可能已在您的计算机上安装了

Xy-picMetaPost

更新:在尝试记住如何使用MetaPost并失败之后......我使用了Google的SketchUp。布局微不足道。也许不同的CAD程序可能适合您。但到目前为止,使用绘图程序是最简单的。也许是OpenOffice Draw?似乎是在作弊,但它最快完成了工作。

这是几分钟内在OpenOffice Draw中制作的快速图像。需要对纵横比进行一些工作,但它显示了基础知识。

更新第二个我想到一个使用像Groovy的GraphicsBuilder这样的声明式样式的工具是最好的。不幸的是,GraphicsBuilder似乎需要反向Groovy 1.6-beta-2。所以转向别的东西,最相似的是...... JavaFX。这是(非常蹩脚,但显示可以做什么)代码:

package hexgrid;

import javafx.scene.shape.Polygon;
import javafx.scene.paint.Color;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.shape.Line;
import javafx.scene.shape.Circle;
import javafx.util.Math;

/**
 * @author arouse
 */
var scale = 60;
var width = 400;
var height = 400;

function hexagon(x: Number, y: Number): Polygon {
    var basicpoints = [1, 0, 0.5, -0.866, -0.5, -0.866, -1, 0, -0.5, 0.866, 0.5, 0.866];
    basicpoints = for (i in basicpoints) i * scale;
    return Polygon {
                points: basicpoints
                fill: Color.WHITE
                translateX: x
                translateY: y
                strokeWidth: 2
                stroke: Color.BLUE
                opacity: 0.3
            }
}
var hexes = Group {
            content: [
                for (x in [0..width step scale * 3]) {
                    for (y in [0..height step 0.866 * scale * 2]) {
                        hexagon(x, y);
                    }
                }
                for (x in [0..width step scale * 3]) {
                    for (y in [0..height step 0.866 * scale * 2]) {
                        hexagon(x + 1.5 * scale, y + 0.866 * scale);
                    }
                }
            ]
        }
var lines60 = Group {
            content: [
                for (y in [0..height step scale]) {
                    Line {
                        startX: 0, startY: 2 * y * 0.866
                        endX: 3 * y, endY: 0
                        strokeWidth: 1
                        stroke: Color.BLACK
                    }
                }
            ]
        }
var lines120 = Group {
            content: [
                    for (y in [(-Math.floor(height/10)*scale)..height step scale]) {
                    Line {
                        startX: 0, startY: 2*0.866*y
                        endX: width, endY: 2*0.866/3*width + 2*0.866*y
                        strokeWidth: 1
                        stroke: Color.BLACK
                    }
                }
            ]
        }
var linesdown = Group {
            content: [
                for (x in [0..width step scale*1.5]) {
                    Line {
                        startX:  x, startY: 0
                        endX:  x, endY: height
                        strokeWidth: 1
                        stroke: Color.BLACK
                    }}
            ]
        }
Stage {
    title: "Hex Grid with dual triangular grid"
    scene: Scene {
        width: width
        height: height
        fill: Color.WHITE
        content: [
            hexes,
            lines60,
            lines120,
            linesdown
        ]
    }
}

这导致了这一点(我承认它可能会好得多):

alt text

优于其他答案:可用于复合任意图像,文本,动画等,完整的编程语言,java互操作。还附带了很棒的教程和广泛的文档。 Netbeans IDE有一个非常好的预览按钮,对于几乎即时的结果视图非常有用。

是的,我可以在代码中做得更好,但是转换和填充有一些棘手的事情。所以我用丑陋的方式做到了。

顺便说一下,这是我的第一个javafx程序。我会感谢修复和更改。

答案 2 :(得分:4)

正如其他人所说,适合您需求的最具可扩展性和文档记录的语言可能是PGF / TikZ。我不到一周前就学会了非常基本的TikZ,所以希望这能证明它的力量:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}

\newcommand{\hexcoord}[2]
{[shift=(0:#1),shift=(60:#1),shift=(0:#2),shift=(-60:#2)]}
% Five-by-five hexagonal grid
\foreach \x in {0,...,4}
\foreach \y in {0,...,4}
\draw\hexcoord{\x}{\y}
(0:1)--(60:1)--(120:1)--(180:1)--(-120:1)--(-60:1)--cycle;

% Dual triangular grid
\foreach \x in {0,...,4}
\foreach \y in {0,...,4}
\foreach \z in {0,60,...,300}
\draw[help lines]\hexcoord{\x}{\y}
(0,0) [rotate=\z,shift=(0:.5),shift=(60:.5)] -- (0,0);

\end{tikzpicture}
\end{document}

结果如下:

alt text

正如在另一个答案中那样,六条线只是LaTeX的样板。请注意,除了意识到60度是360度的六分之一之外,我不必进行任何计算。我通过使用变换和许多极坐标来避免三个的平方根(六边形之间的距离)。如果您不喜欢双网格中的杂散线,可以使用在第二个注释后插入的剪切区域剪切它们:

\clip (0,0)
\hexcoord{ 4}{0}--(0,0)
\hexcoord{ 0}{4}--(0,0)
\hexcoord{-4}{0}--(0,0)
-- cycle;

修改的。实际上,裁剪区域看起来有点糟糕。这是一个更有趣的版本,完整:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}

\newcommand{\hexcoord}[2]
{[shift=(0:#1),shift=(60:#1),shift=(0:#2),shift=(-60:#2)]}
% Five-by-five hexagonal grid
\foreach \x in {0,...,4}
\foreach \y in {0,...,4}
\draw\hexcoord{\x}{\y}
(0:1)--(60:1)--(120:1)--(180:1)--(-120:1)--(-60:1)--cycle;

% Dual triangular grid
\foreach \x in {0,...,4}
\draw[help lines] \hexcoord{0}{\x}(0,0) \hexcoord{4}{0}--(0,0)
\hexcoord{-4}{4}\hexcoord{\x}{-\x}--(0,0)
\hexcoord{0}{-4}--(0,0) \hexcoord{-\x}{\x}--(0,0);

\end{tikzpicture}
\end{document}

结果如下:

alt text

答案 3 :(得分:3)

虽然gnuplot旨在以交互方式可视化数学函数和数据,但它也可用于绘制一些图表。这段代码就是一个例子:

#!/usr/local/bin/gnuplot -p

set size ratio -1       # x and y axes have same unit length
unset border            # erases the axes
unset tics              # erases tic labels

# polygon-center is translated by vector (x0,y0)
x0 = 2.0 * cos(pi/6.0)**2
y0 = sin(pi/3.0)

jmax=4
imax=3


# drawing a triangular grid (joining the centers)
set for [i=0:imax] arrow from i*x0,i*y0  to (i+jmax)*x0,(i-jmax)*y0 nohead lc rgb 'gray' back
set for [j=0:jmax] arrow from j*x0,-j*y0 to (imax+j)*x0,(imax-j)*y0 nohead lc rgb 'gray' back

set for [k=1:imax+jmax-1] arrow \
    from k*x0, (k<=imax ? k : 2*imax-k)*y0 \
    to   k*x0,-(k<=jmax ? k : 2*jmax-k)*y0 nohead lc rgb 'gray' back



# drawing an hexagonal diagram
do for [j=0:jmax] {     # translates center right-down
    do for [i=0:imax] {     # translates center right-up
        # center coordinates
        x(t) = (i+j)*x0 + cos(t*pi/180.0)
        y(t) = (i-j)*y0 + sin(t*pi/180.0)

        # draw an hexagon 
        set obj polygon from x(0),y(0) \
            to x(60),y(60)   to x(120),y(120) to x(180),y(180) \
            to x(240),y(240) to x(300),y(300) to x(0),y(0)
    }
}


# draws the canvas, 1/0=NAN is used to plot nothing :)
plot [-1:13][-5:5] 1/0 notitle

结果如下:

polygons

答案 4 :(得分:2)

Asymptote也可能有用。 (类似于metapost)

答案 5 :(得分:2)

  

......最简单,最简单的代码   预先存在的语言并使用任何语言   预先存在的包,用于绘制   六角网格与其双重   三角形网格叠加在上面   它; ...

在标准Mathematica 7中:

Tessellation[nr_, x_, y_] := Line[Table[{Cos[2 Pi k/nr] + x, Sin[2 Pi k/nr] + y}, {k, nr + 1}]]
draw2T [in_, jn_] := Graphics[{
   {EdgeForm[Opacity[.5]], Thickness[Tiny], LightGray, Table[Tessellation[6, 3 i + 3 ((-1)^j + 1)/4, Sqrt[3]/2 j], {i, in}, {j, jn}]},
   {EdgeForm[Opacity[.5]], Thickness[Large], Gray, Table[Tessellation[3, 3 i + 3 ((-1)^j + 1)/4, (Sqrt[3]/2 j)], {i, in}, {j, jn}]}}]

Mathematica可以将图像导出到:{pdf,网页,html,bmp,eps,gif,jpg,jpg2000,pcx,png,pnm,pxr,原始位图,svg,tiff,ega,emf,wmf}。< BR />

如何在Mathematica中使用多边形:(link
什么是tesselation:(link

输出:draw2T[4, 8]

alt text

在发帖之前,我注意到了:

  

双三角网格是   你连接的三角形网格   每个六边形的中心到   每个邻居的中心   六边形。

为此,您只需要偏移第二个图形。请注意,在将其保存为任何格式之前,它是一组形状,您可以编辑每个元素的视觉效果(多数民众赞成很棒)。

编辑:

使用修复

 draw2T [in_, jn_] := Graphics[{
   {EdgeForm[Opacity[.5]], Thickness[Tiny], LightGray, Table[Tessellation[6, 3 i + 3 ((-1)^j + 1)/4, Sqrt[3]/2 j], {i, in}, {j, jn}]},
   {EdgeForm[Opacity[.5]], Thickness[Large], Gray, Table[Tessellation[3, 0.5 + 3 i + 3 ((-1)^j + 1)/4, Sqrt[3]/2 + (Sqrt[3]/2 j)], {i, in}, {j, jn}]}}]

alt text

答案 6 :(得分:2)

IMO渐近线更适合这类事情(除非你想要一个像geogebra这样的互动工具。)

这很简单,很直接。默认输出为.eps。例如:

size(10cm,0);

guide ppath;  /* for a hexagon's path */
guide tpath;  /* for a triangle's path */
for (int i=1; i<=6; ++i) ppath=ppath--rotate((i-1)*360/6)*E;
for (int i=1; i<=6; ++i) tpath=tpath--rotate((i-1)*360/6)*((0,0)--(0,sqrt(3)/2));

transform T0=shift(1.5,sqrt(3)/2);   /* shift to form a higher row */
transform T1=shift(1.5,-sqrt(3)/2);  /* shift to form a lower row */
transform T2=shift(3,0);             /* shift to the right */

for (int j=0; j<=4; ++j) {
        for (int i=0; i<=4-j; ++i) {
                draw(T0^j*T2^i*(ppath--cycle),blue);  /* multiply each path */
                draw(T0^j*T2^i*tpath,gray);           /* by the transformation */

                draw(T1^j*T2^i*(ppath--cycle),blue);
                draw(T1^j*T2^i*tpath,gray);
        }
}

Output of asymptote code

可能有一种更简单的方法可以做到这一点,但我对渐近线不够熟悉。

答案 7 :(得分:1)

尝试MetaPost

答案 8 :(得分:1)

我总是会推荐PGF/TikZ,尽管我从未试图用它来自动化创作。看看here上令人印象深刻的示例列表。

答案 9 :(得分:1)

还有mkhexgrid但我没试过。另外hexpaper可能很容易适应您的需求。

答案 10 :(得分:1)

您应该查看rfig

它是metapost顶部的一个图层,允许您使用ruby绘制任意图形(并制作PDF幻灯片)。您可以定义自己的函数,这些函数接受参数并绘制形状(例如六边形)。然后你可以反复调用你的函数等。它为你提供了metapost的强大功能,并且具有ruby编程的灵活性。

网站上有一些使用rfig生成的数字示例,它提供了很好的功能样本。

答案 11 :(得分:0)

我通常使用MATLAB。