mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-06 00:07:29 -04:00
Address PR Comments
This commit is contained in:
parent
ac3701ef00
commit
24703f7e6a
@ -198,7 +198,7 @@ E.g. if ``path`` is "/home/user/Pictures/test.png", the returned list will conta
|
||||
%Docstring
|
||||
Creates a unique file path name from a desired path by appending "_<n>" (where "<n>" is an integer number) before the file suffix.
|
||||
|
||||
E.g. if "/path/my_image.png" already exists "/path/my_image_1.png" (and "_2", "_3" etc.) will be checked until a file path that does not already exist is found.
|
||||
E.g. if "/path/my_image.png" already exists "/path/my_image_2.png" (and "_3", "_4" etc.) will be checked until a file path that does not already exist is found.
|
||||
|
||||
:param path: the desired path.
|
||||
|
||||
|
@ -1315,7 +1315,7 @@ The ``rings`` argument optionally specifies a list of polygon rings to render as
|
||||
|
||||
virtual QImage toTiledPatternImage( ) const;
|
||||
%Docstring
|
||||
Renders the symbol layer to an image that can be used as a seamless pattern fill
|
||||
Renders the symbol layer as an image that can be used as a seamless pattern fill
|
||||
for polygons, this method is used by SLD export to generate image tiles for
|
||||
ExternalGraphic polygon fills.
|
||||
|
||||
|
@ -999,12 +999,14 @@ Evaluates a map of properties using the given ``context`` and returns a variant
|
||||
|
||||
static QSize tileSize( int width, int height, double &angleRad /In,Out/ );
|
||||
%Docstring
|
||||
Calculate the minimum size in pixels of a symbol tile given the symbol ``width`` and ``height`` and the grid rotation ``angle`` in radians.
|
||||
Calculate the minimum size in pixels of a symbol tile given the symbol ``width`` and ``height`` and the symbol layer rotation ``angleRad`` in radians (counter clockwise).
|
||||
The method makes approximations and can modify ``angle`` in order to generate the smallest possible tile.
|
||||
|
||||
.. note::
|
||||
:param width: marker width, including margins
|
||||
:param height: marker height, including margins
|
||||
:param angleRad: symbol layer rotation angle in radians (counter clockwise), it may be approximated by the method to minimize the tile size.
|
||||
|
||||
Angle must be >= 0 and < 2 * PI
|
||||
:return: the size of the tile
|
||||
|
||||
.. versionadded:: 3.30
|
||||
%End
|
||||
|
@ -540,7 +540,7 @@ QString QgsFileUtils::uniquePath( const QString &path )
|
||||
QFileInfo info { path };
|
||||
const QString suffix { info.completeSuffix() };
|
||||
const QString pathPattern { QString( suffix.length() > 0 ? path.chopped( suffix.length() + 1 ) : path ).append( QStringLiteral( "_%1." ) ).append( suffix ) };
|
||||
int i { 1 };
|
||||
int i { 2 };
|
||||
QString uniquePath { pathPattern.arg( i ) };
|
||||
while ( QFileInfo::exists( uniquePath ) )
|
||||
{
|
||||
|
@ -228,7 +228,7 @@ class CORE_EXPORT QgsFileUtils
|
||||
/**
|
||||
* Creates a unique file path name from a desired path by appending "_<n>" (where "<n>" is an integer number) before the file suffix.
|
||||
*
|
||||
* E.g. if "/path/my_image.png" already exists "/path/my_image_1.png" (and "_2", "_3" etc.) will be checked until a file path that does not already exist is found.
|
||||
* E.g. if "/path/my_image.png" already exists "/path/my_image_2.png" (and "_3", "_4" etc.) will be checked until a file path that does not already exist is found.
|
||||
*
|
||||
* \param path the desired path.
|
||||
* \return the unmodified path if path is already unique or the new path with "_<n>" (where "<n>" is an integer number) appended to the file name before the suffix.
|
||||
|
@ -1242,7 +1242,7 @@ class CORE_EXPORT QgsFillSymbolLayer : public QgsSymbolLayer
|
||||
double angle() const { return mAngle; }
|
||||
|
||||
/**
|
||||
* Renders the symbol layer to an image that can be used as a seamless pattern fill
|
||||
* Renders the symbol layer as an image that can be used as a seamless pattern fill
|
||||
* for polygons, this method is used by SLD export to generate image tiles for
|
||||
* ExternalGraphic polygon fills.
|
||||
*
|
||||
|
@ -5101,8 +5101,12 @@ QgsStringMap QgsSymbolLayerUtils::evaluatePropertiesMap( const QMap<QString, Qgs
|
||||
QSize QgsSymbolLayerUtils::tileSize( int width, int height, double &angleRad )
|
||||
{
|
||||
|
||||
// Precondition
|
||||
Q_ASSERT( angleRad >= 0 && angleRad < M_PI * 2 );
|
||||
angleRad = std::fmod( angleRad, M_PI * 2 );
|
||||
|
||||
if ( angleRad < 0 )
|
||||
{
|
||||
angleRad += M_PI * 2;
|
||||
}
|
||||
|
||||
// tan with rational sin/cos
|
||||
struct rationalTangent
|
||||
@ -5257,13 +5261,13 @@ QSize QgsSymbolLayerUtils::tileSize( int width, int height, double &angleRad )
|
||||
}
|
||||
}
|
||||
|
||||
if ( qgsDoubleNear( angleRad, 0 ) )
|
||||
if ( qgsDoubleNear( angleRad, 0, 10E-3 ) )
|
||||
{
|
||||
angleRad = 0;
|
||||
tileSize.setWidth( width );
|
||||
tileSize.setHeight( height );
|
||||
}
|
||||
else if ( qgsDoubleNear( angleRad, M_PI_2 ) )
|
||||
else if ( qgsDoubleNear( angleRad, M_PI_2, 10E-3 ) )
|
||||
{
|
||||
angleRad = M_PI_2;
|
||||
tileSize.setWidth( height );
|
||||
@ -5277,9 +5281,8 @@ QSize QgsSymbolLayerUtils::tileSize( int width, int height, double &angleRad )
|
||||
for ( int idx = 0; idx < rationalTangents.count(); ++idx )
|
||||
{
|
||||
const auto item = rationalTangents.at( idx );
|
||||
if ( qgsDoubleNear( item.angle, angleRad ) || item.angle > angleRad )
|
||||
if ( qgsDoubleNear( item.angle, angleRad, 10E-3 ) || item.angle > angleRad )
|
||||
{
|
||||
angleRad = item.angle;
|
||||
rTanIdx = idx;
|
||||
break;
|
||||
}
|
||||
|
@ -898,9 +898,12 @@ class CORE_EXPORT QgsSymbolLayerUtils
|
||||
static QgsStringMap evaluatePropertiesMap( const QMap<QString, QgsProperty> &propertiesMap, const QgsExpressionContext &context );
|
||||
|
||||
/**
|
||||
* Calculate the minimum size in pixels of a symbol tile given the symbol \a width and \a height and the grid rotation \a angle in radians.
|
||||
* Calculate the minimum size in pixels of a symbol tile given the symbol \a width and \a height and the symbol layer rotation \a angleRad in radians (counter clockwise).
|
||||
* The method makes approximations and can modify \a angle in order to generate the smallest possible tile.
|
||||
* \note Angle must be >= 0 and < 2 * PI
|
||||
* \param width marker width, including margins
|
||||
* \param height marker height, including margins
|
||||
* \param angleRad symbol layer rotation angle in radians (counter clockwise), it may be approximated by the method to minimize the tile size.
|
||||
* \return the size of the tile
|
||||
* \since QGIS 3.30
|
||||
*/
|
||||
static QSize tileSize( int width, int height, double &angleRad SIP_INOUT );
|
||||
|
@ -20,6 +20,7 @@ from qgis.core import (
|
||||
Qgis,
|
||||
QgsFileUtils
|
||||
)
|
||||
from qgis.PyQt.QtCore import QTemporaryDir
|
||||
from qgis.testing import unittest
|
||||
from utilities import unitTestDataPath
|
||||
|
||||
@ -311,6 +312,24 @@ class TestQgsFileUtils(unittest.TestCase):
|
||||
self.assertEqual(QgsFileUtils.splitPathToComponents(''), [])
|
||||
self.assertEqual(QgsFileUtils.splitPathToComponents('c:/home/user'), ["c:", "home", "user"])
|
||||
|
||||
def testUniquePath(self):
|
||||
temp_dir = QTemporaryDir()
|
||||
temp_path = temp_dir.path()
|
||||
|
||||
with open(os.path.join(temp_path, 'test.txt'), 'w+') as f:
|
||||
f.close()
|
||||
|
||||
self.assertEqual(QgsFileUtils.uniquePath(os.path.join(temp_path, 'my_test.txt')), os.path.join(temp_path, 'my_test.txt'))
|
||||
|
||||
self.assertEqual(QgsFileUtils.uniquePath(os.path.join(temp_path, 'test.txt')), os.path.join(temp_path, 'test_2.txt'))
|
||||
|
||||
with open(os.path.join(temp_path, 'test_2.txt'), 'w+') as f:
|
||||
f.close()
|
||||
|
||||
self.assertEqual(QgsFileUtils.uniquePath(os.path.join(temp_path, 'test_2.txt')), os.path.join(temp_path, 'test_2_2.txt'))
|
||||
self.assertEqual(QgsFileUtils.uniquePath(os.path.join(temp_path, 'test.txt')), os.path.join(temp_path, 'test_3.txt'))
|
||||
self.assertEqual(QgsFileUtils.uniquePath(os.path.join(temp_path, 'test_1.txt')), os.path.join(temp_path, 'test_1.txt'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
@ -690,11 +690,62 @@ class PyQgsSymbolLayerUtils(unittest.TestCase):
|
||||
[10, 20, math.pi + math.pi / 2 + math.pi / 6, 72, 36, math.pi + math.pi / 2 + 0.5880031703261417], # Angle approx
|
||||
[10, 10, math.pi + math.pi / 2 + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi + math.pi / 2 + math.pi / 4],
|
||||
[10, 20, math.pi + math.pi / 2 + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi + math.pi / 2 + math.pi / 4],
|
||||
|
||||
# Test out of range angles > 2 PI
|
||||
|
||||
# First quadrant
|
||||
[10, 10, math.pi * 2 + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi / 4],
|
||||
[10, 20, math.pi * 2 + math.pi / 2, 20, 10, math.pi / 2],
|
||||
[10, 20, math.pi * 2 + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi / 4],
|
||||
[10, 20, math.pi * 2 + math.pi / 6, 36, 72, 0.5880031703261417], # Angle approx
|
||||
|
||||
# Second quadrant
|
||||
[10, 20, math.pi * 2 + math.pi / 2 + math.pi / 6, 72, 36, math.pi / 2 + 0.5880031703261417], # Angle approx
|
||||
[10, 10, math.pi * 2 + math.pi / 2 + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi / 2 + math.pi / 4],
|
||||
[10, 20, math.pi * 2 + math.pi / 2 + math.pi / 2, 10, 20, math.pi / 2 + math.pi / 2],
|
||||
[10, 20, math.pi * 2 + math.pi / 2 + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi / 2 + math.pi / 4],
|
||||
|
||||
# Third quadrant
|
||||
[10, 20, math.pi * 2 + math.pi + math.pi / 6, 36, 72, math.pi + 0.5880031703261417], # Angle approx
|
||||
[10, 10, math.pi * 2 + math.pi + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi + math.pi / 4],
|
||||
[10, 20, math.pi * 2 + math.pi + math.pi / 2, 20, 10, math.pi + math.pi / 2],
|
||||
[10, 20, math.pi * 2 + math.pi + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi + math.pi / 4],
|
||||
|
||||
# Fourth quadrant
|
||||
[10, 20, math.pi * 2 + math.pi + math.pi / 2 + math.pi / 6, 72, 36, math.pi + math.pi / 2 + 0.5880031703261417], # Angle approx
|
||||
[10, 10, math.pi * 2 + math.pi + math.pi / 2 + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi + math.pi / 2 + math.pi / 4],
|
||||
[10, 20, math.pi * 2 + math.pi + math.pi / 2 + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi + math.pi / 2 + math.pi / 4],
|
||||
|
||||
# Test out of range angles < 0
|
||||
|
||||
# First quadrant
|
||||
[10, 10, - math.pi * 2 + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi / 4],
|
||||
[10, 20, - math.pi * 2 + math.pi / 2, 20, 10, math.pi / 2],
|
||||
[10, 20, - math.pi * 2 + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi / 4],
|
||||
[10, 20, - math.pi * 2 + math.pi / 6, 36, 72, 0.5880031703261417], # Angle approx
|
||||
|
||||
# Second quadrant
|
||||
[10, 20, - math.pi * 2 + math.pi / 2 + math.pi / 6, 72, 36, math.pi / 2 + 0.5880031703261417], # Angle approx
|
||||
[10, 10, - math.pi * 2 + math.pi / 2 + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi / 2 + math.pi / 4],
|
||||
[10, 20, - math.pi * 2 + math.pi / 2 + math.pi / 2, 10, 20, math.pi / 2 + math.pi / 2],
|
||||
[10, 20, - math.pi * 2 + math.pi / 2 + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi / 2 + math.pi / 4],
|
||||
|
||||
# Third quadrant
|
||||
[10, 20, - math.pi * 2 + math.pi + math.pi / 6, 36, 72, math.pi + 0.5880031703261417], # Angle approx
|
||||
[10, 10, - math.pi * 2 + math.pi + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi + math.pi / 4],
|
||||
[10, 20, - math.pi * 2 + math.pi + math.pi / 2, 20, 10, math.pi + math.pi / 2],
|
||||
[10, 20, - math.pi * 2 + math.pi + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi + math.pi / 4],
|
||||
|
||||
# Fourth quadrant
|
||||
[10, 20, - math.pi * 2 + math.pi + math.pi / 2 + math.pi / 6, 72, 36, math.pi + math.pi / 2 + 0.5880031703261417], # Angle approx
|
||||
[10, 10, - math.pi * 2 + math.pi + math.pi / 2 + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi + math.pi / 2 + math.pi / 4],
|
||||
[10, 20, - math.pi * 2 + math.pi + math.pi / 2 + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi + math.pi / 2 + math.pi / 4],
|
||||
|
||||
]
|
||||
|
||||
for width, height, angle, exp_width, exp_height, exp_angle in test_data:
|
||||
(res_size, res_angle) = QgsSymbolLayerUtils.tileSize(width, height, angle)
|
||||
self.assertEqual(res_size.height(), int(exp_height))
|
||||
self.assertEqual(res_size.height(), int(exp_height), angle)
|
||||
self.assertEqual(res_size.width(), int(exp_width))
|
||||
self.assertAlmostEqual(res_angle, exp_angle)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user