<div dir="ltr"><div>In order to facilitate better feedback for users of PDAL command-line tools and API users, I have made a change to the way that stage options are discovered, parsed and handled.  The notable advantage to users is that if they misspell an option name, stage name or provide an option value that's of the wrong type, they're told about the error at the time the pipeline or command line is parsed.  The PDAL 1.2 interface provided no feedback in these cases.  It was easy for a user to do something like provide the option --readers.las.sale_x=.01 and not get the expected output, but not realize that they had misspelled "scale_x" as "sale_x".  Similarly, one might have typed "--reader.las.scale_x=.01" (missed the 's' on 'readers') and not gotten the expected behavior.   </div><div><br></div><div>Unfortunately these changes may break code for users of the API.  The changes will be present in the next release of PDAL and have been merged into the master branch of PDAL on GitHub.  Here's a description of what you may need to do if you maintain your own stage outside of the PDAL source tree.</div><div><br></div><div>Stages must now register their ability to accept options in a new private virtual function called addArgs.  The options (arguments) accepted by a stage are added to the instance of ProgramArgs that is passed to the function.  If you are familiar with ProgramArgs from coding a PDAL kernel, the interface is the same.  If not, here's an example:</div><div><br></div><div>class FooStage</div><div>{</div><div>...</div><div>private:</div><div>    int m_fine;</div><div>    std::string m_veryFine;</div><div>};<br></div><div><br></div><div>void FooStage::addArgs(ProgramArgs& args)</div><div>{</div><div>    args.add("fine", "My Fine Option", m_fine).setPositional();</div><div>    args.add("veryfine", "My Very Fine Option", m_veryFine, "So, so fine");<br></div><div>}</div><div><br></div><div>The first argument to add() is the name of the option.</div><div>The second argument is a description of the option.</div><div>The third argument is a variable to which the option is mapped (variable storing the option's value).</div><div>The optional fourth argument is a default value for the option if not set by the user.  If not provided, the argument is default-initialized.  Types for the variable and default values must match exactly, though special handling allows string constants provided as default arguments to be used when the variable type is a std::string.</div><div><br></div><div>add() returns a reference to the created Arg, to which a pointer can be stored if necessary (usually to check whether the value was set by the user).</div><div>Arg::setPositional() makes the option required (the function name comes from command-line argument handling).  Previous code that handled these options may have looked like:</div><div><br></div><div>void FooStage::processOptions(Options& ops)</div><div>{</div><div>    m_fine = ops.getValueOrThrow<int>("fine");</div><div>    m_veryFine = ops.getValueOrDefault<std::string>("veryfine", "So, so fine");</div><div>}</div><div><br></div><div>Existing processOptions() functions should be removed as they will no longer be called as part of stage processing.  Stages may have also implemented getDefaultOptions().  This function should also be removed as it isn't called and its functionality is incorporated in the new interface.</div><div><br></div><div>Once the arguments are added, one need do nothing more unless required by specific circumstances.  PDAL's prepare() or preview() functions will fill the variables mapped to the options so that they can be used by the stage.  Any variable can be used as an option/argument as long as it's type has a default constructor and provides an input operator from a std::istream that sets the stream's fail bit if the input isn't as expected.  This allows most conversion that was previously performed locally in processOptions() to be encapsulated in the mapped variable's class instead.  Any processing other than options-fetching that was done in processOptions() can be safely moved to a stage's initialize() function.</div><div><br></div><div>If you have trouble or questions, please let me know and I'll be happy to answer and/or help you migrate your code to the new interface.</div><div><br></div><div>Best,</div><div><br></div><div>-- <br></div><div class="gmail_signature" data-smartmail="gmail_signature">Andrew Bell<br><a href="mailto:andrew.bell.ia@gmail.com" target="_blank">andrew.bell.ia@gmail.com</a></div>
</div>