mirror of
https://github.com/qgis/QGIS.git
synced 2025-12-15 00:07:25 -05:00
[FEATURE][processing] Add "random points on lines" algorithm
The Random points on lines algorithm supplements the existing "Random points along line" algorithm, and will prove to be more useful to the majority of users than the "original". Features: The points are distributed randomly over the lines based on "along the line" distance, meaning that the distribution of the points will be flat over the length of the line (each place on the feature has the same probability of being "hit"). The Random points along line, on the other hand, uses a line segment based approach, meaning that the density will depend on the segment length (short segments will have a higher point density than longer ones).
This commit is contained in:
parent
3a74358fee
commit
c774ade88f
@ -112,6 +112,7 @@
|
||||
<file>themes/default/algorithms/mAlgorithmNearestNeighbour.svg</file>
|
||||
<file>themes/default/algorithms/mAlgorithmNetworkAnalysis.svg</file>
|
||||
<file>themes/default/algorithms/mAlgorithmPolygonToLine.svg</file>
|
||||
<file>themes/default/algorithms/mAlgorithmRandomPointsOnLines.svg</file>
|
||||
<file>themes/default/algorithms/mAlgorithmRandomPointsWithinPolygon.svg</file>
|
||||
<file>themes/default/algorithms/mAlgorithmRandomPointsWithinExtent.svg</file>
|
||||
<file>themes/default/algorithms/mAlgorithmRegularPoints.svg</file>
|
||||
|
||||
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 6.35 6.35"
|
||||
version="1.1"
|
||||
id="svg20"
|
||||
sodipodi:docname="mAlgorithmRandomPointsOnLines.svg"
|
||||
inkscape:version="0.92.4 (f8dce91, 2019-08-02)">
|
||||
<metadata
|
||||
id="metadata26">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs24" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1312"
|
||||
inkscape:window-height="1127"
|
||||
id="namedview22"
|
||||
showgrid="false"
|
||||
inkscape:zoom="29.816738"
|
||||
inkscape:cx="7.3227221"
|
||||
inkscape:cy="10.572049"
|
||||
inkscape:window-x="67"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg20" />
|
||||
<g
|
||||
id="g4547"
|
||||
style="stroke:#afafaf;stroke-opacity:0.99435025">
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3733"
|
||||
d="M 0.23699003,0.19522033 2.3692648,3.395074 2.0941816,4.6196379 0.3460723,6.1192849"
|
||||
style="fill:none;stroke:#afafaf;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.99435025" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4540"
|
||||
d="M 2.4225069,0.50226379 5.3064434,1.9131743 4.7119087,5.4537611"
|
||||
style="fill:none;stroke:#afafaf;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.99435025" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4542"
|
||||
d="M 3.842291,1.1500403 2.9105575,1.8510588 3.1856407,3.2176011 3.7180599,6.5807148"
|
||||
style="fill:none;stroke:#afafaf;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.99435025" />
|
||||
</g>
|
||||
<circle
|
||||
cx="4.4182353"
|
||||
cy="1.4027646"
|
||||
id="circle6"
|
||||
style="fill:#cc0000;fill-opacity:1;stroke:#5e5e5e;stroke-width:0.18342039;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
r="0.30516481" />
|
||||
<circle
|
||||
cx="5.0579815"
|
||||
cy="3.4926841"
|
||||
id="circle6-3"
|
||||
style="fill:#cc0000;fill-opacity:1;stroke:#5e5e5e;stroke-width:0.18342039;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
r="0.30516481" />
|
||||
<circle
|
||||
cx="2.8661895"
|
||||
cy="0.72410506"
|
||||
id="circle6-6"
|
||||
style="fill:#cc0000;fill-opacity:1;stroke:#5e5e5e;stroke-width:0.18342039;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
r="0.30516481" />
|
||||
<circle
|
||||
cx="2.9283047"
|
||||
cy="1.8776797"
|
||||
id="circle6-7"
|
||||
style="fill:#cc0000;fill-opacity:1;stroke:#5e5e5e;stroke-width:0.18342039;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
r="0.30516481" />
|
||||
<circle
|
||||
cx="3.7003126"
|
||||
cy="6.3322525"
|
||||
id="circle6-5"
|
||||
style="fill:#cc0000;fill-opacity:1;stroke:#5e5e5e;stroke-width:0.18342039;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
r="0.30516481" />
|
||||
<circle
|
||||
cx="0.95835429"
|
||||
cy="1.2565242"
|
||||
id="circle6-35"
|
||||
style="fill:#cc0000;fill-opacity:1;stroke:#5e5e5e;stroke-width:0.18342039;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
r="0.30516481" />
|
||||
<circle
|
||||
cx="1.5706362"
|
||||
cy="5.0899415"
|
||||
id="circle6-62"
|
||||
style="fill:#cc0000;fill-opacity:1;stroke:#5e5e5e;stroke-width:0.18342039;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
r="0.30516481" />
|
||||
<circle
|
||||
cx="0.80750227"
|
||||
cy="5.7110972"
|
||||
id="circle6-9"
|
||||
style="fill:#cc0000;fill-opacity:1;stroke:#5e5e5e;stroke-width:0.18342039;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
r="0.30516481" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
194
python/plugins/processing/tests/testdata/expected/randompointsonlines.gml
vendored
Normal file
194
python/plugins/processing/tests/testdata/expected/randompointsonlines.gml
vendored
Normal file
@ -0,0 +1,194 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://ogr.maptools.org/ randompointsonlines.xsd"
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml">
|
||||
<gml:boundedBy>
|
||||
<gml:Box>
|
||||
<gml:coord><gml:X>-0.6048972614132321</gml:X><gml:Y>-1</gml:Y></gml:coord>
|
||||
<gml:coord><gml:X>5.5706404884031</gml:X><gml:Y>2.983529974375954</gml:Y></gml:coord>
|
||||
</gml:Box>
|
||||
</gml:boundedBy>
|
||||
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.0">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0.680375434309419,-1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>0</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.1">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>-0.211234146361814,-1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>1</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.2">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0.566198447517212,-1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>2</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.3">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0.596880066952147,-1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>3</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.4">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0.823294715873569,-1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>4</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.5">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>-0.604897261413232,-1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>5</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.6">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>-0.329554488570222,-1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>6</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.7">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0.536459189623808,-1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>7</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.8">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>-0.444450578393624,-1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>8</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.9">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0.107939911590861,-1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>9</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.10">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>4.63030422879655,1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>10</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.11">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5.02166180257582,2.26721545068545</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>11</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.12">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>4.24573385250727,1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>12</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.13">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>4.7532568994615,1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>13</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.14">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5.00278822202651,1.16311098855098</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>14</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.15">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5.00489146772082,1.28615086166781</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>15</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.16">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5.02126252335406,2.24385761621232</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>16</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.17">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5.01650061531363,1.96528599584743</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>17</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.18">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3.48357073824498,1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>18</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.19">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5.02294016604118,2.3419997134092</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>19</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.20">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2.0,0.148289222714595</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>20</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.21">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2.20958450135476,2.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>21</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.22">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2.0,1.24842025927014</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>22</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.23">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3.79936109924074,2.98352997437595</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>23</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.24">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2.0,1.42533776707812</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>24</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.25">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3.0,2.64746304269474</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>25</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.26">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2.0,1.1807269654443</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>26</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.27">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2.0,0.989853181150094</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>27</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.28">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5.5706404884031,2.94703455703008</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>28</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines fid="randompointsonlines.29">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2.0,1.98552220048164</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>29</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
||||
30
python/plugins/processing/tests/testdata/expected/randompointsonlines.xsd
vendored
Normal file
30
python/plugins/processing/tests/testdata/expected/randompointsonlines.xsd
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema targetNamespace="http://ogr.maptools.org/" xmlns:ogr="http://ogr.maptools.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" version="1.0">
|
||||
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
|
||||
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
|
||||
<xs:complexType name="FeatureCollectionType">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureCollectionType">
|
||||
<xs:attribute name="lockId" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="scope" type="xs:string" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="randompointsonlines" type="ogr:randompointsonlines_Type" substitutionGroup="gml:_Feature"/>
|
||||
<xs:complexType name="randompointsonlines_Type">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureType">
|
||||
<xs:sequence>
|
||||
<xs:element name="geometryProperty" type="gml:PointPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="rand_point_id" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:long">
|
||||
<xs:totalDigits value="20"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
80
python/plugins/processing/tests/testdata/expected/randompointsonlines_min1.gml
vendored
Normal file
80
python/plugins/processing/tests/testdata/expected/randompointsonlines_min1.gml
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://ogr.maptools.org/ randompointsonlines_min1.xsd"
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml">
|
||||
<gml:boundedBy>
|
||||
<gml:Box>
|
||||
<gml:coord><gml:X>-0.6048972614132321</gml:X><gml:Y>-1</gml:Y></gml:coord>
|
||||
<gml:coord><gml:X>5.024009965311047</gml:X><gml:Y>4.087663824917874</gml:Y></gml:coord>
|
||||
</gml:Box>
|
||||
</gml:boundedBy>
|
||||
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines_min1 fid="lines.1">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0.680375434309419,-1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>0</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines_min1>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines_min1 fid="lines.1">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>-0.604897261413232,-1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>1</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines_min1>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines_min1 fid="lines.2">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3.78192308908572,1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>2</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines_min1>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines_min1 fid="lines.2">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5.00622356441067,1.36407851802445</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>3</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines_min1>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines_min1 fid="lines.2">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5.02400996531105,2.40458297069628</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>4</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines_min1>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines_min1 fid="lines.4">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2.0,0.472496747038147</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>5</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines_min1>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines_min1 fid="lines.4">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2.0,1.85881400670919</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>6</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines_min1>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines_min1 fid="lines.4">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>4.34649820175951,4.08766382491787</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>7</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines_min1>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines_min1 fid="lines.4">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3.0,2.56327625716933</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>8</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines_min1>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines_min1 fid="lines.4">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3.94050479649075,2.98062185148558</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>9</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines_min1>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:randompointsonlines_min1 fid="lines.4">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3.06145271169873,4.05059520501228</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:rand_point_id>10</ogr:rand_point_id>
|
||||
</ogr:randompointsonlines_min1>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
||||
30
python/plugins/processing/tests/testdata/expected/randompointsonlines_min1.xsd
vendored
Normal file
30
python/plugins/processing/tests/testdata/expected/randompointsonlines_min1.xsd
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema targetNamespace="http://ogr.maptools.org/" xmlns:ogr="http://ogr.maptools.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" version="1.0">
|
||||
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
|
||||
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
|
||||
<xs:complexType name="FeatureCollectionType">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureCollectionType">
|
||||
<xs:attribute name="lockId" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="scope" type="xs:string" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="randompointsonlines_min1" type="ogr:randompointsonlines_min1_Type" substitutionGroup="gml:_Feature"/>
|
||||
<xs:complexType name="randompointsonlines_min1_Type">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureType">
|
||||
<xs:sequence>
|
||||
<xs:element name="geometryProperty" type="gml:PointPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="rand_point_id" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:long">
|
||||
<xs:totalDigits value="20"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
@ -588,6 +588,40 @@ tests:
|
||||
type: vector
|
||||
name: randompointsinextent.gml
|
||||
|
||||
- algorithm: native:randompointsonlines
|
||||
name: Random points on lines, seed 1, multilines - one empty geom
|
||||
params:
|
||||
INCLUDE_LINE_ATTRIBUTES: false
|
||||
INPUT:
|
||||
name: multilines.gml|layername=multilines
|
||||
type: vector
|
||||
MAX_TRIES_PER_POINT: 10
|
||||
MIN_DISTANCE: 0.0
|
||||
POINTS_NUMBER: 10
|
||||
SEED: 1
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/randompointsonlines.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: native:randompointsonlines
|
||||
name: Random points on lines, min distance 1, seed 1, attributes, multilines - one empty geom
|
||||
params:
|
||||
INCLUDE_LINE_ATTRIBUTES: true
|
||||
INPUT:
|
||||
name: multilines.gml|layername=multilines
|
||||
type: vector
|
||||
MAX_TRIES_PER_POINT: 10
|
||||
MIN_DISTANCE: 1.0
|
||||
POINTS_NUMBER: 10
|
||||
SEED: 1
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/randompointsonlines_min1.gml
|
||||
type: vector
|
||||
|
||||
|
||||
|
||||
- algorithm: native:randomextract
|
||||
name: Random extract by number
|
||||
params:
|
||||
|
||||
@ -112,6 +112,7 @@ SET(QGIS_ANALYSIS_SRCS
|
||||
processing/qgsalgorithmraiseexception.cpp
|
||||
processing/qgsalgorithmrandomextract.cpp
|
||||
processing/qgsalgorithmrandompointsextent.cpp
|
||||
processing/qgsalgorithmrandompointsonlines.cpp
|
||||
processing/qgsalgorithmrasterlayeruniquevalues.cpp
|
||||
processing/qgsalgorithmrasterlogicalop.cpp
|
||||
processing/qgsalgorithmrasterize.cpp
|
||||
|
||||
278
src/analysis/processing/qgsalgorithmrandompointsonlines.cpp
Normal file
278
src/analysis/processing/qgsalgorithmrandompointsonlines.cpp
Normal file
@ -0,0 +1,278 @@
|
||||
/***************************************************************************
|
||||
qgsalgorithmrandompointsonlines.cpp
|
||||
---------------------
|
||||
begin : March 2020
|
||||
copyright : (C) 2020 by Håvard Tveite
|
||||
email : havard dot tveite at nmbu dot no
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "qgsalgorithmrandompointsonlines.h"
|
||||
#include "random"
|
||||
|
||||
// The algorithm parameter names:
|
||||
static const QString INPUT = QStringLiteral( "INPUT" );
|
||||
static const QString POINTS_NUMBER = QStringLiteral( "POINTS_NUMBER" );
|
||||
static const QString MIN_DISTANCE = QStringLiteral( "MIN_DISTANCE" );
|
||||
static const QString MAX_TRIES_PER_POINT = QStringLiteral( "MAX_TRIES_PER_POINT" );
|
||||
static const QString SEED = QStringLiteral( "SEED" );
|
||||
static const QString INCLUDE_LINE_ATTRIBUTES = QStringLiteral( "INCLUDE_LINE_ATTRIBUTES" );
|
||||
static const QString OUTPUT = QStringLiteral( "OUTPUT" );
|
||||
static const QString OUTPUT_POINTS = QStringLiteral( "OUTPUT_POINTS" );
|
||||
static const QString POINTS_MISSED = QStringLiteral( "POINTS_MISSED" );
|
||||
static const QString LINES_WITH_MISSED_POINTS = QStringLiteral( "LINES_WITH_MISSED_POINTS" );
|
||||
static const QString FEATURES_WITH_EMPTY_OR_NO_GEOMETRY = QStringLiteral( "FEATURES_WITH_EMPTY_OR_NO_GEOMETRY" );
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
QString QgsRandomPointsOnLinesAlgorithm::name() const
|
||||
{
|
||||
return QStringLiteral( "randompointsonlines" );
|
||||
}
|
||||
|
||||
QString QgsRandomPointsOnLinesAlgorithm::displayName() const
|
||||
{
|
||||
return QObject::tr( "Random points on lines" );
|
||||
}
|
||||
|
||||
QStringList QgsRandomPointsOnLinesAlgorithm::tags() const
|
||||
{
|
||||
return QObject::tr( "seed,attributes,create" ).split( ',' );
|
||||
}
|
||||
|
||||
QString QgsRandomPointsOnLinesAlgorithm::group() const
|
||||
{
|
||||
return QObject::tr( "Vector creation" );
|
||||
}
|
||||
|
||||
QString QgsRandomPointsOnLinesAlgorithm::groupId() const
|
||||
{
|
||||
return QStringLiteral( "vectorcreation" );
|
||||
}
|
||||
|
||||
void QgsRandomPointsOnLinesAlgorithm::initAlgorithm( const QVariantMap & )
|
||||
{
|
||||
|
||||
//addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( INPUT ), QObject::tr( "Input line layer" ), QList< int >() << QgsProcessing::TypeVectorLine ) );
|
||||
addParameter( new QgsProcessingParameterFeatureSource( INPUT, QObject::tr( "Input line layer" ), QList< int >() << QgsProcessing::TypeVectorLine ) );
|
||||
addParameter( new QgsProcessingParameterNumber( POINTS_NUMBER, QObject::tr( "Number of points for each feature" ), QgsProcessingParameterNumber::Integer, 1, false, 1 ) );
|
||||
addParameter( new QgsProcessingParameterDistance( MIN_DISTANCE, QObject::tr( "Minimum distance between points" ), 0, INPUT, true, 0 ) );
|
||||
|
||||
std::unique_ptr< QgsProcessingParameterNumber > maxAttemptsParam = qgis::make_unique< QgsProcessingParameterNumber >( MAX_TRIES_PER_POINT, QObject::tr( "Maximum number of search attempts (for Min. dist. > 0)" ), QgsProcessingParameterNumber::Integer, 10, true, 1, 1000 );
|
||||
maxAttemptsParam->setFlags( maxAttemptsParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
|
||||
addParameter( maxAttemptsParam.release() );
|
||||
|
||||
std::unique_ptr< QgsProcessingParameterNumber > randomSeedParam = qgis::make_unique< QgsProcessingParameterNumber >( SEED, QObject::tr( "Random seed" ), QgsProcessingParameterNumber::Integer, 1, false, 1 );
|
||||
randomSeedParam->setFlags( randomSeedParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
|
||||
addParameter( randomSeedParam.release() );
|
||||
|
||||
std::unique_ptr< QgsProcessingParameterBoolean > includeLineAttrParam = qgis::make_unique< QgsProcessingParameterBoolean >( INCLUDE_LINE_ATTRIBUTES, QObject::tr( "Include line attributes" ), true );
|
||||
includeLineAttrParam->setFlags( includeLineAttrParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
|
||||
addParameter( includeLineAttrParam.release() );
|
||||
|
||||
addParameter( new
|
||||
QgsProcessingParameterFeatureSink( OUTPUT, QObject::tr( "Random points on lines" ), QgsProcessing::TypeVectorPoint ) );
|
||||
|
||||
addOutput( new QgsProcessingOutputNumber( OUTPUT_POINTS, QObject::tr( "Total number of points generated" ) ) );
|
||||
addOutput( new QgsProcessingOutputNumber( POINTS_MISSED, QObject::tr( "Number of missed points" ) ) );
|
||||
addOutput( new QgsProcessingOutputNumber( LINES_WITH_MISSED_POINTS, QObject::tr( "Number of lines with missed points" ) ) );
|
||||
addOutput( new QgsProcessingOutputNumber( FEATURES_WITH_EMPTY_OR_NO_GEOMETRY, QObject::tr( "Number of features with empty or no geometry" ) ) );
|
||||
}
|
||||
|
||||
QString QgsRandomPointsOnLinesAlgorithm::shortHelpString() const
|
||||
{
|
||||
return QObject::tr( "<p>This algorithm creates a point layer, with points placed randomly "
|
||||
"on the lines of the <i><b>Input line layer</b></i>.</p> "
|
||||
"<ul><li>For each feature in the <i><b>Input line layer</b></i>, the algorithm attempts to add "
|
||||
"the specified <i><b>Number of points for each feature</b></i> to the output layer.</li> "
|
||||
"<li>A <i><b>Minimum distance between points</b></i> can be specified.<br> "
|
||||
"A point will not be generated if there is an already generated point "
|
||||
"(on any line feature) within this (Euclidean) distance from "
|
||||
"the generated location. "
|
||||
"If the <i><b>Minimum distance between points</b></i> is too large, it may not be possible to generate "
|
||||
"the specified <i><b>Number of points for each feature</b></i>.</li> "
|
||||
"<li>The <i><b>Maximum number of attempts per point</b></i> "
|
||||
"is only relevant if the <i><b>Minimum distance between points</b></i> is greater than 0. "
|
||||
"The total number of points will be<br> <b>'number of input features'</b> * "
|
||||
"<i><b>Number of points for each feature</b></i><br> if there are no misses.</li> "
|
||||
"<li>The seed for the random generator can be provided (<i>Random seed</i> "
|
||||
"- integer, greater than 0).</li> "
|
||||
"<li>The user can choose not to <i><b>Include line feature attributes</b></i> in "
|
||||
"the attributes of the generated point features.</li> "
|
||||
"</ul> "
|
||||
"<p>Output from the algorithm:</p> "
|
||||
"<ul> "
|
||||
"<li> A point layer containing the random points (<code>OUTPUT</code>).</li> "
|
||||
"<li> The number of generated features (<code>POINTS_GENERATED</code>).</li> "
|
||||
"<li> The number of missed points (<code>POINTS_MISSED</code>).</li> "
|
||||
"<li> The number of features with non-empty geometry and missing points (<code>LINES_WITH_MISSED_POINTS</code>).</li> "
|
||||
"<li> The number of features with an empty or no geometry (<code>LINES_WITH_EMPTY_OR_NO_GEOMETRY</code>).</li> "
|
||||
"</ul>"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
QgsRandomPointsOnLinesAlgorithm *QgsRandomPointsOnLinesAlgorithm::createInstance() const
|
||||
{
|
||||
return new QgsRandomPointsOnLinesAlgorithm();
|
||||
}
|
||||
|
||||
bool QgsRandomPointsOnLinesAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * )
|
||||
{
|
||||
mNumPoints = parameterAsInt( parameters, POINTS_NUMBER, context );
|
||||
mMinDistance = parameterAsDouble( parameters, MIN_DISTANCE, context );
|
||||
mMaxAttempts = parameterAsInt( parameters, MAX_TRIES_PER_POINT, context );
|
||||
mRandSeed = parameterAsInt( parameters, SEED, context );
|
||||
mIncludeLineAttr = parameterAsBoolean( parameters, INCLUDE_LINE_ATTRIBUTES, context );
|
||||
return true;
|
||||
}
|
||||
|
||||
QVariantMap QgsRandomPointsOnLinesAlgorithm::processAlgorithm( const QVariantMap ¶meters,
|
||||
QgsProcessingContext &context, QgsProcessingFeedback *feedback )
|
||||
{
|
||||
std::unique_ptr< QgsFeatureSource > lineSource( parameterAsSource( parameters, INPUT, context ) );
|
||||
if ( !lineSource )
|
||||
throw QgsProcessingException( invalidSourceError( parameters, INPUT ) );
|
||||
|
||||
QgsFields fields;
|
||||
fields.append( QgsField( QStringLiteral( "rand_point_id" ), QVariant::LongLong ) );
|
||||
if ( mIncludeLineAttr )
|
||||
fields.extend( lineSource->fields() );
|
||||
|
||||
QString ldest;
|
||||
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, OUTPUT,
|
||||
context, ldest, fields, QgsWkbTypes::Point, lineSource->sourceCrs() ) );
|
||||
if ( !sink )
|
||||
throw QgsProcessingException( invalidSinkError( parameters, OUTPUT ) );
|
||||
|
||||
//initialize random engine
|
||||
srand( mRandSeed );
|
||||
|
||||
//index for finding close points (mMinDistance > 0)
|
||||
QgsSpatialIndex index;
|
||||
|
||||
int totNPoints = 0;
|
||||
int missedPoints = 0;
|
||||
int missedLines = 0;
|
||||
int emptyOrNullGeom = 0;
|
||||
long tries = 0;
|
||||
long saved = 0;
|
||||
|
||||
long featureCount = 0;
|
||||
long numberOfFeatures = lineSource->featureCount();
|
||||
QgsFeature lFeat;
|
||||
QgsFeatureIterator fitL = mIncludeLineAttr ? lineSource->getFeatures()
|
||||
: lineSource->getFeatures( QgsFeatureRequest().setNoAttributes() );
|
||||
while ( fitL.nextFeature( lFeat ) )
|
||||
{
|
||||
featureCount++;
|
||||
if ( feedback->isCanceled() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ( !lFeat.hasGeometry() )
|
||||
{
|
||||
// Increment invalid features count
|
||||
emptyOrNullGeom++;
|
||||
continue;
|
||||
}
|
||||
QgsGeometry lGeom( lFeat.geometry() );
|
||||
if ( lGeom.isEmpty() )
|
||||
{
|
||||
// Increment invalid features count
|
||||
emptyOrNullGeom++;
|
||||
continue;
|
||||
}
|
||||
double lineLength = lGeom.length();
|
||||
int pointsAddedForThisFeature = 0;
|
||||
for ( long i = 0; i < mNumPoints; i++ )
|
||||
{
|
||||
if ( feedback->isCanceled() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
// Try to add a point (mMaxAttempts attempts)
|
||||
int distCheckIterations = 0;
|
||||
while ( distCheckIterations < mMaxAttempts )
|
||||
{
|
||||
if ( feedback->isCanceled() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
distCheckIterations++;
|
||||
tries++;
|
||||
// Generate a random point
|
||||
double randPos = lineLength * ( double ) rand() / RAND_MAX;
|
||||
QgsGeometry rpGeom = QgsGeometry( lGeom.interpolate( randPos ) );
|
||||
|
||||
if ( !rpGeom.isNull() && !rpGeom.isEmpty() )
|
||||
{
|
||||
if ( mMinDistance != 0 && pointsAddedForThisFeature > 0 )
|
||||
{
|
||||
// Have to check minimum distance to existing points
|
||||
QList<QgsFeatureId> neighbors = index.nearestNeighbor( rpGeom, 1, mMinDistance );
|
||||
if ( !neighbors.empty() )
|
||||
{
|
||||
// Too close!
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// point OK to add
|
||||
QgsFeature f = QgsFeature( totNPoints );
|
||||
QgsAttributes pAttrs = QgsAttributes();
|
||||
pAttrs.append( totNPoints );
|
||||
if ( mIncludeLineAttr )
|
||||
{
|
||||
pAttrs.append( lFeat.attributes() );
|
||||
}
|
||||
f.setAttributes( pAttrs );
|
||||
f.setGeometry( rpGeom );
|
||||
|
||||
if ( mMinDistance != 0 )
|
||||
{
|
||||
index.addFeature( f );
|
||||
}
|
||||
sink->addFeature( f, QgsFeatureSink::FastInsert );
|
||||
totNPoints++;
|
||||
pointsAddedForThisFeature++;
|
||||
saved += ( mMaxAttempts - distCheckIterations );
|
||||
|
||||
feedback->setProgress( static_cast<int>( 100 * static_cast<double>( tries + saved ) / static_cast<double>( mNumPoints * mMaxAttempts * ( numberOfFeatures - emptyOrNullGeom ) ) ) );
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
feedback->setProgress( static_cast<int>( 100 * static_cast<double>( tries + saved ) / static_cast<double>( mNumPoints * mMaxAttempts * ( numberOfFeatures - emptyOrNullGeom ) ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( pointsAddedForThisFeature < mNumPoints )
|
||||
{
|
||||
missedLines++;
|
||||
}
|
||||
}
|
||||
missedPoints = mNumPoints * featureCount - totNPoints;
|
||||
feedback->pushInfo( QObject::tr( "Total number of points generated: "
|
||||
" %1\nNumber of missed points: %2\nLines with missing points: "
|
||||
" %3\nFeatures with empty or missing geometries: %4"
|
||||
).arg( totNPoints ).arg( missedPoints ).arg( missedLines ).arg( emptyOrNullGeom ) );
|
||||
QVariantMap outputs;
|
||||
outputs.insert( OUTPUT, ldest );
|
||||
outputs.insert( OUTPUT_POINTS, totNPoints );
|
||||
outputs.insert( POINTS_MISSED, missedPoints );
|
||||
outputs.insert( LINES_WITH_MISSED_POINTS, missedLines );
|
||||
outputs.insert( FEATURES_WITH_EMPTY_OR_NO_GEOMETRY, emptyOrNullGeom );
|
||||
|
||||
return outputs;
|
||||
}
|
||||
|
||||
///@endcond
|
||||
68
src/analysis/processing/qgsalgorithmrandompointsonlines.h
Normal file
68
src/analysis/processing/qgsalgorithmrandompointsonlines.h
Normal file
@ -0,0 +1,68 @@
|
||||
/***************************************************************************
|
||||
qgsalgorithmrandompointsonlines.h
|
||||
---------------------
|
||||
begin : March 2020
|
||||
copyright : (C) 2020 by Håvard Tveite
|
||||
email : havard dot tveite at nmbu dot no
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef QGSALGORITHMRANDOMPOINTSONLINES_H
|
||||
#define QGSALGORITHMRANDOMPOINTSONLINES_H
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
#include "qgis_sip.h"
|
||||
#include "qgsprocessingalgorithm.h"
|
||||
#include "qgsapplication.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
/**
|
||||
* Native random points on lines creation algorithm.
|
||||
*/
|
||||
class QgsRandomPointsOnLinesAlgorithm : public QgsProcessingAlgorithm
|
||||
{
|
||||
public:
|
||||
|
||||
QgsRandomPointsOnLinesAlgorithm() = default;
|
||||
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
|
||||
QIcon icon() const override { return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmRandomPointsOnLines.svg" ) ); }
|
||||
QString svgIconPath() const override { return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmRandomPointsOnLines.svg" ) ); }
|
||||
QString name() const override;
|
||||
QString displayName() const override;
|
||||
QStringList tags() const override;
|
||||
QString group() const override;
|
||||
QString groupId() const override;
|
||||
QString shortHelpString() const override;
|
||||
QgsRandomPointsOnLinesAlgorithm *createInstance() const override SIP_FACTORY;
|
||||
|
||||
protected:
|
||||
bool prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * ) override;
|
||||
QVariantMap processAlgorithm( const QVariantMap ¶meters,
|
||||
QgsProcessingContext &context,
|
||||
QgsProcessingFeedback *feedback ) override;
|
||||
|
||||
|
||||
private:
|
||||
int mNumPoints;
|
||||
double mMinDistance;
|
||||
int mMaxAttempts;
|
||||
int mRandSeed;
|
||||
bool mIncludeLineAttr;
|
||||
QgsCoordinateReferenceSystem mCrs;
|
||||
|
||||
};
|
||||
|
||||
///@endcond PRIVATE
|
||||
|
||||
#endif // QGSALGORITHMRANDOMPOINTSONLINES_H
|
||||
@ -106,6 +106,7 @@
|
||||
#include "qgsalgorithmraiseexception.h"
|
||||
#include "qgsalgorithmrandomextract.h"
|
||||
#include "qgsalgorithmrandompointsextent.h"
|
||||
#include "qgsalgorithmrandompointsonlines.h"
|
||||
#include "qgsalgorithmrasterlayeruniquevalues.h"
|
||||
#include "qgsalgorithmrasterlogicalop.h"
|
||||
#include "qgsalgorithmrasterize.h"
|
||||
@ -307,6 +308,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
|
||||
addAlgorithm( new QgsRaiseWarningAlgorithm() );
|
||||
addAlgorithm( new QgsRandomExtractAlgorithm() );
|
||||
addAlgorithm( new QgsRandomPointsExtentAlgorithm() );
|
||||
addAlgorithm( new QgsRandomPointsOnLinesAlgorithm() );
|
||||
addAlgorithm( new QgsRasterLayerUniqueValuesReportAlgorithm() );
|
||||
addAlgorithm( new QgsRasterLayerZonalStatsAlgorithm() );
|
||||
addAlgorithm( new QgsRasterLogicalAndAlgorithm() );
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user