代码之家  ›  专栏  ›  技术社区  ›  Brian Campbell Dennis Williamson

绘制几何图形的语言或软件包

  •  19
  • Brian Campbell Dennis Williamson  · 技术社区  · 14 年前

    例如,我想画一个六边形网格,它的双三角形网格叠加在上面。现在,我可以坐下来,用手在肘部涂些润滑油来计算trig,然后想出一些Postscript或SVG来显示这样的网格。但我想知道是否有任何语言或软件包可以帮助我解决这个问题;这使得指定六边形网格、找到中心并在其上绘制三角形网格变得容易。

    代码示例,显示如何容易地创建这样的几何指定的图表,将不胜感激。特别是,请演示绘制六边形网格是多么容易;虽然我可以用任何语言手工绘制所有的线,但我对使这种几何图形简单明了的语言或软件包感兴趣。

    赏金

    Antal S-Z's 例如,回答;他的例子起到了作用,但我正在寻找一种语言,使这个问题更容易。您可以生成一个大致呈矩形的网格,如他的示例所示(奇数行对齐,偶数行对齐),也可以使用 Hex 板(每行右移半个六角形,形成菱形);两者都可以接受。

    程序可以以函数或子程序的形式接受输入,输入的语言可以包含若干行和若干列,也可以接受在指示行和列的命令行上传入的输入。它应该以任何标准和通用图形格式生成输出,如Postscript、PDF、SVG、PNG或 PNM ;输出应包含十六进制网格和三角形网格,以某种对比色、线宽或线条样式使图表清晰。

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

    所以,对于赏金来说,挑战是创建一个最短的程序,用它的叠加三角形网格绘制一个十六进制网格。请张贴你的代码,链接到语言和你使用过的任何软件包,一个粗略的令牌计数,如果可能的话,和一个示例输出图像。现有的答案是,你必须打破这个门槛才能获得资格;它确实起到了作用,但我希望有更简短、更简单的东西。

    12 回复  |  直到 7 年前
        1
  •  11
  •   Antal Spector-Zabusky    14 年前

    我还想推荐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 设置每个六边形的角到角大小, xpos ypos 定位整个网格的左上角, rows cols 确定六边形的数量 triangulate 选项允许您选择对网格进行三角化,并且 start shifted 选项具有 行开始缩进,而不是 第二 划船。我们还允许用户在 \hexgrid ; every hexgrid hex/.style 2 args 将允许它们设置单个六边形的样式(如果需要,甚至可以查询该六边形的位置),并且 every hexgrid triangulator/.style 将允许它们设置三角剖分线的样式。

    \pgfsetmacro 线;六边形的直径是指定的,所以我们必须计算半径、边长,然后计算两边的宽度。以下两个 \foreach \ifHexgridTriangulate \fi

    最后,我们来看看这是什么样子:

    Example hex grids.

        2
  •  4
  •   A. Rex    14 年前

    正如其他人所说,最适合您需要的可扩展和文档化语言可能是PGF/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

    正如另一个答案,六行只是乳胶的样板。请注意,除了意识到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
  •  4
  •   Allen    14 年前

    Xy-pic MetaPost 如果你有TeX,可能已经安装在你的电脑上了。

    更新 :在尝试记住如何使用MetaPost并失败之后。。。我用的是谷歌的SketchUp。布局琐碎。也许另一个CAD程序适合你。但是使用绘图程序是最简单的。也许是OpenOffice绘图?看起来像是作弊,但它做得最快。

    这是几分钟后在OpenOffice中绘制的快速图像。在纵横比方面需要做一些工作,但是它展示了基本的东西。

    更新第二个 我突然想到,一个使用像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程序。我会很感激修复和改变。

        4
  •  3
  •   vagoberto    9 年前

    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

        5
  •  2
  •   alvin    14 年前
        6
  •  2
  •   Margus    14 年前

    ... 最短最简单的代码,在任何 预先存在的语言和使用任何 预先存在的包,用于绘制 六边形网格及其对偶 它。。。

    在标准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}。

    如何在Mathematica中使用多边形:( link
    什么是镶嵌:( 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

        7
  •  2
  •   Eelvex    14 年前

    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

    也许有一种更简单的方法来做这件事,但我对渐近线还不够熟悉。

        8
  •  1
  •   lhf    14 年前

    尝试 MetaPost

        9
  •  1
  •   Benjamin Bannier    14 年前

    我会一直推荐 PGF/TikZ here .

        10
  •  1
  •   lhf    14 年前

    还有 mkhexgrid 但我没有试过。阿尔索 hexpaper 这可能很容易适应你的需要。

        11
  •  1
  •   dsg    14 年前

    你应该退房 rfig .

    网站上有一个使用rfig生成的一些数字的例子,给出了一个很好的功能示例。

        12
  •  0
  •   Jacob    14 年前

    我通常使用MATLAB来实现这一点。