Язык или пакет для рисования геометрических диаграмм - PullRequest
19 голосов
/ 23 октября 2010

Я ищу язык или пакет на существующем языке, который подходит для определения и рисования геометрических диаграмм.

Например, я хотел бы нарисовать гексагональную сетку с наложенной на нее двойной треугольной сеткой. Теперь я могу сесть, нанести немного локтевого смазочного материала, чтобы отработать триггер вручную, и придумать какой-нибудь Postscript или SVG, который будет отображать такую ​​сетку. Но мне интересно, есть ли какие-нибудь языки или пакеты, которые помогут мне с этим; которые позволяют легко определить шестиугольную сетку, найти центры и нарисовать треугольную сетку над ней.

Какой самый простой способ сделать это?

Примеры кода, показывающие, как легко создавать такие геометрически заданные диаграммы, приветствуются. В частности, пожалуйста, покажите, как легко нарисовать гексагональную сетку; хотя я мог сделать это на любом языке, рисуя все линии вручную, мне интересны языки или пакеты, которые делают такую ​​геометрическую диаграмму простой и понятной.

Bounty

Поскольку на этот вопрос дан ответ, но ответ более сложный, чем я бы предпочел, я предложу вознаграждение человеку, который может создать самый короткий и простой код на любом существующем ранее языке и с использованием любого существующего ранее пакет для рисования гексагональной сетки с наложенной на нее двойной треугольной сеткой; двойная треугольная сетка - это треугольная сетка, которую вы получаете, если вы соединяете центр каждого шестиугольника с центром каждого из соседних шестиугольников. См., Например, ответ Antal S-Z ; его пример делает свою работу, но я искал язык, который бы облегчил эту проблему. Вы можете либо создать сетку, которая будет приблизительно прямоугольной, как в его примере (нечетные строки выровнены, а четные строки выровнены), либо сетку в стиле доски Hex (каждая строка сдвинута вправо на половина гексагона, образуя ромб); оба приемлемы.

Программа может принимать ввод в виде функции или подпрограммы на языке, который принимает количество строк и количество столбцов, или принимать ввод, переданный в командной строке с указанием строк и столбцов. Он должен производить вывод в любом стандартном и обычном графическом формате, таком как Postscript, PDF, SVG, PNG или PNM ; выходные данные должны содержать шестнадцатеричную сетку и треугольную сетку, в некоторых контрастных цветах, весе линии или стиле линии, чтобы прояснить диаграмму.

Я ищу самый короткий и простой ответ, как способ найти язык или пакет, который лучше всего подходит для описания диаграмм такого типа; щедрость пойдет на самую короткую программу, которая решит проблему. Это не кодовый гольф, поэтому я не буду считать количество символов или строк кода. Если нет кратчайшего очевидного ответа, я буду измерять на основе количества токенов; сколько токенов на вашем языке нужно, чтобы выразить эту проблему? Таким образом, удобочитаемые константы и имена переменных с использованием библиотечных функций, комментариев, пробелов и т. Д. Все в порядке, поскольку они не увеличивают количество токенов. Это все еще не идеальная метрика (у Лиспа будет еще несколько токенов, так как вам нужно больше скобок для разграничения ваших арифметических выражений, и я уверен, что если вы чрезмерно оптимизируете эту метрику, вы все равно можете создать некоторый нечитаемый код), но это приблизительное руководство по сложности вашего кода.

Итак, задача для награды - создать самую короткую программу, которая рисует шестнадцатеричную сетку с наложенной треугольной сеткой. Пожалуйста, опубликуйте свой код, ссылки на язык и все пакеты, которые вы использовали, приблизительный подсчет токенов, если это возможно, и пример выходного изображения. Существующим ответом является планка, которую вы должны побить, чтобы пройти квалификацию; это делает работу, но я хотел бы что-то короче и проще.

Чтобы у меня было достаточно времени, чтобы посмотреть на ответы и назначить награду, все ответы должны быть представлены как минимум за 24 часа до крайнего срока. Я могу или не могу рассмотреть любые ответы, представленные менее чем за 24 часа до крайнего срока.

Ответы [ 12 ]

10 голосов
/ 24 октября 2010

Я также хотел бы порекомендовать PGF / TikZ с оговоркой, что он находится в TeX. Если вам неудобно заниматься программированием на TeX, это может быть немного головной болью, поскольку есть некоторые… идиосинкразии. (Работа с пустыми пространствами может быть, например, приключением.) Однако, если вы хотите заниматься программированием на TeX, я настоятельно рекомендую это; Я очень часто использую его для рисования фигур, даже если я не работаю в TeX. Кроме того, его руководство абсолютно удивительно , а галерея TeXample содержит массу замечательных примеров.

Пример кода для рисования шестнадцатеричной сетки и ее триангуляции выглядит следующим образом. Я признаю, что это довольно долго, но я думаю, что это действительно не так уж плохо.

\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 имеет начало строки first имеет отступ вместо строки second . Мы также позволим пользователю передавать команды стиля в первом необязательном аргументе \hexgrid; every hexgrid hex/.style 2 args позволит им стилизовать отдельные шестиугольники (и даже запросить позицию этого гексагона, если они захотят), а every hexgrid triangulator/.style позволит им стилизовать линии триангуляции.

Пропустив немного, мы подходим к \pgfsetmacro строкам; указан диаметр шестиугольников, поэтому мы должны вычислить радиус, длину стороны, а затем ширину из стороны в сторону. Следующие два цикла \foreach являются основой кода для рисования и, надеюсь, должны быть достаточно ясными. Обратите внимание, что мы должны принимать во внимание толщину линий при определении вертикального размещения. После этого идет еще более длинный блок кода, между \ifHexgridTriangulate и \fi; это ответственно за триангуляцию сетки, если такая вещь желательна.

Наконец, мы увидим, как это выглядит:

Example hex grids.

4 голосов
/ 26 октября 2010

Как уже говорили другие, наиболее расширяемый и документированный язык, который соответствует вашим потребностям, - это, вероятно, 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

4 голосов
/ 23 октября 2010

Xy-pic или MetaPost , которые, вероятно, уже установлены на вашем компьютере, если у вас есть TeX.

ОБНОВЛЕНИЕ : после попыткипомните, как использовать MetaPost и сбой ... Я использовал SketchUp от Google.Тривиально для макета.Возможно, вам подойдет другая программа САПР.Но с помощью программы для рисования является самым простым.OpenOffice Draw, возможно?Похоже на обман, но он сделал работу быстрее всего.

Вот быстрое изображение, сделанное в OpenOffice Draw за несколько минут.Требуется немного поработать над соотношением сторон, но он демонстрирует основы.

UPDATE the second It came to mind that a tool that uses a declarative style like Groovy's 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.Также поставляется с отличными учебниками и обширной документацией.В среде IDE Netbeans есть очень приятная кнопка предварительного просмотра, которая очень полезна для почти мгновенного просмотра результатов.

И да, я мог бы сделать намного лучше в коде, но были некоторые странные вещи с преобразованиями и заполнением,Так что я сделал это безобразно.

Кстати, это моя первая программа на javafx.Буду признателен за исправления и изменения.

3 голосов
/ 02 декабря 2015

Хотя 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

2 голосов
/ 21 марта 2011

Асимптота IMO лучше подходит для такого рода вещей (если только вам не нужен интерактивный инструмент, такой как геогебра ).

Это просто и намного проще.По умолчанию вывод .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

Возможно, есть еще более простой способ сделать это, но я не достаточно знаком с асимптотой.

2 голосов
/ 31 октября 2010

... самый короткий и простой код на любом существующем ранее языке и использующий любой существующий ранее пакет для рисования шестиугольной сетки с двойной треугольной сеткой, наложенной поверх нее;...

В стандартном 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: ( ссылка )
Что такое тесселяция: ( ссылка )

Вывод для: 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

2 голосов
/ 25 октября 2010

Асимптота также может быть полезна.(аналог метапоста)

1 голос
/ 14 января 2011

Вы должны проверить rfig .

Это слой поверх метапоста, который позволяет вам рисовать произвольные фигуры (и делать слайды PDF), используя ruby.Вы можете определить свои собственные функции, которые принимают аргументы и рисуют фигуры (например, шестиугольник).Затем вы можете повторно вызывать свои функции и т. Д. Это дает вам возможность метапоста с гибкостью программирования на ruby.

На сайте есть пример некоторых рисунков, сгенерированных с использованием rfig, которые дают довольно хороший примерфункциональности.

1 голос
/ 24 октября 2010

Там тоже mkhexgrid но я не пробовал.Также hexpaper , который, вероятно, легко адаптировать к вашим потребностям.

1 голос
/ 23 октября 2010

Я бы всегда рекомендовал PGF / TikZ , хотя я никогда не пытался автоматизировать создание диаграмм с его помощью. Взгляните на впечатляющий список примеров более здесь .

...