PDF4QT/Pdf4QtLibCore/sources/pdfpattern.h

755 lines
31 KiB
C++

// Copyright (C) 2019-2021 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFPATTERN_H
#define PDFPATTERN_H
#include "pdfobject.h"
#include "pdffunction.h"
#include "pdfcolorspaces.h"
#include "pdfmeshqualitysettings.h"
#include "pdfcolorconvertor.h"
#include <QTransform>
#include <QPainterPath>
#include <memory>
class BLContext;
namespace pdf
{
class PDFPattern;
class PDFTilingPattern;
class PDFShadingPattern;
using PDFPatternPtr = std::shared_ptr<PDFPattern>;
enum class PatternType
{
Invalid = 0,
Tiling = 1,
Shading = 2,
};
enum class ShadingType
{
Invalid = 0,
Function = 1,
Axial = 2,
Radial = 3,
FreeFormGouradTriangle = 4,
LatticeFormGouradTriangle = 5,
CoonsPatchMesh = 6,
TensorProductPatchMesh = 7
};
/// Mesh consisting of triangles
class PDFMesh
{
public:
explicit PDFMesh() = default;
struct Triangle
{
uint32_t v1 = 0;
uint32_t v2 = 0;
uint32_t v3 = 0;
QRgb color;
};
/// Adds vertex. Returns index of added vertex.
/// \param vertex Vertex to be added
/// \returns Index of the added vertex
inline uint32_t addVertex(const QPointF& vertex) { const size_t index = m_vertices.size(); m_vertices.emplace_back(vertex); return static_cast<uint32_t>(index); }
/// Adds triangle. Returns index of added triangle.
/// \param triangle Triangle to be added
/// \returns Index of the added vertex
inline uint32_t addTriangle(const Triangle& triangle) { const size_t index = m_triangles.size(); m_triangles.emplace_back(triangle); return static_cast<uint32_t>(index); }
/// Adds quad. Vertices are in clockwise order (so, we have edges v1-v2, v2-v3, v3-v4, v4-v1).
/// \param v1 First vertex (for example, topleft)
/// \param v2 Second vertex (for example, topright)
/// \param v3 Third vertex (for example, bottomright)
/// \param v4 Fourth vertex (for example, bottomleft)
/// \param color Color of the quad.
inline void addQuad(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t v4, QRgb color) { addTriangle({v1, v2, v3, color}); addTriangle({ v1, v3, v4, color}); }
/// Paints the mesh on the painter
/// \param painter Painter, onto which is mesh drawn
/// \param alpha Opacity factor
void paint(QPainter* painter, PDFReal alpha) const;
/// Paints the mesh on the context
/// \param context Painter, onto which is mesh drawn
/// \param alpha Opacity factor
void paint(BLContext& context, PDFReal alpha) const;
/// Transforms the mesh according to the matrix transform
/// \param matrix Matrix transform to be performed
void transform(const QTransform& matrix);
/// Reserves memory for meshing - both number of vertices and triangles.
/// Use this function, if number of vertices and triangles is known.
/// \param vertexCount Vertex count
/// \param triangleCount Triangle count
void reserve(size_t vertexCount, size_t triangleCount) { m_vertices.reserve(vertexCount); m_triangles.reserve(triangleCount); }
const QPainterPath& getBoundingPath() const { return m_boundingPath; }
void setBoundingPath(const QPainterPath& path) { m_boundingPath = path; }
/// Sets the vertex array to the mesh
/// \param vertices New vertex array
void setVertices(std::vector<QPointF>&& vertices) { m_vertices = qMove(vertices); }
/// Sets the triangle array to the mesh
/// \param triangles New triangle array
void setTriangles(std::vector<Triangle>&& triangles) { m_triangles = qMove(triangles); }
/// Merges the vertices/triangles (renumbers triangle indices) to this mesh.
/// Algorithm assumes that vertices/triangles are numbered from zero.
/// \param vertices Added vertex array
/// \param triangles Added triangle array
void addMesh(std::vector<QPointF>&& vertices, std::vector<Triangle>&& triangles);
/// Returns vertex at given index
/// \param index Index of the vertex
const QPointF& getVertex(size_t index) const { return m_vertices[index]; }
/// Returns triangle center. Triangles vertice indices must be valid.
/// \param triangle Triangle
QPointF getTriangleCenter(const Triangle& triangle) const;
/// Sets the background path. In order to draw background properly, the background
/// color must be set to a valid color.
/// \param path Background path
void setBackgroundPath(QPainterPath path) { m_backgroundPath = qMove(path); }
/// Sets the background color (background path is then painted with this color, if it is not
/// empty), if color is invalid, it turns off background painting.
/// \param backgroundColor Background color
void setBackgroundColor(QColor backgroundColor) { m_backgroundColor = backgroundColor; }
/// Returns true, if mesh is empty
bool isEmpty() const { return m_vertices.empty(); }
/// Returns estimate of number of bytes, which this mesh occupies in memory
qint64 getMemoryConsumptionEstimate() const;
/// Apply color conversion
void convertColors(const PDFColorConvertor& colorConvertor);
private:
std::vector<QPointF> m_vertices;
std::vector<Triangle> m_triangles;
QPainterPath m_boundingPath;
QPainterPath m_backgroundPath;
QColor m_backgroundColor;
};
/// Represents tiling/shading pattern
class PDFPattern
{
public:
explicit PDFPattern() = default;
virtual ~PDFPattern() = default;
virtual PatternType getType() const = 0;
virtual const PDFShadingPattern* getShadingPattern() const = 0;
virtual const PDFTilingPattern* getTilingPattern() const = 0;
/// Returns bounding box in the shadings target coordinate system (not in
/// pattern coordinate system).
const QRectF& getBoundingBox() const { return m_boundingBox; }
/// Returns transformation matrix from pattern space to the default
/// target space.
const QTransform& getMatrix() const { return m_matrix; }
/// Create pattern from the object. If error occurs, exception is thrown
/// \param colorSpaceDictionary Color space dictionary
/// \param document Document, owning the pdf object
/// \param object Object defining the pattern
/// \param cms Color management system
/// \param intent Rendering intent
/// \param reporter Error reporter
static PDFPatternPtr createPattern(const PDFDictionary* colorSpaceDictionary,
const PDFDocument* document,
const PDFObject& object,
const PDFCMS* cms,
RenderingIntent intent,
PDFRenderErrorReporter* reporter);
/// Create shading pattern from the object. If error occurs, exception is thrown
/// \param colorSpaceDictionary Color space dictionary
/// \param document Document, owning the pdf object
/// \param object Object defining the shading
/// \param matrix Matrix converting reference coordinate system to the device coordinate system
/// \param patternGraphicState Pattern graphic state
/// \param cms Color management system
/// \param intent Rendering intent
/// \param reporter Error reporter
/// \param ignoreBackgroundColor If set, then ignores background color, even if it is present
static PDFPatternPtr createShadingPattern(const PDFDictionary* colorSpaceDictionary,
const PDFDocument* document,
const PDFObject& shadingObject,
const QTransform& matrix,
const PDFObject& patternGraphicState,
const PDFCMS* cms,
RenderingIntent intent,
PDFRenderErrorReporter* reporter,
bool ignoreBackgroundColor);
protected:
QRectF m_boundingBox;
QTransform m_matrix;
};
class PDFInvalidPattern : public PDFPattern
{
public:
explicit PDFInvalidPattern() = default;
virtual PatternType getType() const override { return PatternType::Invalid; }
virtual const PDFShadingPattern* getShadingPattern() const override { return nullptr; }
virtual const PDFTilingPattern* getTilingPattern() const override { return nullptr; }
};
class PDFTilingPattern : public PDFPattern
{
public:
explicit PDFTilingPattern() = default;
virtual PatternType getType() const override { return PatternType::Tiling; }
virtual const PDFShadingPattern* getShadingPattern() const override { return nullptr; }
virtual const PDFTilingPattern* getTilingPattern() const override { return this; }
enum class PaintType
{
Colored = 1,
Uncolored = 2,
Invalid = 3
};
enum class TilingType
{
ConstantSpacing = 1,
NoDistortion = 2,
ConstantSpacingAndFasterTiling = 3,
Invalid
};
PaintType getPaintingType() const { return m_paintType; }
TilingType getTilingType() const { return m_tilingType; }
PDFReal getXStep() const { return m_xStep; }
PDFReal getYStep() const { return m_yStep; }
const PDFObject& getResources() const { return m_resources; }
const QByteArray& getContent() const { return m_content; }
private:
friend class PDFPattern;
PaintType m_paintType = PaintType::Colored;
TilingType m_tilingType = TilingType::ConstantSpacing;
PDFReal m_xStep = 0.0;
PDFReal m_yStep = 0.0;
PDFObject m_resources;
QByteArray m_content;
};
/// Compute color of sample points from shading pattern. Some sampler implementation
/// uses numerical algorithms (such as Newton-Raphson method for type 6/7 shading), so
/// calculation can be very slow for some types of shadings.
class PDFShadingSampler
{
public:
explicit inline PDFShadingSampler(const PDFShadingPattern* pattern) :
m_pattern(pattern)
{
}
virtual ~PDFShadingSampler() = default;
/// Try to compute color of the point in device space coordinates in the shading. If color
/// can't be computed, then false is returned, otherwise true is returned.
/// \param devicePoint Point in device space coordinates
/// \param outputBuffer Color output buffer (where computed color is stored)
/// \param limit Maximal number of the steps of numerical calculation algorithms (for type 6/7 shading only)
virtual bool sample(const QPointF& devicePoint, PDFColorBuffer outputBuffer, int limit) const = 0;
/// Fill background color to the output buffer. If the background color is not filled,
/// or is invalid, then false is returned, otherwise true is returned.
bool fillBackgroundColor(PDFColorBuffer outputBuffer) const;
protected:
const PDFShadingPattern* m_pattern;
};
/// Shading pattern - smooth color distribution along the pattern's space
class PDFShadingPattern : public PDFPattern
{
public:
explicit PDFShadingPattern() = default;
virtual PatternType getType() const override;
virtual ShadingType getShadingType() const = 0;
virtual const PDFShadingPattern* getShadingPattern() const override { return this; }
virtual const PDFTilingPattern* getTilingPattern() const override { return nullptr; }
/// Creates a colored mesh using settings. Mesh is generated in device space
/// coordinate system. You must transform the mesh, if you want to
/// use it in another coordinate system.
/// \param settings Meshing settings
/// \param cms Color management system
/// \param intent Rendering intent
/// \param reporter Error reporter
/// \param operationControl Operation control
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
const PDFCMS* cms, RenderingIntent intent,
PDFRenderErrorReporter* reporter,
const PDFOperationControl* operationControl) const = 0;
/// Returns patterns graphic state. This state must be applied before
/// the shading pattern is painted to the target device.
const PDFObject& getPatternGraphicState() const { return m_patternGraphicState; }
/// Returns color space of the pattern.
const PDFAbstractColorSpace* getColorSpace() const;
/// Returns color space pointer
const PDFColorSpacePointer& getColorSpacePtr() const { return m_colorSpace; }
/// Returns patterns background color (if pattern has background color).
/// If pattern has not background color, then invalid color is returned.
const QColor& getBackgroundColor() const { return m_backgroundColor; }
/// Returns original background color (in color space of the shading pattern)
const PDFColor& getOriginalBackgroundColor() const { return m_originalBackgroundColor; }
/// Returns true, if shading pattern should be anti-aliased
bool isAntialiasing() const { return m_antiAlias; }
/// Returns matrix transforming pattern space to device space
QTransform getPatternSpaceToDeviceSpaceMatrix(const PDFMeshQualitySettings& settings) const;
/// Returns matrix transforming pattern space to device space
QTransform getPatternSpaceToDeviceSpaceMatrix(const QTransform& userSpaceToDeviceSpaceMatrix) const;
/// Create sampler which can compute shading colors in device space coordinates. If sampler can't
/// be created (or shading is invalid), then nullptr is returned.
/// \param userSpaceToDeviceSpaceMatrix Matrix, which transforms user space points
/// (user space is target space of the shading) to the device space of the paint device.
virtual PDFShadingSampler* createSampler(QTransform userSpaceToDeviceSpaceMatrix) const;
protected:
friend class PDFPattern;
PDFObject m_patternGraphicState;
PDFColorSpacePointer m_colorSpace;
QColor m_backgroundColor;
PDFColor m_originalBackgroundColor;
bool m_antiAlias = false;
};
class PDFSingleDimensionShading : public PDFShadingPattern
{
public:
explicit PDFSingleDimensionShading() = default;
const std::vector<PDFFunctionPtr>& getFunctions() const { return m_functions; }
const QPointF& getStartPoint() const { return m_startPoint; }
const QPointF& getEndPoint() const { return m_endPoint; }
PDFReal getDomainStart() const { return m_domainStart; }
PDFReal getDomainEnd() const { return m_domainEnd; }
bool isExtendStart() const { return m_extendStart; }
bool isExtendEnd() const { return m_extendEnd; }
protected:
friend class PDFPattern;
std::vector<PDFFunctionPtr> m_functions;
QPointF m_startPoint;
QPointF m_endPoint;
PDFReal m_domainStart = 0.0;
PDFReal m_domainEnd = 1.0;
bool m_extendStart = false;
bool m_extendEnd = false;
};
class PDFFunctionShading : public PDFShadingPattern
{
public:
explicit PDFFunctionShading() = default;
virtual ShadingType getShadingType() const override;
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
const PDFCMS* cms,
RenderingIntent intent,
PDFRenderErrorReporter* reporter,
const PDFOperationControl* operationControl) const override;
virtual PDFShadingSampler* createSampler(QTransform userSpaceToDeviceSpaceMatrix) const override;
const QRectF& getDomain() const { return m_domain; }
const QTransform& getDomainToTargetTransform() const { return m_domainToTargetTransform; }
const std::vector<PDFFunctionPtr>& getFunctions() const { return m_functions; }
private:
friend class PDFPattern;
QRectF m_domain; ///< Domain of the color function
QTransform m_domainToTargetTransform; ///< Transformation mapping from domain to shading coordinate space
std::vector<PDFFunctionPtr> m_functions; ///< Color functions
};
class PDFAxialShading : public PDFSingleDimensionShading
{
public:
explicit PDFAxialShading() = default;
virtual ShadingType getShadingType() const override;
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
const PDFCMS* cms,
RenderingIntent intent,
PDFRenderErrorReporter* reporter,
const PDFOperationControl* operationControl) const override;
virtual PDFShadingSampler* createSampler(QTransform userSpaceToDeviceSpaceMatrix) const override;
private:
friend class PDFPattern;
};
class PDFRadialShading : public PDFSingleDimensionShading
{
public:
explicit PDFRadialShading() = default;
virtual ShadingType getShadingType() const override;
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
const PDFCMS* cms,
RenderingIntent intent,
PDFRenderErrorReporter* reporter,
const PDFOperationControl* operationControl) const override;
virtual PDFShadingSampler* createSampler(QTransform userSpaceToDeviceSpaceMatrix) const override;
PDFReal getR0() const { return m_r0; }
PDFReal getR1() const { return m_r1; }
private:
friend class PDFPattern;
PDFReal m_r0 = 0.0;
PDFReal m_r1 = 0.0;
};
class PDFType4567Shading : public PDFShadingPattern
{
public:
explicit PDFType4567Shading() = default;
/// Returns color for given color or function parameter
PDFColor getColor(PDFColor colorOrFunctionParameter) const;
protected:
friend class PDFPattern;
void addSubdividedTriangles(const PDFMeshQualitySettings& settings,
PDFMesh& mesh,
uint32_t v1,
uint32_t v2,
uint32_t v3,
PDFColor c1,
PDFColor c2,
PDFColor c3,
const PDFCMS* cms,
RenderingIntent intent,
PDFRenderErrorReporter* reporter) const;
uint8_t m_bitsPerCoordinate = 0;
uint8_t m_bitsPerComponent = 0;
uint8_t m_bitsPerFlag = 0;
PDFReal m_xmin = 0.0;
PDFReal m_xmax = 0.0;
PDFReal m_ymin = 0.0;
PDFReal m_ymax = 0.0;
std::vector<PDFReal> m_limits;
size_t m_colorComponentCount = 0;
/// Color functions. This array can be empty. If it is empty,
/// then colors should be determined directly from color space.
std::vector<PDFFunctionPtr> m_functions;
/// Data of the shading, containing triangles and colors
QByteArray m_data;
};
class PDFFreeFormGouradTriangleShading : public PDFType4567Shading
{
public:
explicit PDFFreeFormGouradTriangleShading() = default;
virtual ShadingType getShadingType() const override;
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
const PDFCMS* cms,
RenderingIntent intent,
PDFRenderErrorReporter* reporter,
const PDFOperationControl* operationControl) const override;
virtual PDFShadingSampler* createSampler(QTransform userSpaceToDeviceSpaceMatrix) const override;
private:
struct VertexData
{
uint32_t index = 0;
uint8_t flags = 0;
QPointF position;
PDFColor color;
};
friend class PDFPattern;
using InitializeFunction = std::function<void(std::vector<QPointF>&&, size_t)>;
using AddTriangleFunction = std::function<void(const VertexData*, const VertexData*, const VertexData*)>;
bool processTriangles(InitializeFunction initializeMeshFunction,
AddTriangleFunction addTriangle,
const QTransform& userSpaceToDeviceSpaceMatrix,
bool convertColors) const;
};
class PDFLatticeFormGouradTriangleShading : public PDFType4567Shading
{
public:
explicit PDFLatticeFormGouradTriangleShading() = default;
virtual ShadingType getShadingType() const override;
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
const PDFCMS* cms,
RenderingIntent intent,
PDFRenderErrorReporter* reporter,
const PDFOperationControl* operationControl) const override;
virtual PDFShadingSampler* createSampler(QTransform userSpaceToDeviceSpaceMatrix) const override;
private:
friend class PDFPattern;
struct VertexData
{
uint32_t index = 0;
QPointF position;
PDFColor color;
};
using InitializeFunction = std::function<void(std::vector<QPointF>&&, size_t)>;
using AddTriangleFunction = std::function<void(const VertexData*, const VertexData*, const VertexData*)>;
bool processTriangles(InitializeFunction initializeMeshFunction,
AddTriangleFunction addTriangle,
const QTransform& userSpaceToDeviceSpaceMatrix,
bool convertColors) const;
PDFInteger m_verticesPerRow = 0;
};
class PDFTensorPatch
{
public:
enum ColorIndex
{
C_00 = 0,
C_03 = 1,
C_33 = 2,
C_30 = 3
};
using PointMatrix = std::array<std::array<QPointF, 4>, 4>;
using Colors = std::array<PDFColor, 4>;
explicit inline PDFTensorPatch(PointMatrix P, Colors colors) : m_P(P), m_colors(colors) { computeBoundingRectangle(); }
/// Calculates value at point in the patch.
/// \param u Horizontal coordinate of the patch, must be in range [0, 1]
/// \param v Vertical coordinate of the patch, must be in range [0, 1]
QPointF getValue(PDFReal u, PDFReal v) const;
/// Calculates value at point in the patch, possibly derivation, if derivation
/// variables are positive.
/// \param u Horizontal coordinate of the patch, must be in range [0, 1]
/// \param v Vertical coordinate of the patch, must be in range [0, 1]
/// \param derivativeOrderU Derivation order in direction u (0 means no derivation)
/// \param derivativeOrderV Derivation order in direction v (0 means no derivation)
QPointF getValue(PDFReal u, PDFReal v, int derivativeOrderU, int derivativeOrderV) const;
/// Tries to find value (u,v) using Newton-Raphson numerical algorithm method.
/// This can fail and when it fails, false is returned. As initial point, input uv
/// is considered. Also, if maximal number of steps is reached, false is returned.
/// \param[in,out] u Output value of u (passed value is used as a seed)
/// \param[in,out] v Output value of v (passed value is used as a seed)
/// \param x Input x coordinate, for which we want to compute (u, v)
/// \param y Input y coordinate, for which we want to compute (u, v)
/// \param epsilon Epsilon, when distance from the getValue(u, v) and (x, y)
/// is less than epsilon, convergence is reached
/// \param maximalNumberOfSteps Maximal number of steps of Newton-Raphson algorithm
bool getUV(PDFReal& u, PDFReal& v, PDFReal x, PDFReal y, PDFReal epsilon, int maximalNumberOfSteps) const;
/// Calculates first derivate in the surface, in the direction of variable u.
/// \param u Horizontal coordinate of the patch, must be in range [0, 1]
/// \param v Vertical coordinate of the patch, must be in range [0, 1]
QPointF getDerivative_u(PDFReal u, PDFReal v) const { return getValue(u, v, 1, 0); }
/// Calculates second derivate in the surface, in the direction of variable u.
/// \param u Horizontal coordinate of the patch, must be in range [0, 1]
/// \param v Vertical coordinate of the patch, must be in range [0, 1]
QPointF getDerivative_uu(PDFReal u, PDFReal v) const { return getValue(u, v, 2, 0); }
/// Calculates first derivate in the surface, in the direction of variable v.
/// \param u Horizontal coordinate of the patch, must be in range [0, 1]
/// \param v Vertical coordinate of the patch, must be in range [0, 1]
QPointF getDerivative_v(PDFReal u, PDFReal v) const { return getValue(u, v, 0, 1); }
/// Calculates second derivate in the surface, in the direction of variable v.
/// \param u Horizontal coordinate of the patch, must be in range [0, 1]
/// \param v Vertical coordinate of the patch, must be in range [0, 1]
QPointF getDerivative_vv(PDFReal u, PDFReal v) const { return getValue(u, v, 0, 2); }
/// Calculates curvature of the given point in the surface, in the direction of u.
/// \param u Horizontal coordinate of the patch, must be in range [0, 1]
/// \param v Vertical coordinate of the patch, must be in range [0, 1]
PDFReal getCurvature_u(PDFReal u, PDFReal v) const;
/// Calculates curvature of the given point in the surface, in the direction of v.
/// \param u Horizontal coordinate of the patch, must be in range [0, 1]
/// \param v Vertical coordinate of the patch, must be in range [0, 1]
PDFReal getCurvature_v(PDFReal u, PDFReal v) const;
/// Returns matrix of control points
const PointMatrix& getP() const { return m_P; }
/// Returns colors of corner points
const Colors& getColors() const { return m_colors; }
private:
/// Computes Bernstein polynomial B0, B1, B2, B3, for parameter t.
/// If \p derivative is zero, then it evaluates polynomial's value,
/// otherwise it computes value of the derivation of Bx, up to degree 3
/// derivation.
/// \param index Index of polynomial, from 0 to 3 (B0, B1, B2, B3)
/// \param t Parameter of polynomial function
/// \param derivativeOrder Derivative order (0 - value, 1 - first derivation, 2 - second derivation, 3 - third derivation)
static constexpr PDFReal B(int index, PDFReal t, int derivativeOrder);
/// Computes Bernstein polynomial B0 for parameter t.
/// If \p derivative is zero, then it evaluates polynomial's value,
/// otherwise it computes value of the derivation of B0, up to degree 3
/// derivation.
/// \param t Parameter of polynomial function
/// \param derivativeOrder Derivative order (0 - value, 1 - first derivation, 2 - second derivation, 3 - third derivation)
static constexpr PDFReal B0(PDFReal t, int derivative);
/// Computes Bernstein polynomial B1 for parameter t.
/// If \p derivative is zero, then it evaluates polynomial's value,
/// otherwise it computes value of the derivation of B1, up to degree 3
/// derivation.
/// \param t Parameter of polynomial function
/// \param derivativeOrder Derivative order (0 - value, 1 - first derivation, 2 - second derivation, 3 - third derivation)
static constexpr PDFReal B1(PDFReal t, int derivative);
/// Computes Bernstein polynomial B2 for parameter t.
/// If \p derivative is zero, then it evaluates polynomial's value,
/// otherwise it computes value of the derivation of B2, up to degree 3
/// derivation.
/// \param t Parameter of polynomial function
/// \param derivativeOrder Derivative order (0 - value, 1 - first derivation, 2 - second derivation, 3 - third derivation)
static constexpr PDFReal B2(PDFReal t, int derivative);
/// Computes Bernstein polynomial B3 for parameter t.
/// If \p derivative is zero, then it evaluates polynomial's value,
/// otherwise it computes value of the derivation of B3, up to degree 3
/// derivation.
/// \param t Parameter of polynomial function
/// \param derivativeOrder Derivative order (0 - value, 1 - first derivation, 2 - second derivation, 3 - third derivation)
static constexpr PDFReal B3(PDFReal t, int derivative);
static constexpr PDFReal pow2(PDFReal x) { return x * x; }
static constexpr PDFReal pow3(PDFReal x) { return x * x * x; }
void computeBoundingRectangle();
PointMatrix m_P = { };
Colors m_colors = { };
QRectF m_boundingBox; ///< Bounding box of the tensor product patch
};
using PDFTensorPatches = std::vector<PDFTensorPatch>;
class PDFTensorProductPatchShadingBase : public PDFType4567Shading
{
public:
explicit inline PDFTensorProductPatchShadingBase() = default;
virtual PDFShadingSampler* createSampler(QTransform userSpaceToDeviceSpaceMatrix) const override;
virtual PDFTensorPatches createPatches(QTransform userSpaceToDeviceSpaceMatrix, bool transformColor) const = 0;
protected:
struct Triangle;
void fillMesh(PDFMesh& mesh, const PDFMeshQualitySettings& settings, const PDFTensorPatch& patch, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool fastAlgorithm, const PDFOperationControl* operationControl) const;
void fillMesh(PDFMesh& mesh, const QTransform& patternSpaceToDeviceSpaceMatrix, const PDFMeshQualitySettings& settings, const PDFTensorPatches& patches, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, const PDFOperationControl* operationControl) const;
static void addTriangle(std::vector<Triangle>& triangles, const PDFTensorPatch& patch, std::array<QPointF, 3> uvCoordinates);
private:
friend class PDFPattern;
};
class PDFCoonsPatchShading : public PDFTensorProductPatchShadingBase
{
public:
explicit PDFCoonsPatchShading() = default;
virtual ShadingType getShadingType() const override;
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
const PDFCMS* cms,
RenderingIntent intent,
PDFRenderErrorReporter* reporter,
const PDFOperationControl* operationControl) const override;
virtual PDFTensorPatches createPatches(QTransform userSpaceToDeviceSpaceMatrix, bool transformColor) const override;
private:
friend class PDFPattern;
};
class PDFTensorProductPatchShading : public PDFTensorProductPatchShadingBase
{
public:
explicit PDFTensorProductPatchShading() = default;
virtual ShadingType getShadingType() const override;
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings,
const PDFCMS* cms,
RenderingIntent intent,
PDFRenderErrorReporter* reporter,
const PDFOperationControl* operationControl) const override;
virtual PDFTensorPatches createPatches(QTransform userSpaceToDeviceSpaceMatrix, bool transformColor) const override;
private:
friend class PDFPattern;
};
} // namespace pdf
#endif // PDFPATTERN_H