diff options
Diffstat (limited to 'src/object/sp-mesh-array.h')
-rw-r--r-- | src/object/sp-mesh-array.h | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/src/object/sp-mesh-array.h b/src/object/sp-mesh-array.h new file mode 100644 index 0000000..eb28a12 --- /dev/null +++ b/src/object/sp-mesh-array.h @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#ifndef SEEN_SP_MESH_ARRAY_H +#define SEEN_SP_MESH_ARRAY_H +/* + * Authors: + * Tavmjong Bah <tavmjong@free.fr> + * + * Copyrigt (C) 2012 Tavmjong Bah + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +/** + A group of classes and functions for manipulating mesh gradients. + + A mesh is made up of an array of patches. Each patch has four sides and four corners. The sides can + be shared between two patches and the corners between up to four. + + The order of the points for each side always goes from left to right or top to bottom. + For sides 2 and 3 the points must be reversed when used (as in calls to cairo functions). + + Two patches: (C=corner, S=side, H=handle, T=tensor) + + C0 H1 H2 C1 C0 H1 H2 C1 + + ---------- + ---------- + + | S0 | S0 | + H1 | T0 T1 |H1 T0 T1 | H1 + |S3 S1|S3 S1| + H2 | T3 T2 |H2 T3 T2 | H2 + | S2 | S2 | + + ---------- + ---------- + + C3 H1 H2 C2 C3 H1 H2 C2 + + The mesh is stored internally as an array of nodes that includes the tensor nodes. + + Note: This code uses tensor points which are not part of the SVG2 plan at the moment. + Including tensor points was motivated by a desire to experiment with their usefulness + in smoothing color transitions. There doesn't seem to be much advantage for that + purpose. However including them internally allows for storing all the points in + an array which simplifies things like inserting new rows or columns. +*/ + +#include <2geom/point.h> +#include "color.h" + +// For color picking +#include "sp-item.h" + +#include <memory> + +enum SPMeshType { + SP_MESH_TYPE_COONS, + SP_MESH_TYPE_BICUBIC +}; + +enum SPMeshGeometry { + SP_MESH_GEOMETRY_NORMAL, + SP_MESH_GEOMETRY_CONICAL +}; + +enum NodeType { + MG_NODE_TYPE_UNKNOWN, + MG_NODE_TYPE_CORNER, + MG_NODE_TYPE_HANDLE, + MG_NODE_TYPE_TENSOR +}; + +// Is a node along an edge? +enum NodeEdge { + MG_NODE_EDGE_NONE, + MG_NODE_EDGE_TOP = 1, + MG_NODE_EDGE_LEFT = 2, + MG_NODE_EDGE_BOTTOM = 4, + MG_NODE_EDGE_RIGHT = 8 +}; + +enum MeshCornerOperation { + MG_CORNER_SIDE_TOGGLE, + MG_CORNER_SIDE_ARC, + MG_CORNER_TENSOR_TOGGLE, + MG_CORNER_COLOR_SMOOTH, + MG_CORNER_COLOR_PICK, + MG_CORNER_INSERT +}; + +enum MeshNodeOperation { + MG_NODE_NO_SCALE, + MG_NODE_SCALE, + MG_NODE_SCALE_HANDLE +}; + +class SPStop; + +class SPMeshNode { +public: + SPMeshNode() { + node_type = MG_NODE_TYPE_UNKNOWN; + node_edge = MG_NODE_EDGE_NONE; + set = false; + draggable = -1; + path_type = 'u'; + opacity = 0.0; + stop = nullptr; + } + NodeType node_type; + unsigned int node_edge; + bool set; + Geom::Point p; + unsigned int draggable; // index of on-screen node + char path_type; + SPColor color; + double opacity; + SPStop *stop; // Stop corresponding to node. +}; + + +// I for Internal to distinguish it from the Object class +// This is a convenience class... +class SPMeshPatchI { + +private: + std::vector<std::vector< SPMeshNode* > > *nodes; + int row; + int col; + +public: + SPMeshPatchI( std::vector<std::vector< SPMeshNode* > > *n, int r, int c ); + Geom::Point getPoint( unsigned int side, unsigned int point ); + std::vector< Geom::Point > getPointsForSide( unsigned int i ); + void setPoint( unsigned int side, unsigned int point, Geom::Point p, bool set = true ); + char getPathType( unsigned int i ); + void setPathType( unsigned int, char t ); + Geom::Point getTensorPoint( unsigned int i ); + void setTensorPoint( unsigned int i, Geom::Point p ); + bool tensorIsSet(); + bool tensorIsSet( unsigned int i ); + Geom::Point coonsTensorPoint( unsigned int i ); + void updateNodes(); + SPColor getColor( unsigned int i ); + void setColor( unsigned int i, SPColor c ); + double getOpacity( unsigned int i ); + void setOpacity( unsigned int i, double o ); + SPStop* getStopPtr( unsigned int i ); + void setStopPtr( unsigned int i, SPStop* ); +}; + +class SPMeshGradient; +class SPCurve; + +// An array of mesh nodes. +class SPMeshNodeArray { + +// Should be private +public: + SPMeshGradient *mg; + std::vector< std::vector< SPMeshNode* > > nodes; + +public: + // Draggables to nodes + bool draggers_valid; + std::vector< SPMeshNode* > corners; + std::vector< SPMeshNode* > handles; + std::vector< SPMeshNode* > tensors; + +public: + + friend class SPMeshPatchI; + + SPMeshNodeArray() { built = false; mg = nullptr; draggers_valid = false; }; + SPMeshNodeArray( SPMeshGradient *mg ); + SPMeshNodeArray( const SPMeshNodeArray& rhs ); + SPMeshNodeArray& operator=(const SPMeshNodeArray& rhs); + + ~SPMeshNodeArray() { clear(); }; + bool built; + + bool read( SPMeshGradient *mg ); + void write( SPMeshGradient *mg ); + void create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bbox ); + void clear(); + void print(); + + // Fill 'smooth' with a smoothed version by subdividing each patch. + void bicubic( SPMeshNodeArray* smooth, SPMeshType type); + + // Get size of patch + unsigned int patch_rows(); + unsigned int patch_columns(); + + SPMeshNode * node( unsigned int i, unsigned int j ) { return nodes[i][j]; } + + // Operations on corners + bool adjacent_corners( unsigned int i, unsigned int j, SPMeshNode* n[4] ); + unsigned int side_toggle( std::vector< unsigned int > ); + unsigned int side_arc( std::vector< unsigned int > ); + unsigned int tensor_toggle( std::vector< unsigned int > ); + unsigned int color_smooth( std::vector< unsigned int > ); + unsigned int color_pick( std::vector< unsigned int >, SPItem* ); + unsigned int insert( std::vector< unsigned int > ); + + // Update other nodes in response to a node move. + void update_handles( unsigned int corner, std::vector< unsigned int > selected_corners, Geom::Point old_p, MeshNodeOperation op ); + + // Return outline path + std::unique_ptr<SPCurve> outline_path() const; + + // Transform array + void transform(Geom::Affine const &m); + + // Transform mesh to fill box. Return true if not identity transform. + bool fill_box(Geom::OptRect &box); + + // Find bounding box + // Geom::OptRect findBoundingBox(); + + void split_row( unsigned int i, unsigned int n ); + void split_column( unsigned int j, unsigned int n ); + void split_row( unsigned int i, double coord ); + void split_column( unsigned int j, double coord ); +}; + +#endif /* !SEEN_SP_MESH_ARRAY_H */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + c-basic-offset:2 + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : |