1 /****************************************************************************** 2 * Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com) 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following 8 * conditions are met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided 15 * with the distribution. 16 * * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the 17 * names of its contributors may be used to endorse or promote 18 * products derived from this software without specific prior 19 * written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 28 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 32 * OF SUCH DAMAGE. 33 ****************************************************************************/ 34 35 #pragma once 36 37 #include <list> 38 39 #include <pdal/Dimension.hpp> 40 #include <pdal/DimType.hpp> 41 #include <pdal/Log.hpp> 42 #include <pdal/Metadata.hpp> 43 #include <pdal/Options.hpp> 44 #include <pdal/PipelineWriter.hpp> 45 #include <pdal/PluginHelper.hpp> 46 #include <pdal/PointTable.hpp> 47 #include <pdal/PointRef.hpp> 48 #include <pdal/PointView.hpp> 49 #include <pdal/QuickInfo.hpp> 50 #include <pdal/SpatialReference.hpp> 51 #include <pdal/util/ProgramArgs.hpp> 52 53 namespace pdal 54 { 55 56 class ProgramArgs; 57 class StageRunner; 58 class StageWrapper; 59 class Streamable; 60 61 namespace expr 62 { 63 class ConditionalExpression; 64 } 65 66 /** 67 A stage performs the actual processing in PDAL. Stages may read data, 68 modify or filter read data, create metadata or write processed data. 69 70 Stages are linked with setInput() into a pipeline. The pipeline is 71 run with by calling in sequence \ref prepare() and \ref execute() on the 72 stage at the end of the pipeline. PipelineManager can also be used to 73 create and run a pipeline. 74 */ 75 class PDAL_DLL Stage 76 { 77 FRIEND_TEST(OptionsTest, conditional); 78 friend class StageWrapper; 79 friend class StageRunner; 80 friend class Streamable; 81 friend class Reader; 82 friend class Filter; 83 friend class Writer; 84 85 public: 86 enum class WhereMergeMode 87 { 88 Auto, 89 True, 90 False 91 }; 92 93 Stage(); 94 virtual ~Stage(); 95 /** 96 Add a stage to the input list of this stage. 97 98 \param input Stage to use as input. 99 */ setInput(Stage & input)100 void setInput(Stage& input) 101 { m_inputs.push_back(&input); } 102 103 /** 104 Set a file descriptor to which progress information should be written. 105 106 \param fd Progress file descriptor. 107 */ setProgressFd(int fd)108 void setProgressFd(int fd) 109 { m_progressFd = fd; } 110 111 /** 112 Retrieve some basic point information without reading all data when 113 possible. Usually implemented only by Readers. 114 */ 115 QuickInfo preview(); 116 117 /** 118 Prepare a stage for execution. This function needs to be called on the 119 terminal stage of a pipeline (linked set of stages) before \ref execute 120 can be called. Prepare recurses through all input stages. 121 122 \param table PointTable being used for stage pipeline. 123 */ 124 void prepare(PointTableRef table); 125 126 /** 127 Execute a prepared pipeline (linked set of stages). 128 129 This performs the action associated with the stage by executing the 130 \ref run function of each stage in depth first order. Each stage is run 131 to completion (all points are processed) before the next stages is run.o 132 133 \param table Point table being used for stage pipeline. This must be 134 the same \ref table used in the \ref prepare function. 135 */ 136 PointViewSet execute(PointTableRef table); 137 execute(StreamPointTable & table)138 virtual void execute(StreamPointTable& table) 139 { 140 throw pdal_error("Attempting to use stream mode with a non-streamable " 141 "stage."); 142 } 143 144 /** 145 Determine if a pipeline with this stage as a sink is streamable. 146 147 \return Whether the pipeline is streamable. 148 */ pipelineStreamable() const149 virtual bool pipelineStreamable() const 150 { return false; } 151 152 /** 153 Return a pointer to a pipeline's first non-streamable stage, 154 if one exists. 155 156 \return nullptr if the stage is streamable, a pointer to this stage 157 otherwise. 158 */ findNonstreamable() const159 virtual const Stage *findNonstreamable() const 160 { return this; } 161 162 /** 163 Set the spatial reference of a stage. 164 165 Set the spatial reference that will override that being carried by the 166 PointView being processed. This is usually used when reprojecting data 167 to a new spatial reference. The stage spatial reference will be carried 168 by PointViews processes by this stage to subsequent stages. 169 170 If called by a Reader whose spatial reference has been set with option 171 'spatialreference' or 'override_srs', then this function will have no 172 effect. 173 174 \param srs Spatial reference to set. 175 */ 176 void setSpatialReference(SpatialReference const& srs); 177 178 /** 179 Get the spatial reference of the stage. 180 181 Get the spatial reference that will override that being carried by the 182 PointView being processed. This is usually used when reprojecting data 183 to a new spatial reference. The stage spatial reference will be carried 184 by PointViews processes by this stage to subsequent stages. 185 186 \return The stage's spatial reference. 187 */ 188 const SpatialReference& getSpatialReference() const; 189 190 /** 191 Set a stage's options. 192 193 Set the options on a stage, clearing all previously set options. 194 195 \param options Options to set. 196 */ setOptions(Options options)197 void setOptions(Options options) 198 { m_options = options; } 199 200 /** 201 Add options if an option with the same name doesn't already exist on 202 the stage. 203 204 \param opts Options to add. 205 */ 206 void addConditionalOptions(const Options& opts); 207 208 /** 209 Add a stage's options to a ProgramArgs set. 210 211 \param args ProgramArgs to add to. 212 */ 213 void addAllArgs(ProgramArgs& args); 214 215 /** 216 Add options to the existing option set. 217 218 \param opts Options to add. 219 */ addOptions(const Options & opts)220 void addOptions(const Options& opts) 221 { 222 for (const auto& o : opts.getOptions()) 223 m_options.add(o); 224 } 225 226 /** 227 Remove options from a stage's option set. 228 229 \param opts Options to remove. 230 */ removeOptions(const Options & opts)231 void removeOptions(const Options& opts) 232 { 233 for (const auto& o : opts.getOptions()) 234 m_options.remove(o); 235 } 236 237 /** 238 Set the stage's log. 239 240 \param log Log pointer. 241 */ setLog(const LogPtr & log)242 void setLog(const LogPtr& log) 243 { m_log = log; } 244 245 /** 246 Return the stage's log pointer. 247 248 \return Log pointer. 249 */ log() const250 virtual LogPtr log() const 251 { return m_log; } 252 253 /** 254 Push the stage's leader into the log. 255 */ 256 void startLogging() const; 257 258 /** 259 Pop the stage's leader from the log. 260 */ 261 void stopLogging() const; 262 263 /** 264 Determine whether the stage is in debug mode or not. 265 266 \return The stage's debug state. 267 */ isDebug() const268 bool isDebug() const 269 { return m_log && m_log->getLevel() > LogLevel::Debug; } 270 271 /** 272 Return the name of a stage. 273 274 \return The stage's name. 275 */ 276 virtual std::string getName() const = 0; 277 278 /** 279 Set a specific tag name. 280 */ setTag(const std::string & tag)281 void setTag(const std::string& tag) 282 { m_tag = tag; } 283 284 /** 285 Return the tag name of a stage. 286 287 \return The tag name. 288 */ tag() const289 virtual std::string tag() const 290 { return m_tag; } 291 292 /** 293 Return a list of the stage's inputs. 294 295 \return A vector pointers to input stages. 296 **/ getInputs()297 std::vector<Stage*>& getInputs() 298 { return m_inputs; } 299 300 /** 301 Get the stage's metadata node. 302 303 \return Stage's metadata. 304 */ getMetadata() const305 MetadataNode getMetadata() const 306 { return m_metadata; } 307 308 /** 309 Serialize a stage by inserting apporpritate data into the provided 310 MetadataNode. Used to dump a pipeline specification in a portable 311 format. 312 313 \param root Node to which a stages metadata should be added. 314 \param tags Pipeline writer's current list of stage tags. 315 */ 316 void serialize(MetadataNode root, PipelineWriter::TagMap& tags) const; 317 318 /** 319 Parse a stage name from a string. Return the name and update the 320 position in the input string to the end of the stage name. 321 322 \param o Input string to parse. 323 \param pos Parsing start/end position. 324 \return Whether the parsed name is a valid stage name. 325 */ 326 static bool parseName(std::string o, std::string::size_type& pos); 327 328 /** 329 Parse a tag name from a string. Return the name and update the 330 position in the input string to the end of the tag name. 331 332 \param o Input string to parse. 333 \param pos Parsing start/end position. 334 \param tag Parsed tag name. 335 \return Whether the parsed name is a valid tag name. 336 */ 337 static bool parseTagName(std::string o, std::string::size_type& pos); 338 339 protected: 340 Options m_options; ///< Stage's options. 341 MetadataNode m_metadata; ///< Stage's metadata. 342 int m_progressFd; ///< Descriptor for progress info. 343 344 virtual void setSpatialReference(MetadataNode& m, SpatialReference const&); 345 void throwError(const std::string& s) const; 346 /** 347 Return the point count of all point views at the start of execution. 348 Only valid during execute(). 349 350 \return Total number of points in all point views being executed. 351 */ pointCount() const352 point_count_t pointCount() const 353 { return m_pointCount; } 354 /** 355 Return the count of faces in all primary meshes for all point views. 356 Only valid during execute(). 357 358 \return Total number of faces in all point views being executed. 359 */ faceCount() const360 point_count_t faceCount() const 361 { return m_faceCount; } 362 363 private: 364 uint32_t m_verbose; 365 std::string m_logname; 366 std::vector<Stage *> m_inputs; 367 LogPtr m_log; 368 std::string m_logLeader; 369 SpatialReference m_spatialReference; 370 std::unique_ptr<ProgramArgs> m_args; 371 std::string m_tag; 372 // This is never used after it is set. It just provides a place to 373 // bind the user_data argument that is essentially a comment in pipeline 374 // files. 375 std::string m_userDataJSON; 376 point_count_t m_pointCount; 377 point_count_t m_faceCount; 378 // This is never used, but we want something to bind to the argument 379 // we stick in ProgramArgs so that it shows up in help and an options list. 380 std::string m_optionFile; 381 382 Stage& operator=(const Stage&) = delete; 383 Stage(const Stage&) = delete; 384 385 virtual const expr::ConditionalExpression *whereExpr() const = 0; 386 virtual WhereMergeMode mergeMode() const = 0; 387 void setupLog(); 388 void handleOptions(); 389 void countElements(const PointViewSet& views); 390 391 virtual void l_addArgs(ProgramArgs& args); 392 virtual void l_initialize(PointTableRef table); 393 virtual void l_prepared(PointTableRef table); 394 395 /** 396 Potentially split a point view into keeps and skips based on a where clause. 397 398 \param view Point view to split. 399 \param keep PointView to hold the kept points. 400 \param skip PointView to hold the skipped points. 401 */ 402 void splitView(const PointViewPtr& view, PointViewPtr& keep, PointViewPtr& skip); 403 404 /** 405 Get basic metadata (avoids reading points). Implement in subclass. 406 407 \return QuickInfo data. 408 */ inspect()409 virtual QuickInfo inspect() 410 { return QuickInfo(); } 411 412 /** 413 Add arguments(options) handled by this stage. Implement in subclass. 414 415 \param args ProgramArgs object to which arguments should be added. 416 */ addArgs(ProgramArgs &)417 virtual void addArgs(ProgramArgs& /*args*/) 418 {} 419 420 /** 421 Process options. Implement in subclass. 422 423 \param options Options to process. 424 */ processOptions(const Options &)425 virtual void processOptions(const Options& /*options*/) 426 {} 427 428 /** 429 Initialize stage after options have been processed. Implement in 430 subclass. If you don't require the \ref table argument, you 431 can implement the version of this function that takes no arguments 432 instead of this function. 433 434 \param table PointTable associated with pipeline. 435 */ initialize(PointTableRef)436 virtual void initialize(PointTableRef /*table*/) 437 { initialize(); } 438 439 /** 440 Initialize stage after options have been processed. Implement in 441 subclass. 442 */ initialize()443 virtual void initialize() 444 {} 445 446 /** 447 Add dimensions to a layout. 448 449 \param layout Point layout. 450 */ addDimensions(PointLayoutPtr)451 virtual void addDimensions(PointLayoutPtr /*layout*/) 452 {} 453 454 /** 455 Execute a single stage. 456 457 \param table PointTable 458 \param pvSet Input PointViewSet 459 \return Output PointViewSet 460 */ 461 PointViewSet execute(PointTableRef table, PointViewSet& pvSet); 462 463 /** 464 Functions called after dimensions have been added. Implement in 465 subclass. 466 467 \param table PointTable associated with pipeline. 468 */ prepared(PointTableRef)469 virtual void prepared(PointTableRef /*table*/) 470 {} 471 472 /** 473 First part of the execute step. Called after all stages have been 474 prepared. Implement in subclass. 475 476 \param table PointTable associated with the pipeline. 477 */ ready(PointTableRef)478 virtual void ready(PointTableRef /*table*/) 479 {} 480 481 /** 482 Pass all the point views at once to the stage for cases where we need 483 such information. You normally shouldn't need to implement this call. 484 485 \param pvSet PointViewSet being processed for the stage. 486 */ prerun(const PointViewSet &)487 virtual void prerun(const PointViewSet& /*pvSet*/) 488 {} 489 490 /** 491 Process all points in a view. Implement in subclass. 492 493 \param view PointView to process. 494 */ run(PointViewPtr)495 virtual PointViewSet run(PointViewPtr /*view*/) 496 { 497 std::cerr << "Can't run stage = " << getName() << "!\n"; 498 return PointViewSet(); 499 } 500 501 /** 502 Called after all point views have been processed. Implement in subclass. 503 504 \param table PointTable associated with pipeline. 505 */ done(PointTableRef)506 virtual void done(PointTableRef /*table*/) 507 {} 508 509 /* 510 Test hook. 511 */ getOptions() const512 const Options& getOptions() const 513 { return m_options; } 514 515 friend PDAL_DLL std::istream& operator>>(std::istream& in, WhereMergeMode& mode); 516 friend PDAL_DLL std::ostream& operator<<(std::ostream& out, const WhereMergeMode& mode); 517 }; 518 519 } // namespace pdal 520