PDF4QT/Pdf4QtLib/sources/pdfpattern.h

714 lines
30 KiB
C
Raw Normal View History

2021-04-30 20:12:10 +02:00
// Copyright (C) 2019-2021 Jakub Melka
2019-08-25 18:16:37 +02:00
//
2021-08-10 19:22:56 +02:00
// This file is part of PDF4QT.
2019-08-25 18:16:37 +02:00
//
2021-08-10 19:22:56 +02:00
// PDF4QT is free software: you can redistribute it and/or modify
2019-08-25 18:16:37 +02:00
// 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
2021-04-30 20:12:10 +02:00
// with the written consent of the copyright owner, any later version.
2019-08-25 18:16:37 +02:00
//
2021-08-10 19:22:56 +02:00
// PDF4QT is distributed in the hope that it will be useful,
2019-08-25 18:16:37 +02:00
// 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
2021-08-10 19:22:56 +02:00
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
2019-08-25 18:16:37 +02:00
#ifndef PDFPATTERN_H
#define PDFPATTERN_H
#include "pdfobject.h"
#include "pdffunction.h"
#include "pdfcolorspaces.h"
2019-09-28 18:26:31 +02:00
#include "pdfmeshqualitysettings.h"
2019-08-25 18:16:37 +02:00
#include <QMatrix>
#include <memory>
namespace pdf
{
class PDFPattern;
2019-09-25 19:17:52 +02:00
class PDFTilingPattern;
2019-08-31 15:55:59 +02:00
class PDFShadingPattern;
2019-08-25 18:16:37 +02:00
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
};
2019-08-31 14:37:18 +02:00
/// 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
2019-09-29 15:44:35 +02:00
/// \param alpha Opacity factor
void paint(QPainter* painter, PDFReal alpha) const;
2019-08-31 14:37:18 +02:00
/// Transforms the mesh according to the matrix transform
/// \param matrix Matrix transform to be performed
void transform(const QMatrix& 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; }
2019-09-08 18:11:09 +02:00
/// Sets the vertex array to the mesh
/// \param vertices New vertex array
2019-09-08 17:17:12 +02:00
void setVertices(std::vector<QPointF>&& vertices) { m_vertices = qMove(vertices); }
2019-09-08 18:11:09 +02:00
/// Sets the triangle array to the mesh
/// \param triangles New triangle array
2019-09-08 17:17:12 +02:00
void setTriangles(std::vector<Triangle>&& triangles) { m_triangles = qMove(triangles); }
2019-09-22 13:18:42 +02:00
/// 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);
2019-09-08 17:17:12 +02:00
/// 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;
2019-09-08 18:11:09 +02:00
/// 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; }
2019-09-22 13:18:42 +02:00
/// 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;
2020-01-28 19:17:45 +01:00
/// Invert colors
void invertColors();
2019-08-31 14:37:18 +02:00
private:
std::vector<QPointF> m_vertices;
std::vector<Triangle> m_triangles;
QPainterPath m_boundingPath;
2019-09-08 18:11:09 +02:00
QPainterPath m_backgroundPath;
QColor m_backgroundColor;
2019-08-31 14:37:18 +02:00
};
2019-08-25 18:16:37 +02:00
/// Represents tiling/shading pattern
class PDFPattern
{
public:
explicit PDFPattern() = default;
virtual ~PDFPattern() = default;
virtual PatternType getType() const = 0;
2019-08-31 15:55:59 +02:00
virtual const PDFShadingPattern* getShadingPattern() const = 0;
2019-09-25 19:17:52 +02:00
virtual const PDFTilingPattern* getTilingPattern() const = 0;
2019-08-25 18:16:37 +02:00
/// 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 QMatrix& 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
2019-12-25 17:56:17 +01:00
/// \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);
2019-08-25 18:16:37 +02:00
/// 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
2019-12-25 17:56:17 +01:00
/// \param cms Color management system
/// \param intent Rendering intent
/// \param reporter Error reporter
2019-08-25 18:16:37 +02:00
/// \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 QMatrix& matrix,
const PDFObject& patternGraphicState,
2019-12-25 17:56:17 +01:00
const PDFCMS* cms,
RenderingIntent intent,
PDFRenderErrorReporter* reporter,
2019-08-25 18:16:37 +02:00
bool ignoreBackgroundColor);
2019-08-31 14:37:18 +02:00
protected:
2019-08-25 18:16:37 +02:00
QRectF m_boundingBox;
QMatrix m_matrix;
};
2019-09-13 16:28:20 +02:00
class PDFInvalidPattern : public PDFPattern
{
public:
explicit PDFInvalidPattern() = default;
2021-03-06 18:13:21 +01:00
virtual PatternType getType() const override { return PatternType::Invalid; }
2019-09-25 19:17:52 +02:00
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
2019-09-25 19:17:52 +02:00
};
enum class TilingType
{
ConstantSpacing = 1,
NoDistortion = 2,
ConstantSpacingAndFasterTiling = 3,
2019-09-25 19:17:52 +02:00
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;
2019-09-13 16:28:20 +02:00
};
2021-03-01 15:24:04 +01:00
/// 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;
};
2019-08-25 18:16:37 +02:00
/// 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;
2019-08-31 15:55:59 +02:00
virtual const PDFShadingPattern* getShadingPattern() const override { return this; }
2019-09-25 19:17:52 +02:00
virtual const PDFTilingPattern* getTilingPattern() const override { return nullptr; }
2019-08-25 18:16:37 +02:00
2019-08-31 15:55:59 +02:00
/// Creates a colored mesh using settings. Mesh is generated in device space
/// coordinate system. You must transform the mesh, if you want to
2019-09-08 17:17:12 +02:00
/// use it in another coordinate system.
2019-08-31 14:37:18 +02:00
/// \param settings Meshing settings
2019-12-25 17:56:17 +01:00
/// \param cms Color management system
/// \param intent Rendering intent
/// \param reporter Error reporter
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const = 0;
2019-08-31 14:37:18 +02:00
2019-08-25 18:16:37 +02:00
/// 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; }
2019-08-25 18:16:37 +02:00
/// 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; }
2021-03-01 15:24:04 +01:00
/// Returns original background color (in color space of the shading pattern)
const PDFColor& getOriginalBackgroundColor() const { return m_originalBackgroundColor; }
2019-08-25 18:16:37 +02:00
/// Returns true, if shading pattern should be anti-aliased
bool isAntialiasing() const { return m_antiAlias; }
2019-09-16 19:42:14 +02:00
/// Returns matrix transforming pattern space to device space
QMatrix getPatternSpaceToDeviceSpaceMatrix(const PDFMeshQualitySettings& settings) const;
2021-03-13 15:05:15 +01:00
/// Returns matrix transforming pattern space to device space
QMatrix getPatternSpaceToDeviceSpaceMatrix(const QMatrix& userSpaceToDeviceSpaceMatrix) const;
2021-03-01 15:24:04 +01:00
/// 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(QMatrix userSpaceToDeviceSpaceMatrix) const;
2019-08-31 14:37:18 +02:00
protected:
2019-08-25 18:16:37 +02:00
friend class PDFPattern;
PDFObject m_patternGraphicState;
PDFColorSpacePointer m_colorSpace;
QColor m_backgroundColor;
2021-03-01 15:24:04 +01:00
PDFColor m_originalBackgroundColor;
2019-08-25 18:16:37 +02:00
bool m_antiAlias = false;
};
class PDFSingleDimensionShading : public PDFShadingPattern
{
public:
explicit PDFSingleDimensionShading() = default;
2021-03-01 15:24:04 +01:00
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; }
2019-08-31 14:37:18 +02:00
protected:
2019-08-25 18:16:37 +02:00
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;
};
2019-09-08 17:17:12 +02:00
class PDFFunctionShading : public PDFShadingPattern
{
public:
explicit PDFFunctionShading() = default;
virtual ShadingType getShadingType() const override;
2019-12-25 17:56:17 +01:00
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
2021-03-08 19:16:39 +01:00
virtual PDFShadingSampler* createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const override;
const QRectF& getDomain() const { return m_domain; }
const QMatrix& getDomainToTargetTransform() const { return m_domainToTargetTransform; }
const std::vector<PDFFunctionPtr>& getFunctions() const { return m_functions; }
2019-09-08 17:17:12 +02:00
private:
friend class PDFPattern;
QRectF m_domain; ///< Domain of the color function
QMatrix m_domainToTargetTransform; ///< Transformation mapping from domain to shading coordinate space
std::vector<PDFFunctionPtr> m_functions; ///< Color functions
};
2019-08-25 18:16:37 +02:00
class PDFAxialShading : public PDFSingleDimensionShading
{
public:
explicit PDFAxialShading() = default;
virtual ShadingType getShadingType() const override;
2019-12-25 17:56:17 +01:00
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
2021-03-06 18:13:21 +01:00
virtual PDFShadingSampler* createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const override;
2019-08-25 18:16:37 +02:00
private:
friend class PDFPattern;
};
2019-09-12 19:41:12 +02:00
class PDFRadialShading : public PDFSingleDimensionShading
{
public:
explicit PDFRadialShading() = default;
virtual ShadingType getShadingType() const override;
2019-12-25 17:56:17 +01:00
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
2021-03-10 19:01:17 +01:00
virtual PDFShadingSampler* createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const override;
PDFReal getR0() const { return m_r0; }
PDFReal getR1() const { return m_r1; }
2019-09-12 19:41:12 +02:00
private:
friend class PDFPattern;
PDFReal m_r0 = 0.0;
PDFReal m_r1 = 0.0;
};
2019-09-20 18:19:21 +02:00
class PDFType4567Shading : public PDFShadingPattern
2019-09-15 16:50:34 +02:00
{
public:
2019-09-20 18:19:21 +02:00
explicit PDFType4567Shading() = default;
2019-09-15 16:50:34 +02:00
2019-09-20 18:19:21 +02:00
/// Returns color for given color or function parameter
PDFColor getColor(PDFColor colorOrFunctionParameter) const;
2021-03-13 15:05:15 +01:00
protected:
friend class PDFPattern;
2019-12-25 17:56:17 +01:00
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;
2019-09-15 16:50:34 +02:00
uint8_t m_bitsPerCoordinate = 0;
uint8_t m_bitsPerComponent = 0;
2019-09-20 18:19:21 +02:00
uint8_t m_bitsPerFlag = 0;
2019-09-15 16:50:34 +02:00
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;
2019-09-15 18:01:13 +02:00
size_t m_colorComponentCount = 0;
2019-09-15 16:50:34 +02:00
/// 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;
};
2019-09-20 18:19:21 +02:00
class PDFFreeFormGouradTriangleShading : public PDFType4567Shading
2019-09-15 16:50:34 +02:00
{
public:
explicit PDFFreeFormGouradTriangleShading() = default;
virtual ShadingType getShadingType() const override;
2019-12-25 17:56:17 +01:00
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
2021-03-13 15:05:15 +01:00
virtual PDFShadingSampler* createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const override;
2019-09-15 16:50:34 +02:00
private:
2021-03-13 15:05:15 +01:00
struct VertexData
{
uint32_t index = 0;
uint8_t flags = 0;
QPointF position;
PDFColor color;
};
2019-09-15 16:50:34 +02:00
friend class PDFPattern;
2021-03-13 15:05:15 +01:00
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 QMatrix& userSpaceToDeviceSpaceMatrix,
bool convertColors) const;
2019-09-15 16:50:34 +02:00
};
2019-09-20 18:19:21 +02:00
class PDFLatticeFormGouradTriangleShading : public PDFType4567Shading
2019-09-15 16:50:34 +02:00
{
public:
explicit PDFLatticeFormGouradTriangleShading() = default;
virtual ShadingType getShadingType() const override;
2019-12-25 17:56:17 +01:00
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
virtual PDFShadingSampler* createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const override;
2019-09-15 16:50:34 +02:00
private:
friend class PDFPattern;
2019-09-15 18:01:13 +02:00
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 QMatrix& userSpaceToDeviceSpaceMatrix,
bool convertColors) const;
2019-09-15 18:01:13 +02:00
PDFInteger m_verticesPerRow = 0;
2019-09-15 16:50:34 +02:00
};
2019-09-17 19:47:35 +02:00
class PDFTensorPatch
{
public:
2019-09-20 18:19:21 +02:00
enum ColorIndex
{
C_00 = 0,
C_03 = 1,
C_33 = 2,
C_30 = 3
};
2019-09-17 19:47:35 +02:00
using PointMatrix = std::array<std::array<QPointF, 4>, 4>;
2019-09-20 18:19:21 +02:00
using Colors = std::array<PDFColor, 4>;
2019-09-17 19:47:35 +02:00
explicit inline PDFTensorPatch(PointMatrix P, Colors colors) : m_P(P), m_colors(colors) { computeBoundingRectangle(); }
2019-09-17 19:47:35 +02:00
/// 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;
2021-03-14 15:51:06 +01:00
/// 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;
2019-09-17 19:47:35 +02:00
/// 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;
2019-09-20 18:19:21 +02:00
/// Returns matrix of control points
const PointMatrix& getP() const { return m_P; }
/// Returns colors of corner points
const Colors& getColors() const { return m_colors; }
2019-09-17 19:47:35 +02:00
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();
2019-09-20 18:19:21 +02:00
PointMatrix m_P = { };
Colors m_colors = { };
QRectF m_boundingBox; ///< Bounding box of the tensor product patch
2019-09-20 18:19:21 +02:00
};
using PDFTensorPatches = std::vector<PDFTensorPatch>;
class PDFTensorProductPatchShadingBase : public PDFType4567Shading
{
public:
explicit inline PDFTensorProductPatchShadingBase() = default;
2021-03-14 15:51:06 +01:00
virtual PDFShadingSampler* createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const override;
virtual PDFTensorPatches createPatches(QMatrix userSpaceToDeviceSpaceMatrix, bool transformColor) const = 0;
2019-09-20 18:19:21 +02:00
protected:
2019-09-21 15:16:37 +02:00
struct Triangle;
void fillMesh(PDFMesh& mesh, const PDFMeshQualitySettings& settings, const PDFTensorPatch& patch, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool fastAlgorithm) const;
2019-12-25 17:56:17 +01:00
void fillMesh(PDFMesh& mesh, const QMatrix& patternSpaceToDeviceSpaceMatrix, const PDFMeshQualitySettings& settings, const PDFTensorPatches& patches, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const;
2019-09-21 15:16:37 +02:00
static void addTriangle(std::vector<Triangle>& triangles, const PDFTensorPatch& patch, std::array<QPointF, 3> uvCoordinates);
2019-09-20 18:19:21 +02:00
private:
friend class PDFPattern;
};
2019-09-22 13:18:42 +02:00
class PDFCoonsPatchShading : public PDFTensorProductPatchShadingBase
{
public:
explicit PDFCoonsPatchShading() = default;
virtual ShadingType getShadingType() const override;
2019-12-25 17:56:17 +01:00
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
2021-03-14 15:51:06 +01:00
virtual PDFTensorPatches createPatches(QMatrix userSpaceToDeviceSpaceMatrix, bool transformColor) const override;
2019-09-22 13:18:42 +02:00
private:
friend class PDFPattern;
};
2019-09-20 18:19:21 +02:00
class PDFTensorProductPatchShading : public PDFTensorProductPatchShadingBase
{
public:
explicit PDFTensorProductPatchShading() = default;
virtual ShadingType getShadingType() const override;
2019-12-25 17:56:17 +01:00
virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
2021-03-14 15:51:06 +01:00
virtual PDFTensorPatches createPatches(QMatrix userSpaceToDeviceSpaceMatrix, bool transformColor) const override;
2019-09-20 18:19:21 +02:00
private:
friend class PDFPattern;
2019-09-17 19:47:35 +02:00
};
2019-08-25 18:16:37 +02:00
} // namespace pdf
#endif // PDFPATTERN_H