Простой векторный 2D редактор для черчения

Обсуждаются как существующие проекты (перевод документации, информационная система и т.п.), так и создание новых.

Модератор: Модераторы

Аватара пользователя
Sharfik
энтузиаст
Сообщения: 840
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

А что будет делать конечный инструмент? Вижу ГИС картинки.

PS^ Inkscape может помочь сделать приличные кнопки.
Alex2013
долгожитель
Сообщения: 3240
Зарегистрирован: 03.04.2013 11:59:44

Сообщение Alex2013 »

Решил не мудрствовать и добавил сначала индикацию состояния кнопок модификаторов и текущего инструмента и посмотрев на это безобразие (состояние Ctrl Alt и Shift действительно ингода "залипает" ) Сделал явный показ списка фигур
Изображение
(И само собой теперь можно кликом по списку ставить и снимать выделение )
Дополнение вполне работает но нужно "навести блеск" в разных мелочах.

Добавлено спустя 5 часов 40 минут 31 секунду:
Sharfik писал(а):А что будет делать конечный инструмент? Вижу ГИС картинки.
Вообщем все это часть проекта среды для "поддержки мозгового штурма " и создания презентаций на около-мелиорационные темы (Задача обеспечить наглядный выбор вариантов для фермеров, агрономов, руководителей мелиоративных объектов и т.п. - по сути продвинутый вариант инфографики с данными схемами и гис-привязкой (возможно на следующем этапе будет расчетный болк,таблицы, генератор отсчетов и т.п. но пока задача создать эффектную продвинутую (с опорой на реальные разработки ) и наглядную "показуху" некого "наукоемкого процесса".))

Пока что есть что-такое...
Изображение
1 По центру и справа "настоящая ГИС " ( на основе общедоступных интернет сервисов )
2 Слева простой "редактор структурных диаграмм" (тоже векторный но значительно более примитивный )...
3 Сверху панель управления и интеграции + инструментарий для создания презентаций .

А вот снизу будет "промежуточное звено" простой векторный 2D редактор для черчения.
(По сути "векторный блокнот" для упрощенного черчения (возможно частично поверх ГИС карт или упрощенных понятных схем с привязкой к местности ))
Зы
Извиняюсь что не ответил сразу ! ( Не заметили переход на новую станицу форума )
Alex2013
долгожитель
Сообщения: 3240
Зарегистрирован: 03.04.2013 11:59:44

Сообщение Alex2013 »

Тут у меня очедная "вынужденная передислокация" из "темного царства ангины" (Киева) почти отогрелся и постепенно обустраиваюсь.
Надеюсь что скоро выложу очередную сборку .
Alex2013
долгожитель
Сообщения: 3240
Зарегистрирован: 03.04.2013 11:59:44

Сообщение Alex2013 »

Изображение
И так обещанная свежая сборка (на самом деле тестовых сборок было уже несколько но эта более менее полезная и стабильная)

>>>>Min_VGED_BIN_B_0_04_579_7.7z
>>>>Min_VGED_SRC_B_0_04_579_7.7z

Добавил список фигур(можно снимать и устанавливать выделение в "ручном режиме"), удобное переключение режимов "прямого выбора фигур"(немного недоделано но добавление списка и "ручного режима " снимает большую часть возможных проблем ) и скроллбар в панели инструментов
Последний раз редактировалось Alex2013 17.02.2026 19:55:47, всего редактировалось 2 раза.
Аватара пользователя
Alexander
энтузиаст
Сообщения: 888
Зарегистрирован: 18.12.2005 18:10:00
Откуда: оттуда
Контактная информация:

Сообщение Alexander »

Спасибо!
Alex2013
долгожитель
Сообщения: 3240
Зарегистрирован: 03.04.2013 11:59:44

Сообщение Alex2013 »

Пожалуйста ! :idea: (надеюсь на помощь в тестировании)
Зы
В бинарник включил тестовые изображения. ( "избранная халтура" :wink: )
Alex2013
долгожитель
Сообщения: 3240
Зарегистрирован: 03.04.2013 11:59:44

Сообщение Alex2013 »

Первая версия конвертера svg2ged (ged формат записи моего редактора )
( Еще не отлаживал что-то так что может содержать ошибки и частично не работать )

1 Поддерживаемые элементы SVG:
<rect> → TRectangle (или TRoundRectangle если есть rx/ry)
<circle> → TEllipse
<ellipse> → TEllipse
<line> → TLine
<polyline> → TPolyLine
<polygon> → TPolygon
<text> → TText

2 Поддержка стилей:
Цвета (RGB и HEX)
Толщина линий
Стили штрихов
Заливки
Трансформации (translate)

3 Ограничения:
Не поддерживаются сложные пути <path>
Не поддерживаются градиенты
Не поддерживаются маски и фильтры

Код: Выделить всё

Нерабочий код выкинул ...
Последний раз редактировалось Alex2013 21.02.2026 17:19:16, всего редактировалось 1 раз.
Alex2013
долгожитель
Сообщения: 3240
Зарегистрирован: 03.04.2013 11:59:44

Сообщение Alex2013 »

Слегка исправленная версия конвертера svg2ged (собирается и немного работает )

Код: Выделить всё

program svg2ged;

{$mode objfpc}{$H+}

uses
  Classes, SysUtils, DOM, XMLRead, fpjson,
  Math, Graphics;

type
  TDPoint = record
    x, y: double;
  end;

  TFigureData = record
    ClassName: string;
    Points: array of TDPoint;
    PenColor: Integer;
    PenWidth: Integer;
    PenStyle: Integer;  // 0..5
    BrushColor: Integer;
    BrushStyle: Integer; // 0..7
    Rounding: Integer;
    Text: string;
    FontName: string;
    FontSize: Integer;
  end;

  TFiguresArray = array of TFigureData;

// Вспомогательная функция для безопасного получения значения атрибута
function GetAttrValue(Node: TDOMNode; const AttrName: string): string;
var
  Attr: TDOMNode;
begin
  Result := '';
  if Node = nil then Exit;
  
  Attr := Node.Attributes.GetNamedItem(AttrName);
  if Attr <> nil then
    Result := Attr.NodeValue;
end;

function ColorToInt(const AColor: string): Integer;
var
  R, G, B: Integer;
  Temp: string;
begin
  Result := clBlack;
  if AColor = '' then Exit;
  
  // Парсим rgb(r,g,b)
  if Pos('rgb', LowerCase(AColor)) = 1 then
  begin
    Temp := Copy(AColor, 5, Length(AColor) - 5);
    R := StrToIntDef(Trim(Copy(Temp, 1, Pos(',', Temp) - 1)), 0);
    Delete(Temp, 1, Pos(',', Temp));
    G := StrToIntDef(Trim(Copy(Temp, 1, Pos(',', Temp) - 1)), 0);
    Delete(Temp, 1, Pos(',', Temp));
    B := StrToIntDef(Trim(Temp), 0);
    Result := RGBToColor(R, G, B);
  end
  // Парсим hex #RRGGBB
  else if Pos('#', AColor) = 1 then
  begin
    Temp := Copy(AColor, 2, 6);
    if Length(Temp) = 6 then
    begin
      R := StrToIntDef('$' + Copy(Temp, 1, 2), 0);
      G := StrToIntDef('$' + Copy(Temp, 3, 2), 0);
      B := StrToIntDef('$' + Copy(Temp, 5, 2), 0);
      Result := RGBToColor(R, G, B);
    end;
  end
  // Парсим именованные цвета (упрощенно)
  else if AColor = 'black' then Result := clBlack
  else if AColor = 'white' then Result := clWhite
  else if AColor = 'red' then Result := clRed
  else if AColor = 'green' then Result := clGreen
  else if AColor = 'blue' then Result := clBlue
  else if AColor = 'yellow' then Result := clYellow
  else if AColor = 'gray' then Result := clGray
  else if AColor = 'silver' then Result := clSilver
  else if AColor = 'maroon' then Result := clMaroon
  else if AColor = 'purple' then Result := clPurple
  else if AColor = 'fuchsia' then Result := clFuchsia
  else if AColor = 'lime' then Result := clLime
  else if AColor = 'olive' then Result := clOlive
  else if AColor = 'navy' then Result := clNavy
  else if AColor = 'teal' then Result := clTeal
  else if AColor = 'aqua' then Result := clAqua;
end;

function ParseStrokeStyle(const AStrokeDashArray: string): Integer;
begin
  Result := 0; // psSolid по умолчанию
  
  if AStrokeDashArray = '' then Exit;
  
  if Pos('none', LowerCase(AStrokeDashArray)) > 0 then
    Result := 1 // psClear
  else if Pos('dash', LowerCase(AStrokeDashArray)) > 0 then
  begin
    if Pos('dot', LowerCase(AStrokeDashArray)) > 0 then
    begin
      if Pos('dot dot', LowerCase(AStrokeDashArray)) > 0 then
        Result := 5 // psDashDotDot
      else
        Result := 4; // psDashDot
    end
    else
      Result := 3; // psDash
  end
  else if Pos('dot', LowerCase(AStrokeDashArray)) > 0 then
    Result := 2; // psDot
end;

function ParseFillStyle(const AFill: string): Integer;
begin
  Result := 1; // bsClear по умолчанию
  
  if AFill = '' then Exit;
  
  if (AFill <> 'none') and (AFill <> '') then
    Result := 0; // Если есть цвет - Solid
end;

procedure ParseTransform(const ATransform: string; out TX, TY: Double);
var
  Temp: string;
  P: Integer;
begin
  TX := 0; TY := 0;
  if ATransform = '' then Exit;
  
  Temp := LowerCase(ATransform);
  P := Pos('translate(', Temp);
  if P > 0 then
  begin
    Temp := Copy(Temp, P + 10, Length(Temp));
    P := Pos(')', Temp);
    if P > 0 then
    begin
      Temp := Copy(Temp, 1, P - 1);
      P := Pos(',', Temp);
      if P > 0 then
      begin
        TX := StrToFloatDef(Trim(Copy(Temp, 1, P - 1)), 0);
        TY := StrToFloatDef(Trim(Copy(Temp, P + 1, Length(Temp))), 0);
      end
      else
        TX := StrToFloatDef(Trim(Temp), 0);
    end;
  end;
end;

function SVGToGED(const ASVGFile: string): TFiguresArray;
var
  Doc: TXMLDocument;
  Node, Child: TDOMNode;
  i: Integer;
  Figure: TFigureData;
  Points: TStringList;
  PointStr, Temp: string;
  j, k: Integer;
  X, Y, TX, TY: Double;
  AttrValue: string;
begin
  Result := nil;
  Points := TStringList.Create;
  try
    ReadXMLFile(Doc, ASVGFile);
    try
      Node := Doc.DocumentElement.FirstChild;
      while Assigned(Node) do
      begin
        if Node.NodeName = 'rect' then
        begin
          SetLength(Result, Length(Result) + 1);
          Figure.ClassName := 'TRectangle';
          SetLength(Figure.Points, 2);
          
          X := StrToFloatDef(GetAttrValue(Node, 'x'), 0);
          Y := StrToFloatDef(GetAttrValue(Node, 'y'), 0);
          
          Figure.Points[0].x := X;
          Figure.Points[0].y := Y;
          Figure.Points[1].x := X + StrToFloatDef(GetAttrValue(Node, 'width'), 100);
          Figure.Points[1].y := Y + StrToFloatDef(GetAttrValue(Node, 'height'), 100);
          
          Figure.PenColor := ColorToInt(GetAttrValue(Node, 'stroke'));
          Figure.PenWidth := StrToIntDef(GetAttrValue(Node, 'stroke-width'), 1);
          Figure.PenStyle := ParseStrokeStyle(GetAttrValue(Node, 'stroke-dasharray'));
          Figure.BrushColor := ColorToInt(GetAttrValue(Node, 'fill'));
          Figure.BrushStyle := ParseFillStyle(GetAttrValue(Node, 'fill'));
          
          // Проверяем на скругленный прямоугольник
          AttrValue := GetAttrValue(Node, 'rx');
          if AttrValue <> '' then
          begin
            Figure.ClassName := 'TRoundRectangle';
            Figure.Rounding := StrToIntDef(AttrValue, 10);
          end;
          
          Result[High(Result)] := Figure;
        end
        else if Node.NodeName = 'circle' then
        begin
          SetLength(Result, Length(Result) + 1);
          Figure.ClassName := 'TEllipse';
          SetLength(Figure.Points, 2);
          
          X := StrToFloatDef(GetAttrValue(Node, 'cx'), 0);
          Y := StrToFloatDef(GetAttrValue(Node, 'cy'), 0);
          Temp := GetAttrValue(Node, 'r');
          
          Figure.Points[0].x := X - StrToFloatDef(Temp, 50);
          Figure.Points[0].y := Y - StrToFloatDef(Temp, 50);
          Figure.Points[1].x := X + StrToFloatDef(Temp, 50);
          Figure.Points[1].y := Y + StrToFloatDef(Temp, 50);
          
          Figure.PenColor := ColorToInt(GetAttrValue(Node, 'stroke'));
          Figure.PenWidth := StrToIntDef(GetAttrValue(Node, 'stroke-width'), 1);
          Figure.PenStyle := ParseStrokeStyle(GetAttrValue(Node, 'stroke-dasharray'));
          Figure.BrushColor := ColorToInt(GetAttrValue(Node, 'fill'));
          Figure.BrushStyle := ParseFillStyle(GetAttrValue(Node, 'fill'));
          
          Result[High(Result)] := Figure;
        end
        else if Node.NodeName = 'ellipse' then
        begin
          SetLength(Result, Length(Result) + 1);
          Figure.ClassName := 'TEllipse';
          SetLength(Figure.Points, 2);
          
          X := StrToFloatDef(GetAttrValue(Node, 'cx'), 0);
          Y := StrToFloatDef(GetAttrValue(Node, 'cy'), 0);
          
          Figure.Points[0].x := X - StrToFloatDef(GetAttrValue(Node, 'rx'), 50);
          Figure.Points[0].y := Y - StrToFloatDef(GetAttrValue(Node, 'ry'), 50);
          Figure.Points[1].x := X + StrToFloatDef(GetAttrValue(Node, 'rx'), 50);
          Figure.Points[1].y := Y + StrToFloatDef(GetAttrValue(Node, 'ry'), 50);
          
          Figure.PenColor := ColorToInt(GetAttrValue(Node, 'stroke'));
          Figure.PenWidth := StrToIntDef(GetAttrValue(Node, 'stroke-width'), 1);
          Figure.PenStyle := ParseStrokeStyle(GetAttrValue(Node, 'stroke-dasharray'));
          Figure.BrushColor := ColorToInt(GetAttrValue(Node, 'fill'));
          Figure.BrushStyle := ParseFillStyle(GetAttrValue(Node, 'fill'));
          
          Result[High(Result)] := Figure;
        end
        else if Node.NodeName = 'line' then
        begin
          SetLength(Result, Length(Result) + 1);
          Figure.ClassName := 'TLine';
          SetLength(Figure.Points, 2);
          
          Figure.Points[0].x := StrToFloatDef(GetAttrValue(Node, 'x1'), 0);
          Figure.Points[0].y := StrToFloatDef(GetAttrValue(Node, 'y1'), 0);
          Figure.Points[1].x := StrToFloatDef(GetAttrValue(Node, 'x2'), 100);
          Figure.Points[1].y := StrToFloatDef(GetAttrValue(Node, 'y2'), 100);
          
          Figure.PenColor := ColorToInt(GetAttrValue(Node, 'stroke'));
          Figure.PenWidth := StrToIntDef(GetAttrValue(Node, 'stroke-width'), 1);
          Figure.PenStyle := ParseStrokeStyle(GetAttrValue(Node, 'stroke-dasharray'));
          Figure.BrushStyle := 1; // bsClear
          
          Result[High(Result)] := Figure;
        end
        else if (Node.NodeName = 'polyline') or (Node.NodeName = 'polygon') then
        begin
          SetLength(Result, Length(Result) + 1);
          
          if Node.NodeName = 'polyline' then
            Figure.ClassName := 'TPolyLine'
          else
            Figure.ClassName := 'TPolygon';
          
          Temp := GetAttrValue(Node, 'points');
          Points.Clear;
          
          // Простой парсинг точек
          Temp := StringReplace(Temp, ',', ' ', [rfReplaceAll]);
          Temp := StringReplace(Temp, '-', ' -', [rfReplaceAll]);
          Temp := Trim(Temp);
          
          while Pos('  ', Temp) > 0 do
            Temp := StringReplace(Temp, '  ', ' ', [rfReplaceAll]);
          
          Points.DelimitedText := Temp;
          
          SetLength(Figure.Points, Points.Count div 2);
          for j := 0 to (Points.Count div 2) - 1 do
          begin
            Figure.Points[j].x := StrToFloatDef(Points[j * 2], 0);
            Figure.Points[j].y := StrToFloatDef(Points[j * 2 + 1], 0);
          end;
          
          Figure.PenColor := ColorToInt(GetAttrValue(Node, 'stroke'));
          Figure.PenWidth := StrToIntDef(GetAttrValue(Node, 'stroke-width'), 1);
          Figure.PenStyle := ParseStrokeStyle(GetAttrValue(Node, 'stroke-dasharray'));
          Figure.BrushColor := ColorToInt(GetAttrValue(Node, 'fill'));
          Figure.BrushStyle := ParseFillStyle(GetAttrValue(Node, 'fill'));
          
          Result[High(Result)] := Figure;
        end
        else if Node.NodeName = 'text' then
        begin
          SetLength(Result, Length(Result) + 1);
          Figure.ClassName := 'TText';
          SetLength(Figure.Points, 1);
          
          Figure.Points[0].x := StrToFloatDef(GetAttrValue(Node, 'x'), 0);
          Figure.Points[0].y := StrToFloatDef(GetAttrValue(Node, 'y'), 0);
          
          // Применяем трансформацию
          ParseTransform(GetAttrValue(Node, 'transform'), TX, TY);
          Figure.Points[0].x := Figure.Points[0].x + TX;
          Figure.Points[0].y := Figure.Points[0].y + TY;
          
          // Получаем текст
          if Node.FirstChild <> nil then
            Figure.Text := Node.FirstChild.NodeValue;
          
          // Парсим стили
          Figure.PenColor := ColorToInt(GetAttrValue(Node, 'fill'));
          Figure.FontName := GetAttrValue(Node, 'font-family');
          if Figure.FontName = '' then
            Figure.FontName := 'Arial';
            
          AttrValue := GetAttrValue(Node, 'font-size');
          if AttrValue <> '' then
            Figure.FontSize := StrToIntDef(AttrValue, 12)
          else
            Figure.FontSize := 12;
          
          Figure.PenWidth := 1;
          Figure.BrushStyle := 1; // bsClear
          
          Result[High(Result)] := Figure;
        end;
        
        Node := Node.NextSibling;
      end;
      
    finally
      Doc.Free;
    end;
  finally
    Points.Free;
  end;
end;

procedure SaveAsGED(const AFigures: TFiguresArray; const AFileName: string);
var
  Data: TJSONObject;
  FiguresArr: TJSONArray;
  PointsArr: TJSONArray;
  i, j: Integer;
  F: TFigureData;
  JSONObj: TJSONObject;
  ViewState: TJSONObject;
begin
  Data := TJSONObject.Create;
  try
    FiguresArr := TJSONArray.Create;
    
    for i := 0 to High(AFigures) do
    begin
      F := AFigures[i];
      
      JSONObj := TJSONObject.Create;
      JSONObj.Add('Class', F.ClassName);
      
      PointsArr := TJSONArray.Create;
      for j := 0 to High(F.Points) do
        PointsArr.Add(TJSONObject.Create(['x', F.Points[j].x, 'y', F.Points[j].y]));
      JSONObj.Add('Points', PointsArr);
      
      JSONObj.Add('PenStyle', F.PenStyle);
      JSONObj.Add('PenColor', F.PenColor);
      JSONObj.Add('PenWidth', F.PenWidth);
      JSONObj.Add('BrushStyle', F.BrushStyle);
      JSONObj.Add('BrushColor', F.BrushColor);
      
      if F.ClassName = 'TRoundRectangle' then
        JSONObj.Add('Rounding', F.Rounding);
      
      if F.ClassName = 'TText' then
      begin
        JSONObj.Add('Text', F.Text);
        JSONObj.Add('FontName', F.FontName);
        JSONObj.Add('BaseFontSize', F.FontSize);
      end;
      
      FiguresArr.Add(JSONObj);
    end;
    
    Data.Add('GraphicEditor', FiguresArr);
    
    // Добавляем состояние вида
    ViewState := TJSONObject.Create;
    ViewState.Add('scale', 1.0);
    ViewState.Add('offsetX', 0.0);
    ViewState.Add('offsetY', 0.0);
    Data.Add('viewState', ViewState);
    
    with TStringList.Create do
    begin
      Text := Data.FormatJSON;
      SaveToFile(AFileName);
      Free;
    end;
    
  finally
    Data.Free;
  end;
end;

var
  InputFile, OutputFile: string;
  Figures: TFiguresArray;
begin
  if ParamCount < 1 then
  begin
    Writeln('SVG to GED Converter');
    Writeln('Usage: svg2ged.exe input.svg [output.ged]');
    Halt(1);
  end;
  
  InputFile := ParamStr(1);
  if not FileExists(InputFile) then
  begin
    Writeln('Error: File not found - ', InputFile);
    Halt(1);
  end;
  
  if ParamCount >= 2 then
    OutputFile := ParamStr(2)
  else
    OutputFile := ChangeFileExt(InputFile, '.ged');
  
  try
    Writeln('Converting ', InputFile, ' -> ', OutputFile);
    Figures := SVGToGED(InputFile);
    SaveAsGED(Figures, OutputFile);
    Writeln('Done. Converted ', Length(Figures), ' figures.');
  except
    on E: Exception do
      Writeln('Error: ', E.Message);
  end;
end.
Было Svg

Код: Выделить всё

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg xmlns="http://www.w3.org/2000/svg"
     width="467" height="462">
  <rect x="80" y="60" width="250" height="250" rx="20"
     fill="#ff0000" style="stroke:#000000;stroke-width:2px;" />
  
  <rect x="141" y="121" width="251" height="251" rx="4"
      fill="#0000ff" style=" stroke:#000000; stroke-width:2px;
      fill-opacity:0.7;" />

  <rect x="140" y="120" width="250" height="250" rx="40"
     fill="#00ff00" style="stroke:#0000cc; stroke-width:5px;
      fill-opacity:1.0;" />
   <circle cx="100" cy="100" r="50" stroke="black"
    stroke-width="5" fill="red" />
  <polygon
    points=" 60,100 100,180 140,140 180,180 220,100"
    fill="green" stroke-width="2"  />
</svg>
Стало ged

Код: Выделить всё

 
 {
  "GraphicEditor" : [
    {
      "Class" : "TRoundRectangle",
      "Points" : [
        {
          "x" : 8.0000000000000000E+001,
          "y" : 6.0000000000000000E+001
        },
        {
          "x" : 3.3000000000000000E+002,
          "y" : 3.1000000000000000E+002
        }
      ],
      "PenStyle" : 0,
      "PenColor" : 0,
      "PenWidth" : 1,
      "BrushStyle" : 0,
      "BrushColor" : 255,
      "Rounding" : 20
    },
    {
      "Class" : "TRoundRectangle",
      "Points" : [
        {
          "x" : 1.4100000000000000E+002,
          "y" : 1.2100000000000000E+002
        },
        {
          "x" : 3.9200000000000000E+002,
          "y" : 3.7200000000000000E+002
        }
      ],
      "PenStyle" : 0,
      "PenColor" : 0,
      "PenWidth" : 1,
      "BrushStyle" : 0,
      "BrushColor" : 16711680,
      "Rounding" : 4
    },
    {
      "Class" : "TRoundRectangle",
      "Points" : [
        {
          "x" : 1.4000000000000000E+002,
          "y" : 1.2000000000000000E+002
        },
        {
          "x" : 3.9000000000000000E+002,
          "y" : 3.7000000000000000E+002
        }
      ],
      "PenStyle" : 0,
      "PenColor" : 0,
      "PenWidth" : 1,
      "BrushStyle" : 0,
      "BrushColor" : 65280,
      "Rounding" : 40
    },
    {
      "Class" : "TEllipse",
      "Points" : [
        {
          "x" : 5.0000000000000000E+001,
          "y" : 5.0000000000000000E+001
        },
        {
          "x" : 1.5000000000000000E+002,
          "y" : 1.5000000000000000E+002
        }
      ],
      "PenStyle" : 0,
      "PenColor" : 0,
      "PenWidth" : 5,
      "BrushStyle" : 0,
      "BrushColor" : 255
    },
    {
      "Class" : "TPolygon",
      "Points" : [
        {
          "x" : 6.0000000000000000E+001,
          "y" : 1.0000000000000000E+002
        },
        {
          "x" : 1.0000000000000000E+002,
          "y" : 1.8000000000000000E+002
        },
        {
          "x" : 1.4000000000000000E+002,
          "y" : 1.4000000000000000E+002
        },
        {
          "x" : 1.8000000000000000E+002,
          "y" : 1.8000000000000000E+002
        },
        {
          "x" : 2.2000000000000000E+002,
          "y" : 1.0000000000000000E+002
        }
      ],
      "PenStyle" : 0,
      "PenColor" : 0,
      "PenWidth" : 2,
      "BrushStyle" : 0,
      "BrushColor" : 32768
    }
  ],
  "viewState" : {
    "scale" : 1.0000000000000000E+000,
    "offsetX" : 0.0000000000000000E+000,
    "offsetY" : 0.0000000000000000E+000
  }
}

Изображение
Ответить