пятница, 27 ноября 2015 г.

Простой AutoLoad LookUpEdit.

Возникла задача загружать в LookUpEdit значения постепенно, в зависимости от подстроки.
Простейшее решение было найдено на сайте самого DX. Решение прекрасно работает, но дело в том, что поиск в LookUpEdit не поддерживает contains и ищет с начала строки. В примере это решено дописыванием к началу строки искомой подстроки:

      private void GetAutoCompleteList(AutoCompleteListEventArgs e) {
          e.AutoCompleteList.Clear();
          for(int i = 0; i < 10; i++) {
              e.AutoCompleteList.Add(String.Format("{0}{1}", e.AutoSearchText, RandomString(5, true)));
          }
      }
Выглядит это некрасиво. Поэтому что бы не показывать лишние данные нужно внедрить contains.
Для этого переопределим DataAdapter. Пример на VB был найдет здесь и осталось только переписать его на C#.


Сам DataAdapter:

    public class MyLookUpListDataAdapter : LookUpListDataAdapter
    {
        public MyLookUpListDataAdapter(AutoCompleteLookUpEditRepositoryItem item) : base(item)
        {

        }

        public override string FilterField
        {
            get
            {
                if ((Item as AutoCompleteLookUpEditRepositoryItem).FilterField == string.Empty)
                {
                    return base.FilterField;
                }
                return (Item as AutoCompleteLookUpEditRepositoryItem).FilterField;
            }
        }

        protected override string CreateFilterExpression()
        {
            dynamic foo = FilterField;
            if (string.IsNullOrEmpty(FilterPrefix))
            {
                return string.Empty;
            }
            string likeClause = DevExpress.Data.Filtering.Helpers.LikeData.CreateStartsWithPattern(FilterPrefix);
            return new BinaryOperator(FilterField, "%" + likeClause + "%", BinaryOperatorType.Like).ToString();
        }
    }
Так нужно внести изменения в класс AutoCompleteLookUpEditRepositoryItem:
        public string FilterField { set; get; }

        protected override LookUpListDataAdapter CreateDataAdapter()
        {
            return new MyLookUpListDataAdapter(this);
        }

вторник, 10 февраля 2015 г.

Simple Excel report generation with OpenXML.


I'd needed in simple solution to export a search results into Excel in .net application.

At first i create ViewModel using simple types only:
 public class MyReportItem
    {
        public string ObjectType{ get; set; }
        public string Name{ get; set; }
        public string Owner{ get; set; }
        public string District{ set; get; }
        public string Street{ set; get; }
        public string Address{ get; set; }
        public string ObjectContacts{ get; set; }
        public string Specilization{ get; set; }
    }

My objective - create a simple report so i don't want use document template. So i create excel document by OpenXML in stream.

       public MemoryStream CreateReport(List report)
       {
           using (var reader = new MemoryStream())
           {
               var spreadsheetDocument = SpreadsheetDocument.
                   Create(reader, SpreadsheetDocumentType.Workbook);

               var workbookpart = spreadsheetDocument.AddWorkbookPart();
               workbookpart.Workbook = new Workbook();

               var stylesPart = spreadsheetDocument.WorkbookPart.AddNewPart();
               stylesPart.Stylesheet = GenerateStyleSheet();

               stylesPart.Stylesheet.Save();

               var worksheetPart = workbookpart.AddNewPart();

               var sheets = spreadsheetDocument.WorkbookPart.Workbook.AppendChild(new Sheets());

               var sheet = new Sheet
                   {
                   Id = spreadsheetDocument.WorkbookPart.
                       GetIdOfPart(worksheetPart),
                   SheetId = 1,
                   Name = "My sheet"
               };
               sheets.Append(sheet);

               var sd = new SheetData();
               var ws = new Worksheet();
               var columns = new Columns();


               columns.Append(CreateColumnData(1, 35, 30));
               ws.Append(columns);
               ws.Append(sd);

               worksheetPart.Worksheet = ws;
                GenerateColumnsCaptions(ws, report);

               workbookpart.Workbook.Save();

               spreadsheetDocument.Close();

               return reader;
           }

Part with columns not required but i want to set a columns width. and here is method to add Columnto Columns:

        public static Column CreateColumnData(UInt32 startColumnIndex, UInt32 endColumnIndex, double columnWidth)
        {
            var column = new Column
            {
                Min = startColumnIndex,
                Max = endColumnIndex,
                Width = columnWidth,
                CustomWidth = true
            };
            return column;
        }

Here is interesting thing. Columns in Excel table make only visual aspect of table, for setting widht of cells in this column. More, if your cell have a address A4 it's mean that cell located in fourth row, and in this row this cell located on foremost. Columns not binded this cell.

So now we have a empty document, let's fill it with data:

       public Worksheet GenerateColumnsCaptions(Worksheet ws, ReportExcel report)
       {
           var sheetData = ws.GetFirstChild();
           uint rowIntIter = 1; //row iterator
           var colCharIter = 'A'; //column iterator

           var row = new Row { RowIndex = 1 };

           var fields = typeof (MyReportItem).GetFields(
               BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
           var names = Array.ConvertAll(fields, field => field.Name).ToList();

           var trimedNames = names.Select(name => name.Substring(1, name.IndexOf(">", StringComparison.Ordinal)-1)).ToList();
           foreach (var fieldName in trimedNames)
           {
               var newCell = new Cell { CellReference = colCharIter + rowIntIter.ToString(CultureInfo.InvariantCulture), StyleIndex = 1 };
               row.AppendChild(newCell);
               newCell.CellValue = new CellValue(fieldName);
               newCell.DataType = new EnumValue(CellValues.String);

               colCharIter++; // next column
           }

           sheetData.Append(row);

           colCharIter = 'A'; // reset column iterator
           foreach (var объект in report.Объекты)
           {
               rowIntIter++; // next row
               var rowItem = new Row { RowIndex = rowIntIter };

               Type t = объект.Объект.GetType();
               foreach (PropertyInfo info in t.GetProperties())
               {
                   var value = info.GetValue(объект.Объект, null);
                   var valueStr = "-";

                   if (value != null)
                   {
                       valueStr = value.ToString();

                       if (value is DateTime)
                       {
                           var date = (DateTime)value;
                           valueStr = date.ToShortDateString();
                       }
                       if (value is bool)
                       {
                           var date = (bool)value;

                           valueStr = date ? "Yes" : "No";
                       }
                   }
                   rowItem.AppendChild(ReportsRoutines.CreateCell(valueStr, colCharIter + rowIntIter.ToString(CultureInfo.InvariantCulture)));
                   colCharIter++;
               }

               sheetData.Append(rowItem);

               colCharIter = 'A'; // finished with this object so reset column iterator
           }
           return ws;
       }

At first create row with columns captions:

      var colCharIter = 'A';
      var row = new Row { RowIndex = 1 };

      var fields = typeof (MyReportItem).GetFields(
      BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
      var names = Array.ConvertAll(fields, field => field.Name).ToList();

      var trimedNames = names.Select(name => name.Substring(1, name.IndexOf(">", StringComparison.Ordinal)-1)).ToList();
      foreach (var fieldName in trimedNames)
      {
         var newCell = new Cell { CellReference = colCharIter + rowIntIter.ToString(CultureInfo.InvariantCulture), StyleIndex = 1 };
         row.AppendChild(newCell);
         newCell.CellValue = new CellValue(fieldName);
         newCell.DataType = new EnumValue(CellValues.String);

         colCharIter++;
       }

       sheetData.Append(row);

Here i collect my view model's fields names and after trimming garabage setting it one by one in row's cells. Fields are taken in the order in which they appear in class. And if you waht to reorder columns you need just reorder fields in class.

After i getting started to fill document with data:

     colCharIter = 'A';
     foreach (var obj in report)
     {
        rowIntIter++;
        var rowItem = new Row { RowIndex = rowIntIter };

        Type t = obj .GetType();
        foreach (PropertyInfo info in t.GetProperties())
        {
           var value = info.GetValue(obj, null);
           var valueStr = "-";

           if (value != null)
           {
              valueStr = value.ToString();

              if (value is DateTime)
              {
                  var date = (DateTime)value;
                  valueStr = date.ToShortDateString();
               }
               if (value is bool)
               {
                  var date = (bool)value;

                  valueStr = date ? "Yes" : "No";
                }
            }
            rowItem.AppendChild(ReportsRoutines.CreateCell(valueStr, colCharIter + rowIntIter.ToString(CultureInfo.InvariantCulture)));
                   colCharIter++;
          }

          sheetData.Append(rowItem);

          colCharIter = 'A';
        }

Here i iterate through view model fileds and take it's values.

After you can save document using something like:

    var saveFileDialog = new SaveFileDialog { Filter = "*.xlsx|*.xlsx", Title = "Save as..." };
    File.WriteAllBytes(saveFileDialog.FileName, reader.ToArray());

воскресенье, 23 ноября 2014 г.

Копирование элементов макета печати ИнГео.

Работа с макетом печати не очень хорошо освещена в документации к ИнГео, что странно, потому как по крайней мере мне показалась реализация макета печати не очень нативной. И это даже на пользовательском уровне, например работа с таблицами вообще аттас.
Ну да ладно, все это преодолимо. Более интересная задача с которой пришлось столкнутся - это создание макета программно.

Но прежде скажу некоторые детали. В макет печати можно включить несколько видов объектов:

  • Карта
  • Прямоугольник
  • Эллипс
  • Линия
  • Рисунок
  • Текст
  • Таблица

Вот например макет состоящий из участка карты и таблицы:


Теперь займемся клонированием объектов макета. Начнем с простого - с Рисунка. Нужно взять копируемый объект из макета и затем создать новый, пустой рисунок:

    var sourceImage = (IInPicturePictureFigure)MyLayoutWindow.Figures.Find("imageName");
    var targetImage = MyLayoutWindow.Figures.Add(TInPictureFigureType.inftPicture) as IInPicturePictureFigure;
    СкопироватьРисунок(targetImage , sourceImage );
А вот и сам метод для копирования:
     //Рисунок
     public static IInPicturePictureFigure СкопироватьРисунок(IInPicturePictureFigure target, IInPicturePictureFigure source)
     {
        target.Width = source.Width;
        target.Height = source.Height;

        target.Picture = source.Picture;
        target.Stretch = source.Stretch;
        target.HorAlign = source.HorAlign;
        target.VerAlign = source.VerAlign;
        target.TransparentBack = source.TransparentBack;

        target.Pen.Mode = source.Pen.Mode;
        target.Pen.Style = source.Pen.Style;
        target.Pen.WidthInMM = source.Pen.WidthInMM;
        target.Pen.Color = source.Pen.Color;

        target.Brush.HatchColor = source.Brush.HatchColor;
        target.Brush.BackColor = source.Brush.BackColor;
        target.Brush.Transparency = source.Brush.Transparency;
        target.Brush.Style = source.Brush.Style;

        return target;
      }

Как видите метод копирует свойства объекта из существующего в новый. Уже после такого копирования можно установить положение объекта на карте пользуясь свойствами Bottom и Left.
Для остальных объектов макета печати используются аналогичные методы поэтому приведу еще один пример для Прямоугольника:

      //Прямоугольник
      public static IInPictureRectFigure СкопироватьПрямоугольник(IInPictureRectFigure target, IInPictureRectFigure source)
      {
          target.Width = source.Width;
          target.Height = source.Height;

          target.Pen.Mode = source.Pen.Mode;
          target.Pen.Style = source.Pen.Style;
          target.Pen.WidthInMM = source.Pen.WidthInMM;
          target.Pen.Color = source.Pen.Color;

          target.Brush.HatchColor = source.Brush.HatchColor;
          target.Brush.BackColor = source.Brush.BackColor;
          target.Brush.Transparency = source.Brush.Transparency;
          target.Brush.Style = source.Brush.Style;

          return target;
      }

Немного по другому обстоит дело с Таблицей. Дело в том, что у этого объекта есть два набора параметров: дефолтные - находятся в левой панели, и специальные - находится в контекстном меню в Редакторе таблицы.
Дефолтные настройки позволяют настроить таблицу в целом, а так же сделать стиль по умолчанию, который будет применяться ко всем строкам/столбцам/ячейкам. Поэтому если нужно создать таблицу с неизвестного в заранее размера, то стиль нужно задавать именно в левой панели.
Но у шапки таблицы, стиль обычно отличен от стиля остальных ячеек, например первая строка может быть написана болдом или иметь цветовую заливку. Тут в дело вступает Редактор таблицы, он позволяет настроить каждую отдельную строку, колонку или ячейку по своему. Кроме того стандартный текст, для той же шапки таблицы, то же указывается в Редакторе.

Получается чтобы полностью скопировать стиль таблицы нужно копировать два набора параметров.
        //Таблица
        public static IInPictureGridFigure СкопироватьТаблицу(IInPictureGridFigure target, IInPictureGridFigure source)
        {
            target.ColCount = source.ColCount;
            target.RowCount = source.RowCount;
            target.Width = source.Width;
            target.Height = source.Height;


            var targetGridFormat = target.GridFormat;
            var sourceGridFormat = source.GridFormat;

            if (sourceGridFormat.ContainsKinds(TInGridFormatKind.ingfLeftPen))
            {
                targetGridFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfLeftPen, targetGridFormat, sourceGridFormat);
            }

            if (sourceGridFormat.ContainsKinds(TInGridFormatKind.ingfRightPen))
            {
                targetGridFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfRightPen, targetGridFormat, sourceGridFormat);
            }

            if (sourceGridFormat.ContainsKinds(TInGridFormatKind.ingfTopPen))
            {
                targetGridFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfTopPen, targetGridFormat, sourceGridFormat);
            }

            if (sourceGridFormat.ContainsKinds(TInGridFormatKind.ingfBottomPen))
            {
                targetGridFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfBottomPen, targetGridFormat, sourceGridFormat);
            }
            targetGridFormat.Update();

            for (int i = 0; i < source.ColCount; i++)
            {
                var targetColumnFormat = target.GetFormat(i, -1);
                var sourceColumnFormat = source.GetFormat(i, -1);

                var defaultSourceColumnFormat = source.ColFormat;
                var defaultTargetColumnFormat = target.ColFormat;

                if (sourceColumnFormat.ContainsKinds(TInGridFormatKind.ingfColWidth))
                {
                    targetColumnFormat = СкопироватьЭлементSize(TInGridFormatKind.ingfColWidth, targetColumnFormat, sourceColumnFormat);
                }
                else
                {
                    defaultTargetColumnFormat = СкопироватьЭлементSize(TInGridFormatKind.ingfColWidth, defaultTargetColumnFormat, defaultSourceColumnFormat);
                }

                if (sourceColumnFormat.ContainsKinds(TInGridFormatKind.ingfFont))
                {
                    targetColumnFormat = СкопироватьЭлементFont(TInGridFormatKind.ingfFont, targetColumnFormat, sourceColumnFormat);
                }

                if (sourceColumnFormat.ContainsKinds(TInGridFormatKind.ingfTextFormat))
                {
                    targetColumnFormat = СкопироватьЭлементTextFormat(TInGridFormatKind.ingfFont, targetColumnFormat, sourceColumnFormat);
                }

                if (sourceColumnFormat.ContainsKinds(TInGridFormatKind.ingfLeftPen))
                {
                    targetColumnFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfLeftPen, targetColumnFormat, sourceColumnFormat);
                }
                else
                {
                    defaultTargetColumnFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfLeftPen, defaultTargetColumnFormat, defaultSourceColumnFormat);
                }

                if (sourceColumnFormat.ContainsKinds(TInGridFormatKind.ingfRightPen))
                {
                    targetColumnFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfRightPen, targetColumnFormat, sourceColumnFormat);
                }
                else
                {
                    defaultTargetColumnFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfRightPen, defaultTargetColumnFormat, defaultSourceColumnFormat);
                }

                if (sourceColumnFormat.ContainsKinds(TInGridFormatKind.ingfTopPen))
                {
                    targetColumnFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfTopPen, targetColumnFormat, sourceColumnFormat);
                }
                else
                {
                    defaultTargetColumnFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfTopPen, defaultTargetColumnFormat, defaultSourceColumnFormat);
                }

                if (sourceColumnFormat.ContainsKinds(TInGridFormatKind.ingfBottomPen))
                {
                    targetColumnFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfBottomPen, targetColumnFormat, sourceColumnFormat);
                }
                else
                {
                    defaultTargetColumnFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfBottomPen, defaultTargetColumnFormat, defaultSourceColumnFormat);
                }

                defaultTargetColumnFormat.Update();
                targetColumnFormat.Update();
            }

            for (int i = 0; i < source.RowCount; i++)
            {
                var targetRowFormat = target.GetFormat(-1, i);
                var sourceRowFormat = source.GetFormat(-1, i);

                var defaultSourceRowFormat = source.RowFormat;
                var defaultTargetRowFormat = target.RowFormat;

                if (sourceRowFormat.ContainsKinds(TInGridFormatKind.ingfRowHeight))
                {
                    targetRowFormat = СкопироватьЭлементSize(TInGridFormatKind.ingfColWidth, targetRowFormat, sourceRowFormat);
                }
                else
                {
                    defaultTargetRowFormat = СкопироватьЭлементSize(TInGridFormatKind.ingfColWidth, defaultTargetRowFormat, defaultSourceRowFormat);
                }


                if (sourceRowFormat.ContainsKinds(TInGridFormatKind.ingfFont))
                {
                    targetRowFormat = СкопироватьЭлементFont(TInGridFormatKind.ingfFont, targetRowFormat, sourceRowFormat);
                }

                if (sourceRowFormat.ContainsKinds(TInGridFormatKind.ingfTextFormat))
                {
                    targetRowFormat = СкопироватьЭлементTextFormat(TInGridFormatKind.ingfFont, targetRowFormat, sourceRowFormat);
                }

                if (sourceRowFormat.ContainsKinds(TInGridFormatKind.ingfLeftPen))
                {
                    targetRowFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfLeftPen, targetRowFormat, sourceRowFormat);
                }
                else
                {
                    defaultTargetRowFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfLeftPen, defaultTargetRowFormat, defaultSourceRowFormat);
                }

                if (sourceRowFormat.ContainsKinds(TInGridFormatKind.ingfRightPen))
                {
                    targetRowFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfRightPen, targetRowFormat, sourceRowFormat);
                }
                else
                {
                    defaultTargetRowFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfRightPen, defaultTargetRowFormat, defaultSourceRowFormat);
                }

                if (sourceRowFormat.ContainsKinds(TInGridFormatKind.ingfTopPen))
                {
                    targetRowFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfTopPen, targetRowFormat, sourceRowFormat);
                }
                else
                {
                    defaultTargetRowFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfTopPen, defaultTargetRowFormat, defaultSourceRowFormat);
                }

                if (sourceRowFormat.ContainsKinds(TInGridFormatKind.ingfBottomPen))
                {
                    targetRowFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfBottomPen, targetRowFormat, sourceRowFormat);
                }
                else
                {
                    defaultTargetRowFormat = СкопироватьЭлементPen(TInGridFormatKind.ingfBottomPen, defaultTargetRowFormat, defaultSourceRowFormat);
                }

                targetRowFormat.Update();
                defaultTargetRowFormat.Update();
            }

            for (int i = 0; i < source.ColCount; i++)
            {
                for (int j = 0; j < source.RowCount; j++)
                {
                    var targetCellFormat = target.GetFormat(i, j);
                    var sourceCellFormat = source.GetFormat(i, j);

                    var defaultSourceCellFormat = source.CellFormat;
                    var defaultTargetCellFormat = target.CellFormat;

                    if (sourceCellFormat.ContainsKinds(TInGridFormatKind.ingfFont))
                    {
                        targetCellFormat = СкопироватьЭлементFont(TInGridFormatKind.ingfFont, targetCellFormat, sourceCellFormat);
                    }
                    else
                    {
                        defaultTargetCellFormat = СкопироватьЭлементFont(TInGridFormatKind.ingfFont, defaultTargetCellFormat, defaultSourceCellFormat);
                    }

                    if (sourceCellFormat.ContainsKinds(TInGridFormatKind.ingfTextFormat))
                    {
                        targetCellFormat = СкопироватьЭлементTextFormat(TInGridFormatKind.ingfFont, targetCellFormat, sourceCellFormat);
                    }
                    else
                    {
                        defaultTargetCellFormat = СкопироватьЭлементTextFormat(TInGridFormatKind.ingfFont, defaultTargetCellFormat, defaultSourceCellFormat);
                    }

                    if (sourceCellFormat.ContainsKinds(TInGridFormatKind.ingfBrush))
                    {
                        targetCellFormat = СкопироватьЭлементBrush(TInGridFormatKind.ingfFont, targetCellFormat, sourceCellFormat);
                    }
                    else
                    {
                        defaultTargetCellFormat = СкопироватьЭлементBrush(TInGridFormatKind.ingfFont, defaultTargetCellFormat, defaultSourceCellFormat);
                    }

                    if (sourceCellFormat.ContainsKinds(TInGridFormatKind.ingfLeftIndent))
                    {
                        targetCellFormat = СкопироватьЭлементSize(TInGridFormatKind.ingfColWidth, targetCellFormat, sourceCellFormat);
                    }
                    else
                    {
                        defaultTargetCellFormat = СкопироватьЭлементSize(TInGridFormatKind.ingfColWidth, defaultTargetCellFormat, defaultSourceCellFormat);
                    }

                    targetCellFormat.Update();
                    defaultTargetCellFormat.Update();
                }
            }

            for (int i = 0; i < source.ColCount; i++)
            {
                for (int j = 0; j < source.RowCount; j++)
                {
                    target.Text[i, j] = source.Text[i, j];
                }
            }

            return target;
        }

Метод состоит из трех циклов по строкам (RowCount), столбцам (ColCount), и ячейкам. Для каждого элемента определяется есть ли у него специальный формат с помощью ContainsKinds(). Если специальный формат есть, то в новую таблицу копируется он, если нет то копируется дефолтный формат. Для удобства методы копирования отдельных элементов формата вынесены в отдельные методы:

        private static IInGridFormat СкопироватьЭлементPen(TInGridFormatKind inGridFormatKind, IInGridFormat target, IInGridFormat source)
        {
            target.Pen[inGridFormatKind].Style = source.Pen[inGridFormatKind].Style;
            target.Pen[inGridFormatKind].Color = source.Pen[inGridFormatKind].Color;
            target.Pen[inGridFormatKind].Mode = source.Pen[inGridFormatKind].Mode;
            target.Pen[inGridFormatKind].WidthInMM = source.Pen[inGridFormatKind].WidthInMM;

            return target;
        }

        private static IInGridFormat СкопироватьЭлементFont(TInGridFormatKind inGridFormatKind, IInGridFormat target, IInGridFormat source)
        {
            target.Font[inGridFormatKind].Size = source.Font[inGridFormatKind].Size;
            target.Font[inGridFormatKind].Style = source.Font[inGridFormatKind].Style;

            return target;
        }

        private static IInGridFormat СкопироватьЭлементBrush(TInGridFormatKind inGridFormatKind, IInGridFormat target, IInGridFormat source)
        {
            target.Brush[TInGridFormatKind.ingfBrush].BackColor = source.Brush[TInGridFormatKind.ingfBrush].BackColor;
            target.Brush[TInGridFormatKind.ingfBrush].HatchColor = source.Brush[TInGridFormatKind.ingfBrush].HatchColor;
            target.Brush[TInGridFormatKind.ingfBrush].Transparency = source.Brush[TInGridFormatKind.ingfBrush].Transparency;

            return target;
        }

        private static IInGridFormat СкопироватьЭлементSize(TInGridFormatKind inGridFormatKind, IInGridFormat target,
                                                      IInGridFormat source)
        {
            target.Size[inGridFormatKind] = source.Size[inGridFormatKind];

            return target;
        }

        private static IInGridFormat СкопироватьЭлементTextFormat(TInGridFormatKind inGridFormatKind, IInGridFormat target,
                                              IInGridFormat source)
        {
            target.TextFormat[inGridFormatKind] = source.TextFormat[inGridFormatKind];

            return target;
        }

В заключение скажу, что методы копирования не являются полными, я копировал только те элементы формата, которые использовались в моем макете печати.


вторник, 9 сентября 2014 г.

Кириллица в Mapfish print plugin.


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

Для отображения кириллицы я использую кодировку Identity-H. Но ее одной недостаточно, если попробовать напечатать такой пример:

   - !text
       text: "Привет"
       fontEncoding: Identity-H
       align: center

То ничего не напечатается, будет просто пустое место.
Для решения этой проблемы нужно подключить шрифт работающий с данной кодировкой. Мой выбор пал на FreeSans

Подключаются шрифты в отдельном блоке:

scales:
   ....
fonts: 
    - 'E:\GeoServer 2.5.1\data_dir\printing\FreeSans.ttf'
    - 'E:\GeoServer 2.5.1\data_dir\printing\FreeSansOblique.ttf'
hosts:
   ....
layouts:
   ....
Подключение шрифта к элементу:
   - !text
       text: "Привет"
       fontEncoding: Identity-H
       font: FreeSans
       align: center
Теперь все должно работать.

Так же скажу, что подключить шрифты к легенде мне не удалось. Легенда выводится криво - имена стилей показывают кириллицу ,а вот имена слоев нет.
В работе использовалась связка Geoserver 2.5.2 и Print plugin 1.2

воскресенье, 24 августа 2014 г.

Rotation text in line's start point by attribute

I needed to create SLD style for lines with text rotation on angle equals line azimuth in start point of line. Like this:

Data

My table creation script:

CREATE TABLE annotations
(
  gid serial NOT NULL,
  annotation character varying(250),
  the_geom geometry,
  angle character varying(20) DEFAULT 0,
  CONSTRAINT annotations_pkey PRIMARY KEY (gid),
  CONSTRAINT enforce_dims_the_geom CHECK (st_ndims(the_geom) = 2),
  CONSTRAINT enforce_srid_the_geom CHECK (st_srid(the_geom) = 4326)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE annotations
  OWNER TO postgres;

"angle" field - contains line azimuth, to calculate it i use trigger:

CREATE TRIGGER set_angle
  BEFORE INSERT OR UPDATE
  ON annotations
  FOR EACH ROW
  EXECUTE PROCEDURE setangle();

And function:

CREATE OR REPLACE FUNCTION setangle()
  RETURNS trigger AS
$BODY$
BEGIN
   NEW.angle := degrees(
                             ST_Azimuth(
                                ST_Transform(ST_StartPoint(NEW.the_geom),900913)
                              , ST_Transform(ST_EndPoint(NEW.the_geom),900913)
                             )
                          ) - 90;
   RETURN NEW;
END
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION setangle()
  OWNER TO postgres;

As you can notice my table SRID=4326, but in calculation points transform into SRID=900913. It's becouse my application map projection is EPSG:900913. If do not transform point to projection what you will show this table you get difference between line azimuth and angle field value:

Style

Here is my SLD style:



  
    Annotatioans
    
      Annotations
      Annotations white text
      
              
        
          
            
              the_geom
            
          
          
           
             Arial
             fontSize
             normal
             bold
           
          
           
             
               0.0
               0.5
             
             
               0
               5
             
             
              rotationAngle
             
           
          
          
            1
            
              #000000
            
          
          
            #FFFFFF
          
          10
          yes
        
        
          
            #000000
          
        
      
    
  
 

Main part here is Rotation block:


  rotationAngle


четверг, 12 июня 2014 г.

Some sld styles.


Empty star with default marks

For this needed create three point symbolizers with star mark.


    
     
      
       star
       
        #000000
       
      
      18
     
    
    
     
      
       star
       
        #FF0000
       
      
      16
     
    
    
     
      
       star
       
        #FFFFFF
       
      
      10
     
    

All three point symbolizers pretty same, just difference in size and color. But make sure that you put a smallest makr on the top and biggest on down.

Result:


Double dashed line

It's a line dashed with two vertical lines. For this we a needed create three line symbolizers. One with line and two with vertline marks.


    
     
      #00FF00
     
    
    
     
      
       
        
         shape://vertline
         
          #00FF00
          1
         
        
        10
       
      
      10 30
     
    
    
     
      
       
        
         shape://vertline
         
          #00FF00
          1
         
        
        10
       
      
      10 30
      5
     
    

My vertlines is a 1 pixel in width and 10 pixels in lenght. Parameter stroke-dasharray set a distance bitween marks, in my case 30 pixels. Im not sure that clearly know what meen first number 10. Second mark same but with stroke-dashoffset, this paremeter make a offset from the beginning of the line.


Result:

воскресенье, 6 апреля 2014 г.

Simple WMS server using MapServer.

WMS Server

In last time i was instaled a Mapserver+nginx and show a wms layer in browser. Now i want to make a wms server. For this just needed make a correct map file. But before for make sure that MapServer installed correctly run this command in console:

  $ ./mapserv -v 

Output:

    MapServer version x.x.x OUTPUT=GIF OUTPUT=PNG OUTPUT=JPEG OUTPUT=WBMP OUTPUT=PDF OUTPUT=SWF OUTPUT=SVG SUPPORTS=PROJ
    SUPPORTS=FREETYPE SUPPORTS=WMS_SERVER SUPPORTS=WMS_CLIENT SUPPORTS=WFS_SERVER SUPPORTS=WFS_CLIENT SUPPORTS=WCS_SERVER INPUT=JPEG 
    INPUT=POSTGIS INPUT=OGR INPUT=GDAL INPUT=SHAPEFILE DEBUG=MSDEBUG

If SUPPORTS=WMS_SERVER is here - go ahead.

1.WMS Server map file:

MAP
  NAME "Simple map"
  # Map image size
  SIZE 256 256
  UNITS METERS
  CONFIG PROJ_LIB "/usr/share/proj/" #Path to PROJ lib if needed
  SHAPEPATH "/srv/www/maps/shp"  #Path to shape files
  EXTENT 60.4 56.7 60.7 56.9

  #Output projection
  PROJECTION
   "proj=latlong"
   "ellps=WGS84"
   "datum=WGS84"
  END

  # Background color for the map canvas -- change as desired
  IMAGECOLOR 255 255 255
  IMAGEQUALITY 95
  IMAGETYPE png

  #Output file format
  OUTPUTFORMAT
    NAME          "png"
    EXTENSION     "png"
    MIMETYPE      "image/png"
    DRIVER         AGG/PNG
    IMAGEMODE      RGBA
    FORMATOPTION  "INTERLACE=OFF"
  END
   
  # Legend
  LEGEND
    IMAGECOLOR 255 255 255
    STATUS ON
    KEYSIZE 18 12
    LABEL
      TYPE BITMAP
      SIZE MEDIUM
      COLOR 0 0 89
    END
  END


  WEB
    # Set IMAGEPATH to the path where MapServer should
    # write its output.
    IMAGEPATH '/tmp/'

    # Set IMAGEURL to the url that points to IMAGEPATH
    # as defined in your web server configuration
    IMAGEURL '/tmp/'

    # WMS server settings
    METADATA
      'ows_title'          'Simple map'
       ows_onlineresource  'http://MyHost/map/?map=/srv/www/maps/rew.map&'
      "wms_srs"            "EPSG:4326 EPSG:3857"
      "wms_abstract"       "atlands demo WMS"
      "wms_enable_request" "*"
      "wms_encoding"       "utf-8"
    END

    # Template and header/footer settings
    TEMPLATE 'fooOnlyForWMSGetFeatureInfo'
  END

  LAYER
    NAME 'test'
    TYPE POLYGON
    DUMP true
    TEMPLATE fooOnlyForWMSGetFeatureInfo
   #EXTENT 34.59 49.58 34.63 49.6
 DATA my
    METADATA
      'ows_title' 'test'
      wms_srs "EPSG:4326"
    END
    STATUS OFF
    TRANSPARENCY 100

    #Layer projection
    PROJECTION
        "proj=latlong"
 "ellps=WGS84"
 "datum=WGS84"
    END
    CLASS
       NAME 'test' 
       STYLE
         WIDTH 0.91 
         OUTLINECOLOR 0 0 0
         COLOR 214 205 104
       END
    END
  END
END

You can use another projection defenition:

  PROJECTION
    "init=epsg:4326"
  END
But i it evoke an error:
  msProcessProjection(): Projection library error. no system list, errno: 13
For TEMPLATE block using for GetFeatureInfo(). You can find template samples here and extract tamplates,symbols,images and fonts folders into map files directory.

You can try generate a map file using a MapManager.

Check what we have:

   http://MyHost/map/?map=/srv/www/maps/rew.map&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilitiess

In answer you get a xml file with you wms server settings.

2.Client side

On client side i have a application useing Leaflet so i just add a new layer:

   var wms_server = "http://MyHost/map/?map=/srv/www/maps/rew.map&"
   var NewLayer = new L.tileLayer.wms(wms_server, {
     layers: 'limite',
     format: 'image/png',
     transparent: true,
     srs:"EPSG:4326"
   });
   map.addLayer(NewLayer);

Used materials:
1. www.http://gis-lab.info/qa/mapserver-wms.html
2. www.http://en.it-usenet.org/thread/12216/6154/
3. www.http://www.cybervox.ru/wiki/Docs/GIS/Mapserver
4. www.http://profmarcello.blogspot.ru/2013/06/configuracao-de-layers-wms-do-mapserver.html