diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..3dfe05b --- /dev/null +++ b/404.html @@ -0,0 +1,1298 @@ + + + + + + + + + + + + + + + + + + + + + + QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/about/code-of-conduct/index.html b/about/code-of-conduct/index.html new file mode 100644 index 0000000..d2a0dc2 --- /dev/null +++ b/about/code-of-conduct/index.html @@ -0,0 +1,1508 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + IDS SAWPS - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Contributor Covenant Code of Conduct

+

Our Pledge

+

In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation.

+

Our Standards

+

Examples of behaviour that contributes to creating a positive environment +include:

+
    +
  • Using welcoming and inclusive language
  • +
  • Being respectful of differing viewpoints and experiences
  • +
  • Gracefully accepting constructive criticism
  • +
  • Focusing on what is best for the community
  • +
  • Showing empathy towards other community members
  • +
+

Examples of unacceptable behaviour by participants include:

+
    +
  • The use of sexualized language or imagery and unwelcome sexual attention or + advances
  • +
  • Trolling, insulting/derogatory comments, and personal or political attacks
  • +
  • Public or private harassment
  • +
  • Publishing others' private information, such as a physical or electronic + address, without explicit permission
  • +
  • Other conduct which could reasonably be considered inappropriate in a + professional setting
  • +
+

Our Responsibilities

+

Project maintainers are responsible for clarifying the standards of acceptable +behaviour and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behaviour.

+

Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful.

+

Scope

+

This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers.

+

Enforcement

+

Instances of abusive, harassing, or otherwise unacceptable behaviour may be +reported by contacting the project team. All complaints will be reviewed and +investigated and will result in a response that is deemed necessary and +appropriate to the circumstances. The project team is obligated to maintain +confidentiality with regard to the reporter of an incident. Further details of +specific enforcement policies may be posted separately.

+

Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership.

+

Attribution

+

This Code of Conduct is adapted from the Contributor Covenant, version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/about/contribute/index.html b/about/contribute/index.html new file mode 100644 index 0000000..a127b2a --- /dev/null +++ b/about/contribute/index.html @@ -0,0 +1,1631 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Contribute - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Contribute

+ +

🔧 Pull Request Steps

+

This project is open source, so you can create a pull request(PR) after you fix issues. Get a local copy of the plugins checked out for development using the following process.

+

Pull Request

+

Before uploading your PR, run test one last time to check if there are any errors. If it has no errors, commit and then push it!

+

For more information on PR's steps, please see links in the Contributing section.

+

Commit messages

+

Please make this project more fun and easy to scan by using emoji prefixes for your +commit messages (see GitMoji).

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Commit typeEmoji
Initial commit🎉 :tada:
Version tag🔖 :bookmark:
New feature:sparkles:
Bugfix🐛 :bug:
Metadata📇 :card_index:
Documentation📚 :books:
Documenting source code💡 :bulb:
Performance🐎 :racehorse:
Cosmetic💄 :lipstick:
Tests🚨 :rotating_light:
Adding a test:white_check_mark:
Make a test pass✔️ :heavy_check_mark:
General update⚡️ :zap:
Improve format/structure🎨 :art:
Refactor code🔨 :hammer:
Removing code/files🔥 :fire:
Continuous Integration💚 :green_heart:
Security🔒 :lock:
Upgrading dependencies⬆️ :arrow_up:
Downgrading dependencies⬇️ :arrow_down:
Lint👕 :shirt:
Translation👽 :alien:
Text📝 :pencil:
Critical hotfix🚑 :ambulance:
Deploying stuff🚀 :rocket:
Fixing on MacOS🍎 :apple:
Fixing on Linux🐧 :penguin:
Fixing on Windows🏁 :checkered_flag:
Work in progress🚧 :construction:
Adding CI build system👷 :construction_worker:
Analytics or tracking code📈 :chart_with_upwards_trend:
Removing a dependency:heavy_minus_sign:
Adding a dependency:heavy_plus_sign:
Docker🐳 :whale:
Configuration files🔧 :wrench:
Package.json in JS📦 :package:
Merging branches🔀 :twisted_rightwards_arrows:
Bad code / need improv.💩 :hankey:
Reverting changes:rewind:
Breaking changes💥 :boom:
Code review changes👌 :ok_hand:
Accessibility♿️ :wheelchair:
Move/rename repository🚚 :truck:
OtherBe creative
+

💬 Contributing

+ + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/about/credits/index.html b/about/credits/index.html new file mode 100644 index 0000000..a7e7aa9 --- /dev/null +++ b/about/credits/index.html @@ -0,0 +1,1429 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Credits - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Credits

+ +

Author

+

This plugin was developed by:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Tim SuttonNyall DawsonJeremy Prior
TimNyall DawsonJeremy
Coder and Ideas GuyGenius Guru of AwesomenessDocument and Logo Guy
timlinux @ githubnyalldawson @ githubJeremy-Prior @ github
+

Contributors

+

Thanks to:

+
    +
  • Mathieu Pellerin (@nirvn)
  • +
  • Thiasha Vythilingam (@ThiashaV)
  • +
+

We are looking for contributors, add yourself here!

+

Also:

+ + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/about/license/index.html b/about/license/index.html new file mode 100644 index 0000000..a37b79a --- /dev/null +++ b/about/license/index.html @@ -0,0 +1,1713 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + License - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+ +
+ + + +
+
+ + + + + + + + +

GNU General Public License

+

Version 2, June 1991
+Copyright © 1989, 1991 Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

+

Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed.

+

Preamble

+

The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too.

+

When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things.

+

To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it.

+

For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights.

+

We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software.

+

Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations.

+

Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all.

+

The precise terms and conditions for copying, distribution and +modification follow.

+

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

+

0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The “Program”, below, +refers to any such program or work, and a “work based on the Program” +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term “modification”.) Each licensee is addressed as “you”.

+

Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does.

+

1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program.

+

You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee.

+

2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions:

+
    +
  • a) You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change.
  • +
  • b) You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any +part thereof, to be licensed as a whole at no charge to all third +parties under the terms of this License.
  • +
  • c) If the modified program normally reads commands interactively +when run, you must cause it, when started running for such +interactive use in the most ordinary way, to print or display an +announcement including an appropriate copyright notice and a +notice that there is no warranty (or else, saying that you provide +a warranty) and that users may redistribute the program under +these conditions, and telling the user how to view a copy of this +License. (Exception: if the Program itself is interactive but +does not normally print such an announcement, your work based on +the Program is not required to print an announcement.)
  • +
+

These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it.

+

Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program.

+

In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License.

+

3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following:

+
    +
  • a) Accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections +1 and 2 above on a medium customarily used for software interchange; or,
  • +
  • b) Accompany it with a written offer, valid for at least three +years, to give any third party, for a charge no more than your +cost of physically performing source distribution, a complete +machine-readable copy of the corresponding source code, to be +distributed under the terms of Sections 1 and 2 above on a medium +customarily used for software interchange; or,
  • +
  • c) Accompany it with the information you received as to the offer +to distribute corresponding source code. (This alternative is +allowed only for noncommercial distribution and only if you +received the program in object code or executable form with such +an offer, in accord with Subsection b above.)
  • +
+

The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable.

+

If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code.

+

4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance.

+

5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it.

+

6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License.

+

7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program.

+

If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances.

+

It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice.

+

This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License.

+

8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License.

+

9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns.

+

Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and “any +later version”, you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation.

+

10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally.

+

NO WARRANTY

+

11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION.

+

12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES.

+

END OF TERMS AND CONDITIONS

+

How to Apply These Terms to Your New Programs

+

If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms.

+

To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the “copyright” line and a pointer to where the full notice is found.

+
<one line to give the program's name and a brief idea of what it does.>
+Copyright (C) <year>  <name of author>
+
+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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+

Also add information on how to contact you by electronic and paper mail.

+

If the program is interactive, make it output a short notice like this +when it starts in an interactive mode:

+
Gnomovision version 69, Copyright (C) year name of author
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+This is free software, and you are welcome to redistribute it
+under certain conditions; type `show c' for details.
+
+

The hypothetical commands show w and show c should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than show w and show c; they could even be +mouse-clicks or menu items--whatever suits your program.

+

You should also get your employer (if you work as a programmer) or your +school, if any, to sign a “copyright disclaimer” for the program, if +necessary. Here is a sample; alter the names:

+
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+`Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+<signature of Ty Coon>, 1 April 1989
+Ty Coon, President of Vice
+
+

This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License.

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 0000000..1cf13b9 Binary files /dev/null and b/assets/images/favicon.png differ diff --git a/assets/javascripts/bundle.51d95adb.min.js b/assets/javascripts/bundle.51d95adb.min.js new file mode 100644 index 0000000..b20ec68 --- /dev/null +++ b/assets/javascripts/bundle.51d95adb.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Hi=Object.create;var xr=Object.defineProperty;var Pi=Object.getOwnPropertyDescriptor;var $i=Object.getOwnPropertyNames,kt=Object.getOwnPropertySymbols,Ii=Object.getPrototypeOf,Er=Object.prototype.hasOwnProperty,an=Object.prototype.propertyIsEnumerable;var on=(e,t,r)=>t in e?xr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))Er.call(t,r)&&on(e,r,t[r]);if(kt)for(var r of kt(t))an.call(t,r)&&on(e,r,t[r]);return e};var sn=(e,t)=>{var r={};for(var n in e)Er.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&kt)for(var n of kt(e))t.indexOf(n)<0&&an.call(e,n)&&(r[n]=e[n]);return r};var Ht=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Fi=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of $i(t))!Er.call(e,o)&&o!==r&&xr(e,o,{get:()=>t[o],enumerable:!(n=Pi(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Hi(Ii(e)):{},Fi(t||!e||!e.__esModule?xr(r,"default",{value:e,enumerable:!0}):r,e));var fn=Ht((wr,cn)=>{(function(e,t){typeof wr=="object"&&typeof cn!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(wr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(T){return!!(T&&T!==document&&T.nodeName!=="HTML"&&T.nodeName!=="BODY"&&"classList"in T&&"contains"in T.classList)}function f(T){var Ke=T.type,We=T.tagName;return!!(We==="INPUT"&&a[Ke]&&!T.readOnly||We==="TEXTAREA"&&!T.readOnly||T.isContentEditable)}function c(T){T.classList.contains("focus-visible")||(T.classList.add("focus-visible"),T.setAttribute("data-focus-visible-added",""))}function u(T){T.hasAttribute("data-focus-visible-added")&&(T.classList.remove("focus-visible"),T.removeAttribute("data-focus-visible-added"))}function p(T){T.metaKey||T.altKey||T.ctrlKey||(s(r.activeElement)&&c(r.activeElement),n=!0)}function m(T){n=!1}function d(T){s(T.target)&&(n||f(T.target))&&c(T.target)}function h(T){s(T.target)&&(T.target.classList.contains("focus-visible")||T.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(T.target))}function v(T){document.visibilityState==="hidden"&&(o&&(n=!0),B())}function B(){document.addEventListener("mousemove",z),document.addEventListener("mousedown",z),document.addEventListener("mouseup",z),document.addEventListener("pointermove",z),document.addEventListener("pointerdown",z),document.addEventListener("pointerup",z),document.addEventListener("touchmove",z),document.addEventListener("touchstart",z),document.addEventListener("touchend",z)}function re(){document.removeEventListener("mousemove",z),document.removeEventListener("mousedown",z),document.removeEventListener("mouseup",z),document.removeEventListener("pointermove",z),document.removeEventListener("pointerdown",z),document.removeEventListener("pointerup",z),document.removeEventListener("touchmove",z),document.removeEventListener("touchstart",z),document.removeEventListener("touchend",z)}function z(T){T.target.nodeName&&T.target.nodeName.toLowerCase()==="html"||(n=!1,re())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),B(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var un=Ht(Sr=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(c){return!1}},r=t(),n=function(c){var u={next:function(){var p=c.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(c){return encodeURIComponent(c).replace(/%20/g,"+")},i=function(c){return decodeURIComponent(String(c).replace(/\+/g," "))},a=function(){var c=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof c){var d=this;p.forEach(function(re,z){d.append(z,re)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),c._entries&&(c._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Sr);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(f,c){typeof f!="string"&&(f=String(f)),c&&typeof c!="string"&&(c=String(c));var u=document,p;if(c&&(e.location===void 0||c!==e.location.href)){c=c.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=c,u.head.appendChild(p);try{if(p.href.indexOf(c)!==0)throw new Error(p.href)}catch(T){throw new Error("URL unable to set base "+c+" due to "+T)}}var m=u.createElement("a");m.href=f,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=f,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!c)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,B=!0,re=this;["append","delete","set"].forEach(function(T){var Ke=h[T];h[T]=function(){Ke.apply(h,arguments),v&&(B=!1,re.search=h.toString(),B=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var z=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==z&&(z=this.search,B&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},a=i.prototype,s=function(f){Object.defineProperty(a,f,{get:function(){return this._anchorElement[f]},set:function(c){this._anchorElement[f]=c},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(f){s(f)}),Object.defineProperty(a,"search",{get:function(){return this._anchorElement.search},set:function(f){this._anchorElement.search=f,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(a,{toString:{get:function(){var f=this;return function(){return f.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(f){this._anchorElement.href=f,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(f){this._anchorElement.pathname=f},enumerable:!0},origin:{get:function(){var f={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],c=this._anchorElement.port!=f&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(c?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(f){},enumerable:!0},username:{get:function(){return""},set:function(f){},enumerable:!0}}),i.createObjectURL=function(f){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(f){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Sr)});var Qr=Ht((Lt,Kr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Lt=="object"&&typeof Kr=="object"?Kr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Lt=="object"?Lt.ClipboardJS=r():t.ClipboardJS=r()})(Lt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return ki}});var a=i(279),s=i.n(a),f=i(370),c=i.n(f),u=i(817),p=i.n(u);function m(j){try{return document.execCommand(j)}catch(O){return!1}}var d=function(O){var w=p()(O);return m("cut"),w},h=d;function v(j){var O=document.documentElement.getAttribute("dir")==="rtl",w=document.createElement("textarea");w.style.fontSize="12pt",w.style.border="0",w.style.padding="0",w.style.margin="0",w.style.position="absolute",w.style[O?"right":"left"]="-9999px";var k=window.pageYOffset||document.documentElement.scrollTop;return w.style.top="".concat(k,"px"),w.setAttribute("readonly",""),w.value=j,w}var B=function(O,w){var k=v(O);w.container.appendChild(k);var F=p()(k);return m("copy"),k.remove(),F},re=function(O){var w=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},k="";return typeof O=="string"?k=B(O,w):O instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(O==null?void 0:O.type)?k=B(O.value,w):(k=p()(O),m("copy")),k},z=re;function T(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?T=function(w){return typeof w}:T=function(w){return w&&typeof Symbol=="function"&&w.constructor===Symbol&&w!==Symbol.prototype?"symbol":typeof w},T(j)}var Ke=function(){var O=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},w=O.action,k=w===void 0?"copy":w,F=O.container,q=O.target,Le=O.text;if(k!=="copy"&&k!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&T(q)==="object"&&q.nodeType===1){if(k==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(k==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Le)return z(Le,{container:F});if(q)return k==="cut"?h(q):z(q,{container:F})},We=Ke;function Ie(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Ie=function(w){return typeof w}:Ie=function(w){return w&&typeof Symbol=="function"&&w.constructor===Symbol&&w!==Symbol.prototype?"symbol":typeof w},Ie(j)}function Ti(j,O){if(!(j instanceof O))throw new TypeError("Cannot call a class as a function")}function nn(j,O){for(var w=0;w0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof F.action=="function"?F.action:this.defaultAction,this.target=typeof F.target=="function"?F.target:this.defaultTarget,this.text=typeof F.text=="function"?F.text:this.defaultText,this.container=Ie(F.container)==="object"?F.container:document.body}},{key:"listenClick",value:function(F){var q=this;this.listener=c()(F,"click",function(Le){return q.onClick(Le)})}},{key:"onClick",value:function(F){var q=F.delegateTarget||F.currentTarget,Le=this.action(q)||"copy",Rt=We({action:Le,container:this.container,target:this.target(q),text:this.text(q)});this.emit(Rt?"success":"error",{action:Le,text:Rt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(F){return yr("action",F)}},{key:"defaultTarget",value:function(F){var q=yr("target",F);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(F){return yr("text",F)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(F){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return z(F,q)}},{key:"cut",value:function(F){return h(F)}},{key:"isSupported",value:function(){var F=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof F=="string"?[F]:F,Le=!!document.queryCommandSupported;return q.forEach(function(Rt){Le=Le&&!!document.queryCommandSupported(Rt)}),Le}}]),w}(s()),ki=Ri},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,f){for(;s&&s.nodeType!==o;){if(typeof s.matches=="function"&&s.matches(f))return s;s=s.parentNode}}n.exports=a},438:function(n,o,i){var a=i(828);function s(u,p,m,d,h){var v=c.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function f(u,p,m,d,h){return typeof u.addEventListener=="function"?s.apply(null,arguments):typeof m=="function"?s.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return s(v,p,m,d,h)}))}function c(u,p,m,d){return function(h){h.delegateTarget=a(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=f},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(n,o,i){var a=i(879),s=i(438);function f(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!a.string(d))throw new TypeError("Second argument must be a String");if(!a.fn(h))throw new TypeError("Third argument must be a Function");if(a.node(m))return c(m,d,h);if(a.nodeList(m))return u(m,d,h);if(a.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return s(document.body,m,d,h)}n.exports=f},817:function(n){function o(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var f=window.getSelection(),c=document.createRange();c.selectNodeContents(i),f.removeAllRanges(),f.addRange(c),a=f.toString()}return a}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,a,s){var f=this.e||(this.e={});return(f[i]||(f[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var f=this;function c(){f.off(i,c),a.apply(s,arguments)}return c._=a,this.on(i,c,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),f=0,c=s.length;for(f;f{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var is=/["'&<>]/;Jo.exports=as;function as(e){var t=""+e,r=is.exec(t);if(!r)return t;var n,o="",i=0,a=0;for(i=r.index;i0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],a;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(s){a={error:s}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(a)throw a.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||s(m,d)})})}function s(m,d){try{f(n[m](d))}catch(h){p(i[0][3],h)}}function f(m){m.value instanceof Xe?Promise.resolve(m.value.v).then(c,u):p(i[0][2],m)}function c(m){s("next",m)}function u(m){s("throw",m)}function p(m,d){m(d),i.shift(),i.length&&s(i[0][0],i[0][1])}}function mn(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof xe=="function"?xe(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(a){return new Promise(function(s,f){a=e[i](a),o(s,f,a.done,a.value)})}}function o(i,a,s,f){Promise.resolve(f).then(function(c){i({value:c,done:s})},a)}}function A(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var $t=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function De(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Fe=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a)if(this._parentage=null,Array.isArray(a))try{for(var s=xe(a),f=s.next();!f.done;f=s.next()){var c=f.value;c.remove(this)}}catch(v){t={error:v}}finally{try{f&&!f.done&&(r=s.return)&&r.call(s)}finally{if(t)throw t.error}}else a.remove(this);var u=this.initialTeardown;if(A(u))try{u()}catch(v){i=v instanceof $t?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=xe(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{dn(h)}catch(v){i=i!=null?i:[],v instanceof $t?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new $t(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)dn(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&De(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&De(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Or=Fe.EMPTY;function It(e){return e instanceof Fe||e&&"closed"in e&&A(e.remove)&&A(e.add)&&A(e.unsubscribe)}function dn(e){A(e)?e():e.unsubscribe()}var Ae={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,a=o.isStopped,s=o.observers;return i||a?Or:(this.currentObservers=null,s.push(r),new Fe(function(){n.currentObservers=null,De(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,a=n.isStopped;o?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new U;return r.source=this,r},t.create=function(r,n){return new wn(r,n)},t}(U);var wn=function(e){ne(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Or},t}(E);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ne(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,a=n._infiniteTimeWindow,s=n._timestampProvider,f=n._windowTime;o||(i.push(r),!a&&i.push(s.now()+f)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,a=o._buffer,s=a.slice(),f=0;f0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var a=r.actions;n!=null&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Ut);var On=function(e){ne(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Wt);var we=new On(Tn);var R=new U(function(e){return e.complete()});function Dt(e){return e&&A(e.schedule)}function kr(e){return e[e.length-1]}function Qe(e){return A(kr(e))?e.pop():void 0}function Se(e){return Dt(kr(e))?e.pop():void 0}function Vt(e,t){return typeof kr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function zt(e){return A(e==null?void 0:e.then)}function Nt(e){return A(e[ft])}function qt(e){return Symbol.asyncIterator&&A(e==null?void 0:e[Symbol.asyncIterator])}function Kt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Ki(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Qt=Ki();function Yt(e){return A(e==null?void 0:e[Qt])}function Gt(e){return ln(this,arguments,function(){var r,n,o,i;return Pt(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,Xe(r.read())];case 3:return n=a.sent(),o=n.value,i=n.done,i?[4,Xe(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,Xe(o)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Bt(e){return A(e==null?void 0:e.getReader)}function $(e){if(e instanceof U)return e;if(e!=null){if(Nt(e))return Qi(e);if(pt(e))return Yi(e);if(zt(e))return Gi(e);if(qt(e))return _n(e);if(Yt(e))return Bi(e);if(Bt(e))return Ji(e)}throw Kt(e)}function Qi(e){return new U(function(t){var r=e[ft]();if(A(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function Yi(e){return new U(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?_(function(o,i){return e(o,i,n)}):me,Oe(1),r?He(t):zn(function(){return new Xt}))}}function Nn(){for(var e=[],t=0;t=2,!0))}function fe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new E}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,f=s===void 0?!0:s;return function(c){var u,p,m,d=0,h=!1,v=!1,B=function(){p==null||p.unsubscribe(),p=void 0},re=function(){B(),u=m=void 0,h=v=!1},z=function(){var T=u;re(),T==null||T.unsubscribe()};return g(function(T,Ke){d++,!v&&!h&&B();var We=m=m!=null?m:r();Ke.add(function(){d--,d===0&&!v&&!h&&(p=jr(z,f))}),We.subscribe(Ke),!u&&d>0&&(u=new et({next:function(Ie){return We.next(Ie)},error:function(Ie){v=!0,B(),p=jr(re,o,Ie),We.error(Ie)},complete:function(){h=!0,B(),p=jr(re,a),We.complete()}}),$(T).subscribe(u))})(c)}}function jr(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function V(e,t=document){let r=se(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function se(e,t=document){return t.querySelector(e)||void 0}function _e(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function tr(e){return L(b(document.body,"focusin"),b(document.body,"focusout")).pipe(ke(1),l(()=>{let t=_e();return typeof t!="undefined"?e.contains(t):!1}),N(e===_e()),Y())}function Be(e){return{x:e.offsetLeft,y:e.offsetTop}}function Yn(e){return L(b(window,"load"),b(window,"resize")).pipe(Ce(0,we),l(()=>Be(e)),N(Be(e)))}function rr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return L(b(e,"scroll"),b(window,"resize")).pipe(Ce(0,we),l(()=>rr(e)),N(rr(e)))}var Bn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!zr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),xa?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!zr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=ya.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Jn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Zn=typeof WeakMap!="undefined"?new WeakMap:new Bn,eo=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=Ea.getInstance(),n=new Ra(t,r,this);Zn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){eo.prototype[e]=function(){var t;return(t=Zn.get(this))[e].apply(t,arguments)}});var ka=function(){return typeof nr.ResizeObserver!="undefined"?nr.ResizeObserver:eo}(),to=ka;var ro=new E,Ha=I(()=>H(new to(e=>{for(let t of e)ro.next(t)}))).pipe(x(e=>L(Te,H(e)).pipe(C(()=>e.disconnect()))),J(1));function de(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ge(e){return Ha.pipe(S(t=>t.observe(e)),x(t=>ro.pipe(_(({target:r})=>r===e),C(()=>t.unobserve(e)),l(()=>de(e)))),N(de(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ar(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var no=new E,Pa=I(()=>H(new IntersectionObserver(e=>{for(let t of e)no.next(t)},{threshold:0}))).pipe(x(e=>L(Te,H(e)).pipe(C(()=>e.disconnect()))),J(1));function sr(e){return Pa.pipe(S(t=>t.observe(e)),x(t=>no.pipe(_(({target:r})=>r===e),C(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function oo(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=de(e),o=bt(e);return r>=o.height-n.height-t}),Y())}var cr={drawer:V("[data-md-toggle=drawer]"),search:V("[data-md-toggle=search]")};function io(e){return cr[e].checked}function qe(e,t){cr[e].checked!==t&&cr[e].click()}function je(e){let t=cr[e];return b(t,"change").pipe(l(()=>t.checked),N(t.checked))}function $a(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ia(){return L(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(N(!1))}function ao(){let e=b(window,"keydown").pipe(_(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:io("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),_(({mode:t,type:r})=>{if(t==="global"){let n=_e();if(typeof n!="undefined")return!$a(n,r)}return!0}),fe());return Ia().pipe(x(t=>t?R:e))}function Me(){return new URL(location.href)}function ot(e){location.href=e.href}function so(){return new E}function co(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)co(e,r)}function M(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)co(n,o);return n}function fr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function fo(){return location.hash.substring(1)}function uo(e){let t=M("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Fa(){return b(window,"hashchange").pipe(l(fo),N(fo()),_(e=>e.length>0),J(1))}function po(){return Fa().pipe(l(e=>se(`[id="${e}"]`)),_(e=>typeof e!="undefined"))}function Nr(e){let t=matchMedia(e);return Zt(r=>t.addListener(()=>r(t.matches))).pipe(N(t.matches))}function lo(){let e=matchMedia("print");return L(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(N(e.matches))}function qr(e,t){return e.pipe(x(r=>r?t():R))}function ur(e,t={credentials:"same-origin"}){return ve(fetch(`${e}`,t)).pipe(ce(()=>R),x(r=>r.status!==200?Tt(()=>new Error(r.statusText)):H(r)))}function Ue(e,t){return ur(e,t).pipe(x(r=>r.json()),J(1))}function mo(e,t){let r=new DOMParser;return ur(e,t).pipe(x(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),J(1))}function pr(e){let t=M("script",{src:e});return I(()=>(document.head.appendChild(t),L(b(t,"load"),b(t,"error").pipe(x(()=>Tt(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),C(()=>document.head.removeChild(t)),Oe(1))))}function ho(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function bo(){return L(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(ho),N(ho()))}function vo(){return{width:innerWidth,height:innerHeight}}function go(){return b(window,"resize",{passive:!0}).pipe(l(vo),N(vo()))}function yo(){return Q([bo(),go()]).pipe(l(([e,t])=>({offset:e,size:t})),J(1))}function lr(e,{viewport$:t,header$:r}){let n=t.pipe(X("size")),o=Q([n,r]).pipe(l(()=>Be(e)));return Q([r,t,o]).pipe(l(([{height:i},{offset:a,size:s},{x:f,y:c}])=>({offset:{x:a.x-f,y:a.y-c+i},size:s})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(a=>{let s=document.createElement("script");s.src=i,s.onload=a,document.body.appendChild(s)})),Promise.resolve())}var r=class{constructor(n){this.url=n,this.onerror=null,this.onmessage=null,this.onmessageerror=null,this.m=a=>{a.source===this.w&&(a.stopImmediatePropagation(),this.dispatchEvent(new MessageEvent("message",{data:a.data})),this.onmessage&&this.onmessage(a))},this.e=(a,s,f,c,u)=>{if(s===this.url.toString()){let p=new ErrorEvent("error",{message:a,filename:s,lineno:f,colno:c,error:u});this.dispatchEvent(p),this.onerror&&this.onerror(p)}};let o=new EventTarget;this.addEventListener=o.addEventListener.bind(o),this.removeEventListener=o.removeEventListener.bind(o),this.dispatchEvent=o.dispatchEvent.bind(o);let i=document.createElement("iframe");i.width=i.height=i.frameBorder="0",document.body.appendChild(this.iframe=i),this.w.document.open(),this.w.document.write(` + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/documentation/index.html b/developer/documentation/index.html new file mode 100644 index 0000000..ca2d47f --- /dev/null +++ b/developer/documentation/index.html @@ -0,0 +1,1320 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Index - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/documentation/overview/index.html b/developer/documentation/overview/index.html new file mode 100644 index 0000000..4a57811 --- /dev/null +++ b/developer/documentation/overview/index.html @@ -0,0 +1,1392 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Overview - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Working with documentation

+

Documentation is written using mkdocs.

+

Building documentation PDF

+

You can build a copy of the documentation as a PDF file using the following steps:

+
pip install mkdocs-with-pdf
+pip install mkdocs-material
+pip install qrcode
+mkdocs build --config-file mkdocs-pdf.yml
+xdg-open pdfs/QGISAnimationWorkbench.pdf 
+
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/guide/architecture/index.html b/developer/guide/architecture/index.html new file mode 100644 index 0000000..b1703d9 --- /dev/null +++ b/developer/guide/architecture/index.html @@ -0,0 +1,1328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Architecture - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/guide/building/index.html b/developer/guide/building/index.html new file mode 100644 index 0000000..e1e11f0 --- /dev/null +++ b/developer/guide/building/index.html @@ -0,0 +1,1328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Building - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/guide/cloning/index.html b/developer/guide/cloning/index.html new file mode 100644 index 0000000..bd5064d --- /dev/null +++ b/developer/guide/cloning/index.html @@ -0,0 +1,1328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Cloning - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/guide/configuration/index.html b/developer/guide/configuration/index.html new file mode 100644 index 0000000..1072710 --- /dev/null +++ b/developer/guide/configuration/index.html @@ -0,0 +1,1328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Configuration - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/guide/design/index.html b/developer/guide/design/index.html new file mode 100644 index 0000000..2002a15 --- /dev/null +++ b/developer/guide/design/index.html @@ -0,0 +1,1337 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Design - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Design

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/guide/ide-setup/index.html b/developer/guide/ide-setup/index.html new file mode 100644 index 0000000..efc770d --- /dev/null +++ b/developer/guide/ide-setup/index.html @@ -0,0 +1,1479 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + IDE Setup - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Developer Environment

+

In this section, we walk you through setting up a development environment and +describe common workflows for debugging etc.

+

Setup

+

Fork the main branch into your personal repository. Clone it to your local +computer. Install QGIS and the following dependencies.

+
    +
  • debugpy (python library)
  • +
  • convert (imagemagick)
  • +
  • ffmpeg
  • +
  • vscode (don't use flatpak, debugging will not work with QGIS)
  • +
+

Clone the repo and symlink the animation_workbench subfolder into your profile. +Remember to change <profile> in the line below with the actual name of the +profile you will be using.

+
git clone https://github.com/{your-personal-repo}/QGISAnimationWorkbench.git
+ln -s animation_workbench ~.local/share/QGIS/QGIS3/profiles/<profile>/python/plugins
+
+

Enable the plugin in the QGIS plugin manager. You should also install the +Plugin Reloader plugin so +you can quickly deploy changes to your local session in QGIS as you are +working.

+

Debugging

+

We use the VSCode remote debugger with debugpy in order to carry our +debugging workflows such as setting breakpoints, inspecting the application +state, stepping through code etc.

+

To start debugging, you need to put the plugin into developer mode.

+

+

Next, open the QGIS Animation Workbench git checkout (as described above), and +then active the Run and Debug tab (1 in the image below). From the list of +launchers, choose Python: Remote Attach and press the green run icon (2 in +the image below).

+

+

The animation workbench will then resume normal operation, but you will be able +to set breakpoints and inspect objects in CSCode. Please refer to VSCode +documentation for the actual nuts and bolts of using their debugging tools.

+

Packaging

+

Every time a merge is made to the main branch, a package is built automatically.

+
TODO
+
+

Run test

+
TODO
+
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/guide/img/debug_mode.png b/developer/guide/img/debug_mode.png new file mode 100644 index 0000000..9c58716 Binary files /dev/null and b/developer/guide/img/debug_mode.png differ diff --git a/developer/guide/img/debug_mode_vscode.png b/developer/guide/img/debug_mode_vscode.png new file mode 100644 index 0000000..3202031 Binary files /dev/null and b/developer/guide/img/debug_mode_vscode.png differ diff --git a/developer/guide/index.html b/developer/guide/index.html new file mode 100644 index 0000000..64773c3 --- /dev/null +++ b/developer/guide/index.html @@ -0,0 +1,1342 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + QAW - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Developer guide

+

In this section of the documentation, we aim to onboard developers onto the +process of setting up a developer workstation, understanding the system +architecture, contributing back to the project and so forth. Here is a brief +overview of the content provided here:

+
    +
  • Architecture: Here we outline the system architecture using ER Diagrams, Software Component Diagrams etc.
  • +
  • Prerequisites: An overview of the software that needs to be installed before you can start.
  • +
  • Cloning: In this section we cover how to make a local working copy on your own machine.
  • +
  • IDE Setup: Here we walk through setting up your IDE.
  • +
  • Building: This covers tasks related to building the application so you can test it in your browser.
  • +
  • Configuration: This covers standard configuration tasks that need to be done once the site is brought online.
  • +
  • Design: This section describes the visual design approach for the user interface.
  • +
  • Workflows: Examples of typical workflows for adding features, fixing bugs etc.
  • +
  • Testing: This section focuses on setting up end-to-end testing for the project.
  • +
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/guide/prerequisites/index.html b/developer/guide/prerequisites/index.html new file mode 100644 index 0000000..ef5749e --- /dev/null +++ b/developer/guide/prerequisites/index.html @@ -0,0 +1,1328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Prerequisites - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/guide/testing/index.html b/developer/guide/testing/index.html new file mode 100644 index 0000000..6c32a21 --- /dev/null +++ b/developer/guide/testing/index.html @@ -0,0 +1,1328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Testing - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/guide/workflows/index.html b/developer/guide/workflows/index.html new file mode 100644 index 0000000..8340cb6 --- /dev/null +++ b/developer/guide/workflows/index.html @@ -0,0 +1,1328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Workflows - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/index.html b/developer/index.html new file mode 100644 index 0000000..0920f42 --- /dev/null +++ b/developer/index.html @@ -0,0 +1,1332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + QAW - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

For Developers

+ + +

This is the homepage for all developer related documentation.

+
    +
  • The developer guide, which describes common workflows for developers in a tutorial format. This includes instructions on how to set up your developer environment, check out the code, run it locally etc.
  • +
  • The developer manual, which describes each python module and its classes, functions etc. This section is autogenerated.
  • +
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/manual/index.html b/developer/manual/index.html new file mode 100644 index 0000000..778bab7 --- /dev/null +++ b/developer/manual/index.html @@ -0,0 +1,1331 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + QAW - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Developer manual

+

Welcome to the QGIS Animation Workbench developer manual. This section of the documentation describes how to participate in the development of the application and what the various components. The manual is intended to function as a reference for the application. For narrative / workflow based tutorials, you may prefer to work through our developer guide. Here is a brief overview of the content provided here:

+
    +
  • : Coming soon
  • +
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..016c71e --- /dev/null +++ b/index.html @@ -0,0 +1,1364 @@ + + + + + + + + + + + + + + + + + + + + + + + + Home - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

QGIS Animation Workbench

+

Welcome to the QGIS Animation Workbench (QAW). QAW is a QGIS Plugin that will help you bring your maps to life! Let's start with a quick overview. Click on the image below to view a 14 minute walkthrough on YouTube.

+

Overview

+

🤖 Why QGIS Animation Workbench?

+

QGIS Animation Bench exists because we wanted to use all the awesome cartography features in QGIS and make cool, animated maps! +QGIS already includes the Temporal Manager which allows you to produce animations for time-based data. But what if you want to +make animations where you travel around the map, zooming in and out, and perhaps making features on the map wiggle and jiggle as the +animation progresses? That is what the animation workbench tries to solve...

+

🎨 Features

+
    +
  • Modes : Supports 3 modes: Sphere, Planar and Static.
  • +
  • Sphere: Creates a spinning globe effect. Like Google Earth might do, but with your own data and cartography.
  • +
  • Planar: Lets you move from feature to feature on a flat map, pausing at each if you want to.
  • +
  • Static: The frame of reference stays the same and you can animate the symbology within that scene.
  • +
  • Add music to your exported videos - see the Creative Commons website for a list of places where you can download free music (make sure it does not have a 'No Derivative Works' license).
  • +
  • Multithreaded, efficient rendering workflow. The plugin is designed to work well even on very modest hardware. If you have a fast PC, you can crank up the size to the thread pool to process more jobs at the same time.
  • +
+
+

Supports only English currently - we may add other languages in the future if there is demand.

+
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 0000000..3623d76 --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"QGIS Animation Workbench","text":"

Welcome to the QGIS Animation Workbench (QAW). QAW is a QGIS Plugin that will help you bring your maps to life! Let's start with a quick overview. Click on the image below to view a 14 minute walkthrough on YouTube.

"},{"location":"#why-qgis-animation-workbench","title":"\ud83e\udd16 Why QGIS Animation Workbench?","text":"

QGIS Animation Bench exists because we wanted to use all the awesome cartography features in QGIS and make cool, animated maps! QGIS already includes the Temporal Manager which allows you to produce animations for time-based data. But what if you want to make animations where you travel around the map, zooming in and out, and perhaps making features on the map wiggle and jiggle as the animation progresses? That is what the animation workbench tries to solve...

"},{"location":"#features","title":"\ud83c\udfa8 Features","text":"
  • Modes : Supports 3 modes: Sphere, Planar and Static.
  • Sphere: Creates a spinning globe effect. Like Google Earth might do, but with your own data and cartography.
  • Planar: Lets you move from feature to feature on a flat map, pausing at each if you want to.
  • Static: The frame of reference stays the same and you can animate the symbology within that scene.
  • Add music to your exported videos - see the Creative Commons website for a list of places where you can download free music (make sure it does not have a 'No Derivative Works' license).
  • Multithreaded, efficient rendering workflow. The plugin is designed to work well even on very modest hardware. If you have a fast PC, you can crank up the size to the thread pool to process more jobs at the same time.

Supports only English currently - we may add other languages in the future if there is demand.

"},{"location":"about/code-of-conduct/","title":"Contributor Covenant Code of Conduct","text":""},{"location":"about/code-of-conduct/#our-pledge","title":"Our Pledge","text":"

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.

"},{"location":"about/code-of-conduct/#our-standards","title":"Our Standards","text":"

Examples of behaviour that contributes to creating a positive environment include:

  • Using welcoming and inclusive language
  • Being respectful of differing viewpoints and experiences
  • Gracefully accepting constructive criticism
  • Focusing on what is best for the community
  • Showing empathy towards other community members

Examples of unacceptable behaviour by participants include:

  • The use of sexualized language or imagery and unwelcome sexual attention or advances
  • Trolling, insulting/derogatory comments, and personal or political attacks
  • Public or private harassment
  • Publishing others' private information, such as a physical or electronic address, without explicit permission
  • Other conduct which could reasonably be considered inappropriate in a professional setting
"},{"location":"about/code-of-conduct/#our-responsibilities","title":"Our Responsibilities","text":"

Project maintainers are responsible for clarifying the standards of acceptable behaviour and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behaviour.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

"},{"location":"about/code-of-conduct/#scope","title":"Scope","text":"

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

"},{"location":"about/code-of-conduct/#enforcement","title":"Enforcement","text":"

Instances of abusive, harassing, or otherwise unacceptable behaviour may be reported by contacting the project team. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

"},{"location":"about/code-of-conduct/#attribution","title":"Attribution","text":"

This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

"},{"location":"about/contribute/","title":"Contribute","text":""},{"location":"about/contribute/#pull-request-steps","title":"\ud83d\udd27 Pull Request Steps","text":"

This project is open source, so you can create a pull request(PR) after you fix issues. Get a local copy of the plugins checked out for development using the following process.

"},{"location":"about/contribute/#pull-request","title":"Pull Request","text":"

Before uploading your PR, run test one last time to check if there are any errors. If it has no errors, commit and then push it!

For more information on PR's steps, please see links in the Contributing section.

"},{"location":"about/contribute/#commit-messages","title":"Commit messages","text":"

Please make this project more fun and easy to scan by using emoji prefixes for your commit messages (see GitMoji).

Commit type Emoji Initial commit \ud83c\udf89 :tada: Version tag \ud83d\udd16 :bookmark: New feature \u2728 :sparkles: Bugfix \ud83d\udc1b :bug: Metadata \ud83d\udcc7 :card_index: Documentation \ud83d\udcda :books: Documenting source code \ud83d\udca1 :bulb: Performance \ud83d\udc0e :racehorse: Cosmetic \ud83d\udc84 :lipstick: Tests \ud83d\udea8 :rotating_light: Adding a test \u2705 :white_check_mark: Make a test pass \u2714\ufe0f :heavy_check_mark: General update \u26a1\ufe0f :zap: Improve format/structure \ud83c\udfa8 :art: Refactor code \ud83d\udd28 :hammer: Removing code/files \ud83d\udd25 :fire: Continuous Integration \ud83d\udc9a :green_heart: Security \ud83d\udd12 :lock: Upgrading dependencies \u2b06\ufe0f :arrow_up: Downgrading dependencies \u2b07\ufe0f :arrow_down: Lint \ud83d\udc55 :shirt: Translation \ud83d\udc7d :alien: Text \ud83d\udcdd :pencil: Critical hotfix \ud83d\ude91 :ambulance: Deploying stuff \ud83d\ude80 :rocket: Fixing on MacOS \ud83c\udf4e :apple: Fixing on Linux \ud83d\udc27 :penguin: Fixing on Windows \ud83c\udfc1 :checkered_flag: Work in progress \ud83d\udea7 :construction: Adding CI build system \ud83d\udc77 :construction_worker: Analytics or tracking code \ud83d\udcc8 :chart_with_upwards_trend: Removing a dependency \u2796 :heavy_minus_sign: Adding a dependency \u2795 :heavy_plus_sign: Docker \ud83d\udc33 :whale: Configuration files \ud83d\udd27 :wrench: Package.json in JS \ud83d\udce6 :package: Merging branches \ud83d\udd00 :twisted_rightwards_arrows: Bad code / need improv. \ud83d\udca9 :hankey: Reverting changes \u23ea :rewind: Breaking changes \ud83d\udca5 :boom: Code review changes \ud83d\udc4c :ok_hand: Accessibility \u267f\ufe0f :wheelchair: Move/rename repository \ud83d\ude9a :truck: Other Be creative"},{"location":"about/contribute/#contributing","title":"\ud83d\udcac Contributing","text":"
  • Code of Conduct
  • Contributing Guideline
  • Commit Convention
  • Issue Guidelines
"},{"location":"about/credits/","title":"Credits","text":""},{"location":"about/credits/#author","title":"Author","text":"

This plugin was developed by:

Tim Sutton Nyall Dawson Jeremy Prior Coder and Ideas Guy Genius Guru of Awesomeness Document and Logo Guy timlinux @ github nyalldawson @ github Jeremy-Prior @ github"},{"location":"about/credits/#contributors","title":"Contributors","text":"

Thanks to:

  • Mathieu Pellerin (@nirvn)
  • Thiasha Vythilingam (@ThiashaV)

We are looking for contributors, add yourself here!

Also:

  • NHN and Tui Editor for the great README which I based this one on.
"},{"location":"about/license/","title":"GNU General Public License","text":"

Version 2, June 1991 Copyright \u00a9 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

"},{"location":"about/license/#preamble","title":"Preamble","text":"

The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.

When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.

To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.

For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.

We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.

Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.

Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.

The precise terms and conditions for copying, distribution and modification follow.

"},{"location":"about/license/#terms-and-conditions-for-copying-distribution-and-modification","title":"TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION","text":"

0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The \u201cProgram\u201d, below, refers to any such program or work, and a \u201cwork based on the Program\u201d means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term \u201cmodification\u201d.) Each licensee is addressed as \u201cyou\u201d.

Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.

1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.

You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:

  • a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
  • b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
  • c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.

In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:

  • a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
  • b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
  • c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.

4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.

6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.

7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.

9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and \u201cany later version\u201d, you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.

10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.

"},{"location":"about/license/#no-warranty","title":"NO WARRANTY","text":"

11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \u201cAS IS\u201d WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

END OF TERMS AND CONDITIONS

"},{"location":"about/license/#how-to-apply-these-terms-to-your-new-programs","title":"How to Apply These Terms to Your New Programs","text":"

If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.

To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the \u201ccopyright\u201d line and a pointer to where the full notice is found.

<one line to give the program's name and a brief idea of what it does.>\nCopyright (C) <year>  <name of author>\n\nThis program is free software; you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation; either version 2 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License along\nwith this program; if not, write to the Free Software Foundation, Inc.,\n51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this when it starts in an interactive mode:

Gnomovision version 69, Copyright (C) year name of author\nGnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\nThis is free software, and you are welcome to redistribute it\nunder certain conditions; type `show c' for details.\n

The hypothetical commands show w and show c should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than show w and show c; they could even be mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your school, if any, to sign a \u201ccopyright disclaimer\u201d for the program, if necessary. Here is a sample; alter the names:

Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n`Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n<signature of Ty Coon>, 1 April 1989\nTy Coon, President of Vice\n

This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License.

"},{"location":"developer/","title":"For Developers","text":"

This is the homepage for all developer related documentation.

  • The developer guide, which describes common workflows for developers in a tutorial format. This includes instructions on how to set up your developer environment, check out the code, run it locally etc.
  • The developer manual, which describes each python module and its classes, functions etc. This section is autogenerated.
"},{"location":"developer/documentation/overview/","title":"Working with documentation","text":"

Documentation is written using mkdocs.

"},{"location":"developer/documentation/overview/#building-documentation-pdf","title":"Building documentation PDF","text":"

You can build a copy of the documentation as a PDF file using the following steps:

pip install mkdocs-with-pdf\npip install mkdocs-material\npip install qrcode\nmkdocs build --config-file mkdocs-pdf.yml\nxdg-open pdfs/QGISAnimationWorkbench.pdf \n
"},{"location":"developer/guide/","title":"Developer guide","text":"

In this section of the documentation, we aim to onboard developers onto the process of setting up a developer workstation, understanding the system architecture, contributing back to the project and so forth. Here is a brief overview of the content provided here:

  • Architecture: Here we outline the system architecture using ER Diagrams, Software Component Diagrams etc.
  • Prerequisites: An overview of the software that needs to be installed before you can start.
  • Cloning: In this section we cover how to make a local working copy on your own machine.
  • IDE Setup: Here we walk through setting up your IDE.
  • Building: This covers tasks related to building the application so you can test it in your browser.
  • Configuration: This covers standard configuration tasks that need to be done once the site is brought online.
  • Design: This section describes the visual design approach for the user interface.
  • Workflows: Examples of typical workflows for adding features, fixing bugs etc.
  • Testing: This section focuses on setting up end-to-end testing for the project.
"},{"location":"developer/guide/design/","title":"Design","text":""},{"location":"developer/guide/ide-setup/","title":"Developer Environment","text":"

In this section, we walk you through setting up a development environment and describe common workflows for debugging etc.

"},{"location":"developer/guide/ide-setup/#setup","title":"Setup","text":"

Fork the main branch into your personal repository. Clone it to your local computer. Install QGIS and the following dependencies.

  • debugpy (python library)
  • convert (imagemagick)
  • ffmpeg
  • vscode (don't use flatpak, debugging will not work with QGIS)

Clone the repo and symlink the animation_workbench subfolder into your profile. Remember to change <profile> in the line below with the actual name of the profile you will be using.

git clone https://github.com/{your-personal-repo}/QGISAnimationWorkbench.git\nln -s animation_workbench ~.local/share/QGIS/QGIS3/profiles/<profile>/python/plugins\n

Enable the plugin in the QGIS plugin manager. You should also install the Plugin Reloader plugin so you can quickly deploy changes to your local session in QGIS as you are working.

"},{"location":"developer/guide/ide-setup/#debugging","title":"Debugging","text":"

We use the VSCode remote debugger with debugpy in order to carry our debugging workflows such as setting breakpoints, inspecting the application state, stepping through code etc.

To start debugging, you need to put the plugin into developer mode.

Next, open the QGIS Animation Workbench git checkout (as described above), and then active the Run and Debug tab (1 in the image below). From the list of launchers, choose Python: Remote Attach and press the green run icon (2 in the image below).

The animation workbench will then resume normal operation, but you will be able to set breakpoints and inspect objects in CSCode. Please refer to VSCode documentation for the actual nuts and bolts of using their debugging tools.

"},{"location":"developer/guide/ide-setup/#packaging","title":"Packaging","text":"

Every time a merge is made to the main branch, a package is built automatically.

TODO\n
"},{"location":"developer/guide/ide-setup/#run-test","title":"Run test","text":"
TODO\n
"},{"location":"developer/manual/","title":"Developer manual","text":"

Welcome to the QGIS Animation Workbench developer manual. This section of the documentation describes how to participate in the development of the application and what the various components. The manual is intended to function as a reference for the application. For narrative / workflow based tutorials, you may prefer to work through our developer guide. Here is a brief overview of the content provided here:

  • : Coming soon
"},{"location":"user/","title":"For Users","text":"

This is the homepage for all user related documentation.

The user content is divided into three sections:

  • The quickstart tutorial, which aims to get you familiar with the basics of platform in around 5 minutes.
  • The user guide, which describes common workflows in a tutorial format.
  • The user manual, which describes each page of the user interface and what the various options on that page do.
"},{"location":"user/guide/","title":"Index","text":""},{"location":"user/guide/#tutorial-1-point-along-a-line","title":"Tutorial 1: Point Along A Line","text":"

This tutorial introduces the concept of moving a point along a line within your animated map.

1. Download and extract the Required Tutorial Zip Folder

2. Open the tutorial_1.qgz project file that is in the folder. When you first open it you you see something like this:

3. Select the premade line layer (1), and click on the Add Symbol Layer (green plus symbol) button (2) to it.

Change the new Symbol Layer (3) type to marker line and then style it (4) so that it is more visible.

4. Change the Symbol Layer's settings so that the point is only on the first vertex (5) and and not at equidistant intervals.

Change the offset along the line to be Percentage (6).

Click the Dropdown Menu (7) \u2794Edit... (8) and then add the following code snippet

    -- Point Along Line Code Snippet\n    (@current_hover_frame/@hover_frames) * 100\n

The snippet tells QGIS how far along the line (as a percentage of the line length) to render the point in each frame.

5. Open the Workbench and select Fixed Extent (9).

Click on Map Canvas Extent (10) and set the the Frames to 300 (11) (for a 10 second output at 30 frames per second).

6. Skip over the Intro, Outro, and Soundtrack tabs. In the Output tab, set the output format (12) and resolution (13), and set the output location's path (14).

7. Click Run and render your output.

After this tutorial you should have a better idea of how to make a point move along a line. An expansion to this example would be to make the moving point a dynamically changing marker (like the markers in tutorial 1). Go have fun!

"},{"location":"user/guide/#tutorial-2-basic-dynamically-changing-markers","title":"Tutorial 2: Basic Dynamically Changing Markers","text":"

This tutorial aims to show you the basics of creating, and animating, a static layer to use with the Animation Workbench. There are three pre-made layers to allow the main focus of the tutorial to be on the Animation Workbench and not on QGIS as a whole.

1. Download and extract the Required Tutorial Zip Folder

2. Open the tutorial_2.qgz project file that is in the folder. \u00a0

3. Set the CRS of your project to WGS84/UTM zone 35S (EPSG: 32735).

4. In the Browser, expand the tutorial_2.gpkg and add the three pre-made layers (VaalDam, SouthAfrica, and route) (A) to your project.

5. In the Layers Panel, arrange the layers in the following order: route, VaalDam, SouthAfrica. Then right-click on the VaalDam layer and Zoom to Layer(s) (B)

Style the three layers to your preferred style. \u00a0

6. Now create a new layer in the tutorial_2.gpkg by clicking Layer\u2794Create Layer\u2794 New GeoPackage Layer... (C).

Click on the Ellipsis (D), navigate to and select the tutorial_2.gpkg, and click Save. Change the Table name to fish (E), set the Geometry type as Point (F), and change the CRS to match the Project CRS (G).

Click on OK and then click Add New Layer on the window that pops up. \u00a0

7. Select the fish layer and then click on Toggle Editing\u2794Add Point Feature (H).

Add a few points wherever you feel they should go (Hint: This is a fish layer so adding them above the dam layer would be best). Don't worry about naming the points, just add them.

Save your changes by clicking on Save Layer Edits just next to the Toggle Editing button. Then stop editing the layer. \u00a0

8. Repeat steps 6. and 7. but change the Table name to bird and add the points over the land areas.

9. Select the fish layer and then in the Layer styling toolbar (I) change the Symbol layer type to Raster Image Marker (J).

Select the marker image by clicking the Dropdown menu\u2794Select File... (K) and then choosing fish\u2794fish_0000.png.

Click Open

10. Change the marker's Size Unit to Meters at Scale (L)

and set the Width and Height to 1000. \u00a0

11. Repeat Steps 9. and 10. with the bird layer but instead choosing bird\u2794bird_0000.png and setting the Width and Height to 3000.

In QGIS 3.26, or later, the Symbol layer type can simply be selected as Animated Marker and Step 12. can be skipped.

12. To animate the fish and bird layers using the QGIS Expressions system click the Dropdown Menu\u2794Edit... (M).

For the fish layer use the following expression:

    @project_home\n    || \n    '/fish/fish_00'\n    ||\n    lpad(to_string( @frame_number % 32), 2, '0')\n    ||\n    '.png'\n

And for the bird layer use:

    @project_home\n    ||\n    '/bird/bird_00'\n    || \n    lpad(to_string(@frame_number % 9), 2, '0')\n    || \n    '.png'\n

Refer to the What is the Workbench doing? section for an explanation about what the above code snippet is doing.

13. Open the Animation Workbench (refer to the Using the Animation Workbench section if you are unsure how to open the Workbench).

In the Animation Plan tab set:

  • the Render Mode to Planar (N),
  • the Animation Layer to route (O) using the dropdown menu,
  • the Zoom Range (P) to 1:270000 for the Minimum and 1:135000 for the Maximum,
  • the Frame rate per second to 9 fps (Q),
  • the Travel duration to 4,00 s (R),
  • and the Feature hover duration to 2,00 s (S)

Enable both the Pan and Zoom easings and set them to linear.

14. Skip past the Intro, Outro, and Soundtrack tabs to the Output tab. Set the Output Format as Animated Gif (T) and the Output Resolution to 720p (1280x720) (U). The Output Resolution can be set as any of the three choices but was set at 720 for this tutorial for the sake of speed. Set the output location to one you can find easily (V)

15. Click Run and watch what the Workbench is doing in the Progress tab. Once the Workbench is finished running, you should end up with an output similar to this:

After this tutorial you should have a better understanding of how to create a point layer in your project and then to change the Single Symbol markers into stationary animated markers. A key focus is the idea that you can tell versions of QGIS before 3.26 to dynamically change markers using short code snippets. Versions of QGIS post 3.26 allow a user to simply use the Animated Marker feature without editing an expression.

"},{"location":"user/guide/#tutorial-3-flying-points","title":"Tutorial 3: Flying Points","text":"

This tutorial aims to show you how add a flying point animation to points on your map using built-in QGIS functionalities (The geometry generator line) and introduced variables from the workbench.

1. Download and extract the Required Tutorial Zip Folder

2. Open the tutorial_3.qgz project file. When you first open the project file you should be greeted with something like this:

3. Create a new point layer in a new geopackage by clicking Layer\u2794Create Layer\u2794 New GeoPackage Layer.... Click on the Ellipsis (three dots) next to the Database textbox and navigate to the folder that the tutorial_3.qgz file is located in. Type the File name \"tutorial_3\" (1) and ensure the file will be saved as a GeoPackage (2) and click Save (3).

Change the Table name to flying_points (4), set the Geometry type as Point (5) and change the CRS to match the Project CRS (6).

Click OK (7) \u00a0

4. Click on Toggle Editing\u2794Add Point Feature (8).

And randomly add points to your map. Depending on your computer's capabilites, you can add more, or fewer, points than the example below.

Save your Layer Edits and toggle off the Editing tool. \u00a0

5. Style the points layer.

Select the flying_points (9) layer and in the Layer Styling toolbar click on the Add Symbol Layer (green plus symbol) button (10).

Select the top Simple Marker (11) and change its Symbol layer type to Geometry Generator (12)

and then set the Geometry type to LineString / MultiLineString (13).

Change the line's Symbol layer type to Marker Line (14).

Add a second Simple marker to the marker line so that you end up with something like this:

Style the various Simple Markers to your preferred look.

6. Select the Geometry Generator symbol layer (15) and add this code to it:

    wave_randomized(\n    make_line(\n    $geometry, geometry(@hover_feature)), \n    100, 1000, 1000, 10000, 1)\n

More information about what changing the numbers will affect can be found in the QGIS expressions editor. \u00a0

7. A few options need to be changed in the Marker Line symbol layer (16): The Marker placement needs to be set to On first vertex (17) and, the Offset along line needs to be changed to Percentage (18). The click the Dropdown menu next to Offset along line and select Edit... (19).

In the Expression String Builder add the following code snippet:

    100 - to_int((@current_hover_frame / @hover_frames) * 100 )\n

Click OK

8. Select the first Simple Marker symbol layer (20) in the Marker Line symbol layer. Scroll down to Offset and click on the Dropdown Menu\u2794Edit.. (21).

In the Expression String Builder add the following code snippet:

    -- Taken from https://spicyyoghurt.com/tools/easing-functions\n    --    t = Time - Amount of time that has passed since the beginning of the animation. Usually starts at 0 and is slowly increased using a game loop or other update function.\n    --    b = Beginning value - The starting point of the animation. Usually it's a static value, you can start at 0 for example.\n    --    c = Change in value - The amount of change needed to go from starting point to end point. It's also usually a static value.\n    --    d = Duration - Amount of time the animation will take. Usually a static value aswell.\n    -- Sinusoidal\n    -- -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;\n\n    -- Use with the animation in static mode\n    if(@hover_feature_id != $id,\n    array(\n        (-@hover_frames / 2) * (cos( (pi() * @frame_number / @hover_frames ) - 1)) ,\n        (-@hover_frames / 2) * (sin( (pi() * @frame_number / @hover_frames ) - 1)) \n        ),\n        array (0,0))\n

Click OK

9. Open the Animation Workbench (22)

10. Set up the Animation Plan with:

  • the Render Mode to Planar (23),
  • the Animation Layer to flying_points (24) using the dropdown menu,
  • the Zoom Range (25) to 1:22000000 for the Minimum and 1:11000000 for the Maximum,
  • the Frame rate per second to 9 fps (26),
  • the Travel duration to 2,00 s (27),
  • the Feature hover duration to 2,00 s (28),
  • and the Zoom Easing as InCirc (29)

With a decently specced computer you can up the fps and get the points to fly faster in your output. \u00a0

11. Add license-free media to the Intro, Outro, and Soundtrack.

Make sure your Soundtrack is as long as, or longer than, your final animation will be (including the Intro, Animation, and Outro).

12. Set the Output Format as Movie (MP4) (30) and the Output Resolution to 1080 (1920x1080) (31). The Output Resolution can be set as any of the three choices but was set at 1080 for this tutorial for the sake of speed. Set the output location (32) to one you can easily locate.

13. Click Run and get an output. The GIF below is the visual output of the tutorial if you followed step-by-step and set the parameters to exactly what was stated.

The link to a more complex output (with an Intro, an Outro, and a Soundtrack) can be found here

After this tutorial you should have a better idea of how you can use a mixture of built-in QGIS functionalites and the workbench's introduced variables to generate interesting outputs.

"},{"location":"user/guide/#tutorial-4-spinning-globe","title":"Tutorial 4: Spinning Globe","text":"

Given a global point layer and countries layer like this:

You can create a nice spinning globe effect like this:

I set up the animation workbench like this:

For the above animated GIF, I compressed it using imagemagick like this:

convert globe.gif -coalesce -resize 700x525 -fuzz 2% +dither -layers Optimize +map globe_small.gif\n

This is a handy technique if you want to generate small file size animations.

For the points I made a red marker using a quarter circle that spins around the points like this:

The rotation field expression is this:

if (@id = @hover_feature_id, \n    0-((1440 * (@current_hover_frame/@hover_frames)) % 360),\n    0)\n

This will spin around 4 times during the hover cycle.

For the ocean (AOI in the layers list), I generated a grid of 1 degree cells covering the earth. You need to do it as smaller polygons instead of one large polygon because QGIS will run into issues reprojecting a single polygon whose edges lie on the date line.

Here is how the final video came out:

"},{"location":"user/guide/tutorial1/","title":"1 Points on a Line","text":""},{"location":"user/guide/tutorial1/#tutorial-1-point-along-a-line","title":"Tutorial 1: Point Along A Line","text":"

This tutorial introduces the concept of moving a point along a line within your animated map.

1. Download and extract the Required Tutorial Zip Folder

2. Open the tutorial_1.qgz project file that is in the folder. When you first open it you you see something like this:

3. Select the premade line layer (1), and click on the Add Symbol Layer (green plus symbol) button (2) to it.

Change the new Symbol Layer (3) type to marker line and then style it (4) so that it is more visible.

4. Change the Symbol Layer's settings so that the point is only on the first vertex (5) and and not at equidistant intervals.

Change the offset along the line to be Percentage (6).

Click the Dropdown Menu (7) \u2794Edit... (8) and then add the following code snippet

    -- Point Along Line Code Snippet\n    (@current_hover_frame/@hover_frames) * 100\n

The snippet tells QGIS how far along the line (as a percentage of the line length) to render the point in each frame.

5. Open the Workbench and select Fixed Extent (9).

Click on Map Canvas Extent (10) and set the the Frames to 300 (11) (for a 10 second output at 30 frames per second).

6. Skip over the Intro, Outro, and Soundtrack tabs. In the Output tab, set the output format (12) and resolution (13), and set the output location's path (14).

7. Click Run and render your output.

After this tutorial you should have a better idea of how to make a point move along a line. An expansion to this example would be to make the moving point a dynamically changing marker (like the markers in tutorial 1). Go have fun!

"},{"location":"user/guide/tutorial2/","title":"2 Dynamic Markers","text":""},{"location":"user/guide/tutorial2/#tutorial-2-basic-dynamically-changing-markers","title":"Tutorial 2: Basic Dynamically Changing Markers","text":"

This tutorial aims to show you the basics of creating, and animating, a static layer to use with the Animation Workbench. There are three pre-made layers to allow the main focus of the tutorial to be on the Animation Workbench and not on QGIS as a whole.

1. Download and extract the Required Tutorial Zip Folder

2. Open the tutorial_2.qgz project file that is in the folder. \u00a0

3. Set the CRS of your project to WGS84/UTM zone 35S (EPSG: 32735).

4. In the Browser, expand the tutorial_2.gpkg and add the three pre-made layers (VaalDam, SouthAfrica, and route) (A) to your project.

5. In the Layers Panel, arrange the layers in the following order: route, VaalDam, SouthAfrica. Then right-click on the VaalDam layer and Zoom to Layer(s) (B)

Style the three layers to your preferred style. \u00a0

6. Now create a new layer in the tutorial_2.gpkg by clicking Layer\u2794Create Layer\u2794 New GeoPackage Layer... (C).

Click on the Ellipsis (D), navigate to and select the tutorial_2.gpkg, and click Save. Change the Table name to fish (E), set the Geometry type as Point (F), and change the CRS to match the Project CRS (G).

Click on OK and then click Add New Layer on the window that pops up. \u00a0

7. Select the fish layer and then click on Toggle Editing\u2794Add Point Feature (H).

Add a few points wherever you feel they should go (Hint: This is a fish layer so adding them above the dam layer would be best). Don't worry about naming the points, just add them.

Save your changes by clicking on Save Layer Edits just next to the Toggle Editing button. Then stop editing the layer. \u00a0

8. Repeat steps 6. and 7. but change the Table name to bird and add the points over the land areas.

9. Select the fish layer and then in the Layer styling toolbar (I) change the Symbol layer type to Raster Image Marker (J).

Select the marker image by clicking the Dropdown menu\u2794Select File... (K) and then choosing fish\u2794fish_0000.png.

Click Open

10. Change the marker's Size Unit to Meters at Scale (L)

and set the Width and Height to 1000. \u00a0

11. Repeat Steps 9. and 10. with the bird layer but instead choosing bird\u2794bird_0000.png and setting the Width and Height to 3000.

In QGIS 3.26, or later, the Symbol layer type can simply be selected as Animated Marker and Step 12. can be skipped.

12. To animate the fish and bird layers using the QGIS Expressions system click the Dropdown Menu\u2794Edit... (M).

For the fish layer use the following expression:

    @project_home\n    || \n    '/fish/fish_00'\n    ||\n    lpad(to_string( @frame_number % 32), 2, '0')\n    ||\n    '.png'\n

And for the bird layer use:

    @project_home\n    ||\n    '/bird/bird_00'\n    || \n    lpad(to_string(@frame_number % 9), 2, '0')\n    || \n    '.png'\n

Refer to the What is the Workbench doing? section for an explanation about what the above code snippet is doing.

13. Open the Animation Workbench (refer to the Using the Animation Workbench section if you are unsure how to open the Workbench).

In the Animation Plan tab set:

  • the Render Mode to Planar (N),
  • the Animation Layer to route (O) using the dropdown menu,
  • the Zoom Range (P) to 1:270000 for the Minimum and 1:135000 for the Maximum,
  • the Frame rate per second to 9 fps (Q),
  • the Travel duration to 4,00 s (R),
  • and the Feature hover duration to 2,00 s (S)

Enable both the Pan and Zoom easings and set them to linear.

14. Skip past the Intro, Outro, and Soundtrack tabs to the Output tab. Set the Output Format as Animated Gif (T) and the Output Resolution to 720p (1280x720) (U). The Output Resolution can be set as any of the three choices but was set at 720 for this tutorial for the sake of speed. Set the output location to one you can find easily (V)

15. Click Run and watch what the Workbench is doing in the Progress tab. Once the Workbench is finished running, you should end up with an output similar to this:

After this tutorial you should have a better understanding of how to create a point layer in your project and then to change the Single Symbol markers into stationary animated markers. A key focus is the idea that you can tell versions of QGIS before 3.26 to dynamically change markers using short code snippets. Versions of QGIS post 3.26 allow a user to simply use the Animated Marker feature without editing an expression.

"},{"location":"user/guide/tutorial3/","title":"3 Flying Points","text":""},{"location":"user/guide/tutorial3/#tutorial-3-flying-points","title":"Tutorial 3: Flying Points","text":"

This tutorial aims to show you how add a flying point animation to points on your map using built-in QGIS functionalities (The geometry generator line) and introduced variables from the workbench.

1. Download and extract the Required Tutorial Zip Folder

2. Open the tutorial_3.qgz project file. When you first open the project file you should be greeted with something like this:

3. Create a new point layer in a new geopackage by clicking Layer\u2794Create Layer\u2794 New GeoPackage Layer.... Click on the Ellipsis (three dots) next to the Database textbox and navigate to the folder that the tutorial_3.qgz file is located in. Type the File name \"tutorial_3\" (1) and ensure the file will be saved as a GeoPackage (2) and click Save (3).

Change the Table name to flying_points (4), set the Geometry type as Point (5) and change the CRS to match the Project CRS (6).

Click OK (7) \u00a0

4. Click on Toggle Editing\u2794Add Point Feature (8).

And randomly add points to your map. Depending on your computer's capabilites, you can add more, or fewer, points than the example below.

Save your Layer Edits and toggle off the Editing tool. \u00a0

5. Style the points layer.

Select the flying_points (9) layer and in the Layer Styling toolbar click on the Add Symbol Layer (green plus symbol) button (10).

Select the top Simple Marker (11) and change its Symbol layer type to Geometry Generator (12)

and then set the Geometry type to LineString / MultiLineString (13).

Change the line's Symbol layer type to Marker Line (14).

Add a second Simple marker to the marker line so that you end up with something like this:

Style the various Simple Markers to your preferred look.

6. Select the Geometry Generator symbol layer (15) and add this code to it:

    wave_randomized(\n    make_line(\n    $geometry, geometry(@hover_feature)), \n    100, 1000, 1000, 10000, 1)\n

More information about what changing the numbers will affect can be found in the QGIS expressions editor. \u00a0

7. A few options need to be changed in the Marker Line symbol layer (16): The Marker placement needs to be set to On first vertex (17) and, the Offset along line needs to be changed to Percentage (18). The click the Dropdown menu next to Offset along line and select Edit... (19).

In the Expression String Builder add the following code snippet:

    100 - to_int((@current_hover_frame / @hover_frames) * 100 )\n

Click OK

8. Select the first Simple Marker symbol layer (20) in the Marker Line symbol layer. Scroll down to Offset and click on the Dropdown Menu\u2794Edit.. (21).

In the Expression String Builder add the following code snippet:

    -- Taken from https://spicyyoghurt.com/tools/easing-functions\n    --    t = Time - Amount of time that has passed since the beginning of the animation. Usually starts at 0 and is slowly increased using a game loop or other update function.\n    --    b = Beginning value - The starting point of the animation. Usually it's a static value, you can start at 0 for example.\n    --    c = Change in value - The amount of change needed to go from starting point to end point. It's also usually a static value.\n    --    d = Duration - Amount of time the animation will take. Usually a static value aswell.\n    -- Sinusoidal\n    -- -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;\n\n    -- Use with the animation in static mode\n    if(@hover_feature_id != $id,\n    array(\n        (-@hover_frames / 2) * (cos( (pi() * @frame_number / @hover_frames ) - 1)) ,\n        (-@hover_frames / 2) * (sin( (pi() * @frame_number / @hover_frames ) - 1)) \n        ),\n        array (0,0))\n

Click OK

9. Open the Animation Workbench (22)

10. Set up the Animation Plan with:

  • the Render Mode to Planar (23),
  • the Animation Layer to flying_points (24) using the dropdown menu,
  • the Zoom Range (25) to 1:22000000 for the Minimum and 1:11000000 for the Maximum,
  • the Frame rate per second to 9 fps (26),
  • the Travel duration to 2,00 s (27),
  • the Feature hover duration to 2,00 s (28),
  • and the Zoom Easing as InCirc (29)

With a decently specced computer you can up the fps and get the points to fly faster in your output. \u00a0

11. Add license-free media to the Intro, Outro, and Soundtrack.

Make sure your Soundtrack is as long as, or longer than, your final animation will be (including the Intro, Animation, and Outro).

12. Set the Output Format as Movie (MP4) (30) and the Output Resolution to 1080 (1920x1080) (31). The Output Resolution can be set as any of the three choices but was set at 1080 for this tutorial for the sake of speed. Set the output location (32) to one you can easily locate.

13. Click Run and get an output. The GIF below is the visual output of the tutorial if you followed step-by-step and set the parameters to exactly what was stated.

The link to a more complex output (with an Intro, an Outro, and a Soundtrack) can be found here

After this tutorial you should have a better idea of how you can use a mixture of built-in QGIS functionalites and the workbench's introduced variables to generate interesting outputs.

"},{"location":"user/guide/tutorial4/","title":"4 Spinning Globe","text":""},{"location":"user/guide/tutorial4/#tutorial-4-spinning-globe","title":"Tutorial 4: Spinning Globe","text":"

Given a global point layer and countries layer like this:

You can create a nice spinning globe effect like this:

I set up the animation workbench like this:

For the above animated GIF, I compressed it using imagemagick like this:

convert globe.gif -coalesce -resize 700x525 -fuzz 2% +dither -layers Optimize +map globe_small.gif\n

This is a handy technique if you want to generate small file size animations.

For the points I made a red marker using a quarter circle that spins around the points like this:

The rotation field expression is this:

if (@id = @hover_feature_id, \n    0-((1440 * (@current_hover_frame/@hover_frames)) % 360),\n    0)\n

This will spin around 4 times during the hover cycle.

For the ocean (AOI in the layers list), I generated a grid of 1 degree cells covering the earth. You need to do it as smaller polygons instead of one large polygon because QGIS will run into issues reprojecting a single polygon whose edges lie on the date line.

Here is how the final video came out:

"},{"location":"user/guide/tutorial5/","title":"Tutorial 5: Planar Map Animation","text":"

Given a global point layer and countries layer like this:

You can create a nice planar map animation effect like this:

In planar mode, we do not pan and zoom the map from feature to feature. Rather, the map zoom stays constant and the variables for

  • current_hover_frame
  • hover_frames
  • hover_feature_id

are updated as we iterate over the features of your animation layer. In this example project I duplicated the animation point layer twice. The first (lower) copy is used to 'drive' the animation, whilst the second (upper) layer shows only the feature currently being hovered over, with animation effects applied to that feature.

I set up the animation workbench like this:

For the above animated GIF, I compressed it using imagemagick like this:

convert globe.gif -coalesce -resize 700x525 -fuzz 2% +dither -layers Optimize +map globe_small.gif\n

This is a handy technique if you want to generate small file size animations.

"},{"location":"user/guide/tutorial5/#expressions-used","title":"Expressions Used","text":""},{"location":"user/guide/tutorial5/#copyright-decoration","title":"Copyright Decoration","text":"

Firstly for debugging, we use the following copyright label in View \u21d2 Decorations \u21d2 Copyright Label. You can use the checkbox in the Copyright configuration dialog to toggle this on and off. This will help you while debugging / tweaking your animations. When you are ready to render your final product, simply turn it off before rendering.

[%\n' \\nRotation:' ||  to_string( 0-((1440 * (@current_hover_frame/@hover_frames)) % 360)) ||\n'\\nFeature Variables:' ||\n' \\n------------------------' ||\n' \\nPrevious Feature ' || to_string(coalesce(attribute(@previous_feature, 'name'), '-'))  ||\n' \\nPrevious Feature ID ' || to_string(coalesce(@previous_feature_id, '-'))  ||\n' \\n' ||\n' \\nNext Feature ' || to_string(coalesce(attribute(@next_feature, 'name'), '-'))  ||\n' \\nNext Feature ID ' || to_string(coalesce(@next_feature_id, '-'))  ||\n' \\n' ||\n' \\nHover Feature ' || to_string(coalesce(attribute(@hover_feature, 'name'), '-'))  ||\n' \\nHover Feature ID ' || to_string(coalesce(@hover_feature_id, '-'))  ||\n' \\n' ||\n' \\nFrom Feature ' || to_string(coalesce(attribute(@from_feature, 'name'), '-'))  ||\n' \\nFrom Feature ID ' || to_string(coalesce(@from_feature_id, '-'))  ||\n' \\n' ||\n' \\nTo Feature ' || to_string(coalesce(attribute(@to_feature, 'name'), '-'))  ||\n' \\nTo Feature ID ' || to_string(coalesce(@to_feature_id, '-'))  ||\n' \\n' ||\n' \\nTotal Hover Frames ' || to_string(coalesce(@hover_frames, 0))  ||\n' \\nCurrent Hover Frame ' || to_string(coalesce(@current_hover_frame, 0))  ||\n' \\nTotal Travel Frames ' || to_string(coalesce(@travel_frames, 0))  ||\n' \\nCurrent Travel Frame ' || to_string(coalesce(@current_travel_frame, 0))  ||\n' \\nTotal Frame Count ' || to_string(coalesce(@total_frame_count, 0))  ||\n' \\nFrame Number ' || to_string(coalesce(@frame_number, 0))  ||\n' \\nFrame Rate ' || to_string(coalesce(@frame_rate, 0))  ||\n' \\nwith Current Animation Action: ' || @current_animation_action ||\n' \\nTo Direction ' ||  coalesce(format_number(degrees(azimuth( geometry(@hover_feature), geometry(@previous_feature) ) ) ), 0) || \n' \\nFrom Direction ' ||  coalesce(format_number(degrees( azimuth( geometry(@hover_feature), geometry(@next_feature) ) ) ), 0)%]\n
"},{"location":"user/guide/tutorial5/#symbol-rotation","title":"Symbol Rotation","text":"

For the points I made a red marker using a quarter circle that spins around the points like this:

The first line of the listing from the previous section gives you a hint about how we can vary the rotation of a symbol depending on how far through the animation sequence we are. With the addition of an if clause, we can apply this rotation only to features that are being hovered over during the planar animation.

if (\n  @id = @hover_feature_id, \n  0-((1440 * (@current_hover_frame/@hover_frames)) % 360), \n  0)\n

This if clause has the effect of excluding calculation for any feature that is not the current hover feature.

This will spin around 4 times during the hover cycle. This is because four rotations are 4 x 360 = 1440. We calculate the percentage of completion for the current hover frame (@current_hover_frame/@hover_frames) and then multiply our rotation product by the current completion percentage. Lastly we calculate the modulus of this (% 360) to compute how far along we are in the current rotation. More advanced users could substitute 1440 with a project variable so that it is easy to change the number of desired rotations in a single place.

"},{"location":"user/guide/tutorial5/#symbol-size","title":"Symbol Size","text":"

The rotating symbol layer and the other symbol layers in our animation layer are similarly hidden if the feature being rendered is not the hover_feature_id using an expression like this:

if ( @id = @hover_feature_id,  10, 0)\n

This has the effect of setting the symbol size to 0 if it is not the feature we are focussing on.

"},{"location":"user/guide/tutorial5/#other-planar-experiments","title":"Other Planar Experiments","text":"

With the basic concepts of working with planar animations covered above, you can do other interesting things.

"},{"location":"user/guide/tutorial5/#generate-a-line","title":"Generate a line","text":"

In this example, we can generate a line using the Geometry Generator function in QGIS. The line will start from the previous point, extend through the current point and terminate and the next point.

if ( \n  $id = @hover_feature_id,\n   make_line(\n    geometry(@previous_feature),\n    geometry(@hover_feature),\n    geometry(@next_feature)\n  ),\n  $geometry)\n

We wrap it in an if clause again so that the line is not rendered if the current feature being rendered is not the same as the current animation feature.

There may be some edge cases where there is no previous or next feature. This example does not try to deal with these cases but you could easily add some logic that checks if each of the three components making up the line is null or not.

"},{"location":"user/guide/tutorial5/#generate-a-curve","title":"Generate a curve","text":"

We can extend the above example by creating a curve rather than a line, for a more natural looking connection between the hover feature and its previous and following feature.

if ( \n  $id = @hover_feature_id,\n   smooth(\n    make_line(\n      geometry(@previous_feature),\n      geometry(@hover_feature),\n      geometry(@next_feature)\n    ),\n    iterations:=1,\n    offset:=0.2,\n    min_length:=-1,\n    max_angle:=180),\n  $geometry)\n

If you increase the number of iterations, you can achieve a more and more smoothed out line, at the expense of processing time.

if ( \n  $id = @hover_feature_id,\n   smooth(\n    make_line(\n      geometry(@previous_feature),\n      geometry(@hover_feature),\n      geometry(@next_feature)\n    ),\n    iterations:=5,\n    offset:=0.2,\n    min_length:=-1,\n    max_angle:=180),\n  $geometry)\n
"},{"location":"user/guide/tutorial5/#subtring-the-line","title":"Subtring the Line","text":"

As a much more advanced example, you can extract a substring of the smoothed line that connects the previous, current and next features. Don't get put off by the with_variable elements - they just allow us to re-use calculations in our expression.

First, let's start with extracting the first half of the smoothed line:

if ( \n    $id = @hover_feature_id,\n    with_variable(\n        'smoothed_line',\n        smooth(\n          make_line(\n              geometry(@previous_feature),\n                geometry(@hover_feature),\n                geometry(@next_feature)\n          ),\n      iterations:=5,\n      offset:=0.2,\n      min_length:=-1,\n      max_angle:=180),\n          with_variable(\n              'line_length',\n          length(@smoothed_line),\n          line_substring(@smoothed_line, 0, @line_length / 2 ))),\n  $geometry)\n
"},{"location":"user/guide/tutorial5/#animating-the-substring","title":"Animating the substring","text":"

If we follow the same approach as above, but vary the start and length of the line clip, we can create some cool line animation effects.

if ( \n    $id = @hover_feature_id,\n    with_variable(\n        'smoothed_line',\n        smooth(\n          make_line(\n              geometry(@previous_feature),\n                geometry(@hover_feature),\n                geometry(@next_feature)\n          ),\n      iterations:=5,\n      offset:=0.2,\n      min_length:=-1,\n      max_angle:=180),\n          with_variable(\n              'line_length',\n          length(@smoothed_line),\n          line_substring(\n                    @smoothed_line, \n                    @line_length * (@current_hover_frame/@hover_frames), \n                    @line_length ))),\n\n  $geometry)\n\n
"},{"location":"user/guide/tutorial5/#final-render","title":"Final Render","text":"

There are still a few details that would need to be taken care of to reach a final solution - in particular taking care of datelines and the like. But here is a little example of what we managed to make thus far (without any debugging text).

"},{"location":"user/manual/","title":"User manual","text":"

Welcome to the QGIS Animation Workbench user manual. This section of the documentation describes the application and what the various components of each dialog do. The manual is intended to function as a reference for the application. For narrative / workflow based tutorials, you may prefer to work through our user guide. Here is a brief overview of the content provided here:

  • : This section describes how to set up a project ready for use in creating an animation.
  • : This section describes the different elements of the main workbench UI.
  • : This section explains how the animation workbench functions internally.
  • : Here we provide various snippets as examples of how you can achieve different effects using the workbench.
  • : This is an exhaustive list of all of the variables exposed by the animation workbench.
  • : Still have questions? Here are some answers to common questions.
"},{"location":"user/manual/faq/","title":"Frequently Asked Questions","text":""},{"location":"user/manual/faq/#can-i-add-any-image-to-the-intro-or-outro","title":"Can I add any image to the intro or outro?","text":"

As long as you can provide the proper attribution for an image you can use it in your project.

"},{"location":"user/manual/faq/#i-have-an-older-less-powerful-computer-will-it-handle-running-this-workbench","title":"I have an older, less powerful, computer, will it handle running this workbench?","text":"

If you open the standard QGIS settings dialog and select the Animation Workbench options you can follow the advice with regards to lowering the number of threads allowed during rendering to help you computer cope. Rendering shorter movies or GIFs (i.e. fewer frames) will also help. Below is an example of running a job with 9000 frames at 60fps and 999 frames per feature

And the subsequent CPU load during processing:

After processing:

And here is the resulting video:

https://youtu.be/1quc3xPdJsU

"},{"location":"user/manual/faq/#i-get-an-error-when-rendering-because-of-my-intro-outro-images","title":"I get an error when rendering because of my intro / outro images","text":"

Currently your filenames should not contain spaces or special characters

.(, ), [, ], {, }, <, >, /, \\, :, *, ?, |, \", &, etc.).\n
"},{"location":"user/manual/faq/#can-i-use-a-movie-as-the-intro-outro-media","title":"Can I use a movie as the intro / outro media?","text":"

This is planned but not yet implemented. Tim - check.

"},{"location":"user/manual/faq/#can-i-pay-you-to-add-some-features","title":"Can I pay you to add some features?","text":"

This is a fun / hobby project, currently we want other contributors who also want to have a fun experience with building this plugin and contribute in-kind efforts to the project. Both Kartoza and North-Road offer commercial development services but not for this plugin which is a intended to provide an experimental, no-pressure space for us to work on something fun for QGIS.

"},{"location":"user/manual/project_preparation/","title":"How to set up a project to work with the animation plugin","text":"

1. The first step for getting an output using the Workbench is to create a QGIS Project \u00a0 Open QGIS and click on Project \u2794 New

Next, add new layers to your project. You will want a few layers; one, or more, backing layer(s) (vector layers or XYZ Tiles), a layer for the workbench to follow, and one, or more, layer(s) of animated points. The example in this section only has one animated layer. \u00a0

To add a layer, go to Layer \u2794 Create Layer and then select the type of layer you want to add. The example adds a point layer to a GeoPackage to make the project more portable.

Once you have added your layers you need to add features to the layers. This is done by selecting a layer and then clicking Toggle Editing (1) \u2794 Add PointFeature (2). Then click around on your map to add as few, or as many, features as you need.

The example project has four layers: two point layers (3) and two backing layers (4).

A simple way to add a vector base layer is to type \"world\" into the coordinate textbox

Finally, style your layers to make your project look aesthetically pleasing. To style your layers you must select the layer you want to style and then using the Layer Styling toolbar, play around with the style of the layer until it suits you. A good practice is to have your backing layers as more muted colours and your desired features as more eye-catching colours.

You now have a QGIS Project. \u00a0

2. The next step is to choose which features you want to be animated. \u00a0

Pick the layer (or layers) that you want to have animations. Then either find, or create, the animation for the layer. Make sure you have all the correct attribution for any animations you use. Below is an example of a simple fish animation split into its frames. The frames are repeated to slow down the animation's playback speed.

  • Now use the QGIS Expressions system with the variables introduced by the Animation Workbench to define behaviours of your symbols during flight and hover modes of your animation. \u00a0 Select the layer you want to animate and open the Layer Styling toolbar.

If you are using QGIS 3.26 you can simply use the new animated point symbol, or if you're using an older version of QGIS 3.x follow the instructions below.

The layer should contain a Raster Image Marker. Once you have selected the marker you want to use click on the QGIS Expressions dropdown menu (5) and click on Edit (6).

You can also make a marker move along a line relative to the frame of the animation. Use the Code Snippets Section for more in-depth help.

The example below works with the animation from earlier.

@project_home\n|| \n'/fish/fish_00'\n||\nlpad(to_string( @frame_number % 32), 2, '0')\n||\n'.png'\n

3. Configure your animation

After animating your markers it's time to configure your animation. Open the Animated Workbench and begin choosing between the different modes and options. \u00a0

Open the Workbench by clicking the Animation Workbench (7) icon in the Plugin Toolbar.

Configure the settings for your animation. The screenshot below is configured for the example presented in this section. The Animation Layer is selected as route (8) because that is the path that the output animation will fly along. The Zoom Range (9) was selected from the Map Canvas Extent, and the Frame rate per second (fps) (10) was set to match the number of frames of the animated markers so that they will play nicely in the output. The other settings were selected as a personal choice.

Select the Output Resolution (11) and a location for your output by clicking on the ellipsis (three dots) or by typing in the desired file path (12).

Refer to the Workbench User Interface section for more information about what various settings and buttons accomplish.

4. Render your animation! \u00a0 Click Run and render your output. The output below is the output from the example.

"},{"location":"user/manual/snippets/","title":"Snippets","text":""},{"location":"user/manual/snippets/#qgis-support","title":"\ud83c\udf0f QGIS Support","text":"

Should work with and version of QGIS 3.x. If you have QGIS 3.26 or better you can benefit from the animated icon support (see @nyalldawson's most excellent patch #48060).

For QGIS versions below 3.26, you can animate markers by unpacking a GIF image into its constituent frames and then referencing a specific frame from the symbol data defined property for the image file. Note that to do this extraction below you need to have the Open Source ImageMagick application installed:

First extract a gif to a sequence of images:

convert cat.gif -coalesce cat_%05d.png\n

Example of how to create a dynamically changing image marker based on the current frame count:

@project_home \n||\n'/gifs/cat_000'\n|| \nlpad(to_string( @frame_number % 48 ), 2, '0')\n|| \n'.png'\n

Note that for the above, 48 is the number of frames that the GIF was composed of, and it assumes the frames are in the project directory in a subfolder called gifs.

"},{"location":"user/manual/snippets/#line-of-travel","title":"Line of travel","text":"

In this example we use a geometry generator to create a line between the origin point and the destination point:

if (@from_feature_id = $id OR @to_feature_id = $id,\n -- read this from inside to out so \n -- last tranform the geometry back to the map crs\n transform( \n  -- densify the geometry so that when we transform\n  -- back it makes a great circle\n  densify_by_count(  \n   -- move the geometry into a crs that \n   -- shows a great circle as a straight line\n   transform( \n    -- make a line from the previous pont to the next point\n    make_line( \n     geometry(@from_feature), \n     geometry(@to_feature)\n    ),  \n    @map_crs, 'EPSG:4326'),\n   99), \n  'EPSG:4326',  @map_crs),\n None)\n

"},{"location":"user/manual/snippets/#showing-diagnostic-info-as-a-copyright-label","title":"Showing diagnostic info as a copyright label","text":"

Showing diagnostic information in the QGIS copyright label:

[%\n'Feature Variables:' ||\n' \\n------------------------' ||\n' \\nPrevious Feature ' || to_string(coalesce(attribute(@previous_feature, 'name'), '-'))  ||\n' \\nPrevious Feature ID ' || to_string(coalesce(@previous_feature_id, '-'))  ||\n' \\n' ||\n' \\nNext Feature ' || to_string(coalesce(attribute(@next_feature, 'name'), '-'))  ||\n' \\nNext Feature ID ' || to_string(coalesce(@next_feature_id, '-'))  ||\n' \\n' ||\n' \\nHover Feature ' || to_string(coalesce(attribute(@hover_feature, 'name'), '-'))  ||\n' \\nHover Feature ID ' || to_string(coalesce(@hover_feature_id, '-'))  ||\n' \\n' ||\n' \\nFrom Feature ' || to_string(coalesce(attribute(@from_feature, 'name'), '-'))  ||\n' \\nFrom Feature ID ' || to_string(coalesce(@from_feature_id, '-'))  ||\n' \\n' ||\n' \\nTo Feature ' || to_string(coalesce(attribute(@to_feature, 'name'), '-'))  ||\n' \\nTo Feature ID ' || to_string(coalesce(@to_feature_id, '-'))  ||\n' \\n' ||\n' \\nTotal Hover Frames ' || to_string(coalesce(@hover_frames, 0))  ||\n' \\nCurrent Hover Frame ' || to_string(coalesce(@current_hover_frame, 0))  ||\n' \\nTotal Travel Frames ' || to_string(coalesce(@travel_frames, 0))  ||\n' \\nCurrent Travel Frame ' || to_string(coalesce(@current_travel_frame, 0))  ||\n' \\nTotal Frame Count ' || to_string(coalesce(@total_frame_count, 0))  ||\n' \\nFrame Number ' || to_string(coalesce(@frame_number, 0))  ||\n' \\nFrame Rate ' || to_string(coalesce(@frame_rate, 0))  ||\n' \\nwith Current Animation Action: ' || @current_animation_action ||\n' \\nTo Direction ' ||  coalesce(format_number(degrees(azimuth( geometry(@hover_feature), geometry(@previous_feature) ) ) ), 0) || \n' \\nFrom Direction ' ||  coalesce(format_number(degrees( azimuth( geometry(@hover_feature), geometry(@next_feature) ) ) ), 0)\n%]\n\n\n

Example output:

"},{"location":"user/manual/snippets/#variable-size-of-labels","title":"Variable size of labels","text":"

Variably changing the size on a label as we approach it in the animation:

```40 * ((@frame_number % @hover_frames) / @hover_frames)

\n## Calculating the angle between points\n\nYou can calculate the angle between the hover point and the previous point like this:\n\n```python\ncoalesce(\n format_number(\n  degrees( \n   azimuth( \n    geometry(@hover_feature), \n    geometry(@previous_feature) \n   )\n  )\n ), 0)\n
"},{"location":"user/manual/snippets/#rotation","title":"Rotation","text":"

You can set the angle of rotation for a symbol using this expression:

Using this technique you can also create an animation effect showing the source direction of travel and the new destination.

scale_linear (\n @current_hover_frame,\n 0,\n @hover_frames,\n degrees( \n  azimuth( \n   geometry(@hover_feature), \n   geometry(@previous_feature) \n  )\n ),\n degrees( \n  azimuth( \n   geometry(@hover_feature), \n   geometry(@next_feature) \n  )\n )\n)\n

Will produce something like this:

"},{"location":"user/manual/snippets/#flying-points-cluster","title":"Flying points cluster","text":"

Here is an example where we animate all the points in a cluster that are not the hover point. We use an easing function to make the animation have an interesting circular motion.

-- Taken from https://spicyyoghurt.com/tools/easing-functions\n--    t = Time - Amount of time that has passed since the beginning of the animation. Usually starts at 0 and is slowly increased using a game loop or other update function.\n--    b = Beginning value - The starting point of the animation. Usually it's a static value, you can start at 0 for example.\n--    c = Change in value - The amount of change needed to go from starting point to end point. It's also usually a static value.\n--    d = Duration - Amount of time the animation will take. Usually a static value aswell.\n-- Sinusoidal\n-- -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;\n\n-- Use with the animation in static mode\nif(@hover_feature_id != $id,\narray(\n  (-@hover_frames / 2) * (cos( (pi() * @frame_number / @hover_frames ) - 1)) ,\n (-@hover_frames / 2) * (sin( (pi() * @frame_number / @hover_frames ) - 1)) \n),\narray (0,0))\n\n

This function should be applied to the offset X,Y property of the symbol.

"},{"location":"user/manual/under_the_hood/","title":"What is the Workbench doing?","text":"
  • What does the workbench do?

    The workbench creates animations from QGIS by generating multiple static frames (images) and then combining those frames into an animation. The user tells QGIS how the frames should change from one to the other. In QGIS 3.26 and later the animated markers allow markers to be animated without the use of the expressions system. \u00a0

  • How do the animated markers work?

    In the code snippet below, the user tells QGIS that as the frame count increments by one the Raster Image Marker should change to the next image in the sequence.

    py @project_home || '/fish/fish_00' || lpad(to_string( @frame_number % 32), 2, '0') || '.png'

    The user specifies the path of the image (@project_home/fish/fish_00). Then the lpad(to_string( @frame_number % 32), 2, '0') tells QGIS to convert the frame number to a string and then modulus the number of frames by the number of animation frames (32) (i.e. QGIS divides the number of frames by 32 and then repeats the sequence when the remainder is zero). The 2 and '0' in the snippet tell QGIS to pad the /fish/fish_00 with two zeroes at the end. Finally the '.png' tells QGIS the type of file to finish off the path. \u00a0

  • Frame Output location on Windows

    For users on a Windows machine who are interested in seeing the frames before they are combined into an animation (GIF or movie) you can find them by going to \"C:\\Users\\Username\\AppData\\Local\\Temp\\animation_workbench-0000000000.png\". Bear in mind that AppData is a hidden file, so it's preferable to not make changes unless explicitly told otherwise. \u00a0

  • Frame Output on Linux

    The frames should be in your /tmp directory.

"},{"location":"user/manual/variables/","title":"\ud83e\uddee QGIS Expression Variables","text":"

The animation workbench exposes or modifies a number of different QGIS Expression variables that you can use to achieve different dynamic rendering effects.

"},{"location":"user/manual/variables/#common-variables","title":"Common variables","text":"

These variables will always be available, regardless of the animation mode

Variable Notes frame_number Frame number within the current dwell or pan range. frame_rate Number of frames per second that the video will be rendered at. total_frame_count Total number of frames for the whole animation across all features."},{"location":"user/manual/variables/#fixed-extent-mode-variables-with-layer","title":"Fixed extent mode variables (with layer)","text":"

These variables are available when in the fixed extent animation mode when a vector layer has been set

Variable Notes hover_feature The feature we are currently hovering over hover_feature_id Feature ID for the feature we a current hovering over previous_feature The previously visited feature (or NULL if there isn't one) previous_feature_id Feature ID for the previously visited feature (or NULL if there isn't one) next_feature The next feature to visit after the current one (or NULL if there isn't one) next_feature_id Feature ID for the next feature to visit after the current one (or NULL if there isn't one) current_hover_frame The frame number for the current feature (i.e. how many frames we have hovered at the current feature) hover_frames Number of frames we will hover at the current feature for current_animation_action Always \"Hovering\""},{"location":"user/manual/variables/#planarsphere-modes","title":"Planar/Sphere modes","text":"

These variables are available in the Planar or Sphere mode.

Variable Notes current_animation_action Either \"Hovering\" or \"Travelling\""},{"location":"user/manual/variables/#when-hovering","title":"When hovering","text":"

These variables are available in planar or sphere mode, when the animation is currently hovering over a feature

Variable Notes hover_feature The feature we are currently hovering over hover_feature_id The feature ID for the feature we are currently hovering over previous_feature The previously visited feature (or NULL if there isn't one) previous_feature_id Feature ID for the previously visited feature (or NULL if there isn't one) next_feature The next feature to visit after the current one (or NULL if there isn't one) next_feature_id Feature ID for the next feature to visit after the current one (or NULL if there isn't one) current_hover_frame The frame number for the current feature (i.e. how many frames we have hovered at the current feature) hover_frames Number of frames we will hover at the current feature for"},{"location":"user/manual/variables/#when-travelling","title":"When travelling","text":"

These variables are available in planar or sphere mode, when the animation is currently travelling between two features

Variable Notes from_feature The feature we are travelling away from from_feature_id The feature ID for the feature we are travelling away from to_feature The feature we are heading toward to_feature_id The feature ID for the feature we are heading toward current_travel_frame The frame number for the current travel operation travel_frames Number of frames we will travel between the current features"},{"location":"user/manual/variables/#example-expressions","title":"Example expressions","text":"

Visit the snippets section of our documentation for example expressions.

"},{"location":"user/manual/workbench_ui/","title":"The Workbench User Interface","text":""},{"location":"user/manual/workbench_ui/#animation-plan","title":"Animation Plan","text":"
  • Render Modes (1): These determine the behaviour and type of animation
  • Sphere: The coordinate reference system (CRS) will be manipulated to create a spinning globe effect. Like Google Earth might do, but with your own data and cartography.
  • Planar: The coordinate reference system (CRS) will not be altered, but the camera will pan and zoom to each point. It lets you move from feature to feature on a flat map, pausing at each if you want to.
  • Fixed extent: The frame of reference stays the same and you can animate the symbology within that scene.

  • Animation Layer (2):

  • Dropdown menu: This allows you to select which map layer you want the animation to follow.
  • Loop from final feature back to first feature: allows for a seamlessly looping output GIF or movie(MP4).

  • Zoom Range (3): The scale range that the animation should move through.

  • Minimum (exclusive): The zenith (highest point) of the animation when it zooms out while travelling between points, i.e. the most \"zoomed out\".
  • Maximum (inclusive): The scale (zoom level) used when we arrive at each point, i.e. the most \"zoomed in\".

  • Data defined settings (4)

  • Scale

    • Minimum: User-defined minimum scale
    • Maximum: User-defined maximum scale
  • Animation Frames (5)

  • Frame rate per second (fps): When writing to video or gif, how many frames per second to use.
  • Travel Duration: This is the number of seconds that the animation will take during animation from one feature to the next.
  • Feature Hover duration: This is the number of seconds that the animation will hover over each feature.

  • Extent (6):
  • Can be manually entered using North, East, South, and West coordinates as limits.
  • Can be calculated from a map layer, the layout map, or a bookmark.
  • Can be set to match the Map Canvas Extent
  • Can be set as a rectangular extent using the Draw on Canvas feature.

  • Pan and Zoom Easings (7)

  • What are Easings: Easings are transitions from one state to another along a smooth curve. A user can specify the shape of the curve used.
  • Pan Easings (XY): The pan easing will determine the motion characteristics of the camera on the X and Y axis as it flies across the scene (i.e. how it accelerates or decelerates between points)
  • Zoom Easing (Z): The pan easing will determine the motion characteristics of the camera on the Z axis as it flies across the scene (i.e. how the camera zooms in and out of the points)

  • Frame previews (8): A preview of what each frame of the animation will look like. A user can decide which Frame to view.

"},{"location":"user/manual/workbench_ui/#intro-tab","title":"Intro Tab","text":"

Edit the intro section of the generated movie here.

  • Media: List of the various images or movies selected for the intro section. You can drag and drop items in the list to change the play order.
  • Add Media (Plus sign) (1): Add images or movies
  • Remove Media (Minus sign) (2): Remove images or movies

  • Duration (3): For images, you can set a duration for each image (in seconds).

  • Preview Frame (4): This shows what the media will look like.

  • Details: Provides details about where the media is stored on your computer.

"},{"location":"user/manual/workbench_ui/#outro-tab","title":"Outro Tab","text":"

Edit the outro section of the generated movie here.

  • Media: List of the various images or movies selected for the outro section. You can drag and drop items in the list to change the play order.
  • Add Media (Plus sign) (1): Add images or movies
  • Remove Media (Minus sign) (2): Remove images or movies

  • Duration (3): For images, you can set a duration for each image (in seconds).

  • Preview Frame (4): This shows what the media will look like.

  • Details: Provides details about where the media is stored on your computer.

"},{"location":"user/manual/workbench_ui/#soundtrack-tab","title":"Soundtrack Tab","text":"
  • Media: List of the various sound files (.mp3 or .wav) to play during the generated movie. You can drag and drop items in the list to change the play order.
  • Add Media (Plus sign) (1): Add sound files (.mp3 or .wav) to play during the generated movie.
  • Remove Media (Minus sign) (2): Remove sound files (.mp3 or .wav)

  • Duration (3): The cumulative length of your soundtracks should be as long, or longer, than your movie, including the intro/outro sections. If the soundtrack is longer than the movie it will be truncated (shortened) when the movie ends.

  • Details: Provides details about where the media is stored on your computer.

"},{"location":"user/manual/workbench_ui/#output","title":"Output","text":"
  • Output Options: Select which output format you would like. Regardless of the format chosen, a folder of images will be created, one image per frame.
  • Re-use cached Images (1): This will not erase cached images on disk and will resume processing from the last cached image.
  • Animated GIF (2): For this export to work, you need to have the ImageMagick 'convert' application available on your system.
  • Movie (MP4) (3): For this option to work, you need to have the 'ffmpeg' application on your system.
  • Output Resolution (4): Allows a user to specify one of four image resolutions for the output animation. The numbers in brackets for the first three options represent the width and height of the output in pixels (i.e. width x height), and the fourth option matches the output's size to the size of the Map Canvas on the screen.
  • File selection (ellipsis) (5): This lets a user select the location where the output will be stored.
"},{"location":"user/manual/workbench_ui/#progress","title":"Progress","text":"
  • Frame Preview (1): A preview of what each frame of the animation will look like. It changes automatically as the workbench runs.
  • Progress (2): This provides a detailed look at what is happening while the workbench runs.
  • Total Tasks: This number represents the total number of frames that will be generated by the workbench.
  • Completed Tasks: The number of tasks that have completed being processed.
  • Remaining Features: The number of features from your animation layer that still need to be processed.
  • Active Tasks: The number of tasks (threads) currently being run by the workbench
  • Features Complete: The number of tasks that have been processed by the workbench.
  • Logs (3): A detailed list of what steps the workbench is doing (a record of processing)
  • Progress Bar (4): A visual representation of the workbench's progression as a percentage.
"},{"location":"user/manual/workbench_ui/#other-buttons","title":"Other Buttons","text":"
  • Run: Starts the process of getting an output from the workbench. It is greyed out until a user provides a destination for the output file.
  • Close: Closes the workbench.
  • Cancel: Ends the workbench processing at whatever point it has reached when the button is pressed.
  • Help: Opens a link to the Animation Workbench documentation.
"},{"location":"user/quickstart/","title":"Quickstart","text":"

Content needed

"},{"location":"user/quickstart/configure/","title":"Initial Configuration","text":"

There is nothing really to configure! We do provide a few options in the configuration dialog, but most users should not need to change them.

You can access the QGIS Animation Workbench plugin options by opening the standard QGIS Setting dialog and clicking on the animation workbench tab.

Settings \u2794 Options

  • Animation Workbench plugin Options (1)

Currently there are just three configuration options:

  • Number of concurrent render tasks (2): This is the number of concurrent tasks that will be used to render animations. The default is 1.
  • Enable developer mode (3): This is a developer option that enables the developers to see an icon in the toolbar which will start the debug remote server.
  • Verbose logging mode (4): This will add extra messages in the logging pane to help you understand what is going on during the rendering process.
"},{"location":"user/quickstart/install/","title":"Installing the QGIS Animation Workbench plugin","text":"

In this section we explain how to install the plugin.

"},{"location":"user/quickstart/install/#install-from-plugin-manager","title":"Install from plugin manager","text":"

To access the QGIS Plugin Manager you simply need to select Plugins \u27a1 Manage and Install Plugins... (1) in the Menu Toolbar.

Once the QGIS Plugin Manager loads, you need to navigate to the All (2) tab and type \"animation\" into the search bar (3). Select QGIS Animation Workbench from the list of available plugins and then select Install Plugin (4).

Once the Animation Workbench is installed, you can access it by clicking on the Animation Workbench icon (5) in the Plugin Toolbar.

Note if you are on Ubuntu, you may need to install the Qt5 multimedia libraries.

sudo apt install PyQt5.QtMultimedia\n
"},{"location":"user/quickstart/install/#manual-install-from-github-tagged-release","title":"Manual install from GitHub (tagged release)","text":"

To install, visit the Github Repository, click on the Actions tab, and click on the Make QGIS Plugin Zip For Manual Installs workflow (the bottom one).

Click on the most recent workflow run (the top one).

Scroll down on the on the page.

And click on animation_workbench to download the most recent build of the plugin

Download the animation_workbench.zip file and open it in QGIS using the plugin manager as described below.

  1. Open QGIS
  2. Plugins \u27a1 Manage and install plugins ...
  3. Choose the Install from zip tab
  4. Select the animation_workbench.zip download
  5. Click the Install Plugin button.

Note if you are on Ubuntu, you may need to install the Qt5 multimedia libraries.

sudo apt install PyQt5.QtMultimedia\n
"},{"location":"user/quickstart/using/","title":"Using the Animation Workbench","text":"

In this section, we describe the general workflow for using the Animation Workbench.

"},{"location":"user/quickstart/using/#process-overview","title":"Process Overview","text":"
  1. Create a QGIS project!
  2. Identify features that will be animated.
  3. Use the QGIS Expressions system with the variables introduced by the Animation Workbench to define behaviours of your symbols during flight and hover modes of your animation.
  4. Open the Animation Workbench and configure your animation, choosing between the different modes and options.
  5. Render your animation!
"},{"location":"user/quickstart/using/#more-in-depth-process","title":"More in Depth Process","text":"

1. Create a QGIS Project \u00a0 Open QGIS and click on Project \u2794 New

Add new layers to your project

A simple way to add a base layer is to type \"world\" (1) into the coordinate textbox

Style the layers you've added to make your project look a bit better. Select the layer (2) you want to style and in the Layer Styling toolbar (3), style the layer to look appealing to you.

2. Identify features that will be animated. \u00a0

Pick the layer (or layers) that you want to animate. Then either find or create the animation for the layer. Make sure you have all the correct attribution for any animations you use. Below is an example of an animation split into its frames.

3. Use the QGIS Expressions system with the variables introduced by the Animation Workbench to define behaviours of your symbols during flight and hover modes of your animation. \u00a0

Select the layer you want to animate and open the Layer Styling toolbar.

If you are using QGIS 3.26 you can simply use the new animated point symbol, or if you're using an older version of QGIS 3.x follow the instructions below.

The layer should be a Raster Image Marker. Once you have selected the image you want to use click on the QGIS Expressions dropdown menu (4) and click on Edit (5).

Use the Code Snippets Section for more in depth help. The example below works with the bird animation from earlier

   @project_home\n   ||\n   '/bird/bird_00'\n   || \n   lpad(to_string(@frame_number % 9), 2, '0')\n   || \n   '.png'\n

1. Open the Animation Workbench and configure your animation, choosing between the different modes and options. \u00a0

Open the Workbench by clicking the Animation Workbench (6) icon in the Plugin Toolbar.

Configure the settings for your animation. The screenshot below is configured for the example presented in this section. The Animation Layer is selected as route (7) because that is the path the animation will fly along, the Zoom Range (8) was selected from the Map Canvas Extent, and the Frame rate per second (9) was set to 9 to match the bird animation.

Set your desired Output Options (10) Select a location for your output (11).

Refer to the Workbench User Interface Section for more information about what various settings and buttons accomplish.

2. Render your animation! \u00a0 Click Run and render your output. The output below is the output from the example.

"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..5dcddbf --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,193 @@ + + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + + None + 2023-12-19 + daily + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000..be97703 Binary files /dev/null and b/sitemap.xml.gz differ diff --git a/user/guide/img/tut_1/001_InitialOpen_1.png b/user/guide/img/tut_1/001_InitialOpen_1.png new file mode 100644 index 0000000..b7a0fd3 Binary files /dev/null and b/user/guide/img/tut_1/001_InitialOpen_1.png differ diff --git a/user/guide/img/tut_1/002_AddSymbolLayer_1.png b/user/guide/img/tut_1/002_AddSymbolLayer_1.png new file mode 100644 index 0000000..00bbbd8 Binary files /dev/null and b/user/guide/img/tut_1/002_AddSymbolLayer_1.png differ diff --git a/user/guide/img/tut_1/003_StyleSymbolLayer_1.png b/user/guide/img/tut_1/003_StyleSymbolLayer_1.png new file mode 100644 index 0000000..828fe36 Binary files /dev/null and b/user/guide/img/tut_1/003_StyleSymbolLayer_1.png differ diff --git a/user/guide/img/tut_1/004_SymbolLayerSettings_1.png b/user/guide/img/tut_1/004_SymbolLayerSettings_1.png new file mode 100644 index 0000000..cf4afde Binary files /dev/null and b/user/guide/img/tut_1/004_SymbolLayerSettings_1.png differ diff --git a/user/guide/img/tut_1/005_EditExpression_1.png b/user/guide/img/tut_1/005_EditExpression_1.png new file mode 100644 index 0000000..aaf130b Binary files /dev/null and b/user/guide/img/tut_1/005_EditExpression_1.png differ diff --git a/user/guide/img/tut_1/006_OffsetSnippet_1.png b/user/guide/img/tut_1/006_OffsetSnippet_1.png new file mode 100644 index 0000000..f02dbc5 Binary files /dev/null and b/user/guide/img/tut_1/006_OffsetSnippet_1.png differ diff --git a/user/guide/img/tut_1/007_AnimationPlan_1.png b/user/guide/img/tut_1/007_AnimationPlan_1.png new file mode 100644 index 0000000..bbfd90b Binary files /dev/null and b/user/guide/img/tut_1/007_AnimationPlan_1.png differ diff --git a/user/guide/img/tut_1/008_OutputTab_1.png b/user/guide/img/tut_1/008_OutputTab_1.png new file mode 100644 index 0000000..f93512c Binary files /dev/null and b/user/guide/img/tut_1/008_OutputTab_1.png differ diff --git a/user/guide/img/tut_1/output.gif b/user/guide/img/tut_1/output.gif new file mode 100644 index 0000000..b7f6324 Binary files /dev/null and b/user/guide/img/tut_1/output.gif differ diff --git a/user/guide/img/tut_2/001_ChooseCRS_1.png b/user/guide/img/tut_2/001_ChooseCRS_1.png new file mode 100644 index 0000000..94852fe Binary files /dev/null and b/user/guide/img/tut_2/001_ChooseCRS_1.png differ diff --git a/user/guide/img/tut_2/002_AddBackingLayers_1.png b/user/guide/img/tut_2/002_AddBackingLayers_1.png new file mode 100644 index 0000000..c068252 Binary files /dev/null and b/user/guide/img/tut_2/002_AddBackingLayers_1.png differ diff --git a/user/guide/img/tut_2/003_ZoomToDam_1.png b/user/guide/img/tut_2/003_ZoomToDam_1.png new file mode 100644 index 0000000..8fff6e7 Binary files /dev/null and b/user/guide/img/tut_2/003_ZoomToDam_1.png differ diff --git a/user/guide/img/tut_2/004_AddNewLayer_1.png b/user/guide/img/tut_2/004_AddNewLayer_1.png new file mode 100644 index 0000000..8b8fbb9 Binary files /dev/null and b/user/guide/img/tut_2/004_AddNewLayer_1.png differ diff --git a/user/guide/img/tut_2/005_LayerSettings_1.png b/user/guide/img/tut_2/005_LayerSettings_1.png new file mode 100644 index 0000000..58d30d0 Binary files /dev/null and b/user/guide/img/tut_2/005_LayerSettings_1.png differ diff --git a/user/guide/img/tut_2/006_EditLayerPoints_1.png b/user/guide/img/tut_2/006_EditLayerPoints_1.png new file mode 100644 index 0000000..b57e1a6 Binary files /dev/null and b/user/guide/img/tut_2/006_EditLayerPoints_1.png differ diff --git a/user/guide/img/tut_2/007_AddedPoints_1.png b/user/guide/img/tut_2/007_AddedPoints_1.png new file mode 100644 index 0000000..2a648da Binary files /dev/null and b/user/guide/img/tut_2/007_AddedPoints_1.png differ diff --git a/user/guide/img/tut_2/008_BothLayersAdded_1.png b/user/guide/img/tut_2/008_BothLayersAdded_1.png new file mode 100644 index 0000000..b2143fc Binary files /dev/null and b/user/guide/img/tut_2/008_BothLayersAdded_1.png differ diff --git a/user/guide/img/tut_2/009_ChangetoRIM_1.png b/user/guide/img/tut_2/009_ChangetoRIM_1.png new file mode 100644 index 0000000..44d1358 Binary files /dev/null and b/user/guide/img/tut_2/009_ChangetoRIM_1.png differ diff --git a/user/guide/img/tut_2/010_SelectImage_1.png b/user/guide/img/tut_2/010_SelectImage_1.png new file mode 100644 index 0000000..a0e84a1 Binary files /dev/null and b/user/guide/img/tut_2/010_SelectImage_1.png differ diff --git a/user/guide/img/tut_2/011_ChangeSizeToMAS_1.png b/user/guide/img/tut_2/011_ChangeSizeToMAS_1.png new file mode 100644 index 0000000..c9eec45 Binary files /dev/null and b/user/guide/img/tut_2/011_ChangeSizeToMAS_1.png differ diff --git a/user/guide/img/tut_2/012_EditExpression_1.png b/user/guide/img/tut_2/012_EditExpression_1.png new file mode 100644 index 0000000..dbe857a Binary files /dev/null and b/user/guide/img/tut_2/012_EditExpression_1.png differ diff --git a/user/guide/img/tut_2/013_FishExpression_1.png b/user/guide/img/tut_2/013_FishExpression_1.png new file mode 100644 index 0000000..c8879a1 Binary files /dev/null and b/user/guide/img/tut_2/013_FishExpression_1.png differ diff --git a/user/guide/img/tut_2/014_BirdExpression_1.png b/user/guide/img/tut_2/014_BirdExpression_1.png new file mode 100644 index 0000000..0783206 Binary files /dev/null and b/user/guide/img/tut_2/014_BirdExpression_1.png differ diff --git a/user/guide/img/tut_2/015_AnimationPlan_1.png b/user/guide/img/tut_2/015_AnimationPlan_1.png new file mode 100644 index 0000000..ff9feb4 Binary files /dev/null and b/user/guide/img/tut_2/015_AnimationPlan_1.png differ diff --git a/user/guide/img/tut_2/016_Output_1.png b/user/guide/img/tut_2/016_Output_1.png new file mode 100644 index 0000000..ed4ba61 Binary files /dev/null and b/user/guide/img/tut_2/016_Output_1.png differ diff --git a/user/guide/img/tut_2/tut_2_output.gif b/user/guide/img/tut_2/tut_2_output.gif new file mode 100644 index 0000000..a1a2cdd Binary files /dev/null and b/user/guide/img/tut_2/tut_2_output.gif differ diff --git a/user/guide/img/tut_3/001_InitialOpen_1.png b/user/guide/img/tut_3/001_InitialOpen_1.png new file mode 100644 index 0000000..8816aca Binary files /dev/null and b/user/guide/img/tut_3/001_InitialOpen_1.png differ diff --git a/user/guide/img/tut_3/002_CreateNewGpkg_1.png b/user/guide/img/tut_3/002_CreateNewGpkg_1.png new file mode 100644 index 0000000..6aac83e Binary files /dev/null and b/user/guide/img/tut_3/002_CreateNewGpkg_1.png differ diff --git a/user/guide/img/tut_3/003_CreateNewLayer_1.png b/user/guide/img/tut_3/003_CreateNewLayer_1.png new file mode 100644 index 0000000..b49c2a0 Binary files /dev/null and b/user/guide/img/tut_3/003_CreateNewLayer_1.png differ diff --git a/user/guide/img/tut_3/004_1_ToggleEditing_1.png b/user/guide/img/tut_3/004_1_ToggleEditing_1.png new file mode 100644 index 0000000..32610c7 Binary files /dev/null and b/user/guide/img/tut_3/004_1_ToggleEditing_1.png differ diff --git a/user/guide/img/tut_3/004_2_PointsAdded_1.png b/user/guide/img/tut_3/004_2_PointsAdded_1.png new file mode 100644 index 0000000..28767bc Binary files /dev/null and b/user/guide/img/tut_3/004_2_PointsAdded_1.png differ diff --git a/user/guide/img/tut_3/005_AddSymbolLayer_1.png b/user/guide/img/tut_3/005_AddSymbolLayer_1.png new file mode 100644 index 0000000..e5e5e73 Binary files /dev/null and b/user/guide/img/tut_3/005_AddSymbolLayer_1.png differ diff --git a/user/guide/img/tut_3/006_GeometryGenerator_1.png b/user/guide/img/tut_3/006_GeometryGenerator_1.png new file mode 100644 index 0000000..f8a0e1f Binary files /dev/null and b/user/guide/img/tut_3/006_GeometryGenerator_1.png differ diff --git a/user/guide/img/tut_3/007_GeomLine_1.png b/user/guide/img/tut_3/007_GeomLine_1.png new file mode 100644 index 0000000..8aeaab3 Binary files /dev/null and b/user/guide/img/tut_3/007_GeomLine_1.png differ diff --git a/user/guide/img/tut_3/008_MarkerLine_1.png b/user/guide/img/tut_3/008_MarkerLine_1.png new file mode 100644 index 0000000..95f3036 Binary files /dev/null and b/user/guide/img/tut_3/008_MarkerLine_1.png differ diff --git a/user/guide/img/tut_3/009_MarkerLineSymbol_1.png b/user/guide/img/tut_3/009_MarkerLineSymbol_1.png new file mode 100644 index 0000000..0b7cc74 Binary files /dev/null and b/user/guide/img/tut_3/009_MarkerLineSymbol_1.png differ diff --git a/user/guide/img/tut_3/010_AddGeometry_1.png b/user/guide/img/tut_3/010_AddGeometry_1.png new file mode 100644 index 0000000..c234470 Binary files /dev/null and b/user/guide/img/tut_3/010_AddGeometry_1.png differ diff --git a/user/guide/img/tut_3/011_EditMarkerLine_1.png b/user/guide/img/tut_3/011_EditMarkerLine_1.png new file mode 100644 index 0000000..53fe8a2 Binary files /dev/null and b/user/guide/img/tut_3/011_EditMarkerLine_1.png differ diff --git a/user/guide/img/tut_3/012_OffsetExpression_1.png b/user/guide/img/tut_3/012_OffsetExpression_1.png new file mode 100644 index 0000000..c94c37e Binary files /dev/null and b/user/guide/img/tut_3/012_OffsetExpression_1.png differ diff --git a/user/guide/img/tut_3/013_EditMarkerSymbol_1.png b/user/guide/img/tut_3/013_EditMarkerSymbol_1.png new file mode 100644 index 0000000..35420e8 Binary files /dev/null and b/user/guide/img/tut_3/013_EditMarkerSymbol_1.png differ diff --git a/user/guide/img/tut_3/014_MarkerExpression_1.png b/user/guide/img/tut_3/014_MarkerExpression_1.png new file mode 100644 index 0000000..b571021 Binary files /dev/null and b/user/guide/img/tut_3/014_MarkerExpression_1.png differ diff --git a/user/guide/img/tut_3/015_OpenAW_1.png b/user/guide/img/tut_3/015_OpenAW_1.png new file mode 100644 index 0000000..4bf44db Binary files /dev/null and b/user/guide/img/tut_3/015_OpenAW_1.png differ diff --git a/user/guide/img/tut_3/016_AnimationPlan_1.png b/user/guide/img/tut_3/016_AnimationPlan_1.png new file mode 100644 index 0000000..161e527 Binary files /dev/null and b/user/guide/img/tut_3/016_AnimationPlan_1.png differ diff --git a/user/guide/img/tut_3/017_Output_1.png b/user/guide/img/tut_3/017_Output_1.png new file mode 100644 index 0000000..585d6ce Binary files /dev/null and b/user/guide/img/tut_3/017_Output_1.png differ diff --git a/user/guide/img/tut_3/tutorial_3_output_1.gif b/user/guide/img/tut_3/tutorial_3_output_1.gif new file mode 100644 index 0000000..0018535 Binary files /dev/null and b/user/guide/img/tut_3/tutorial_3_output_1.gif differ diff --git a/user/guide/img/tut_4/0_project.png b/user/guide/img/tut_4/0_project.png new file mode 100644 index 0000000..5c61e9a Binary files /dev/null and b/user/guide/img/tut_4/0_project.png differ diff --git a/user/guide/img/tut_4/1_animation_settings.png b/user/guide/img/tut_4/1_animation_settings.png new file mode 100644 index 0000000..a34f61e Binary files /dev/null and b/user/guide/img/tut_4/1_animation_settings.png differ diff --git a/user/guide/img/tut_4/2023-December- 1-Screenshot.png b/user/guide/img/tut_4/2023-December- 1-Screenshot.png new file mode 100644 index 0000000..bc53631 Binary files /dev/null and b/user/guide/img/tut_4/2023-December- 1-Screenshot.png differ diff --git a/user/guide/img/tut_4/2023-December- 1-Screenshot_1.png b/user/guide/img/tut_4/2023-December- 1-Screenshot_1.png new file mode 100644 index 0000000..4712ac0 Binary files /dev/null and b/user/guide/img/tut_4/2023-December- 1-Screenshot_1.png differ diff --git a/user/guide/img/tut_4/2023-December- 1-Screenshot_2.png b/user/guide/img/tut_4/2023-December- 1-Screenshot_2.png new file mode 100644 index 0000000..0f7397b Binary files /dev/null and b/user/guide/img/tut_4/2023-December- 1-Screenshot_2.png differ diff --git a/user/guide/img/tut_4/2023-December- 1-Screenshot_3.png b/user/guide/img/tut_4/2023-December- 1-Screenshot_3.png new file mode 100644 index 0000000..eb9e0b7 Binary files /dev/null and b/user/guide/img/tut_4/2023-December- 1-Screenshot_3.png differ diff --git a/user/guide/img/tut_4/2023-November-16-Screenshot.png b/user/guide/img/tut_4/2023-November-16-Screenshot.png new file mode 100644 index 0000000..2078ccf Binary files /dev/null and b/user/guide/img/tut_4/2023-November-16-Screenshot.png differ diff --git a/user/guide/img/tut_4/2023-November-16-Screenshot_1.png b/user/guide/img/tut_4/2023-November-16-Screenshot_1.png new file mode 100644 index 0000000..bf2c36e Binary files /dev/null and b/user/guide/img/tut_4/2023-November-16-Screenshot_1.png differ diff --git a/user/guide/img/tut_4/2023-November-16-Screenshot_2.png b/user/guide/img/tut_4/2023-November-16-Screenshot_2.png new file mode 100644 index 0000000..efa1270 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-16-Screenshot_2.png differ diff --git a/user/guide/img/tut_4/2023-November-17-Screenshot.png b/user/guide/img/tut_4/2023-November-17-Screenshot.png new file mode 100644 index 0000000..5d08d50 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-17-Screenshot.png differ diff --git a/user/guide/img/tut_4/2023-November-18-Screenshot.png b/user/guide/img/tut_4/2023-November-18-Screenshot.png new file mode 100644 index 0000000..973bd69 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-18-Screenshot.png differ diff --git a/user/guide/img/tut_4/2023-November-20-Screenshot.png b/user/guide/img/tut_4/2023-November-20-Screenshot.png new file mode 100644 index 0000000..df943c6 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-20-Screenshot.png differ diff --git a/user/guide/img/tut_4/2023-November-20-Screenshot_1.png b/user/guide/img/tut_4/2023-November-20-Screenshot_1.png new file mode 100644 index 0000000..4060419 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-20-Screenshot_1.png differ diff --git a/user/guide/img/tut_4/2023-November-20-Screenshot_2.png b/user/guide/img/tut_4/2023-November-20-Screenshot_2.png new file mode 100644 index 0000000..3d426ba Binary files /dev/null and b/user/guide/img/tut_4/2023-November-20-Screenshot_2.png differ diff --git a/user/guide/img/tut_4/2023-November-20-Screenshot_3.png b/user/guide/img/tut_4/2023-November-20-Screenshot_3.png new file mode 100644 index 0000000..92420b1 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-20-Screenshot_3.png differ diff --git a/user/guide/img/tut_4/2023-November-20-Screenshot_4.png b/user/guide/img/tut_4/2023-November-20-Screenshot_4.png new file mode 100644 index 0000000..786aa50 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-20-Screenshot_4.png differ diff --git a/user/guide/img/tut_4/2023-November-20-Screenshot_5.png b/user/guide/img/tut_4/2023-November-20-Screenshot_5.png new file mode 100644 index 0000000..292e8a1 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-20-Screenshot_5.png differ diff --git a/user/guide/img/tut_4/2023-November-20-Screenshot_6.png b/user/guide/img/tut_4/2023-November-20-Screenshot_6.png new file mode 100644 index 0000000..0f003d9 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-20-Screenshot_6.png differ diff --git a/user/guide/img/tut_4/2023-November-20-Screenshot_7.png b/user/guide/img/tut_4/2023-November-20-Screenshot_7.png new file mode 100644 index 0000000..f42fc1f Binary files /dev/null and b/user/guide/img/tut_4/2023-November-20-Screenshot_7.png differ diff --git a/user/guide/img/tut_4/2023-November-20-Screenshot_8.png b/user/guide/img/tut_4/2023-November-20-Screenshot_8.png new file mode 100644 index 0000000..8e406b3 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-20-Screenshot_8.png differ diff --git a/user/guide/img/tut_4/2023-November-20-Screenshot_9.png b/user/guide/img/tut_4/2023-November-20-Screenshot_9.png new file mode 100644 index 0000000..4b1bb9c Binary files /dev/null and b/user/guide/img/tut_4/2023-November-20-Screenshot_9.png differ diff --git a/user/guide/img/tut_4/2023-November-21-Screenshot.png b/user/guide/img/tut_4/2023-November-21-Screenshot.png new file mode 100644 index 0000000..7045371 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-21-Screenshot.png differ diff --git a/user/guide/img/tut_4/2023-November-21-Screenshot_1.png b/user/guide/img/tut_4/2023-November-21-Screenshot_1.png new file mode 100644 index 0000000..4255b2e Binary files /dev/null and b/user/guide/img/tut_4/2023-November-21-Screenshot_1.png differ diff --git a/user/guide/img/tut_4/2023-November-21-Screenshot_2.png b/user/guide/img/tut_4/2023-November-21-Screenshot_2.png new file mode 100644 index 0000000..e334cfa Binary files /dev/null and b/user/guide/img/tut_4/2023-November-21-Screenshot_2.png differ diff --git a/user/guide/img/tut_4/2023-November-21-Screenshot_3.png b/user/guide/img/tut_4/2023-November-21-Screenshot_3.png new file mode 100644 index 0000000..ae41d0d Binary files /dev/null and b/user/guide/img/tut_4/2023-November-21-Screenshot_3.png differ diff --git a/user/guide/img/tut_4/2023-November-22-Screenshot.png b/user/guide/img/tut_4/2023-November-22-Screenshot.png new file mode 100644 index 0000000..1676ef6 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-22-Screenshot.png differ diff --git a/user/guide/img/tut_4/2023-November-22-Screenshot_1.png b/user/guide/img/tut_4/2023-November-22-Screenshot_1.png new file mode 100644 index 0000000..060b52b Binary files /dev/null and b/user/guide/img/tut_4/2023-November-22-Screenshot_1.png differ diff --git a/user/guide/img/tut_4/2023-November-22-Screenshot_2.png b/user/guide/img/tut_4/2023-November-22-Screenshot_2.png new file mode 100644 index 0000000..7b1de50 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-22-Screenshot_2.png differ diff --git a/user/guide/img/tut_4/2023-November-23-Screenshot.png b/user/guide/img/tut_4/2023-November-23-Screenshot.png new file mode 100644 index 0000000..bbaf48f Binary files /dev/null and b/user/guide/img/tut_4/2023-November-23-Screenshot.png differ diff --git a/user/guide/img/tut_4/2023-November-23-Screenshot_1.png b/user/guide/img/tut_4/2023-November-23-Screenshot_1.png new file mode 100644 index 0000000..31ddce8 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-23-Screenshot_1.png differ diff --git a/user/guide/img/tut_4/2023-November-24-Screenshot.png b/user/guide/img/tut_4/2023-November-24-Screenshot.png new file mode 100644 index 0000000..d83280d Binary files /dev/null and b/user/guide/img/tut_4/2023-November-24-Screenshot.png differ diff --git a/user/guide/img/tut_4/2023-November-27-Screenshot.png b/user/guide/img/tut_4/2023-November-27-Screenshot.png new file mode 100644 index 0000000..82fe654 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-27-Screenshot.png differ diff --git a/user/guide/img/tut_4/2023-November-27-Screenshot_1.png b/user/guide/img/tut_4/2023-November-27-Screenshot_1.png new file mode 100644 index 0000000..054a1de Binary files /dev/null and b/user/guide/img/tut_4/2023-November-27-Screenshot_1.png differ diff --git a/user/guide/img/tut_4/2023-November-27-Screenshot_2.png b/user/guide/img/tut_4/2023-November-27-Screenshot_2.png new file mode 100644 index 0000000..330ac1d Binary files /dev/null and b/user/guide/img/tut_4/2023-November-27-Screenshot_2.png differ diff --git a/user/guide/img/tut_4/2023-November-27-Screenshot_3.png b/user/guide/img/tut_4/2023-November-27-Screenshot_3.png new file mode 100644 index 0000000..b979829 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-27-Screenshot_3.png differ diff --git a/user/guide/img/tut_4/2023-November-28-Screenshot.png b/user/guide/img/tut_4/2023-November-28-Screenshot.png new file mode 100644 index 0000000..a706351 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-28-Screenshot.png differ diff --git a/user/guide/img/tut_4/2023-November-28-Screenshot_1.png b/user/guide/img/tut_4/2023-November-28-Screenshot_1.png new file mode 100644 index 0000000..72267cb Binary files /dev/null and b/user/guide/img/tut_4/2023-November-28-Screenshot_1.png differ diff --git a/user/guide/img/tut_4/2023-November-28-Screenshot_2.png b/user/guide/img/tut_4/2023-November-28-Screenshot_2.png new file mode 100644 index 0000000..065a507 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-28-Screenshot_2.png differ diff --git a/user/guide/img/tut_4/2023-November-28-Screenshot_3.png b/user/guide/img/tut_4/2023-November-28-Screenshot_3.png new file mode 100644 index 0000000..604f8dc Binary files /dev/null and b/user/guide/img/tut_4/2023-November-28-Screenshot_3.png differ diff --git a/user/guide/img/tut_4/2023-November-28-Screenshot_4.png b/user/guide/img/tut_4/2023-November-28-Screenshot_4.png new file mode 100644 index 0000000..ae72c74 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-28-Screenshot_4.png differ diff --git a/user/guide/img/tut_4/2023-November-28-Screenshot_5.png b/user/guide/img/tut_4/2023-November-28-Screenshot_5.png new file mode 100644 index 0000000..0bd25d5 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-28-Screenshot_5.png differ diff --git a/user/guide/img/tut_4/2023-November-28-Screenshot_6.png b/user/guide/img/tut_4/2023-November-28-Screenshot_6.png new file mode 100644 index 0000000..6ca8f89 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-28-Screenshot_6.png differ diff --git a/user/guide/img/tut_4/2023-November-29-Screenshot.png b/user/guide/img/tut_4/2023-November-29-Screenshot.png new file mode 100644 index 0000000..cd3e7d9 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-29-Screenshot.png differ diff --git a/user/guide/img/tut_4/2023-November-29-Screenshot_1.png b/user/guide/img/tut_4/2023-November-29-Screenshot_1.png new file mode 100644 index 0000000..f288fd4 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-29-Screenshot_1.png differ diff --git a/user/guide/img/tut_4/2023-November-29-Screenshot_2.png b/user/guide/img/tut_4/2023-November-29-Screenshot_2.png new file mode 100644 index 0000000..0a47f0e Binary files /dev/null and b/user/guide/img/tut_4/2023-November-29-Screenshot_2.png differ diff --git a/user/guide/img/tut_4/2023-November-29-Screenshot_3.png b/user/guide/img/tut_4/2023-November-29-Screenshot_3.png new file mode 100644 index 0000000..a32c3e3 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-29-Screenshot_3.png differ diff --git a/user/guide/img/tut_4/2023-November-29-Screenshot_4.png b/user/guide/img/tut_4/2023-November-29-Screenshot_4.png new file mode 100644 index 0000000..835e1a6 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-29-Screenshot_4.png differ diff --git a/user/guide/img/tut_4/2023-November-29-Screenshot_5.png b/user/guide/img/tut_4/2023-November-29-Screenshot_5.png new file mode 100644 index 0000000..eeff438 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-29-Screenshot_5.png differ diff --git a/user/guide/img/tut_4/2023-November-29-Screenshot_6.png b/user/guide/img/tut_4/2023-November-29-Screenshot_6.png new file mode 100644 index 0000000..3af86d4 Binary files /dev/null and b/user/guide/img/tut_4/2023-November-29-Screenshot_6.png differ diff --git a/user/guide/img/tut_4/2023-November-29-Screenshot_7.png b/user/guide/img/tut_4/2023-November-29-Screenshot_7.png new file mode 100644 index 0000000..5f95a7d Binary files /dev/null and b/user/guide/img/tut_4/2023-November-29-Screenshot_7.png differ diff --git a/user/guide/img/tut_4/2023-November-29-Screenshot_8.png b/user/guide/img/tut_4/2023-November-29-Screenshot_8.png new file mode 100644 index 0000000..871c7ff Binary files /dev/null and b/user/guide/img/tut_4/2023-November-29-Screenshot_8.png differ diff --git a/user/guide/img/tut_4/expression.png b/user/guide/img/tut_4/expression.png new file mode 100644 index 0000000..392fb5a Binary files /dev/null and b/user/guide/img/tut_4/expression.png differ diff --git a/user/guide/img/tut_4/globe_small.gif b/user/guide/img/tut_4/globe_small.gif new file mode 100644 index 0000000..354cd1c Binary files /dev/null and b/user/guide/img/tut_4/globe_small.gif differ diff --git a/user/guide/img/tut_5/planar_map.gif b/user/guide/img/tut_5/planar_map.gif new file mode 100644 index 0000000..210c32a Binary files /dev/null and b/user/guide/img/tut_5/planar_map.gif differ diff --git a/user/guide/img/tut_5/planar_map_final.gif b/user/guide/img/tut_5/planar_map_final.gif new file mode 100644 index 0000000..fcdb1f2 Binary files /dev/null and b/user/guide/img/tut_5/planar_map_final.gif differ diff --git a/user/guide/img/tut_5/planar_map_line_shrinks.gif b/user/guide/img/tut_5/planar_map_line_shrinks.gif new file mode 100644 index 0000000..0183da8 Binary files /dev/null and b/user/guide/img/tut_5/planar_map_line_shrinks.gif differ diff --git a/user/guide/img/tut_5/planar_map_settings.png b/user/guide/img/tut_5/planar_map_settings.png new file mode 100644 index 0000000..7d30fac Binary files /dev/null and b/user/guide/img/tut_5/planar_map_settings.png differ diff --git a/user/guide/img/tut_5/simple_line.png b/user/guide/img/tut_5/simple_line.png new file mode 100644 index 0000000..687ea41 Binary files /dev/null and b/user/guide/img/tut_5/simple_line.png differ diff --git a/user/guide/img/tut_5/smoothed_line.png b/user/guide/img/tut_5/smoothed_line.png new file mode 100644 index 0000000..d318537 Binary files /dev/null and b/user/guide/img/tut_5/smoothed_line.png differ diff --git a/user/guide/img/tut_5/smoothed_line2.png b/user/guide/img/tut_5/smoothed_line2.png new file mode 100644 index 0000000..ee0ca6f Binary files /dev/null and b/user/guide/img/tut_5/smoothed_line2.png differ diff --git a/user/guide/img/tut_5/smoothed_line_clipped.png b/user/guide/img/tut_5/smoothed_line_clipped.png new file mode 100644 index 0000000..75b07c7 Binary files /dev/null and b/user/guide/img/tut_5/smoothed_line_clipped.png differ diff --git a/user/guide/img/tut_5/spinning_point_example.gif b/user/guide/img/tut_5/spinning_point_example.gif new file mode 100644 index 0000000..23152d1 Binary files /dev/null and b/user/guide/img/tut_5/spinning_point_example.gif differ diff --git a/user/guide/index.html b/user/guide/index.html new file mode 100644 index 0000000..1e2db06 --- /dev/null +++ b/user/guide/index.html @@ -0,0 +1,1683 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Index - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + +

Index

+ +

Tutorial 1: Point Along A Line

+

This tutorial introduces the concept of moving a point along a line within your animated +map.

+

1. Download and extract the Required Tutorial Zip Folder

+

2. Open the tutorial_1.qgz project file that is in the folder. When you first open it you +you see something like this:

+

Initial Open

+

3. Select the premade line layer (1), and click on the Add Symbol Layer +(green plus symbol) button (2) to it.

+

Add Symbol Layer

+

Change the new Symbol Layer (3) type to marker line and then style it (4) so that it is more visible.

+

Style Symbol Layer

+

4. Change the Symbol Layer's settings so that the point is only on the first vertex (5) and +and not at equidistant intervals.

+

Change the offset along the line to be Percentage (6).

+

Symbol Layer Settings

+

Click the Dropdown Menu (7) ➔Edit... (8) and then add the following code snippet

+

Edit Expression

+
    -- Point Along Line Code Snippet
+    (@current_hover_frame/@hover_frames) * 100
+
+

Offset along line Snippet

+

The snippet tells QGIS how far along the line (as a percentage of the line length) to +render the point in each frame.

+

5. Open the Workbench and select Fixed Extent (9).

+

Click on Map Canvas Extent (10) and set the the Frames to 300 (11) (for a 10 second +output at 30 frames per second).

+

Animation Plan

+

6. Skip over the Intro, Outro, and Soundtrack tabs. In the Output tab, set the output +format (12) and resolution (13), and set the output location's path (14).

+

Output Tab

+

7. Click Run and render your output.

+

Point Along Line Output GIF

+

After this tutorial you should have a better idea of how to make a point move along a line. +An expansion to this example would be to make the moving point a dynamically changing +marker (like the markers in tutorial 1). Go have fun!

+

Tutorial 2: Basic Dynamically Changing Markers

+

This tutorial aims to show you the basics of creating, and animating, a static layer to use +with the Animation Workbench. There are three pre-made layers to allow the main focus of +the tutorial to be on the Animation Workbench and not on QGIS as a whole.

+

1. Download and extract the Required Tutorial Zip Folder

+

2. Open the tutorial_2.qgz project file that is in the folder. + 

+

3. Set the CRS of your project to WGS84/UTM zone 35S (EPSG: 32735).

+

Choose CRS

+

4. In the Browser, expand the tutorial_2.gpkg and add the three pre-made layers +(VaalDam, SouthAfrica, and route) (A) to your project.

+

Add Backing Layers

+

5. In the Layers Panel, arrange the layers in the following order: route, VaalDam, +SouthAfrica. Then right-click on the VaalDam layer and Zoom to Layer(s) (B)

+

Zoom to Dam

+

Style the three layers to your preferred style. + 

+

6. Now create a new layer in the tutorial_2.gpkg by clicking LayerCreate Layer➔ +New GeoPackage Layer... (C).

+

Create New Layer

+

Click on the Ellipsis (D), navigate to and select the tutorial_2.gpkg, and +click Save. Change the Table name to fish (E), set the Geometry type as Point (F), and +change the CRS to match the Project CRS (G).

+

Layer Settings

+

Click on OK and then click Add New Layer on the window that pops up. + 

+

7. Select the fish layer and then click on Toggle EditingAdd Point Feature (H).

+

Edit Layer Points

+

Add a few points wherever you feel they should go (Hint: This is a fish layer so adding +them above the dam layer would be best). Don't worry about naming the points, just add +them.

+

Added Points

+

Save your changes by clicking on Save Layer Edits just next to the Toggle Editing +button. Then stop editing the layer. + 

+

8. Repeat steps 6. and 7. but change the Table name to bird and add the points over +the land areas.

+

Both Layers Added

+

9. Select the fish layer and then in the Layer styling toolbar (I) change the +Symbol layer type to Raster Image Marker (J).

+

Change to RIM

+

Select the marker image by clicking the Dropdown menuSelect File... (K) +and then choosing fishfish_0000.png.

+

Select Image

+

Click Open

+

10. Change the marker's Size Unit to Meters at Scale (L)

+

Change Size to MAS

+

and set the Width and Height to 1000. + 

+

11. Repeat Steps 9. and 10. with the bird layer but instead choosing birdbird_0000.png +and setting the Width and Height to 3000.

+

 

+
+

In QGIS 3.26, or later, the Symbol layer type can simply be selected as +Animated Marker and Step 12. can be skipped.

+
+

12. To animate the fish and bird layers using the QGIS Expressions system click the +Dropdown MenuEdit... (M).

+

Edit Expression

+

For the fish layer use the following expression:

+

Fish Expression

+
    @project_home
+    || 
+    '/fish/fish_00'
+    ||
+    lpad(to_string( @frame_number % 32), 2, '0')
+    ||
+    '.png'
+
+

And for the bird layer use:

+

Bird Expression

+
    @project_home
+    ||
+    '/bird/bird_00'
+    || 
+    lpad(to_string(@frame_number % 9), 2, '0')
+    || 
+    '.png'
+
+
+

Refer to the What is the Workbench doing? section for an explanation + about what the above code snippet is doing.

+
+

13. Open the Animation Workbench (refer to the Using the Animation Workbench section +if you are unsure how to open the Workbench).

+

In the Animation Plan tab set:

+
    +
  • the Render Mode to Planar (N),
  • +
  • the Animation Layer to route (O) using the dropdown menu,
  • +
  • the Zoom Range (P) to 1:270000 for the Minimum and 1:135000 for the Maximum,
  • +
  • the Frame rate per second to 9 fps (Q),
  • +
  • the Travel duration to 4,00 s (R),
  • +
  • and the Feature hover duration to 2,00 s (S)
  • +
+

Enable both the Pan and Zoom easings and set them to linear.

+

Animation Plan

+

14. Skip past the Intro, Outro, and Soundtrack tabs to the Output tab. Set the +Output Format as Animated Gif (T) and the Output Resolution to +720p (1280x720) (U). The Output Resolution can be set as any of the three +choices but was set at 720 for this tutorial for the sake of speed. Set the output +location to one you can find easily (V)

+

Output Tab

+

15. Click Run and watch what the Workbench is doing in the Progress tab. Once the +Workbench is finished running, you should end up with an output similar to this:

+

Output GIF

+

After this tutorial you should have a better understanding of how to create a point layer +in your project and then to change the Single Symbol markers into stationary animated +markers. A key focus is the idea that you can tell versions of QGIS before 3.26 to dynamically +change markers using short code snippets. Versions of QGIS post 3.26 allow a user to +simply use the Animated Marker feature without editing an expression.

+

Tutorial 3: Flying Points

+

This tutorial aims to show you how add a flying point animation to points on your map using +built-in QGIS functionalities (The geometry generator line) and introduced variables from +the workbench.

+

1. Download and extract the Required Tutorial Zip Folder

+

2. Open the tutorial_3.qgz project file. +When you first open the project file you should be greeted with something like this:

+

Initial Open

+

3. Create a new point layer in a new geopackage by clicking LayerCreate Layer➔ + New GeoPackage Layer.... Click on the Ellipsis (three dots) next to the Database +textbox and navigate to the folder that the tutorial_3.qgz file is located in. Type the File +name "tutorial_3" (1) and ensure the file will be saved as a GeoPackage (2) and click +Save (3).

+

Create New GeoPackage

+

Change the Table name to flying_points (4), set the Geometry type as Point (5) and +change the CRS to match the Project CRS (6).

+

Create New layer

+

Click OK (7) + 

+

4. Click on Toggle EditingAdd Point Feature (8).

+

Toggle Editing

+

And randomly add points to your map. Depending on your computer's capabilites, you +can add more, or fewer, points than the example below.

+

Points Added

+

Save your Layer Edits and toggle off the Editing tool. + 

+

5. Style the points layer.

+

Select the flying_points (9) layer and in the Layer Styling toolbar click on the +Add Symbol Layer (green plus symbol) button (10).

+

Add Symbol Layer

+

Select the top Simple Marker (11) and change its Symbol layer type to +Geometry Generator (12)

+

Geometry Generator

+

and then set the Geometry type to LineString / MultiLineString (13).

+

Geometry Line

+

Change the line's Symbol layer type to Marker Line (14).

+

Marker Line

+

Add a second Simple marker to the marker line so that you end up with something like +this:

+

Marker Line Symbol

+

Style the various Simple Markers to your preferred look.

+

 

+

6. Select the Geometry Generator symbol layer (15) and add this code to it:

+
    wave_randomized(
+    make_line(
+    $geometry, geometry(@hover_feature)), 
+    100, 1000, 1000, 10000, 1)
+
+

Add Geometry

+
+

More information about what changing the numbers will affect can be found in the +QGIS expressions editor. + 

+
+

7. A few options need to be changed in the Marker Line symbol layer (16): The Marker +placement needs to be set to On first vertex (17) and, the Offset along line needs to be +changed to Percentage (18). The click the Dropdown menu next to Offset along line and +select Edit... (19).

+

Edit Marker Line

+

In the Expression String Builder add the following code snippet:

+
    100 - to_int((@current_hover_frame / @hover_frames) * 100 )
+
+

Offset Expression

+

Click OK

+

8. Select the first Simple Marker symbol layer (20) in the Marker Line symbol layer. Scroll +down to Offset and click on the Dropdown MenuEdit.. (21).

+

Edit Marker Symbol

+

In the Expression String Builder add the following code snippet:

+
    -- Taken from https://spicyyoghurt.com/tools/easing-functions
+    --    t = Time - Amount of time that has passed since the beginning of the animation. Usually starts at 0 and is slowly increased using a game loop or other update function.
+    --    b = Beginning value - The starting point of the animation. Usually it's a static value, you can start at 0 for example.
+    --    c = Change in value - The amount of change needed to go from starting point to end point. It's also usually a static value.
+    --    d = Duration - Amount of time the animation will take. Usually a static value aswell.
+    -- Sinusoidal
+    -- -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
+
+    -- Use with the animation in static mode
+    if(@hover_feature_id != $id,
+    array(
+        (-@hover_frames / 2) * (cos( (pi() * @frame_number / @hover_frames ) - 1)) ,
+        (-@hover_frames / 2) * (sin( (pi() * @frame_number / @hover_frames ) - 1)) 
+        ),
+        array (0,0))
+
+

Marker Expression

+

Click OK

+

9. Open the Animation Workbench (22)

+

Open AW

+

10. Set up the Animation Plan with:

+
    +
  • the Render Mode to Planar (23),
  • +
  • the Animation Layer to flying_points (24) using the dropdown menu,
  • +
  • the Zoom Range (25) to 1:22000000 for the Minimum and 1:11000000 for the + Maximum,
  • +
  • the Frame rate per second to 9 fps (26),
  • +
  • the Travel duration to 2,00 s (27),
  • +
  • the Feature hover duration to 2,00 s (28),
  • +
  • and the Zoom Easing as InCirc (29)
  • +
+

Animation Plan

+
+

With a decently specced computer you can up the fps and get the points to fly +faster in your output. + 

+
+

11. Add license-free media to the Intro, Outro, and Soundtrack.

+
+

Make sure your Soundtrack is as long as, or longer than, your final animation will be +(including the Intro, Animation, and Outro).

+
+

 

+

12. Set the Output Format as Movie (MP4) (30) and the Output Resolution to +1080 (1920x1080) (31). The Output Resolution can be set as any of the three +choices but was set at 1080 for this tutorial for the sake of speed. Set the output +location (32) to one you can easily locate.

+

Output

+

13. Click Run and get an output. The GIF below is the visual output of the tutorial if you +followed step-by-step and set the parameters to exactly what was stated.

+

Output Gif

+

The link to a more complex output (with an Intro, an Outro, and a Soundtrack) can +be found here

+

 

+

After this tutorial you should have a better idea of how you can use a mixture of built-in +QGIS functionalites and the workbench's introduced variables to generate interesting outputs.

+

Tutorial 4: Spinning Globe

+

Given a global point layer and countries layer like this:

+

+

You can create a nice spinning globe effect like this:

+

+

I set up the animation workbench like this:

+

+

For the above animated GIF, I compressed it using imagemagick like this:

+
convert globe.gif -coalesce -resize 700x525 -fuzz 2% +dither -layers Optimize +map globe_small.gif
+
+

This is a handy technique if you want to generate small file size animations.

+

For the points I made a red marker using a quarter circle that spins around the points like this:

+

+

The rotation field expression is this:

+
if (@id = @hover_feature_id, 
+    0-((1440 * (@current_hover_frame/@hover_frames)) % 360),
+    0)
+
+

This will spin around 4 times during the hover cycle.

+

For the ocean (AOI in the layers list), I generated a grid of 1 degree cells covering the earth. You need to do it as smaller polygons instead of one large polygon because QGIS will run into issues reprojecting a single polygon whose edges lie on the date line.

+

Here is how the final video came out:

+ + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/guide/tutorial1/index.html b/user/guide/tutorial1/index.html new file mode 100644 index 0000000..0d41af8 --- /dev/null +++ b/user/guide/tutorial1/index.html @@ -0,0 +1,1416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 1 Points on a Line - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

1 Points on a Line

+ +

Tutorial 1: Point Along A Line

+

This tutorial introduces the concept of moving a point along a line within your animated +map.

+

1. Download and extract the Required Tutorial Zip Folder

+

2. Open the tutorial_1.qgz project file that is in the folder. When you first open it you +you see something like this:

+

Initial Open

+

3. Select the premade line layer (1), and click on the Add Symbol Layer +(green plus symbol) button (2) to it.

+

Add Symbol Layer

+

Change the new Symbol Layer (3) type to marker line and then style it (4) so that it is more visible.

+

Style Symbol Layer

+

4. Change the Symbol Layer's settings so that the point is only on the first vertex (5) and +and not at equidistant intervals.

+

Change the offset along the line to be Percentage (6).

+

Symbol Layer Settings

+

Click the Dropdown Menu (7) ➔Edit... (8) and then add the following code snippet

+

Edit Expression

+
    -- Point Along Line Code Snippet
+    (@current_hover_frame/@hover_frames) * 100
+
+

Offset along line Snippet

+

The snippet tells QGIS how far along the line (as a percentage of the line length) to +render the point in each frame.

+

5. Open the Workbench and select Fixed Extent (9).

+

Click on Map Canvas Extent (10) and set the the Frames to 300 (11) (for a 10 second +output at 30 frames per second).

+

Animation Plan

+

6. Skip over the Intro, Outro, and Soundtrack tabs. In the Output tab, set the output +format (12) and resolution (13), and set the output location's path (14).

+

Output Tab

+

7. Click Run and render your output.

+

Point Along Line Output GIF

+

After this tutorial you should have a better idea of how to make a point move along a line. +An expansion to this example would be to make the moving point a dynamically changing +marker (like the markers in tutorial 1). Go have fun!

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/guide/tutorial2/index.html b/user/guide/tutorial2/index.html new file mode 100644 index 0000000..8ee1001 --- /dev/null +++ b/user/guide/tutorial2/index.html @@ -0,0 +1,1495 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 2 Dynamic Markers - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

2 Dynamic Markers

+ +

Tutorial 2: Basic Dynamically Changing Markers

+

This tutorial aims to show you the basics of creating, and animating, a static layer to use +with the Animation Workbench. There are three pre-made layers to allow the main focus of +the tutorial to be on the Animation Workbench and not on QGIS as a whole.

+

1. Download and extract the Required Tutorial Zip Folder

+

2. Open the tutorial_2.qgz project file that is in the folder. + 

+

3. Set the CRS of your project to WGS84/UTM zone 35S (EPSG: 32735).

+

Choose CRS

+

4. In the Browser, expand the tutorial_2.gpkg and add the three pre-made layers +(VaalDam, SouthAfrica, and route) (A) to your project.

+

Add Backing Layers

+

5. In the Layers Panel, arrange the layers in the following order: route, VaalDam, +SouthAfrica. Then right-click on the VaalDam layer and Zoom to Layer(s) (B)

+

Zoom to Dam

+

Style the three layers to your preferred style. + 

+

6. Now create a new layer in the tutorial_2.gpkg by clicking LayerCreate Layer➔ +New GeoPackage Layer... (C).

+

Create New Layer

+

Click on the Ellipsis (D), navigate to and select the tutorial_2.gpkg, and +click Save. Change the Table name to fish (E), set the Geometry type as Point (F), and +change the CRS to match the Project CRS (G).

+

Layer Settings

+

Click on OK and then click Add New Layer on the window that pops up. + 

+

7. Select the fish layer and then click on Toggle EditingAdd Point Feature (H).

+

Edit Layer Points

+

Add a few points wherever you feel they should go (Hint: This is a fish layer so adding +them above the dam layer would be best). Don't worry about naming the points, just add +them.

+

Added Points

+

Save your changes by clicking on Save Layer Edits just next to the Toggle Editing +button. Then stop editing the layer. + 

+

8. Repeat steps 6. and 7. but change the Table name to bird and add the points over +the land areas.

+

Both Layers Added

+

9. Select the fish layer and then in the Layer styling toolbar (I) change the +Symbol layer type to Raster Image Marker (J).

+

Change to RIM

+

Select the marker image by clicking the Dropdown menuSelect File... (K) +and then choosing fishfish_0000.png.

+

Select Image

+

Click Open

+

10. Change the marker's Size Unit to Meters at Scale (L)

+

Change Size to MAS

+

and set the Width and Height to 1000. + 

+

11. Repeat Steps 9. and 10. with the bird layer but instead choosing birdbird_0000.png +and setting the Width and Height to 3000.

+

 

+
+

In QGIS 3.26, or later, the Symbol layer type can simply be selected as +Animated Marker and Step 12. can be skipped.

+
+

12. To animate the fish and bird layers using the QGIS Expressions system click the +Dropdown MenuEdit... (M).

+

Edit Expression

+

For the fish layer use the following expression:

+

Fish Expression

+
    @project_home
+    || 
+    '/fish/fish_00'
+    ||
+    lpad(to_string( @frame_number % 32), 2, '0')
+    ||
+    '.png'
+
+

And for the bird layer use:

+

Bird Expression

+
    @project_home
+    ||
+    '/bird/bird_00'
+    || 
+    lpad(to_string(@frame_number % 9), 2, '0')
+    || 
+    '.png'
+
+
+

Refer to the What is the Workbench doing? section for an explanation + about what the above code snippet is doing.

+
+

13. Open the Animation Workbench (refer to the Using the Animation Workbench section +if you are unsure how to open the Workbench).

+

In the Animation Plan tab set:

+
    +
  • the Render Mode to Planar (N),
  • +
  • the Animation Layer to route (O) using the dropdown menu,
  • +
  • the Zoom Range (P) to 1:270000 for the Minimum and 1:135000 for the Maximum,
  • +
  • the Frame rate per second to 9 fps (Q),
  • +
  • the Travel duration to 4,00 s (R),
  • +
  • and the Feature hover duration to 2,00 s (S)
  • +
+

Enable both the Pan and Zoom easings and set them to linear.

+

Animation Plan

+

14. Skip past the Intro, Outro, and Soundtrack tabs to the Output tab. Set the +Output Format as Animated Gif (T) and the Output Resolution to +720p (1280x720) (U). The Output Resolution can be set as any of the three +choices but was set at 720 for this tutorial for the sake of speed. Set the output +location to one you can find easily (V)

+

Output Tab

+

15. Click Run and watch what the Workbench is doing in the Progress tab. Once the +Workbench is finished running, you should end up with an output similar to this:

+

Output GIF

+

After this tutorial you should have a better understanding of how to create a point layer +in your project and then to change the Single Symbol markers into stationary animated +markers. A key focus is the idea that you can tell versions of QGIS before 3.26 to dynamically +change markers using short code snippets. Versions of QGIS post 3.26 allow a user to +simply use the Animated Marker feature without editing an expression.

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/guide/tutorial3/index.html b/user/guide/tutorial3/index.html new file mode 100644 index 0000000..656b6fb --- /dev/null +++ b/user/guide/tutorial3/index.html @@ -0,0 +1,1522 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 3 Flying Points - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

3 Flying Points

+ +

Tutorial 3: Flying Points

+

This tutorial aims to show you how add a flying point animation to points on your map using +built-in QGIS functionalities (The geometry generator line) and introduced variables from +the workbench.

+

1. Download and extract the Required Tutorial Zip Folder

+

2. Open the tutorial_3.qgz project file. +When you first open the project file you should be greeted with something like this:

+

Initial Open

+

3. Create a new point layer in a new geopackage by clicking LayerCreate Layer➔ + New GeoPackage Layer.... Click on the Ellipsis (three dots) next to the Database +textbox and navigate to the folder that the tutorial_3.qgz file is located in. Type the File +name "tutorial_3" (1) and ensure the file will be saved as a GeoPackage (2) and click +Save (3).

+

Create New GeoPackage

+

Change the Table name to flying_points (4), set the Geometry type as Point (5) and +change the CRS to match the Project CRS (6).

+

Create New layer

+

Click OK (7) + 

+

4. Click on Toggle EditingAdd Point Feature (8).

+

Toggle Editing

+

And randomly add points to your map. Depending on your computer's capabilites, you +can add more, or fewer, points than the example below.

+

Points Added

+

Save your Layer Edits and toggle off the Editing tool. + 

+

5. Style the points layer.

+

Select the flying_points (9) layer and in the Layer Styling toolbar click on the +Add Symbol Layer (green plus symbol) button (10).

+

Add Symbol Layer

+

Select the top Simple Marker (11) and change its Symbol layer type to +Geometry Generator (12)

+

Geometry Generator

+

and then set the Geometry type to LineString / MultiLineString (13).

+

Geometry Line

+

Change the line's Symbol layer type to Marker Line (14).

+

Marker Line

+

Add a second Simple marker to the marker line so that you end up with something like +this:

+

Marker Line Symbol

+

Style the various Simple Markers to your preferred look.

+

 

+

6. Select the Geometry Generator symbol layer (15) and add this code to it:

+
    wave_randomized(
+    make_line(
+    $geometry, geometry(@hover_feature)), 
+    100, 1000, 1000, 10000, 1)
+
+

Add Geometry

+
+

More information about what changing the numbers will affect can be found in the +QGIS expressions editor. + 

+
+

7. A few options need to be changed in the Marker Line symbol layer (16): The Marker +placement needs to be set to On first vertex (17) and, the Offset along line needs to be +changed to Percentage (18). The click the Dropdown menu next to Offset along line and +select Edit... (19).

+

Edit Marker Line

+

In the Expression String Builder add the following code snippet:

+
    100 - to_int((@current_hover_frame / @hover_frames) * 100 )
+
+

Offset Expression

+

Click OK

+

8. Select the first Simple Marker symbol layer (20) in the Marker Line symbol layer. Scroll +down to Offset and click on the Dropdown MenuEdit.. (21).

+

Edit Marker Symbol

+

In the Expression String Builder add the following code snippet:

+
    -- Taken from https://spicyyoghurt.com/tools/easing-functions
+    --    t = Time - Amount of time that has passed since the beginning of the animation. Usually starts at 0 and is slowly increased using a game loop or other update function.
+    --    b = Beginning value - The starting point of the animation. Usually it's a static value, you can start at 0 for example.
+    --    c = Change in value - The amount of change needed to go from starting point to end point. It's also usually a static value.
+    --    d = Duration - Amount of time the animation will take. Usually a static value aswell.
+    -- Sinusoidal
+    -- -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
+
+    -- Use with the animation in static mode
+    if(@hover_feature_id != $id,
+    array(
+        (-@hover_frames / 2) * (cos( (pi() * @frame_number / @hover_frames ) - 1)) ,
+        (-@hover_frames / 2) * (sin( (pi() * @frame_number / @hover_frames ) - 1)) 
+        ),
+        array (0,0))
+
+

Marker Expression

+

Click OK

+

9. Open the Animation Workbench (22)

+

Open AW

+

10. Set up the Animation Plan with:

+
    +
  • the Render Mode to Planar (23),
  • +
  • the Animation Layer to flying_points (24) using the dropdown menu,
  • +
  • the Zoom Range (25) to 1:22000000 for the Minimum and 1:11000000 for the + Maximum,
  • +
  • the Frame rate per second to 9 fps (26),
  • +
  • the Travel duration to 2,00 s (27),
  • +
  • the Feature hover duration to 2,00 s (28),
  • +
  • and the Zoom Easing as InCirc (29)
  • +
+

Animation Plan

+
+

With a decently specced computer you can up the fps and get the points to fly +faster in your output. + 

+
+

11. Add license-free media to the Intro, Outro, and Soundtrack.

+
+

Make sure your Soundtrack is as long as, or longer than, your final animation will be +(including the Intro, Animation, and Outro).

+
+

 

+

12. Set the Output Format as Movie (MP4) (30) and the Output Resolution to +1080 (1920x1080) (31). The Output Resolution can be set as any of the three +choices but was set at 1080 for this tutorial for the sake of speed. Set the output +location (32) to one you can easily locate.

+

Output

+

13. Click Run and get an output. The GIF below is the visual output of the tutorial if you +followed step-by-step and set the parameters to exactly what was stated.

+

Output Gif

+

The link to a more complex output (with an Intro, an Outro, and a Soundtrack) can +be found here

+

 

+

After this tutorial you should have a better idea of how you can use a mixture of built-in +QGIS functionalites and the workbench's introduced variables to generate interesting outputs.

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/guide/tutorial4/index.html b/user/guide/tutorial4/index.html new file mode 100644 index 0000000..780c79a --- /dev/null +++ b/user/guide/tutorial4/index.html @@ -0,0 +1,1400 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 4 Spinning Globe - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

4 Spinning Globe

+ +

Tutorial 4: Spinning Globe

+

Given a global point layer and countries layer like this:

+

+

You can create a nice spinning globe effect like this:

+

+

I set up the animation workbench like this:

+

+

For the above animated GIF, I compressed it using imagemagick like this:

+
convert globe.gif -coalesce -resize 700x525 -fuzz 2% +dither -layers Optimize +map globe_small.gif
+
+

This is a handy technique if you want to generate small file size animations.

+

For the points I made a red marker using a quarter circle that spins around the points like this:

+

+

The rotation field expression is this:

+
if (@id = @hover_feature_id, 
+    0-((1440 * (@current_hover_frame/@hover_frames)) % 360),
+    0)
+
+

This will spin around 4 times during the hover cycle.

+

For the ocean (AOI in the layers list), I generated a grid of 1 degree cells covering the earth. You need to do it as smaller polygons instead of one large polygon because QGIS will run into issues reprojecting a single polygon whose edges lie on the date line.

+

Here is how the final video came out:

+ + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/guide/tutorial5/index.html b/user/guide/tutorial5/index.html new file mode 100644 index 0000000..9080c12 --- /dev/null +++ b/user/guide/tutorial5/index.html @@ -0,0 +1,1741 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 5 Planar Map - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Tutorial 5: Planar Map Animation

+

Given a global point layer and countries layer like this:

+

+

You can create a nice planar map animation effect like this:

+

+

In planar mode, we do not pan and zoom the map from feature to feature. Rather, the map zoom stays constant and the variables for

+
    +
  • current_hover_frame
  • +
  • hover_frames
  • +
  • hover_feature_id
  • +
+

are updated as we iterate over the features of your animation layer. In this +example project I duplicated the animation point layer twice. The first (lower) +copy is used to 'drive' the animation, whilst the second (upper) layer shows +only the feature currently being hovered over, with animation effects applied +to that feature.

+

I set up the animation workbench like this:

+

+

For the above animated GIF, I compressed it using imagemagick like this:

+
convert globe.gif -coalesce -resize 700x525 -fuzz 2% +dither -layers Optimize +map globe_small.gif
+
+

This is a handy technique if you want to generate small file size animations.

+

Expressions Used

+ +

Firstly for debugging, we use the following copyright label in View ⇒ +Decorations ⇒ Copyright Label. You can use the checkbox in the Copyright +configuration dialog to toggle this on and off. This will help you while +debugging / tweaking your animations. When you are ready to render your final +product, simply turn it off before rendering.

+
[%
+' \nRotation:' ||  to_string( 0-((1440 * (@current_hover_frame/@hover_frames)) % 360)) ||
+'\nFeature Variables:' ||
+' \n------------------------' ||
+' \nPrevious Feature ' || to_string(coalesce(attribute(@previous_feature, 'name'), '-'))  ||
+' \nPrevious Feature ID ' || to_string(coalesce(@previous_feature_id, '-'))  ||
+' \n' ||
+' \nNext Feature ' || to_string(coalesce(attribute(@next_feature, 'name'), '-'))  ||
+' \nNext Feature ID ' || to_string(coalesce(@next_feature_id, '-'))  ||
+' \n' ||
+' \nHover Feature ' || to_string(coalesce(attribute(@hover_feature, 'name'), '-'))  ||
+' \nHover Feature ID ' || to_string(coalesce(@hover_feature_id, '-'))  ||
+' \n' ||
+' \nFrom Feature ' || to_string(coalesce(attribute(@from_feature, 'name'), '-'))  ||
+' \nFrom Feature ID ' || to_string(coalesce(@from_feature_id, '-'))  ||
+' \n' ||
+' \nTo Feature ' || to_string(coalesce(attribute(@to_feature, 'name'), '-'))  ||
+' \nTo Feature ID ' || to_string(coalesce(@to_feature_id, '-'))  ||
+' \n' ||
+' \nTotal Hover Frames ' || to_string(coalesce(@hover_frames, 0))  ||
+' \nCurrent Hover Frame ' || to_string(coalesce(@current_hover_frame, 0))  ||
+' \nTotal Travel Frames ' || to_string(coalesce(@travel_frames, 0))  ||
+' \nCurrent Travel Frame ' || to_string(coalesce(@current_travel_frame, 0))  ||
+' \nTotal Frame Count ' || to_string(coalesce(@total_frame_count, 0))  ||
+' \nFrame Number ' || to_string(coalesce(@frame_number, 0))  ||
+' \nFrame Rate ' || to_string(coalesce(@frame_rate, 0))  ||
+' \nwith Current Animation Action: ' || @current_animation_action ||
+' \nTo Direction ' ||  coalesce(format_number(degrees(azimuth( geometry(@hover_feature), geometry(@previous_feature) ) ) ), 0) || 
+' \nFrom Direction ' ||  coalesce(format_number(degrees( azimuth( geometry(@hover_feature), geometry(@next_feature) ) ) ), 0)%]
+
+

Symbol Rotation

+

For the points I made a red marker using a quarter circle that spins around the +points like this:

+

+

The first line of the listing from the previous section gives you a hint about +how we can vary the rotation of a symbol depending on how far through the +animation sequence we are. With the addition of an if clause, we can apply +this rotation only to features that are being hovered over during the planar +animation.

+
if (
+  @id = @hover_feature_id, 
+  0-((1440 * (@current_hover_frame/@hover_frames)) % 360), 
+  0)
+
+

This if clause has the effect of excluding calculation for any feature that is not the current hover feature.

+

This will spin around 4 times during the hover cycle. This is because four +rotations are 4 x 360 = 1440. We calculate the percentage of completion for +the current hover frame (@current_hover_frame/@hover_frames) and then +multiply our rotation product by the current completion percentage. Lastly we +calculate the modulus of this (% 360) to compute how far along we are in +the current rotation. More advanced users could substitute 1440 with a project +variable so that it is easy to change the number of desired rotations in a +single place.

+

Symbol Size

+

The rotating symbol layer and the other symbol layers in our animation layer are +similarly hidden if the feature being rendered is not the hover_feature_id +using an expression like this:

+
if ( @id = @hover_feature_id,  10, 0)
+
+

This has the effect of setting the symbol size to 0 if it is not the feature we +are focussing on.

+

Other Planar Experiments

+

With the basic concepts of working with planar animations covered above, you can do other interesting things.

+

Generate a line

+

In this example, we can generate a line using the Geometry Generator function in QGIS. The line will start from the previous point, extend through the current point and terminate and the next point.

+

+
if ( 
+  $id = @hover_feature_id,
+   make_line(
+    geometry(@previous_feature),
+    geometry(@hover_feature),
+    geometry(@next_feature)
+  ),
+  $geometry)
+
+

We wrap it in an if clause again so that the line is not rendered if the +current feature being rendered is not the same as the current animation +feature.

+

There may be some edge cases where there is no previous or next feature. This +example does not try to deal with these cases but you could easily add some +logic that checks if each of the three components making up the line is null or +not.

+

Generate a curve

+

We can extend the above example by creating a curve rather than a line, for a +more natural looking connection between the hover feature and its previous and +following feature.

+

+
if ( 
+  $id = @hover_feature_id,
+   smooth(
+    make_line(
+      geometry(@previous_feature),
+      geometry(@hover_feature),
+      geometry(@next_feature)
+    ),
+    iterations:=1,
+    offset:=0.2,
+    min_length:=-1,
+    max_angle:=180),
+  $geometry)
+
+

If you increase the number of iterations, you can achieve a more and more +smoothed out line, at the expense of processing time.

+

+
if ( 
+  $id = @hover_feature_id,
+   smooth(
+    make_line(
+      geometry(@previous_feature),
+      geometry(@hover_feature),
+      geometry(@next_feature)
+    ),
+    iterations:=5,
+    offset:=0.2,
+    min_length:=-1,
+    max_angle:=180),
+  $geometry)
+
+

Subtring the Line

+

As a much more advanced example, you can extract a substring of the smoothed +line that connects the previous, current and next features. Don't get put off +by the with_variable elements - they just allow us to re-use calculations +in our expression.

+

First, let's start with extracting the first half of the smoothed line:

+

+
if ( 
+    $id = @hover_feature_id,
+    with_variable(
+        'smoothed_line',
+        smooth(
+          make_line(
+              geometry(@previous_feature),
+                geometry(@hover_feature),
+                geometry(@next_feature)
+          ),
+      iterations:=5,
+      offset:=0.2,
+      min_length:=-1,
+      max_angle:=180),
+          with_variable(
+              'line_length',
+          length(@smoothed_line),
+          line_substring(@smoothed_line, 0, @line_length / 2 ))),
+  $geometry)
+
+

Animating the substring

+

If we follow the same approach as above, but vary the start and length of the +line clip, we can create some cool line animation effects.

+

+
if ( 
+    $id = @hover_feature_id,
+    with_variable(
+        'smoothed_line',
+        smooth(
+          make_line(
+              geometry(@previous_feature),
+                geometry(@hover_feature),
+                geometry(@next_feature)
+          ),
+      iterations:=5,
+      offset:=0.2,
+      min_length:=-1,
+      max_angle:=180),
+          with_variable(
+              'line_length',
+          length(@smoothed_line),
+          line_substring(
+                    @smoothed_line, 
+                    @line_length * (@current_hover_frame/@hover_frames), 
+                    @line_length ))),
+
+  $geometry)
+
+
+

Final Render

+

There are still a few details that would need to be taken care of to reach a +final solution - in particular taking care of datelines and the like. But here is +a little example of what we managed to make thus far (without any debugging +text).

+

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/index.html b/user/index.html new file mode 100644 index 0000000..916ed59 --- /dev/null +++ b/user/index.html @@ -0,0 +1,1334 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + QAW - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

For Users

+ + +

This is the homepage for all user related documentation.

+

The user content is divided into three sections:

+
    +
  • The quickstart tutorial, which aims to get you familiar with the basics of platform in around 5 minutes.
  • +
  • The user guide, which describes common workflows in a tutorial format.
  • +
  • The user manual, which describes each page of the user interface and what the various options on that page do.
  • +
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/manual/faq/index.html b/user/manual/faq/index.html new file mode 100644 index 0000000..2ace3ea --- /dev/null +++ b/user/manual/faq/index.html @@ -0,0 +1,1464 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + FAQ - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + +

Frequently Asked Questions

+

Can I add any image to the intro or outro?

+

As long as you can provide the proper attribution for an image you can use it in your project.

+

I have an older, less powerful, computer, will it handle running this workbench?

+

If you open the standard QGIS settings dialog and select the Animation Workbench options +you can follow the advice with regards to lowering the number of threads allowed during +rendering to help you computer cope. Rendering shorter movies or GIFs (i.e. fewer frames) +will also help. Below is an example of running a job with 9000 frames at 60fps and 999 +frames per feature

+

imagem

+

And the subsequent CPU load during processing:

+

cpu

+

After processing:

+

imagem

+

And here is the resulting video:

+

https://youtu.be/1quc3xPdJsU

+

I get an error when rendering because of my intro / outro images

+

Currently your filenames should not contain spaces or special characters

+
.(, ), [, ], {, }, <, >, /, \, :, *, ?, |, ", &, etc.).
+
+

Can I use a movie as the intro / outro media?

+

This is planned but not yet implemented. Tim - check.

+

Can I pay you to add some features?

+

This is a fun / hobby project, currently we want other contributors who also want to +have a fun experience with building this plugin and contribute in-kind efforts to the +project. Both Kartoza and North-Road +offer commercial development services but not for this plugin which is a intended to +provide an experimental, no-pressure space for us to work on something fun for QGIS.

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/manual/img/001_AnimationPlan_SpherePlanar_1.png b/user/manual/img/001_AnimationPlan_SpherePlanar_1.png new file mode 100644 index 0000000..967fda0 Binary files /dev/null and b/user/manual/img/001_AnimationPlan_SpherePlanar_1.png differ diff --git a/user/manual/img/002_AnimationPlan_FixedExtent_1.png b/user/manual/img/002_AnimationPlan_FixedExtent_1.png new file mode 100644 index 0000000..adcde67 Binary files /dev/null and b/user/manual/img/002_AnimationPlan_FixedExtent_1.png differ diff --git a/user/manual/img/003_IntroTab_1.png b/user/manual/img/003_IntroTab_1.png new file mode 100644 index 0000000..17cf806 Binary files /dev/null and b/user/manual/img/003_IntroTab_1.png differ diff --git a/user/manual/img/004_OutroTab_1.png b/user/manual/img/004_OutroTab_1.png new file mode 100644 index 0000000..a8529a1 Binary files /dev/null and b/user/manual/img/004_OutroTab_1.png differ diff --git a/user/manual/img/005_SoundtrackTab_1.png b/user/manual/img/005_SoundtrackTab_1.png new file mode 100644 index 0000000..88d6560 Binary files /dev/null and b/user/manual/img/005_SoundtrackTab_1.png differ diff --git a/user/manual/img/006_OutputTab_1.png b/user/manual/img/006_OutputTab_1.png new file mode 100644 index 0000000..2ce8164 Binary files /dev/null and b/user/manual/img/006_OutputTab_1.png differ diff --git a/user/manual/img/007_ProgressTab_1.png b/user/manual/img/007_ProgressTab_1.png new file mode 100644 index 0000000..eb74433 Binary files /dev/null and b/user/manual/img/007_ProgressTab_1.png differ diff --git a/user/manual/img/008_NewProject_1.png b/user/manual/img/008_NewProject_1.png new file mode 100644 index 0000000..47595d3 Binary files /dev/null and b/user/manual/img/008_NewProject_1.png differ diff --git a/user/manual/img/009_AddLayers_1.png b/user/manual/img/009_AddLayers_1.png new file mode 100644 index 0000000..e35ebc6 Binary files /dev/null and b/user/manual/img/009_AddLayers_1.png differ diff --git a/user/manual/img/010_AddFeatures_1.png b/user/manual/img/010_AddFeatures_1.png new file mode 100644 index 0000000..0e35602 Binary files /dev/null and b/user/manual/img/010_AddFeatures_1.png differ diff --git a/user/manual/img/011_LayersList_10.png b/user/manual/img/011_LayersList_10.png new file mode 100644 index 0000000..1a15101 Binary files /dev/null and b/user/manual/img/011_LayersList_10.png differ diff --git a/user/manual/img/012_StyledLayers_1.png b/user/manual/img/012_StyledLayers_1.png new file mode 100644 index 0000000..2b5e803 Binary files /dev/null and b/user/manual/img/012_StyledLayers_1.png differ diff --git a/user/manual/img/013_FishAnimation_1.png b/user/manual/img/013_FishAnimation_1.png new file mode 100644 index 0000000..fdb71b2 Binary files /dev/null and b/user/manual/img/013_FishAnimation_1.png differ diff --git a/user/manual/img/014_EditExpression_1.png b/user/manual/img/014_EditExpression_1.png new file mode 100644 index 0000000..959a3dd Binary files /dev/null and b/user/manual/img/014_EditExpression_1.png differ diff --git a/user/manual/img/015_FishExpression_1.png b/user/manual/img/015_FishExpression_1.png new file mode 100644 index 0000000..3cb8421 Binary files /dev/null and b/user/manual/img/015_FishExpression_1.png differ diff --git a/user/manual/img/016_OpenAW_1.png b/user/manual/img/016_OpenAW_1.png new file mode 100644 index 0000000..81ed383 Binary files /dev/null and b/user/manual/img/016_OpenAW_1.png differ diff --git a/user/manual/img/017_AnimationPlan_1.png b/user/manual/img/017_AnimationPlan_1.png new file mode 100644 index 0000000..61e8877 Binary files /dev/null and b/user/manual/img/017_AnimationPlan_1.png differ diff --git a/user/manual/img/018_Output_1.png b/user/manual/img/018_Output_1.png new file mode 100644 index 0000000..327f720 Binary files /dev/null and b/user/manual/img/018_Output_1.png differ diff --git a/user/manual/img/animated-rotating-symbol.gif b/user/manual/img/animated-rotating-symbol.gif new file mode 100644 index 0000000..75362ce Binary files /dev/null and b/user/manual/img/animated-rotating-symbol.gif differ diff --git a/user/manual/img/flying-points.gif b/user/manual/img/flying-points.gif new file mode 100644 index 0000000..455d575 Binary files /dev/null and b/user/manual/img/flying-points.gif differ diff --git a/user/manual/img/make-line.png b/user/manual/img/make-line.png new file mode 100644 index 0000000..4d16f7d Binary files /dev/null and b/user/manual/img/make-line.png differ diff --git a/user/manual/img/manual_output.gif b/user/manual/img/manual_output.gif new file mode 100644 index 0000000..236afc5 Binary files /dev/null and b/user/manual/img/manual_output.gif differ diff --git a/user/manual/img/marker-offset.png b/user/manual/img/marker-offset.png new file mode 100644 index 0000000..89240d0 Binary files /dev/null and b/user/manual/img/marker-offset.png differ diff --git a/user/manual/img/rotated-symbol-properties.png b/user/manual/img/rotated-symbol-properties.png new file mode 100644 index 0000000..c7e7986 Binary files /dev/null and b/user/manual/img/rotated-symbol-properties.png differ diff --git a/user/manual/img/rotated-symbol.png b/user/manual/img/rotated-symbol.png new file mode 100644 index 0000000..9253113 Binary files /dev/null and b/user/manual/img/rotated-symbol.png differ diff --git a/user/manual/index.html b/user/manual/index.html new file mode 100644 index 0000000..690917d --- /dev/null +++ b/user/manual/index.html @@ -0,0 +1,1336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + QAW - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

User manual

+

Welcome to the QGIS Animation Workbench user manual. This section of the documentation describes the application and what the various components of each dialog do. The manual is intended to function as a reference for the application. For narrative / workflow based tutorials, you may prefer to work through our user guide. Here is a brief overview of the content provided here:

+
    +
  • : This section describes how to set up a project ready for use in creating an animation.
  • +
  • : This section describes the different elements of the main workbench UI.
  • +
  • : This section explains how the animation workbench functions internally.
  • +
  • : Here we provide various snippets as examples of how you can achieve different effects using the workbench.
  • +
  • : This is an exhaustive list of all of the variables exposed by the animation workbench.
  • +
  • : Still have questions? Here are some answers to common questions.
  • +
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/manual/project_preparation/index.html b/user/manual/project_preparation/index.html new file mode 100644 index 0000000..37fc724 --- /dev/null +++ b/user/manual/project_preparation/index.html @@ -0,0 +1,1434 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Preparing your project - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

How to set up a project to work with the animation plugin

+

1. The first step for getting an output using the Workbench is to create a QGIS Project +  +Open QGIS and click on ProjectNew

+

New Project

+

 

+

Next, add new layers to your project. You will want a few layers; one, or more, backing +layer(s) (vector layers or XYZ Tiles), a layer for the workbench to follow, and one, +or more, layer(s) of animated points. The example in this section only has one animated +layer. + 

+

To add a layer, go to LayerCreate Layer and then select the type of layer you +want to add. The example adds a point layer to a GeoPackage to make the project more +portable.

+

Add Layers

+

Once you have added your layers you need to add features to the layers. This is done +by selecting a layer and then clicking Toggle Editing (1) ➔ Add PointFeature (2). +Then click around on your map to add as few, or as many, features as you need.

+

Add Features

+

The example project has four layers: two point layers (3) and two backing layers (4).

+

Layer List

+
+

A simple way to add a vector base layer is to type "world" into the coordinate +textbox

+
+

Finally, style your layers to make your project look aesthetically pleasing. To +style your layers you must select the layer you want to style and then using the +Layer Styling toolbar, play around with the style of the layer until it suits you. A +good practice is to have your backing layers as more muted colours and your desired +features as more eye-catching colours.

+

Style Layers

+

  +You now have a QGIS Project. + 

+

2. The next step is to choose which features you want to be animated. + 

+

Pick the layer (or layers) that you want to have animations. Then either find, or create, +the animation for the layer. Make sure you have all the correct attribution for any +animations you use. Below is an example of a simple fish animation split into its frames. +The frames are repeated to slow down the animation's playback speed.

+

Fish Animation Frames

+
    +
  • Now use the QGIS Expressions system with the variables introduced by the Animation +Workbench to define behaviours of your symbols during flight and hover modes of your +animation. +  +Select the layer you want to animate and open the Layer Styling toolbar.
  • +
+
+

If you are using QGIS 3.26 you can simply use the new animated point symbol, +or if you're using an older version of QGIS 3.x follow the instructions below.

+
+

The layer should contain a Raster Image Marker. Once you have selected the marker you +want to use click on the QGIS Expressions dropdown menu (5) and click on Edit (6).

+

Edit Expression

+

 

+
+

You can also make a marker move along a line relative to the frame of the animation. +Use the Code Snippets Section for more in-depth help.

+
+

The example below works with the animation from earlier.

+

Expression Snippet

+
@project_home
+|| 
+'/fish/fish_00'
+||
+lpad(to_string( @frame_number % 32), 2, '0')
+||
+'.png'
+
+

3. Configure your animation

+

After animating your markers it's time to configure your animation. Open the Animated +Workbench and begin choosing between the different modes and options. + 

+

Open the Workbench by clicking the Animation Workbench (7) icon in the Plugin Toolbar.

+

Open Workbench

+

Configure the settings for your animation. The screenshot below is configured for +the example presented in this section. The Animation Layer is selected as route (8) +because that is the path that the output animation will fly along. The Zoom Range (9) was +selected from the Map Canvas Extent, and the Frame rate per second (fps) (10) was set to +match the number of frames of the animated markers so that they will play nicely in +the output. The other settings were selected as a personal choice.

+

Animation Plan

+

Select the Output Resolution (11) and a location for your output by clicking on the +ellipsis (three dots) or by typing in the desired file path (12).

+

Output Location

+
+

Refer to the Workbench User Interface section for more information about +what various settings and buttons accomplish.

+
+

4. Render your animation! +  +Click Run and render your output. The output below is the output from the example.

+

Output GIF

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/manual/snippets/index.html b/user/manual/snippets/index.html new file mode 100644 index 0000000..ee5ea7f --- /dev/null +++ b/user/manual/snippets/index.html @@ -0,0 +1,1595 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Expression Examples - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Snippets

+

🌏 QGIS Support

+

Should work with and version of QGIS 3.x. If you have QGIS 3.26 or better you can benefit from the animated icon support (see @nyalldawson's most excellent patch #48060).

+

For QGIS versions below 3.26, you can animate markers by unpacking a GIF image into its constituent frames and then referencing a specific frame from the symbol data defined property for the image file. Note that to do this extraction below you need to have the Open Source ImageMagick application installed:

+

First extract a gif to a sequence of images:

+
convert cat.gif -coalesce cat_%05d.png
+
+

Example of how to create a dynamically changing image marker based on the current frame count:

+
@project_home 
+||
+'/gifs/cat_000'
+|| 
+lpad(to_string( @frame_number % 48 ), 2, '0')
+|| 
+'.png'
+
+

Note that for the above, 48 is the number of frames that the GIF was composed of, and it assumes the frames are in the project directory in a subfolder called gifs.

+

Line of travel

+

In this example we use a geometry generator to create a line between the origin point and the destination point:

+
if (@from_feature_id = $id OR @to_feature_id = $id,
+ -- read this from inside to out so 
+ -- last tranform the geometry back to the map crs
+ transform( 
+  -- densify the geometry so that when we transform
+  -- back it makes a great circle
+  densify_by_count(  
+   -- move the geometry into a crs that 
+   -- shows a great circle as a straight line
+   transform( 
+    -- make a line from the previous pont to the next point
+    make_line( 
+     geometry(@from_feature), 
+     geometry(@to_feature)
+    ),  
+    @map_crs, 'EPSG:4326'),
+   99), 
+  'EPSG:4326',  @map_crs),
+ None)
+
+

Example output

+ +

Showing diagnostic information in the QGIS copyright label:

+
[%
+'Feature Variables:' ||
+' \n------------------------' ||
+' \nPrevious Feature ' || to_string(coalesce(attribute(@previous_feature, 'name'), '-'))  ||
+' \nPrevious Feature ID ' || to_string(coalesce(@previous_feature_id, '-'))  ||
+' \n' ||
+' \nNext Feature ' || to_string(coalesce(attribute(@next_feature, 'name'), '-'))  ||
+' \nNext Feature ID ' || to_string(coalesce(@next_feature_id, '-'))  ||
+' \n' ||
+' \nHover Feature ' || to_string(coalesce(attribute(@hover_feature, 'name'), '-'))  ||
+' \nHover Feature ID ' || to_string(coalesce(@hover_feature_id, '-'))  ||
+' \n' ||
+' \nFrom Feature ' || to_string(coalesce(attribute(@from_feature, 'name'), '-'))  ||
+' \nFrom Feature ID ' || to_string(coalesce(@from_feature_id, '-'))  ||
+' \n' ||
+' \nTo Feature ' || to_string(coalesce(attribute(@to_feature, 'name'), '-'))  ||
+' \nTo Feature ID ' || to_string(coalesce(@to_feature_id, '-'))  ||
+' \n' ||
+' \nTotal Hover Frames ' || to_string(coalesce(@hover_frames, 0))  ||
+' \nCurrent Hover Frame ' || to_string(coalesce(@current_hover_frame, 0))  ||
+' \nTotal Travel Frames ' || to_string(coalesce(@travel_frames, 0))  ||
+' \nCurrent Travel Frame ' || to_string(coalesce(@current_travel_frame, 0))  ||
+' \nTotal Frame Count ' || to_string(coalesce(@total_frame_count, 0))  ||
+' \nFrame Number ' || to_string(coalesce(@frame_number, 0))  ||
+' \nFrame Rate ' || to_string(coalesce(@frame_rate, 0))  ||
+' \nwith Current Animation Action: ' || @current_animation_action ||
+' \nTo Direction ' ||  coalesce(format_number(degrees(azimuth( geometry(@hover_feature), geometry(@previous_feature) ) ) ), 0) || 
+' \nFrom Direction ' ||  coalesce(format_number(degrees( azimuth( geometry(@hover_feature), geometry(@next_feature) ) ) ), 0)
+%]
+
+
+
+

Example output:

+

copyright-label

+

Variable size of labels

+

Variably changing the size on a label as we approach it in the animation:

+

```40 * ((@frame_number % @hover_frames) / @hover_frames)

+

+## Calculating the angle between points
+
+You can calculate the angle between the hover point and the previous point like this:
+
+```python
+coalesce(
+ format_number(
+  degrees( 
+   azimuth( 
+    geometry(@hover_feature), 
+    geometry(@previous_feature) 
+   )
+  )
+ ), 0)
+
+

Rotation

+

You can set the angle of rotation for a symbol using this expression:

+

Rotated Symbol Preview

+

Rotated Symbol Preview

+

Using this technique you can also create an animation effect showing the source +direction of travel and the new destination.

+
scale_linear (
+ @current_hover_frame,
+ 0,
+ @hover_frames,
+ degrees( 
+  azimuth( 
+   geometry(@hover_feature), 
+   geometry(@previous_feature) 
+  )
+ ),
+ degrees( 
+  azimuth( 
+   geometry(@hover_feature), 
+   geometry(@next_feature) 
+  )
+ )
+)
+
+

Will produce something like this:

+

Animated Rotated Symbol Preview

+

Flying points cluster

+

Here is an example where we animate all the points in a cluster that are not the hover point. We use an easing function to make the animation have an interesting circular motion.

+

Animated Flying Points Symbol Preview

+
-- Taken from https://spicyyoghurt.com/tools/easing-functions
+--    t = Time - Amount of time that has passed since the beginning of the animation. Usually starts at 0 and is slowly increased using a game loop or other update function.
+--    b = Beginning value - The starting point of the animation. Usually it's a static value, you can start at 0 for example.
+--    c = Change in value - The amount of change needed to go from starting point to end point. It's also usually a static value.
+--    d = Duration - Amount of time the animation will take. Usually a static value aswell.
+-- Sinusoidal
+-- -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
+
+-- Use with the animation in static mode
+if(@hover_feature_id != $id,
+array(
+  (-@hover_frames / 2) * (cos( (pi() * @frame_number / @hover_frames ) - 1)) ,
+ (-@hover_frames / 2) * (sin( (pi() * @frame_number / @hover_frames ) - 1)) 
+),
+array (0,0))
+
+
+

This function should be applied to the offset X,Y property of the symbol.

+

Offset

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/manual/under_the_hood/index.html b/user/manual/under_the_hood/index.html new file mode 100644 index 0000000..b220880 --- /dev/null +++ b/user/manual/under_the_hood/index.html @@ -0,0 +1,1382 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Under the hood - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

What is the Workbench doing?

+
    +
  • +

    What does the workbench do?

    +

    The workbench creates animations from QGIS by generating multiple static frames (images) +and then combining those frames into an animation. The user tells QGIS how the frames +should change from one to the other. In QGIS 3.26 and later the animated markers +allow markers to be animated without the use of the expressions system. + 

    +
  • +
  • +

    How do the animated markers work?

    +

    In the code snippet below, the user tells QGIS that as the frame count increments by +one the Raster Image Marker should change to the next image in the sequence.

    +

    Code Snippet

    +

    py + @project_home + || + '/fish/fish_00' + || + lpad(to_string( @frame_number % 32), 2, '0') + || + '.png'

    +

    The user specifies the path of the image (@project_home/fish/fish_00). Then the +lpad(to_string( @frame_number % 32), 2, '0') tells QGIS to convert the frame +number to a string and then modulus the number of frames by the number of animation +frames (32) (i.e. QGIS divides the number of frames by 32 and then repeats the +sequence when the remainder is zero). The 2 and '0' in the snippet tell +QGIS to pad the /fish/fish_00 with two zeroes at the end. Finally the '.png' tells +QGIS the type of file to finish off the path. + 

    +
  • +
  • +

    Frame Output location on Windows

    +

    For users on a Windows machine who are interested in seeing the frames before they +are combined into an animation (GIF or movie) you can find them by going to +"C:\Users\Username\AppData\Local\Temp\animation_workbench-0000000000.png". Bear in +mind that AppData is a hidden file, so it's preferable to not make changes unless +explicitly told otherwise. + 

    +
  • +
  • +

    Frame Output on Linux

    +

    The frames should be in your /tmp directory.

    +
  • +
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/manual/variables/index.html b/user/manual/variables/index.html new file mode 100644 index 0000000..c2f9a46 --- /dev/null +++ b/user/manual/variables/index.html @@ -0,0 +1,1636 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Expression Variables - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

🧮 QGIS Expression Variables

+

The animation workbench exposes or modifies a number of different QGIS Expression variables that you can use to achieve different dynamic rendering effects.

+

Common variables

+

These variables will always be available, regardless of the animation mode

+ + + + + + + + + + + + + + + + + + + + + +
VariableNotes
frame_numberFrame number within the current dwell or pan range.
frame_rateNumber of frames per second that the video will be rendered at.
total_frame_countTotal number of frames for the whole animation across all features.
+

Fixed extent mode variables (with layer)

+

These variables are available when in the fixed extent animation mode when a vector layer has been set

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
VariableNotes
hover_featureThe feature we are currently hovering over
hover_feature_idFeature ID for the feature we a current hovering over
previous_featureThe previously visited feature (or NULL if there isn't one)
previous_feature_idFeature ID for the previously visited feature (or NULL if there isn't one)
next_featureThe next feature to visit after the current one (or NULL if there isn't one)
next_feature_idFeature ID for the next feature to visit after the current one (or NULL if there isn't one)
current_hover_frameThe frame number for the current feature (i.e. how many frames we have hovered at the current feature)
hover_framesNumber of frames we will hover at the current feature for
current_animation_actionAlways "Hovering"
+

Planar/Sphere modes

+

These variables are available in the Planar or Sphere mode.

+ + + + + + + + + + + + + +
VariableNotes
current_animation_actionEither "Hovering" or "Travelling"
+

When hovering

+

These variables are available in planar or sphere mode, when the animation is currently hovering over a feature

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
VariableNotes
hover_featureThe feature we are currently hovering over
hover_feature_idThe feature ID for the feature we are currently hovering over
previous_featureThe previously visited feature (or NULL if there isn't one)
previous_feature_idFeature ID for the previously visited feature (or NULL if there isn't one)
next_featureThe next feature to visit after the current one (or NULL if there isn't one)
next_feature_idFeature ID for the next feature to visit after the current one (or NULL if there isn't one)
current_hover_frameThe frame number for the current feature (i.e. how many frames we have hovered at the current feature)
hover_framesNumber of frames we will hover at the current feature for
+

When travelling

+

These variables are available in planar or sphere mode, when the animation is currently travelling between two features

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
VariableNotes
from_featureThe feature we are travelling away from
from_feature_idThe feature ID for the feature we are travelling away from
to_featureThe feature we are heading toward
to_feature_idThe feature ID for the feature we are heading toward
current_travel_frameThe frame number for the current travel operation
travel_framesNumber of frames we will travel between the current features
+

Example expressions

+

Visit the snippets section of our documentation for example expressions.

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/manual/workbench_ui/index.html b/user/manual/workbench_ui/index.html new file mode 100644 index 0000000..3ba63c6 --- /dev/null +++ b/user/manual/workbench_ui/index.html @@ -0,0 +1,1649 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + The workbench user interface - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

The Workbench User Interface

+

Animation Plan

+

Sphere and Planar

+
    +
  • Render Modes (1): These determine the behaviour and type of animation
  • +
  • Sphere: The coordinate reference system (CRS) will be manipulated to create a + spinning globe effect. Like Google Earth might do, but with your own data and + cartography.
  • +
  • Planar: The coordinate reference system (CRS) will not be altered, but the camera + will pan and zoom to each point. It lets you move from feature to feature on a + flat map, pausing at each if you want to.
  • +
  • +

    Fixed extent: The frame of reference stays the same and you can animate the + symbology within that scene.

    +
  • +
  • +

    Animation Layer (2):

    +
  • +
  • Dropdown menu: This allows you to select which map layer you want the animation + to follow.
  • +
  • +

    Loop from final feature back to first feature: allows for a seamlessly looping + output GIF or movie(MP4).

    +
  • +
  • +

    Zoom Range (3): The scale range that the animation should move through.

    +
  • +
  • Minimum (exclusive): The zenith (highest point) of the animation when it zooms out + while travelling between points, i.e. the most "zoomed out".
  • +
  • +

    Maximum (inclusive): The scale (zoom level) used when we arrive at each point, + i.e. the most "zoomed in".

    +
  • +
  • +

    Data defined settings (4)

    +
  • +
  • +

    Scale

    +
      +
    • Minimum: User-defined minimum scale
    • +
    • Maximum: User-defined maximum scale
    • +
    +
  • +
  • +

    Animation Frames (5)

    +
  • +
  • Frame rate per second (fps): When writing to video or gif, how many frames per + second to use.
  • +
  • Travel Duration: This is the number of seconds that the animation will take during + animation from one feature to the next.
  • +
  • Feature Hover duration: This is the number of seconds that the animation will hover + over each feature.
  • +
+

Fixed Extent

+
    +
  • Extent (6):
  • +
  • Can be manually entered using North, East, South, and West coordinates as limits.
  • +
  • Can be calculated from a map layer, the layout map, or a bookmark.
  • +
  • Can be set to match the Map Canvas Extent
  • +
  • +

    Can be set as a rectangular extent using the Draw on Canvas feature.

    +
  • +
  • +

    Pan and Zoom Easings (7)

    +
  • +
  • What are Easings: Easings are transitions from one state to another along a smooth + curve. A user can specify the shape of the curve used.
  • +
  • Pan Easings (XY): The pan easing will determine the motion characteristics of the + camera on the X and Y axis as it flies across the scene (i.e. how it accelerates + or decelerates between points)
  • +
  • +

    Zoom Easing (Z): The pan easing will determine the motion characteristics of the + camera on the Z axis as it flies across the scene (i.e. how the camera zooms in + and out of the points)

    +
  • +
  • +

    Frame previews (8): A preview of what each frame of the animation will look like. A + user can decide which Frame to view.

    +
  • +
+

Intro Tab

+

Edit the intro section of the generated movie here.

+

Intro Tab

+
    +
  • Media: List of the various images or movies selected for the intro section. You can + drag and drop items in the list to change the play order.
  • +
  • Add Media (Plus sign) (1): Add images or movies
  • +
  • +

    Remove Media (Minus sign) (2): Remove images or movies

    +
  • +
  • +

    Duration (3): For images, you can set a duration for each image (in seconds).

    +
  • +
  • +

    Preview Frame (4): This shows what the media will look like.

    +
  • +
  • +

    Details: Provides details about where the media is stored on your computer.

    +
  • +
+

Outro Tab

+

Edit the outro section of the generated movie here.

+

Outro Tab

+
    +
  • Media: List of the various images or movies selected for the outro section. You can + drag and drop items in the list to change the play order.
  • +
  • Add Media (Plus sign) (1): Add images or movies
  • +
  • +

    Remove Media (Minus sign) (2): Remove images or movies

    +
  • +
  • +

    Duration (3): For images, you can set a duration for each image (in seconds).

    +
  • +
  • +

    Preview Frame (4): This shows what the media will look like.

    +
  • +
  • +

    Details: Provides details about where the media is stored on your computer.

    +
  • +
+

Soundtrack Tab

+

Soundtrack Tab

+
    +
  • Media: List of the various sound files (.mp3 or .wav) to play during the generated movie. + You can drag and drop items in the list to change the play order.
  • +
  • Add Media (Plus sign) (1): Add sound files (.mp3 or .wav) to play during the + generated movie.
  • +
  • +

    Remove Media (Minus sign) (2): Remove sound files (.mp3 or .wav)

    +
  • +
  • +

    Duration (3): The cumulative length of your soundtracks should be as long, or longer, + than your movie, including the intro/outro sections. If the soundtrack is longer + than the movie it will be truncated (shortened) when the movie ends.

    +
  • +
  • +

    Details: Provides details about where the media is stored on your computer.

    +
  • +
+

Output

+

Output Tab

+
    +
  • Output Options: Select which output format you would like. Regardless of the format chosen, + a folder of images will be created, one image per frame.
  • +
  • Re-use cached Images (1): This will not erase cached images on disk and will resume + processing from the last cached image.
  • +
  • Animated GIF (2): For this export to work, you need to have the ImageMagick 'convert' + application available on your system.
  • +
  • Movie (MP4) (3): For this option to work, you need to have the 'ffmpeg' application + on your system.
  • +
  • Output Resolution (4): Allows a user to specify one of four image resolutions + for the output animation. The numbers in brackets for the first three options represent + the width and height of the output in pixels (i.e. width x height), and the fourth + option matches the output's size to the size of the Map Canvas on the screen.
  • +
  • File selection (ellipsis) (5): This lets a user select the location where the output + will be stored.
  • +
+

Progress

+

Progress Tab

+
    +
  • Frame Preview (1): A preview of what each frame of the animation will look like. + It changes automatically as the workbench runs.
  • +
  • Progress (2): This provides a detailed look at what is happening while the workbench + runs.
  • +
  • Total Tasks: This number represents the total number of frames that will be generated + by the workbench.
  • +
  • Completed Tasks: The number of tasks that have completed being processed.
  • +
  • Remaining Features: The number of features from your animation layer that still need + to be processed.
  • +
  • Active Tasks: The number of tasks (threads) currently being run by the workbench
  • +
  • Features Complete: The number of tasks that have been processed by the workbench.
  • +
  • Logs (3): A detailed list of what steps the workbench is doing (a record of processing)
  • +
  • Progress Bar (4): A visual representation of the workbench's progression as a percentage.
  • +
+

Other Buttons

+
    +
  • Run: Starts the process of getting an output from the workbench. It is greyed out + until a user provides a destination for the output file.
  • +
  • Close: Closes the workbench.
  • +
  • Cancel: Ends the workbench processing at whatever point it has reached when the + button is pressed.
  • +
  • Help: Opens a link to the Animation Workbench documentation.
  • +
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/quickstart/configure/index.html b/user/quickstart/configure/index.html new file mode 100644 index 0000000..8ba5f9f --- /dev/null +++ b/user/quickstart/configure/index.html @@ -0,0 +1,1357 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Initial Configuration - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Initial Configuration

+

There is nothing really to configure! We do provide a few options in the +configuration dialog, but most users should not need to change them.

+

You can access the QGIS Animation Workbench plugin options by opening the standard +QGIS Setting dialog and clicking on the animation workbench tab.

+
+

Settings ➔ Options

+
+

Settings Dialog

+
    +
  • Animation Workbench plugin Options (1)
  • +
+

Currently there are just three configuration options:

+
    +
  • Number of concurrent render tasks (2): This is the number of concurrent tasks +that will be used to render animations. The default is 1.
  • +
  • Enable developer mode (3): This is a developer option that enables the developers +to see an icon in the toolbar which will start the debug remote server.
  • +
  • Verbose logging mode (4): This will add extra messages in the logging pane to +help you understand what is going on during the rendering process.
  • +
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/quickstart/img/001_PluginManager_1.png b/user/quickstart/img/001_PluginManager_1.png new file mode 100644 index 0000000..dbddb19 Binary files /dev/null and b/user/quickstart/img/001_PluginManager_1.png differ diff --git a/user/quickstart/img/002_SearchForPlugin_1.png b/user/quickstart/img/002_SearchForPlugin_1.png new file mode 100644 index 0000000..fdfe573 Binary files /dev/null and b/user/quickstart/img/002_SearchForPlugin_1.png differ diff --git a/user/quickstart/img/003_AWLaunch_1.png b/user/quickstart/img/003_AWLaunch_1.png new file mode 100644 index 0000000..5fb1680 Binary files /dev/null and b/user/quickstart/img/003_AWLaunch_1.png differ diff --git a/user/quickstart/img/004_NewProject_1.png b/user/quickstart/img/004_NewProject_1.png new file mode 100644 index 0000000..47595d3 Binary files /dev/null and b/user/quickstart/img/004_NewProject_1.png differ diff --git a/user/quickstart/img/005_AddLayers_1.png b/user/quickstart/img/005_AddLayers_1.png new file mode 100644 index 0000000..c4e140a Binary files /dev/null and b/user/quickstart/img/005_AddLayers_1.png differ diff --git a/user/quickstart/img/006_StylingLayers_1.png b/user/quickstart/img/006_StylingLayers_1.png new file mode 100644 index 0000000..3a71fac Binary files /dev/null and b/user/quickstart/img/006_StylingLayers_1.png differ diff --git a/user/quickstart/img/007_AnimatedLayer_1.png b/user/quickstart/img/007_AnimatedLayer_1.png new file mode 100644 index 0000000..e812ba6 Binary files /dev/null and b/user/quickstart/img/007_AnimatedLayer_1.png differ diff --git a/user/quickstart/img/008_EditExpression_1.png b/user/quickstart/img/008_EditExpression_1.png new file mode 100644 index 0000000..008f6e6 Binary files /dev/null and b/user/quickstart/img/008_EditExpression_1.png differ diff --git a/user/quickstart/img/009_Expression_1.png b/user/quickstart/img/009_Expression_1.png new file mode 100644 index 0000000..586268a Binary files /dev/null and b/user/quickstart/img/009_Expression_1.png differ diff --git a/user/quickstart/img/010_OpenAW_1.png b/user/quickstart/img/010_OpenAW_1.png new file mode 100644 index 0000000..ecc7403 Binary files /dev/null and b/user/quickstart/img/010_OpenAW_1.png differ diff --git a/user/quickstart/img/011_OutputSetup_1.png b/user/quickstart/img/011_OutputSetup_1.png new file mode 100644 index 0000000..268d3c8 Binary files /dev/null and b/user/quickstart/img/011_OutputSetup_1.png differ diff --git a/user/quickstart/img/012_Output_1.png b/user/quickstart/img/012_Output_1.png new file mode 100644 index 0000000..6046617 Binary files /dev/null and b/user/quickstart/img/012_Output_1.png differ diff --git a/user/quickstart/img/013_Configure_1.png b/user/quickstart/img/013_Configure_1.png new file mode 100644 index 0000000..e204c5d Binary files /dev/null and b/user/quickstart/img/013_Configure_1.png differ diff --git a/user/quickstart/img/QAW-IntroThumbnail.jpg b/user/quickstart/img/QAW-IntroThumbnail.jpg new file mode 100644 index 0000000..aa6ecf5 Binary files /dev/null and b/user/quickstart/img/QAW-IntroThumbnail.jpg differ diff --git a/user/quickstart/img/install_0000.png b/user/quickstart/img/install_0000.png new file mode 100644 index 0000000..43cd45e Binary files /dev/null and b/user/quickstart/img/install_0000.png differ diff --git a/user/quickstart/img/install_0001.png b/user/quickstart/img/install_0001.png new file mode 100644 index 0000000..c8e2f8e Binary files /dev/null and b/user/quickstart/img/install_0001.png differ diff --git a/user/quickstart/img/install_0002.png b/user/quickstart/img/install_0002.png new file mode 100644 index 0000000..4d38398 Binary files /dev/null and b/user/quickstart/img/install_0002.png differ diff --git a/user/quickstart/img/install_0003.png b/user/quickstart/img/install_0003.png new file mode 100644 index 0000000..7cdec8b Binary files /dev/null and b/user/quickstart/img/install_0003.png differ diff --git a/user/quickstart/img/options.png b/user/quickstart/img/options.png new file mode 100644 index 0000000..d199aa7 Binary files /dev/null and b/user/quickstart/img/options.png differ diff --git a/user/quickstart/img/output.gif b/user/quickstart/img/output.gif new file mode 100644 index 0000000..0fd24ef Binary files /dev/null and b/user/quickstart/img/output.gif differ diff --git a/user/quickstart/index.html b/user/quickstart/index.html new file mode 100644 index 0000000..b0ea755 --- /dev/null +++ b/user/quickstart/index.html @@ -0,0 +1,1328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + QAW - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Quickstart

+

Content needed

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/quickstart/install/index.html b/user/quickstart/install/index.html new file mode 100644 index 0000000..399a258 --- /dev/null +++ b/user/quickstart/install/index.html @@ -0,0 +1,1444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Installation - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Installing the QGIS Animation Workbench plugin

+

In this section we explain how to install the plugin.

+

Install from plugin manager

+

To access the QGIS Plugin Manager you simply need to select +PluginsManage and Install Plugins... (1) in the Menu Toolbar.

+

Plugin Repository

+

Once the QGIS Plugin Manager loads, you need to navigate to the All (2) +tab and type "animation" into the search bar (3). Select QGIS Animation +Workbench from the list of available plugins and then select Install Plugin +(4).

+

Search For and Install Plugin

+

Once the Animation Workbench is installed, you can access it by clicking on the +Animation Workbench icon (5) in the Plugin Toolbar.

+

Launch the Workbench

+
+

Note if you are on Ubuntu, you may need to install the Qt5 multimedia +libraries.

+
+
sudo apt install PyQt5.QtMultimedia
+
+

Manual install from GitHub (tagged release)

+

To install, visit the Github +Repository, click on the +Actions tab, and click on the Make QGIS Plugin Zip For Manual Installs +workflow (the bottom one).

+

Install 0000

+

Click on the most recent workflow run (the top one).

+

Install 0001

+

Scroll down on the on the page.

+

Install 0002

+

And click on animation_workbench to download the most recent build of the plugin

+

Install 0003

+

Download the animation_workbench.zip file and open it in QGIS using the plugin +manager as described below.

+
    +
  1. Open QGIS
  2. +
  3. Plugins ➡ Manage and install plugins ...
  4. +
  5. Choose the Install from zip tab +image
  6. +
  7. Select the animation_workbench.zip download
  8. +
  9. Click the Install Plugin button.
  10. +
+
+

Note if you are on Ubuntu, you may need to install the Qt5 multimedia +libraries.

+
+
sudo apt install PyQt5.QtMultimedia
+
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user/quickstart/using/index.html b/user/quickstart/using/index.html new file mode 100644 index 0000000..4315856 --- /dev/null +++ b/user/quickstart/using/index.html @@ -0,0 +1,1480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Using the Workbench - QGIS Animation Workbench + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Using the Animation Workbench

+

In this section, we describe the general workflow for using the Animation Workbench.

+

Process Overview

+
    +
  1. Create a QGIS project!
  2. +
  3. Identify features that will be animated.
  4. +
  5. Use the QGIS Expressions system with the variables introduced by the Animation + Workbench to define behaviours of your symbols during flight and hover modes of your + animation.
  6. +
  7. Open the Animation Workbench and configure your animation, choosing between the + different modes and options.
  8. +
  9. Render your animation!
  10. +
+

More in Depth Process

+

1. Create a QGIS Project +  +Open QGIS and click on ProjectNew

+

New Project

+

 

+

Add new layers to your project

+

Add Layers

+
+

A simple way to add a base layer is to type "world" (1) into the coordinate +textbox

+
+

Style the layers you've added to make your project look a bit better. Select the +layer (2) you want to style and in the Layer Styling toolbar (3), style the layer to +look appealing to you.

+

Style Layers

+

 

+

2. Identify features that will be animated. + 

+

Pick the layer (or layers) that you want to animate. Then either find or create the +animation for the layer. Make sure you have all the correct attribution for any +animations you use. Below is an example of an animation split into its frames.

+

Animation Frames

+

3. Use the QGIS Expressions system with the variables introduced by the Animation +Workbench to define behaviours of your symbols during flight and hover modes of your +animation. + 

+

Select the layer you want to animate and open the Layer Styling toolbar.

+
+

If you are using QGIS 3.26 you can simply use the new animated point symbol, +or if you're using an older version of QGIS 3.x follow the instructions below.

+
+

The layer should be a Raster Image Marker. Once you have selected the image you +want to use click on the QGIS Expressions dropdown menu (4) and click on Edit (5).

+

Edit Expression

+

  +Use the Code Snippets Section for more in depth help. The +example below works with the bird animation from earlier

+

Expression Snippet

+
   @project_home
+   ||
+   '/bird/bird_00'
+   || 
+   lpad(to_string(@frame_number % 9), 2, '0')
+   || 
+   '.png'
+
+

1. Open the Animation Workbench and configure your animation, choosing between the +different modes and options. + 

+

Open the Workbench by clicking the Animation Workbench (6) icon in the Plugin Toolbar.

+

Open Workbench

+

Configure the settings for your animation. The screenshot below is configured for +the example presented in this section. The Animation Layer is selected as route (7) +because that is the path the animation will fly along, the Zoom Range (8) was selected +from the Map Canvas Extent, and the Frame rate per second (9) was set to 9 to match +the bird animation.

+

Output Setup

+

Set your desired Output Options (10) Select a location for your output (11).

+

Output Location

+
+

Refer to the Workbench User Interface Section for more information about +what various settings and buttons accomplish.

+
+

2. Render your animation! +  +Click Run and render your output. The output below is the output from the example.

+

Output

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file