Как повернуть SVG-символ на заданный угол?

Вопросы по свободной ГИС QGIS. Сообщения об ошибках, предложения по улучшению, локализация.
Ответить
GIS-dev
Участник
Сообщения: 54
Зарегистрирован: 27 авг 2009, 11:01
Репутация: 1

Как повернуть SVG-символ на заданный угол?

Сообщение GIS-dev » 07 мар 2011, 20:35

Мне необходимо отрисовать символы (стрелки) в слое, направленные в произвольные стороны. Символ стрелки хранится в файле SVG и загружается таким кодом:

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


.................................
QgsSymbol * Arrow = new QgsSymbol(QGis::Point,"","","Arrow");
Arrow->setNamedPointSymbol("svg:arrow.svg");
Arrow->setPointSize(15.0);
QgsUniqueValueRenderer *ArrowRenderer = new QgsUniqueValueRenderer(ArrowLayer->geometryType());
ArrowRenderer->setClassificationField(0);
ArrowRenderer->insertValue("Arow",Arrow);
QgsFeature fet;
fet.setGeometry(QgsGeometry::fromPoint(QgsPoint(lon,lat)));
attrib2.insert(0,"Arrow");
fet.setAttributeMap(attrib2);
fetList.append(fet);
pr->addFeatures(fetList);
ArrowLayer->setRenderer(ArrowRenderer);
.................................

Гугление не дало ответа на вопрос, можно ли (а сама QGIS умет вращать символ на произвольный угол!) разверуть загруженный символ на заданный угол и как это сделать. Нужно ли вертеть сам символ или это прерогатива рендерера? Ничего похожего на QgsSymbol->rotate(angle); в документации я не нашел...

Voltron
Гуру
Сообщения: 2627
Зарегистрирован: 29 мар 2007, 14:12
Репутация: 34
Откуда: Ukraine

Re: Как повернуть SVG-символ на заданный угол?

Сообщение Voltron » 07 мар 2011, 21:46

При использовании «старой» символики за поворот символа отвечает рендерер, угол поворота берется из атрибутивной таблицы слоя, если он там есть.

При использовании «новой» символики, угол поворота определяется свойством angle самого символа. Задать угол можно вызвав метод setAngle().

Т.е. ответом на ваш вопрос будет «Да, можно». Реализация зависит от используемой символики.

GIS-dev
Участник
Сообщения: 54
Зарегистрирован: 27 авг 2009, 11:01
Репутация: 1

Re: Как повернуть SVG-символ на заданный угол?

Сообщение GIS-dev » 08 мар 2011, 17:04

А как для "новой" версии связывается объект QgsFeature с символом QgsMarkerSymbolV2 через рендерер QgsCategorizedSymbolRendererV2 (или по-другому)? У объекта QgsFeature есть "AttributeMap" и "TypeName". У рендерера QgsCategorizedSymbolRendererV2 есть "ClassAttribute" и "QgsRendererCategoryV2". Конструктор QgsRendererCategoryV2 в качестве второго аргумента принимает QgsMarkerSymbolV2, первый аргумент очевидно идентифицирует категорию с этим символом. Но с чем он ассоциируется у QgsFeature? С каким атрибутом?.. Как я ни пытался их комбинировать, вывести символ на карту "новой" версией символики мне не удалось. При полном отсутствии документации по этим классам и методам крайне затруднительно только по их названиям найти взаимосвязь между ними.

И ещё вопрос, при создании символа QgsMarkerSymbolV2 в слое QgsSvgMarkerSymbolLayerV2 для него полное имя файла должно указываться с префиксом "svg:" или только путь с именем файла?

Voltron
Гуру
Сообщения: 2627
Зарегистрирован: 29 мар 2007, 14:12
Репутация: 34
Откуда: Ukraine

Re: Как повернуть SVG-символ на заданный угол?

Сообщение Voltron » 08 мар 2011, 17:59

GIS-dev писал(а):А как для "новой" версии связывается объект QgsFeature с символом QgsMarkerSymbolV2 через рендерер QgsCategorizedSymbolRendererV2 (или по-другому)?
У вас неправильное понимание работы символики. Начнем с того, что отдельные «фичи» (feature) не связываются с символом и рендерером. Рендерер назначается всему слою, а не отдельным объектам. Задача рендерера - отобрать объекты для отображения и собственно отобразить их. Параметры визуализации могут зависеть от атрибутов объекта (например если используется отрисовка категориями).

Т.е. вам надо сформировать список категорий на основе какого-либо атрибута, для каждой категории задать свой символ (renderer.updateCategorySymbol), назначить рендерер слою (layer.setRenderer). Дальше рендерер сам разберется какой объект каким символом рисовать.
GIS-dev писал(а):При полном отсутствии документации по этим классам и методам крайне затруднительно только по их названиям найти взаимосвязь между ними
Я вас умоляю... у вас есть исходники, они самая лучшая документация.
GIS-dev писал(а):И ещё вопрос, при создании символа QgsMarkerSymbolV2 в слое QgsSvgMarkerSymbolLayerV2 для него полное имя файла должно указываться с префиксом "svg:" или только путь с именем файла?
Префикс не нужен. Путь к файлу может быть как абсолютный, так и относительный; относительные пути записываются в виде

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

/symbol/Star1.svg

GIS-dev
Участник
Сообщения: 54
Зарегистрирован: 27 авг 2009, 11:01
Репутация: 1

Re: Как повернуть SVG-символ на заданный угол?

Сообщение GIS-dev » 08 мар 2011, 20:13

Voltron писал(а):У вас неправильное понимание работы символики. Начнем с того, что отдельные «фичи» (feature) не связываются с символом и рендерером. Рендерер назначается всему слою, а не отдельным объектам. Задача рендерера - отобрать объекты для отображения и собственно отобразить их. Параметры визуализации могут зависеть от атрибутов объекта (например если используется отрисовка категориями).

Т.е. вам надо сформировать список категорий на основе какого-либо атрибута, для каждой категории задать свой символ (renderer.updateCategorySymbol), назначить рендерер слою (layer.setRenderer). Дальше рендерер сам разберется какой объект каким символом рисовать.
Возможно я не совсем внятно выразился. Под связью я имел ввиду один из атрибутов объекта ("фичи") и соответствующий ему атрибут(?) в списке категорий рендерера, которому присвоен заданный символ.

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


Layer = new QgsVectorLayer("Point", "some name", "memory"); // Создаем слой в памяти
QgsVectorDataProvider *pr = Layer->dataProvider();// Получаем провайдер для добавления фичи в слой
QgsSvgMarkerSymbolLayerV2 *SvgMarker = new QgsSvgMarkerSymbolLayerV2("arrow.svg",25.0,0.0);// Cоздаем слой для символа второй версии
QgsSymbolLayerV2List SvgMarkerList;
SvgMarkerList.append(SvgMarker);
QgsMarkerSymbolV2 *Arrow = new QgsMarkerSymbolV2(SvgMarkerList);// Создаем символ "Arrow"

QgsCategorizedSymbolRendererV2 *Renderer = new QgsCategorizedSymbolRendererV2();// Cоздаем рендерер с категориями

Renderer->updateCategorySymbol(0,Arrow);// Заносим символ в список категорий
Renderer->updateCategoryValue(0,"Arrow");// Заносим значение для этого символа под тем же индексом

//QgsRendererCategoryV2 *Cathegory = new QgsRendererCategoryV2("Arrow",Arrow,"");
// ... или как было у меня -
//Renderer->addCategory(*Cathegory);// добавляем категорию рендереру с теми же параметрами, что и выше

QgsFeature fet;
fet.setGeometry(QgsGeometry::fromPoint(QgsPoint(x,y)));// Создаем фичу для одной точки с геометрией

attrib.insert(0,"Arrow");
fet.setAttributeMap(attrib);// Создаем один атрибут для фичи, со значением, соответствующим категории символа стрелки. (Здесь непонятно, нет метода setClassificationField, который у "старого" рендерера определял, индекс атрибута для собственно классификации фич. У нового есть метод "setClassAttribute", но что должна содержать символьная строка на его входе, непонятно.)
fetList.append(fet);
pr->addFeatures(fetList);// Добавляем фичу к слою

Layer->setRendererV2(Renderer);// Устанавливаем "новый" рендерер слою
Layer->setUsingRendererV2(TRUE);// и активируем его

QgsMapLayerRegistry::instance()->addMapLayer(Layer, TRUE);// Далее стандартные действия присоединения слоя к карте
myLayerSet.append(QgsMapCanvasLayer(Layer, TRUE));

mypMapCanvas->setLayerSet(myLayerSet);

Возможно, ключевая ошибка в этом коде отсутствии метода "setClassificationField" у класса "QgsCategorizedSymbolRendererV2" и необходимости использования вместо него "setClassAttribute"? Но символьную строку с чем, с какими данными давать ему на вход? В старом рендерере в setClassificationField я давал на вход индекс в списке атрибутов и все работало...
Voltron писал(а):Я вас умоляю... у вас есть исходники, они самая лучшая документация.
Это так... Только это и самая неэффективная по скорости получения информации "документация". :(
Последний раз редактировалось GIS-dev 09 мар 2011, 03:00, всего редактировалось 1 раз.

Voltron
Гуру
Сообщения: 2627
Зарегистрирован: 29 мар 2007, 14:12
Репутация: 34
Откуда: Ukraine

Re: Как повернуть SVG-символ на заданный угол?

Сообщение Voltron » 08 мар 2011, 20:59

GIS-dev писал(а):Возможно я не совсем внятно выразился. Под связью я имел ввиду один из атрибутов объекта ("фичи") и соответствующий ему атрибут(?) в списке категорий рендерера, которому присвоен заданный символ.
-----------------------skip------------------------------
Но символьную строку с чем, с какими данными давать ему на вход? В старом рендерере в setClassificationField я давал на вход индекс в списке атрибутов и все работало...
Понял. Тогда все просто, вам нужно использовать метод

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

void QgsCategorizedSymbolRendererV2::setClassAttribute( QString attr )
Это аналог setClassificationField из старой символики. Здесь attr это имя атрибута по которому выполнена классификация. Если атрибут называется "direction", то именно эту строку и передавайте.

Кстати, в вашем коде отсутствует создания полей, вероятно, пропустили когда писали на форум.
GIS-dev писал(а):Это так... Только это и самая неэффективная по скорости получения информации "документация". :(
Не буду спорить, т.к. на вкус и цвет все фломастеры разные.

GIS-dev
Участник
Сообщения: 54
Зарегистрирован: 27 авг 2009, 11:01
Репутация: 1

Re: Как повернуть SVG-символ на заданный угол?

Сообщение GIS-dev » 09 мар 2011, 08:00

Voltron писал(а): Кстати, в вашем коде отсутствует создания полей, вероятно, пропустили когда писали на форум.
Полей фичи? Насколько я понимаю логику работы ее класса, наименования атрибутов и их значения(поля?) задаются так:

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

QgsFeature fet;// Новая фича без атрибутов
fet.setGeometry(QgsGeometry::fromPoint(QgsPoint(x,y)));
attrib.insert(0,"name1");attrib.insert(1,"name2");// Создаем список именованных атрибутов
fet.setAttributeMap(attrib);// Присваиваем список фиче.
fet.addAttribute(0,"Arrow");fet.addAttribute(1,"something");// Присваиваем атрибуту с именем "name1" значение "Arrow", "name2" - "something" или же это делается как-то по-другому?.. Больше ничего похожего на методы задания полей я у класса QgsFeature не нашел...

Кстати, в списке категорий рендерера какой параметр используется для выборки атрибута фичи, "Value", или может быть, "Label"? Впрочем я им присваивал одинаковые значения, без малейшего результата... Возможно пропускаю всего один какой-то момент, не позволяющий рендереру отобразить символ для фичи.

Да, и ещё, какая связь между тремя параметрами класса QgsRendererCategoryV2 (Value, Symbol и Label) и параметром ClassAttribute рендерера? В категории символ составляет единое целое с Value и Label, а как они связаны с ClassAttribute?
Считая, что структура слоёв и фич в чём-то похожа например на организацию баз данных PostGIS, логично предположить, что все фичи одного слоя имеют одинаковое количество и состав полей, подобно записям PostGIS в одной таблице (таблица будет соответствовать слою). В этом случае названия и свойства полей должны быть ассоциированы не с фичей, а со слоем, а фичи долны содержать только значения полей, прописанных в слое. Но в QGIS фичи могут создаваться независимо от слоёв. В отличии от PostGIS, я не могу пока представить логическую структуру взаимосвязей объектов QGIS.

GIS-dev
Участник
Сообщения: 54
Зарегистрирован: 27 авг 2009, 11:01
Репутация: 1

Re: Как повернуть SVG-символ на заданный угол?

Сообщение GIS-dev » 09 мар 2011, 18:41

Уф!.. Символ отобразился...
Основная проблема была в отсутствии типа поля:

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


attribFields = new QgsField();
attribFields->setName("Arrow");
attribFields->setType(QVariant.String);// Тип поля - без него символ не отображался
attribFieldsList.append(*attribFields);
pr->addAttributes(attribFieldsList);

GIS-dev
Участник
Сообщения: 54
Зарегистрирован: 27 авг 2009, 11:01
Репутация: 1

Re: Как повернуть SVG-символ на заданный угол?

Сообщение GIS-dev » 10 мар 2011, 10:15

Снова снег на голову: перестала работать прозрачность слоя... Если раньше методом "Layer->setTransparency();" можно было задать прозрачность, теперь независимо от его параметра, слой всегда непрозрачный. Похоже, для слоя с рендерером "QgsCategorizedSymbolRendererV2" эта функция не работает. Не работает и метод "Arrow->setAlpha(0.0);" для символа (хотя например тут же "setAngle();" для этого же символа исправно поворачивает его на заданный угол). При этом если сам SVG-символ изначально содержит полупрозрачные элементы, они отображаются корректно, с полупрозрачностью. Может быть для слоя с рендерером по категориям разработчики не предусмотрели полупрозрачность, предполагая, что если она нужна, то будет задаваться в SVG-файле символа?

Ответить

Вернуться в «QGIS»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 23 гостя