1 /*
2  *    Copyright 2012, 2013 Thomas Schöps
3  *    Copyright 2012-2019 Kai Pastor
4  *
5  *    This file is part of OpenOrienteering.
6  *
7  *    OpenOrienteering is free software: you can redistribute it and/or modify
8  *    it under the terms of the GNU General Public License as published by
9  *    the Free Software Foundation, either version 3 of the License, or
10  *    (at your option) any later version.
11  *
12  *    OpenOrienteering is distributed in the hope that it will be useful,
13  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *    GNU General Public License for more details.
16  *
17  *    You should have received a copy of the GNU General Public License
18  *    along with OpenOrienteering.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 
22 #ifndef OPENORIENTEERING_POINT_SYMBOL_H
23 #define OPENORIENTEERING_POINT_SYMBOL_H
24 
25 #include <memory>
26 #include <vector>
27 
28 #include <Qt>
29 #include <QtGlobal>
30 
31 #include "symbol.h"
32 
33 // IWYU pragma: no_include "core/objects/object.h"
34 
35 class QPainterPath;
36 class QXmlStreamReader;
37 class QXmlStreamWriter;
38 
39 namespace OpenOrienteering {
40 
41 class Map;
42 class MapColor;
43 class MapColorMap;
44 class MapCoordF;
45 class ObjectRenderables;
46 class SymbolPropertiesWidget;
47 class SymbolSettingDialog;
48 class VirtualCoordVector;
49 
50 
51 /**
52  * Symbol for PointObjects.
53  *
54  * Apart from its own settings which are presented to the user as "[Midpoint
55  * symbol]" in the point symbol editor, this class can contain a list of
56  * elements together with a symbol for each element. All elements and the
57  * PointObject's own settings make up the appearance of the point symbol.
58  * The reason the own settings are left in is just efficiency, as for some
59  * symbols like crop land, a really huge number of point objects may be generated.
60  */
61 class PointSymbol : public Symbol
62 {
63 friend class PointSymbolSettings;
64 friend class PointSymbolEditorWidget;
65 friend class OCAD8FileImport;
66 friend class XMLImportExport;
67 public:
68 	/** Constructs an empty point symbol. */
69 	PointSymbol() noexcept;
70 	~PointSymbol() override;
71 
72 protected:
73 	explicit PointSymbol(const PointSymbol& proto);
74 	PointSymbol* duplicate() const override;
75 
76 public:
77 	bool validate() const override;
78 
79 	void createRenderables(
80 	        const Object *object,
81 	        const VirtualCoordVector &coords,
82 	        ObjectRenderables &output,
83 	        RenderableOptions options ) const override;
84 
85 	void createRenderablesScaled(const MapCoordF& coord, qreal rotation, ObjectRenderables& output, qreal coord_scale = 1) const;
86 
87 	void createRenderablesIfCenterInside(const MapCoordF& point_coord, qreal rotation, const QPainterPath* outline, ObjectRenderables& output) const;
88 	void createPrimitivesIfCompletelyInside(const MapCoordF& point_coord, const QPainterPath* outline, ObjectRenderables& output) const;
89 	void createRenderablesIfCompletelyInside(const MapCoordF& point_coord, qreal rotation, const QPainterPath* outline, ObjectRenderables& output) const;
90 	void createPrimitivesIfPartiallyInside(const MapCoordF& point_coord, const QPainterPath* outline, ObjectRenderables& output) const;
91 	void createRenderablesIfPartiallyInside(const MapCoordF& point_coord, qreal rotation, const QPainterPath* outline, ObjectRenderables& output) const;
92 
93 	void colorDeletedEvent(const MapColor* color) override;
94 	bool containsColor(const MapColor* color) const override;
95 	const MapColor* guessDominantColor() const override;
96 	void replaceColors(const MapColorMap& color_map) override;
97 	void scale(double factor) override;
98 
99 	qreal dimensionForIcon() const override;
100 
101 	// Contained objects and symbols (elements)
102 
103 	/** Returns the number of contained elements. */
104 	int getNumElements() const;
105 	/** Adds a new element consisting of object and symbol at the given index. */
106 	void addElement(int pos, Object* object, Symbol* symbol);
107 	/** Returns the object of the i-th element. */
108 	Object* getElementObject(int pos);
109 	/** Returns the object of the i-th element. */
110 	const Object* getElementObject(int pos) const;
111 	/** Returns the symbol of the i-th element. */
112 	Symbol* getElementSymbol(int pos);
113 	/** Returns the symbol of the i-th element. */
114 	const Symbol* getElementSymbol(int pos) const;
115 	/** Deletes the i-th element. */
116 	void deleteElement(int pos);
117 
118 	/**
119 	 * Returns true if the point contains no elements and does not create
120 	 * renderables itself. Useful to check if it can be deleted.
121 	 */
122 	bool isEmpty() const;
123 
124 	/**
125 	 * Checks if the contained elements are rotationally symmetrical around
126 	 * the origin (this means, only point elements at (0,0) are allowed).
127 	 */
128 	bool isSymmetrical() const;
129 
130 	// Getters / Setters
131 	using Symbol::setRotatable; /* public visibility */
getInnerRadius()132 	inline int getInnerRadius() const {return inner_radius;}
setInnerRadius(int value)133 	inline void setInnerRadius(int value) {inner_radius = value;}
getInnerColor()134 	inline const MapColor* getInnerColor() const {return inner_color;}
setInnerColor(const MapColor * color)135 	inline void setInnerColor(const MapColor* color) {inner_color = color;}
getOuterWidth()136 	inline int getOuterWidth() const {return outer_width;}
setOuterWidth(int value)137 	inline void setOuterWidth(int value) {outer_width = value;}
getOuterColor()138 	inline const MapColor* getOuterColor() const {return outer_color;}
setOuterColor(const MapColor * color)139 	inline void setOuterColor(const MapColor* color) {outer_color = color;}
140 
141 	SymbolPropertiesWidget* createPropertiesWidget(SymbolSettingDialog* dialog) override;
142 
143 
144 protected:
145 	void saveImpl(QXmlStreamWriter& xml, const Map& map) const override;
146 	bool loadImpl(QXmlStreamReader& xml, const Map& map, SymbolDictionary& symbol_dict, int version) override;
147 	bool equalsImpl(const Symbol* other, Qt::CaseSensitivity case_sensitivity) const override;
148 
149 
150 	/// \todo Expose elements more directly in PointSymbol API.
151 	struct Element
152 	{
153 		std::unique_ptr<Symbol> symbol;
154 		std::unique_ptr<Object> object;
155 	};
156 	std::vector<Element> elements;
157 
158 	const MapColor* inner_color;
159 	const MapColor* outer_color;
160 	int inner_radius;		// in 1/1000 mm
161 	int outer_width;		// in 1/1000 mm
162 };
163 
164 
165 }  // namespace OpenOrienteering
166 
167 #endif
168