1 // SPDX-License-Identifier: GPL-2.0-or-later 2 #ifndef SEEN_SP_MESH_ARRAY_H 3 #define SEEN_SP_MESH_ARRAY_H 4 /* 5 * Authors: 6 * Tavmjong Bah <tavmjong@free.fr> 7 * 8 * Copyrigt (C) 2012 Tavmjong Bah 9 * 10 * Released under GNU GPL v2+, read the file 'COPYING' for more information. 11 */ 12 13 /** 14 A group of classes and functions for manipulating mesh gradients. 15 16 A mesh is made up of an array of patches. Each patch has four sides and four corners. The sides can 17 be shared between two patches and the corners between up to four. 18 19 The order of the points for each side always goes from left to right or top to bottom. 20 For sides 2 and 3 the points must be reversed when used (as in calls to cairo functions). 21 22 Two patches: (C=corner, S=side, H=handle, T=tensor) 23 24 C0 H1 H2 C1 C0 H1 H2 C1 25 + ---------- + ---------- + 26 | S0 | S0 | 27 H1 | T0 T1 |H1 T0 T1 | H1 28 |S3 S1|S3 S1| 29 H2 | T3 T2 |H2 T3 T2 | H2 30 | S2 | S2 | 31 + ---------- + ---------- + 32 C3 H1 H2 C2 C3 H1 H2 C2 33 34 The mesh is stored internally as an array of nodes that includes the tensor nodes. 35 36 Note: This code uses tensor points which are not part of the SVG2 plan at the moment. 37 Including tensor points was motivated by a desire to experiment with their usefulness 38 in smoothing color transitions. There doesn't seem to be much advantage for that 39 purpose. However including them internally allows for storing all the points in 40 an array which simplifies things like inserting new rows or columns. 41 */ 42 43 #include <2geom/point.h> 44 #include "color.h" 45 46 // For color picking 47 #include "sp-item.h" 48 49 #include <memory> 50 51 enum SPMeshType { 52 SP_MESH_TYPE_COONS, 53 SP_MESH_TYPE_BICUBIC 54 }; 55 56 enum SPMeshGeometry { 57 SP_MESH_GEOMETRY_NORMAL, 58 SP_MESH_GEOMETRY_CONICAL 59 }; 60 61 enum NodeType { 62 MG_NODE_TYPE_UNKNOWN, 63 MG_NODE_TYPE_CORNER, 64 MG_NODE_TYPE_HANDLE, 65 MG_NODE_TYPE_TENSOR 66 }; 67 68 // Is a node along an edge? 69 enum NodeEdge { 70 MG_NODE_EDGE_NONE, 71 MG_NODE_EDGE_TOP = 1, 72 MG_NODE_EDGE_LEFT = 2, 73 MG_NODE_EDGE_BOTTOM = 4, 74 MG_NODE_EDGE_RIGHT = 8 75 }; 76 77 enum MeshCornerOperation { 78 MG_CORNER_SIDE_TOGGLE, 79 MG_CORNER_SIDE_ARC, 80 MG_CORNER_TENSOR_TOGGLE, 81 MG_CORNER_COLOR_SMOOTH, 82 MG_CORNER_COLOR_PICK, 83 MG_CORNER_INSERT 84 }; 85 86 enum MeshNodeOperation { 87 MG_NODE_NO_SCALE, 88 MG_NODE_SCALE, 89 MG_NODE_SCALE_HANDLE 90 }; 91 92 class SPStop; 93 94 class SPMeshNode { 95 public: SPMeshNode()96 SPMeshNode() { 97 node_type = MG_NODE_TYPE_UNKNOWN; 98 node_edge = MG_NODE_EDGE_NONE; 99 set = false; 100 draggable = -1; 101 path_type = 'u'; 102 opacity = 0.0; 103 stop = nullptr; 104 } 105 NodeType node_type; 106 unsigned int node_edge; 107 bool set; 108 Geom::Point p; 109 unsigned int draggable; // index of on-screen node 110 char path_type; 111 SPColor color; 112 double opacity; 113 SPStop *stop; // Stop corresponding to node. 114 }; 115 116 117 // I for Internal to distinguish it from the Object class 118 // This is a convenience class... 119 class SPMeshPatchI { 120 121 private: 122 std::vector<std::vector< SPMeshNode* > > *nodes; 123 int row; 124 int col; 125 126 public: 127 SPMeshPatchI( std::vector<std::vector< SPMeshNode* > > *n, int r, int c ); 128 Geom::Point getPoint( unsigned int side, unsigned int point ); 129 std::vector< Geom::Point > getPointsForSide( unsigned int i ); 130 void setPoint( unsigned int side, unsigned int point, Geom::Point p, bool set = true ); 131 char getPathType( unsigned int i ); 132 void setPathType( unsigned int, char t ); 133 Geom::Point getTensorPoint( unsigned int i ); 134 void setTensorPoint( unsigned int i, Geom::Point p ); 135 bool tensorIsSet(); 136 bool tensorIsSet( unsigned int i ); 137 Geom::Point coonsTensorPoint( unsigned int i ); 138 void updateNodes(); 139 SPColor getColor( unsigned int i ); 140 void setColor( unsigned int i, SPColor c ); 141 double getOpacity( unsigned int i ); 142 void setOpacity( unsigned int i, double o ); 143 SPStop* getStopPtr( unsigned int i ); 144 void setStopPtr( unsigned int i, SPStop* ); 145 }; 146 147 class SPMeshGradient; 148 class SPCurve; 149 150 // An array of mesh nodes. 151 class SPMeshNodeArray { 152 153 // Should be private 154 public: 155 SPMeshGradient *mg; 156 std::vector< std::vector< SPMeshNode* > > nodes; 157 158 public: 159 // Draggables to nodes 160 bool draggers_valid; 161 std::vector< SPMeshNode* > corners; 162 std::vector< SPMeshNode* > handles; 163 std::vector< SPMeshNode* > tensors; 164 165 public: 166 167 friend class SPMeshPatchI; 168 SPMeshNodeArray()169 SPMeshNodeArray() { built = false; mg = nullptr; draggers_valid = false; }; 170 SPMeshNodeArray( SPMeshGradient *mg ); 171 SPMeshNodeArray( const SPMeshNodeArray& rhs ); 172 SPMeshNodeArray& operator=(const SPMeshNodeArray& rhs); 173 ~SPMeshNodeArray()174 ~SPMeshNodeArray() { clear(); }; 175 bool built; 176 177 bool read( SPMeshGradient *mg ); 178 void write( SPMeshGradient *mg ); 179 void create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bbox ); 180 void clear(); 181 void print(); 182 183 // Fill 'smooth' with a smoothed version by subdividing each patch. 184 void bicubic( SPMeshNodeArray* smooth, SPMeshType type); 185 186 // Get size of patch 187 unsigned int patch_rows(); 188 unsigned int patch_columns(); 189 node(unsigned int i,unsigned int j)190 SPMeshNode * node( unsigned int i, unsigned int j ) { return nodes[i][j]; } 191 192 // Operations on corners 193 bool adjacent_corners( unsigned int i, unsigned int j, SPMeshNode* n[4] ); 194 unsigned int side_toggle( std::vector< unsigned int > ); 195 unsigned int side_arc( std::vector< unsigned int > ); 196 unsigned int tensor_toggle( std::vector< unsigned int > ); 197 unsigned int color_smooth( std::vector< unsigned int > ); 198 unsigned int color_pick( std::vector< unsigned int >, SPItem* ); 199 unsigned int insert( std::vector< unsigned int > ); 200 201 // Update other nodes in response to a node move. 202 void update_handles( unsigned int corner, std::vector< unsigned int > selected_corners, Geom::Point old_p, MeshNodeOperation op ); 203 204 // Return outline path 205 std::unique_ptr<SPCurve> outline_path() const; 206 207 // Transform array 208 void transform(Geom::Affine const &m); 209 210 // Transform mesh to fill box. Return true if not identity transform. 211 bool fill_box(Geom::OptRect &box); 212 213 // Find bounding box 214 // Geom::OptRect findBoundingBox(); 215 216 void split_row( unsigned int i, unsigned int n ); 217 void split_column( unsigned int j, unsigned int n ); 218 void split_row( unsigned int i, double coord ); 219 void split_column( unsigned int j, double coord ); 220 }; 221 222 #endif /* !SEEN_SP_MESH_ARRAY_H */ 223 224 /* 225 Local Variables: 226 mode:c++ 227 c-file-style:"stroustrup" 228 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) 229 c-basic-offset:2 230 indent-tabs-mode:nil 231 fill-column:99 232 End: 233 */ 234 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : 235