Advertising Inquiries? Click here for our ad rates and policies.
GamesFirst! is a longstanding independent online videogame magazine. GamesFirst! Internet Magazine was founded in 1995 by Zap Reicken and Cactus Computers in Moscow, Idaho. The domain was registered in 1996, and GF! became one of the first PC gaming websites online.
In 1998, GamesFirst! was bought by Rick Fehrenbacher and Al Wildey, two professors at the University of Idaho. In 1999, GamesFirst! attended E3 for the first time, and the site also began its multiplatform gaming coverage that year with the addition of Shawn Rider as the Consoles section editor.
Together, these three defined the direction of GF! for the years to come: Thoughtful and candid content. Games are for everyone. Games are a form of art. Games are worthy of study and attention. It is an adherence to these tenets that has guided GF! ever since.
By 2001 the \"consoles\" section had become absorbed into the main site, and GF! had firmly established itself as a presence in gaming journalism. The site was sold once again, this time to former Consoles Editor, Shawn Rider and longtime GF! writers Sarah Wichlacz and Jeff Luther. The site has remained under the same ownership, with the exception of Jeff Luther, who stepped away from the site in 2004.
Shawn and Sarah continue to own GF!, and Aaron Stanton has come on to fill the role of Assistant Editor. Aaron has been with the site since 2000, when he began as a PC reviewer. In August of 2005, as a part of our 10th Anniversary celebration, Shawn recoded the site into its most advanced incarnation yet. In 2005, GF! also launched two major new features: Twoplayer Comic, and the GF! Weekly Wrap-Up Podcast, both of which are weekly publications created by GF! Staff.
Of course GamesFirst! would be nothing without the many talented individuals who have poured their hearts into the site. The site is a collaborative effort, and everyone at GF! is motivated by a love of games and gaming. With correspondents all over the world, GF! has managed to remain a force in online gaming journalism.
Shawn Rider || View full profile.
Aaron Stanton || View full profile.
Sarah Wichlacz || View full profile.
Eric Qualls || View full profile.
Chris Martin || View full profile.
Tristan Mayshark || View full profile.
David Mackiewicz || View full profile.
Andy Blair || View full profile.
Matt Baldwin || View full profile.
Matt James || View full profile.
Monica Hafer || View full profile.
Jeremy Kauffman || View full profile.
Rick Fehrenbacher || View full profile.
Noah Kroese || View full profile.
Jamie Gergen || View full profile.
Jason Perkins || View full profile.
Amanda Bateman || View full profile.
Sean Hilliard || View full profile.
RJ Brooks || View full profile.
Drew Celestino || View full profile.
Chris Galbraith || View full profile.
Eric Bodrero || View full profile.
Blaine Krumpe || View full profile.
George Holomshek || View full profile.
Steffan Del Piano || View full profile.
Laurie Taylor || View full profile.
Jason Frank || View full profile.
Val Townsend || View full profile.
James Gardiner || View full profile.
GamesFirst! is a trademark of GamesFirst! Magazine. All other product, brand and publication names are registered trademarks or trademarks of their respective companies. All copyrights are held by GamesFirst! Magazine or their respective owners. Some of the game description text and product names may have been used without permission. No challenge is intended to the status of any trademarks or copyrights, and their use without the appropriate symbols should not be construed as a challenge to such status. GamesFirst! Magazine does not make any representation or warranty, expressed or implied, with respect to any information herein. GamesFirst! Magazine disclaims any liability whatsoever for any use of such information.


Universal Upholstery combine quality products with highly skilled craftsmanship to create beautifully re-trimmed vehicles such as VW Transporters, Motorhomes and Static Caravans. With each project being tailored to the customer's choice, a range of high quality products are essential to the end result Universal Upholstery is so well known for.
Once we at Boyriven understood the specification of the materials needed, we arranged for a sample card to be sent to the customer in order for a fabric selected.
Two colours had been chosen for the vehicle; however the finish was not quite what the customer was looking for. We worked with our supplier to source an exclusive material outside of our standard ranges to meet the requirements.


The location is currently planned for the entrance of the County Administration building. Get there a little early. If it's moved, there will be signs redirecting you.
Community forum on Truth Act Forum on Sheriff – ICE collaboration – 3:30 pm.
The Board of Supervisors will be holding a community forum to provide information to the public concerning Immigration & Customs Enforcement (ICE) access to any individuals housed in county jail facilities. This forum is required to comply with requirements of the 2017 Assembly bill 2792, – "Transparent Review of Unjust Transfers and Holds (TRUTH)" Act.
Posted on December 3, 2018 by indivisibleventuraTagged 805immigrant.org, CAUSE, County Board of Supervisors, Gun Control, Gun show, Indivisible Ventura, Truth Act Forum.
Previous Previous post: Mon – 12/3: They stop our breath in wonder when we see them. When we hear them. Now it's time to fight for them.
Next Next post: Tues 12/4: Enroll now. For us Californians, the deadline is Jan. 15th.


VHeadline.com : Thursday, September 26, 2002 — During the past few days, representatives of the International Press Institute (IPI) and the Inter-American Press Society (SIP) have been in Venezuela to evaluate the situation of the mass media here.
I don't know why they came.
The main front-page story in El Nacional Monday said that IPI president Jorge Fascetto sees President Chavez Frias as another Peron, Fujimori or Stroesner … and Vice-president Rangel as another Montesinos.
He and his friends came to evaluate?
Well, dear representatives of SIP and IPI, listen to all the crocodile-tear stories of the commercial media that you want to and publish the reports that you wrote before you came. But here's a media story to which you didn't listen, and for which the reader doesn't have to pay. And let me warn you there are a lot more such stories in Venezuela. Little by little, they will come out, and the world will hear about them. Many have already been written in the alternative press and told by alternative radio and TV stations … it's just that your commercial press friends are afraid to publish them.
This is the story of Nicolas Rivera Muentes about what happened to him while President Chavez Frias was not in power, and what the democratic opposition have managed to do with him since.
Nicolas is the 26-year-old father of three children (ages 4, 4 and 2). His family lives in the working class suburb of Caricuao, where he is employed as a supervisor of children under the care of the National Institute of Children (INAM).
He is also a director of Radio Perola … a community radio station in Caricuao, one of about 150 volunteers who keep the station on air. As one of the stations announcers, he had a music program called SOLO SALSA (Only Salsa).
On April 12 … the day that Mr. Carmona Estanga declared himself President of Venezuela … Radio Perola was raided by the PTJ police. There was no one there. At 9:00 p.m., the police raided the INAM offices where Nicolas worked, forced him into a vehicle and then drove him around the area for several hours.
(In Venezuela this is called "ruleteo" … a common name for an illegal police process which consists in putting person in a vehicle, driving him/her around without a definite destination while s/he is harassed, interrogated or beaten!).
Nicolas was beaten continually while he was asked for information about the radio station's equipment and about the other volunteers at the station. He was taken home at 1:00 a.m. April 13. His house was raided and, in the presence of his father, mother, wife, brothers (ages 25, 15 and 15), brother-in-law and children, Nicolas was beaten again for approximately two hours. Afterwards, he was again "ruleteado" and threatened with death if he didn't take them to the radio transmitter.
At one moment he was taken out of the vehicle, beaten, kicked and hit with weapons. He was then taken to PTJ headquarters and again beaten. He was kept there without food or water until April 14, when the coup had already failed. He had been charged for complicity in an intentional homicide, but the spurious charge was thrown out by another judge and he was released.
All of this information was taken from a complaint made to the Inter-American Commission of Human Rights of the Organization of American States (OAS), May 10, 2002.
These actions were also reported to the local police. Not having received any response, Nicolas went to the PTJ on June 28, accompanied by his wife and some friends. He was arrested again, supposedly appearing in a video shooting a weapon, and since that time has been imprisoned as a common criminal. Friends tell me he carried a tape-recorder with him that day.
Other members of the family were also handcuffed and Nicolas' father pulled by his hair.
When I visited with the family yesterday afternoon, Nicolas mother had just returned from talking to a government Human Rights official. One of her children asked her "Did you cry, Mom?" She just looked at him. There was no need to reply.
She told me that Nicolas had always been a dreamer, hoping for a better and more just world.
She was also concerned about her other children, especially the boys who are still volunteers with Radio Perola. While we were conversing, one of the boys shook my hand and went out the door.
Having finished our conversation and while walking in the direction of the bus stop, a friend turned on his portable radio: Good afternoon and welcome again to 'SOLO SALSA.' This is your host, Victor Hugo Rivera. It was a voice I had heard moments before. Now it was coming over Radio Perola. It was Nicolas' teenage brother.
Now the whole world knows something about an authentic journalist in Venezuela that the representatives of the SIP and the IPI don't seem to care about. Do you?
There's a dreamer in prison here in Venezuela … but his dream is still free.


"Stop telling me I only have eighteen summers with my kids.
Stop telling me I only have nine hundred and forty Saturday's with them. Well that number is a lot lower for me now.
Stop telling me to soak it all up and enjoy every moment.
You know what's stressing me out in motherhood? Blogs and posts and books that are telling me all of those things.
Stressing me out so much I can't enjoy it because I'm too busy stressing and doing the math to find out how many Saturday's or summers or enjoyable moments I have left or how many I've already missed out on.
Y'all some parents were only blessed with one Summer with their baby, some don't enjoy every single minute or moment because they are the proud parents of a screaming toddler or a teenager that they don't even recognize right now.
Some parents never even get one Saturday with their child because they never made it that far.
So, stop telling me what I'm missing, stop telling me how many summers I have or Saturday's and that it's all so limited and stop telling me I'm a bad mom if I don't enjoy every single flipping minute of motherhood during those Saturday's or summers.
Stop telling me all of those things because the truth is none of us are promised one more minute, one more day.
We are not promised one more summer or one more Saturday or even one more moment to enjoy or not enjoy.
So, instead remind me to enjoy it when I can and tell me it's okay on the days that I don't really find it too fun to have a toddler pull a complete meltdown in the middle of the store.
Then remind me if I'm really blessed I'll get to see my grown-up kids after they are eighteen not just on Saturday's or during the summer but a lot more days of the week.
So, stop telling me it's all going to end, and I better enjoy it because have mercy you are stressing me out more than motherhood ever could.
Now if you'll excuse me I am going to go back outside with my three guys while we enjoy this non-eventful Sunday.
One that's not crammed with all the things we need to do before they turn eighteen or before my nine hundred and forty Saturday's dwindle down even more.
This story was written by Nikki Pennington of Grief To Hope with Nikki Pennington. The article originally appeared here. Submit your story here, and subscribe to our best love stories here.
Provide hope for someone struggling. SHARE this story on Facebook with your friends and family.


Click to save big with 22 latest 2017 Happy Crafters coupons & promo codes. Check out the best happy crafters coupon of November 2017 now.
Happy Crafters Promo Codes for June, 2018. Save with 2 active Happy Crafters promo codes, coupons, and free shipping deals. 🔥 Today's Top Deal: Save 18% Off On Happy Face Pattern Iron On Vinyl - Grey Wooden Snowflakes.
Happy Crafters, Morgantown, West Virginia. 154,540 likes · 1,495 talking about this · 57 were here. Exclusive deals and give-a-ways for HappyCrafters.com!
Get 30 Happy Crafters coupon codes and promo codes at CouponBirds. Click to enjoy the latest deals and coupons of Happy Crafters and save up to 40% when making purchase at checkout.
Up to 10% off Happy Crafters items + Free P&P at Happy Crafters. 7 Happy Crafters promo codes and coupons for June 2018. Offers end soon!
Happy_Crafters shares 30 coupon codes and promo codes. Get 30% off discount and save money online.


Download treating the trauma survivor an essential guide to trauma informed care in pdf or read treating the trauma survivor an essential guide to trauma informed care in pdf online books in PDF, EPUB and Mobi Format. Click Download or Read Online button to get treating the trauma survivor an essential guide to trauma informed care in pdf book now. This site is like a library, Use search box in the widget to get ebook that you want.
Medical informatics is a field which continues to evolve with developments and improvements in foundational methods, applications, and technology, constantly offering opportunities for supporting the customization of healthcare to individual patients. This book presents the proceedings of the 16th World Congress of Medical and Health Informatics (MedInfo2017), held in Hangzhou, China, in August 2017, which also marked the 50th anniversary of the International Medical Informatics Association (IMIA). The central theme of MedInfo2017 was "Precision Healthcare through Informatics", and the scientific program was divided into five tracks: connected and digital health; human data science; human, organizational, and social aspects; knowledge management and quality; and safety and patient outcomes. The 249 accepted papers and 168 posters included here span the breadth and depth of sub-disciplines in biomedical and health informatics, such as clinical informatics; nursing informatics; consumer health informatics; public health informatics; human factors in healthcare; bioinformatics; translational informatics; quality and safety; research at the intersection of biomedical and health informatics; and precision medicine. The book will be of interest to all those who wish to keep pace with advances in the science, education, and practice of biomedical and health informatics worldwide.
Somatic Methods for Affect Regulation is a unique resource that presents a variety of approaches for working somatically with youth. Chapters provide an overview of the relevant neuroscience research with a specific focus on affect regulation. The somatic techniques showcased in the book are evidence-based and illustrated with case studies showing their impact. Importantly, the chapters are also chock full of practical information, including strategies for working with dysregulated youth, information for collaborative and cooperative care, and an appendix with checklists and worksheets to help clinicians plan, guide, and assess their work.
COMPRARE e affittare CASA alle CANARIE: Costi, tasse, spese e guadagni di un immobile a reddito a Gran Canaria.


Kim has written a series of articles published in a state-wide Minnesota magazine, the CMR Resorter Reporter, over the last 15 years. Green cleaning has been a big priority since day one of resort ownership. The articles were meant to share wisdom with other fellow resorters as the Community of Minnesota Resorts motto is: resorters helping resorters. Some guests may be interested in articles -but mostly, they just want the recipes of Natural Cleaning Solutions left in cabins for them to use. HA! Here ya go, peeps: RECIPES HERE.
To bleach or not to bleach . . .
For a healthy RESORT, and a healthy YOU!
18 second clip of Lake in September . . .


text:
2020 Tour de France route revealed | Gravel, 29 categorised climbs, 4 summit finishes, no TTT
Mountain time trial on La Planche des Belles Filles is set to be the definitive stage of the 2020 Tour de France
By Colin Henrys
Published: August 14, 2020 at 12:00 pm
A mountain time trial on La Planche des Belles Filles is set to be the definitive stage of the 2020 Tour de France – which starts in Nice on Saturday 29 August – with this year's race set to feature a varied and testing route.
At the route launch, Tour de France director Christian Prudhomme introduced a race which, as ever, features key stages in the Pyrenees and the Alps but in which the final battles will be staged in the Vosges Mountains.
The highlight of the race will be the penultimate stage, a time trial starting in Lure and concluding on the Planche des Belles Filles. The 36km test is the only time trial on the 2020 route.
8 key climbs from the 2020 Tour de France | Epic ascents to watch or ride
Etape du Tour to start in Nice and tackle three climbs in Southern Alps
2020 WorldTour team bikes guide
La Planche des Belles Filles itself is 5.9km long, with an average gradient of 8.5 per cent. There is a real sting in the tail as the gradient approaches one-in-four near the top, however.
Among the four summit finishes on the route are the Alpine ski resort of Orcières-Merlette 1850, Mont Aigoual and Puy Mary in the Central Massif, and Grand Colombier in the Juras.
Intermediate climbs include the Col de la Lusette, Col de Peyresourde, Col de la Hourcere, Col de Marie-Blanque, Montee de la Selle de Fromentel, Col de la Madeleine and the gravel-covered Montee de Plateau des Glieres.
All six of France's mountain ranges are covered by the route, which for 2020 stays entirely within France.
A mountain time trial on La Planche des Belles Filles will be the definitive stage of the 2020 Tour de France.
Tour de France / ASO
Nice Grand Départ
It was already known the 2020 Tour de France would roll out from Nice, with the race now set to begin on Saturday 29 August. The race was due to take place in July but was postponed due to the coronavirus pandemic.
The race starts with a 156km opening stage composed of two loops of a small circuit around Nice and one bigger circuit, with a flat finale expected to suit the sprinters.
Stage two is the first climbing test – a 190km stage that starts and finishes in Nice and includes the Col de la Colmiane, Col de Turini and Col d'Eze. The route will also be used for the Etape du Tour sportive, which will now take place in 2021.
Early climbing tests
The peloton faces another big climbing test on stage four, when the ski resort of Orcières-Merlette (1,825m) hosts the stage finish – a hairpin-laden, 7.1km final ascent with an average gradient of 6.7 per cent.
It will be the first stage to finish atop the resort since a time trial in 1989.
Another climb returning for the first time in more than three decades is Mont Aigoual – last featured in 1987 – where stage six concludes at 1,560m. The stage also includes the Col de la Lusette (11.7km at 7.3 per cent).
The first week concludes in the Pyrenees, before a flat, coastal stage between Île d'Oléron and Île de Ré starts week two – a stage on which crosswinds could be a major factor.
The Col du Grand Colombier is the final climb of the second week of racing – the summit finish to stage 15 on Saturday 12 July.
Peaking at 1,501m, the peloton will tackle the southern ascent – a 17.4km climb with an average gradient of 7.1 per cent.
Egan Bernal flourished in the mountains at the 2019 Tour de France to claim his first title.
Zac Williams/SWPix.com
Mountain time trial
The final week then includes stage finishes at Villard-de-Lans and the stunning Col de la Loze – the race's highest summit finish at 2,304m – before the eagerly-awaited time trial up La Planche des Belles Filles.
The race concludes, as ever, on the Champs-Élysées in Paris with a largely ceremonial stage ending with the traditional final sprint battle on the famous avenue on Sunday 20 September.
Bernal won last year's Tour de France, taking the yellow jersey from Julian Alaphilippe on a rain-shortened 19th stage to seal victory for the first time ahead of the Paris finale.
The Colombian was the first rider to win the race for Team Ineos since it took over the sponsorship of the former Team Sky.
Between Sir Bradley Wiggins, Chris Froome, Geraint Thomas and now Bernal, the team has won seven of the last eight editions of the race.
Bernal leads the team again this year and is among the favourites for the yellow jersey, while the mountain time trial in Thibaut Pinot's backyard on stage 20 should excite the Frenchman.
With more climbs and no long, flat time trials, Pinot, Bernal and Romain Bardet could all feature at the sharp end of the battle for the yellow jersey.
Stage 20 will pass right through the backyard of Thibaut Pinot.
SWpix.com (t/a photography hub Ltd)
Tour de France 2020: route
Saturday 29 August – stage one: Nice to Nice (156km)
Sunday 30 August – stage two: Nice to Nice (187km)
Monday 31 August – stage three: Nice to Sisteron (198km)
Tuesday 1 September – stage four: Sisteron to Orcières-Merlette 1,850 (157km, summit finish)
Wednesday 2 September – stage five: Gap to Privas (183km)
Thursday 3 September – stage six: Le Teil to Mont Aigoual (191km, summit finish)
Friday 4 September – stage seven: Millau to Lavaur (168km)
Saturday 5 September – stage eight: Cazeres to Loudenvielle (140km)
Sunday 6 September – stage nine: Pau to Laruns (154km)
Monday 7 September – rest day one
Tuesday 8 September – stage ten: Île d'Oléron to Île de Ré (170km)
Wednesday 9 September – stage 11: Chatelaillon-Plage to Poitiers (167km)
Thursday 10 September – stage 12: Chavigny to Sarran (218km)
Friday 11 September – stage 13: Chatel-Guyon to Puy Mary (191km, summit finish)
Saturday 12 September – stage 14: Clermont-Ferrand to Lyon (197km)
Sunday 13 September – stage 15: Lyon to Grand Colombier (175km, summit finish)
Monday 14 September – rest day two
Tuesday 15 September – stage 16: Tour du Pin to Villard-de-Lans (164km, summit finish)
Wednesday 16 September – stage 17: Grenoble to Méribel (168km, summit finish)
Thursday 17 September – stage 18: Méribel to La Roche-sur-Foron (168km)
Friday 18 September – stage 19: Bourg-en-Bresse to Champagnole (160km)
Saturday 19 September – stage 20: Lure to La Planche des Belles Filles (individual time trial, 36km)
Sunday 20 September – stage 21: Mantes-la-Jolie to Paris (122km)
When does the 2020 Tour de France start?
The 2020 edition of the Tour de France will now start in Nice on Saturday 29 August.
Colin Henrys
Colin is a freelance sports journalist who first started reporting on cycling during the 2013 Tour de France on a month-long internship with RoadCyclingUK. The cycling bug bit so hard he was still there when Geraint Thomas rode to victory five years later. Much more comfortable writing about other people riding bikes than doing so himself, he remains unconvinced of the merits of shaving his legs and his Cube Peloton Race still bears the scars of his first battles with clipless pedals. While he counts the (lower slopes of the) Alps and Pyrenees among the places he has ridden, family life means his body is best suited to dragging a children's trailer along a coastal path than conquering mountains…

redpajama_set_name: RedPajamaCommonCrawl


Native American Payday Loans "Loans By World Com Is It A Scam". There are always going to be times when you could use extra cash. You may find that there are unexpected expenses that put a damper on your day or there are some bills that you simply want to get paid off so that you can get your finances balanced. Because of all of the reasons why anyone could need money in a flash, there are a lot of people who are now looking to help from Loans By World.com payday loans. In order to get the most out of the experience, it is going to be best that you learn all that you can about this loan option so that you can determine if it is going to be the right choice for you and your current situation. You can get payday loan with low credit score by using Loans By World Com Is It A Scam, and read reviews.
Searching for Loans By World Com Is It A Scam. $100$1000 Rapid Cash in 30 Minutes Moment. Urgent and Safe Software. Easy, Easy Safe. Submit an application for Sunday cash Currently.
There are a great deal of misconceptions available in relation to pay day loans and cash advances. Basically speaking, a cash advance is a kind of short-term loan. Usually, a cash loan loan is one that may not last any longer than 2 weeks.
With all of the options available today regarding money advance loans, what exactly is it that creates one company superior to another? Personal is a cash advance company that has been in operation and helping countless customers just like yourself since 1999. This can be a company that is a member of the CFSA, Community Financial Services Of America, and has been around good standing since this time. If you are searching for ways to get cash fast so you meet all of the criteria, you could potentially just realize that this is basically the most suitable option to get you what exactly you need.
When you are interested in a advance loan or payday advance, you should know that this cash amount is often based on both your net income and also the state that you currently are living in. Each state has their own personal group of regulations associated with the maximum sum of money which a resident has the capacity to borrow as well as how much time they could borrow the funds. Based on the limits that are allowed in your state Personal pay day loans will review your level of net income and after that go to a determination of methods much you may borrow.
The fees that happen to be involved will also vary based on the suggest that you live in. When you are looking for your money advance, we will not require a credit consult with any of the major bureaus. This is why a advance loan or perhaps a pay day loan is frequently times a wise borrowing opportunity for everyone who has credit that is below perfect.


Last night I some how found myself looking at e-books on Amazon wishing I could read them but alas I don't have a Kindle. I was chatting with my dad and he was all like you realize that you don't have to have one to read e-books from Amazon right? You can get the app on your computer or phone and read them from there. It was like the heavens opened up and a great beam of light was shining down on me. Life. Changing.
There are so many books to read!! So many to add to my list and read that are already on my list.
I downloaded this guy cause I saw some other bloggers chatting about it and it seemed like a good one to jump into right away since it was only $2.99.
Then I discovered there are books like this guy.
This one is free!! Don't get me wrong $2.99 for anything is really good but free is waaaaay better! There are so many topics to choose from. You have tons of fiction and non-fiction, anything from mysteries to ebooks on World War II. I'm officially in heaven!
I always love to read but lately with the way life has been on the go it's been difficult to hit up the library for books, especially since you then have to make sure you return them on time! Being able to have it right there on my phone or computer when I want it is a great feeling. Don't need to worry about only making halfway through before the due date is up. Although the feel and smell of a book will always be the best thing.
Check out websites like these for free ebook downloads.
Or look at your local library. Usually ebooks from the library have a time limit, they're like Cinderella.
I love ebooks. let me know you find those books helpful!
I just downloaded an app called OverDrive, it's linked to my library and I can borrow loads of ebooks for free! I'm mildly obsessed with it!


text:
#ifndef M3D_VISUALIZATIONUTILS_IMPL_H
#define M3D_VISUALIZATIONUTILS_IMPL_H

#if WITH_VTK

#include <iostream>
#include <stdlib.h>
#include <vector>
#include <list>

#include <vtkRenderer.h>
#include <vtkActor.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderWindow.h>
#include <vtkDataSetMapper.h>
#include <vtkProperty.h>

#include <vtkCellArray.h>
#include <vtkCellData.h>
#include <vtkCleanPolyData.h>
#include <vtkDataArray.h>
#include <vtkDataSetSurfaceFilter.h>
#include <vtkDelaunay3D.h>
#include <vtkDelaunay2D.h>
#include <vtkDoubleArray.h>
#include <vtkFieldData.h>
#include <vtkGeometryFilter.h>
#include <vtkHexahedron.h>
#include <vtkImageData.h>
#include <vtkLookupTable.h>
#include <vtkPointData.h>
#include <vtkPolyDataConnectivityFilter.h>
#include <vtkPolyDataWriter.h>
#include <vtkQuad.h>
#include <vtkRectilinearGridWriter.h>
#include <vtkSmartPointer.h>
#include <vtkDataSetSurfaceFilter.h>
#include <vtkType.h>
#include <vtkUnsignedCharArray.h>
#include <vtkUnstructuredGrid.h>
#include <vtkUnstructuredGridWriter.h>
#include <vtkVersion.h>
#include <vtkVertex.h>
#include <vtkVoxel.h>
#include <vtkXMLImageDataWriter.h>
#include <vtkXMLPolyDataWriter.h>
#include <vtkXMLRectilinearGridWriter.h>
#include <vtkXMLUnstructuredGridWriter.h>

#include <meanie3D/clustering.h>

#include "visit.h"

namespace m3D {
    namespace utils {

        using namespace std;

        /** Global variable maintaining the dimension mapping */
        template<typename T>
        vector<size_t> VisitUtils<T>::VTK_DIMENSION_INDEXES;

        // Macro for safe access
#define get_vtk_index(i) VTK_DIMENSION_INDEXES.empty() ? i : VTK_DIMENSION_INDEXES[i]

        /* ---------------------------------------------------------------- */
        /* General VTK data structure mapping/handling                      */
        /* ---------------------------------------------------------------- */

        template<typename T>
        void
        VisitUtils<T>::update_vtk_dimension_mapping(vector<string> dim_names,
                                                    vector<string> vtk_dim_names) {
            // VTK dimension mapping

            if (!vtk_dim_names.empty()) {
                vector<size_t> vtk_dimension_indexes;

                // Number of values should be the same in --dimensions and --vtk-dimensions

                if (vtk_dim_names.size() != dim_names.size()) {
                    cerr << "FATAL: --dimensions and --vtk-dimensions must have \
                        the same number of arguments" << endl;
                    exit(EXIT_FAILURE);
                }

                // Check if all dimensions are accounted for in --vtk-dimensions

                for (size_t i = 0; i < vtk_dim_names.size(); i++) {
                    vector<string>::iterator vi = find(dim_names.begin(), dim_names.end(), vtk_dim_names[i]);

                    if (vi == dim_names.end()) {
                        cerr << "FATAL: --vtk-dimensions - entry "
                             << vtk_dim_names[i]
                             << " has no pendant in attribute \
                                'featurespace_dimensions'" << endl;
                        exit(EXIT_FAILURE);
                    }

                    int index = utils::vectors::index_of_first(dim_names, vtk_dim_names[i]);

                    vtk_dimension_indexes.push_back((size_t) index);
                }

                utils::VisitUtils<T>::VTK_DIMENSION_INDEXES = vtk_dimension_indexes;

                VTK_DIMENSION_INDEXES = vtk_dimension_indexes;
            }
        }

        template<typename T>
        void
        VisitUtils<T>::get_vtk_image_dimensions(const CoordinateSystem <T> *cs, int &nx, int &ny, int &nz) {
            assert(cs->rank() > 0 && cs->rank() <= 3);
            nx = ny = nz = 1;
            if (cs->rank() == 1) {
                nx = cs->dimensions()[get_vtk_index(0)].getSize();
            } else if (cs->rank() == 2) {
                nx = cs->dimensions()[get_vtk_index(0)].getSize();
                ny = cs->dimensions()[get_vtk_index(1)].getSize();
            } else {
                nx = cs->dimensions()[get_vtk_index(0)].getSize();
                ny = cs->dimensions()[get_vtk_index(1)].getSize();
                nz = cs->dimensions()[get_vtk_index(2)].getSize();
            }
        }

        template<typename T>
        void
        VisitUtils<T>::get_vtk_coords(const vector<T> &coords, T &x, T &y, T &z) {
            assert(coords.size() > 0 && coords.size() <= 3);

            x = y = z = 0;

            if (coords.size() == 1) {
                x = coords.at(get_vtk_index(0));
            } else if (coords.size() == 2) {
                x = coords.at(get_vtk_index(0));
                y = coords.at(get_vtk_index(1));
            } else {
                x = coords.at(get_vtk_index(0));
                y = coords.at(get_vtk_index(1));
                z = coords.at(get_vtk_index(2));
            }
        }

        template<typename T>
        void
        VisitUtils<T>::get_vtk_gridpoint(const vector<int> &gp, int &gx, int &gy, int &gz) {
            assert(gp.size() > 0 && gp.size() <= 3);

            gx = gy = gz = 0;

            if (gp.size() == 1) {
                gx = gp.at(get_vtk_index(0));
            } else if (gp.size() == 2) {
                gx = gp.at(get_vtk_index(0));
                gy = gp.at(get_vtk_index(1));
            } else {
                gx = gp.at(get_vtk_index(0));
                gy = gp.at(get_vtk_index(1));
                gz = gp.at(get_vtk_index(2));
            }
        }

        template<typename T>
        void
        copy_vtk_coordinate_data(const CoordinateSystem <T> *cs, size_t index, vtkDoubleArray *coords) {
            NcVar vx = cs->dimension_variables().at(index);
            const T *dim_data = cs->get_dimension_data_ptr(vx);
            NcDim dx = cs->dimensions().at(index);
            coords->SetNumberOfValues(dx.getSize());
            for (int i = 0; i < dx.getSize(); i++) {
                double value = dim_data[i];
                coords->SetValue(i, value);
            }
        }

        template<typename T>
        vtkRectilinearGrid *
        VisitUtils<T>::allocate_vtk_rectilinear_grid(const CoordinateSystem <T> *cs,
                                                     vector<vtkDoubleArray *> &coord_pointers) {
            assert(cs->rank() > 0 && cs->rank() <= 3);
            int nx = 0, ny = 0, nz = 0;
            get_vtk_image_dimensions(cs, nx, ny, nz);
            vtkRectilinearGrid *rgrid = vtkRectilinearGrid::New();
            rgrid->SetDimensions(nx, ny, nz);
            for (int i = 0; i < cs->rank(); i++) {
                vtkDoubleArray *coords = vtkDoubleArray::New();
                coords->SetNumberOfComponents(1);
                copy_vtk_coordinate_data(cs, get_vtk_index(i), coords);
                coord_pointers.push_back(coords);
                if (i == 0) {
                    rgrid->SetXCoordinates(coords);
                } else if (i == 1) {
                    rgrid->SetYCoordinates(coords);
                } else {
                    rgrid->SetZCoordinates(coords);
                }
            }

            // supply 1-D arrays with value 0 for the
            // empty dimensions
            for (int i = 2; i >= 0; i--) {
                if (i >= cs->rank()) {
                    vtkDoubleArray *coords = vtkDoubleArray::New();
                    coords->SetNumberOfComponents(1);
                    coords->InsertNextValue(0.0);
                    coord_pointers.push_back(coords);
                    if (i == 0) {
                        rgrid->SetXCoordinates(coords);
                    } else if (i == 1) {
                        rgrid->SetYCoordinates(coords);
                    } else {
                        rgrid->SetZCoordinates(coords);
                    }
                }
            }
            return rgrid;
        }

        template<typename T>
        vtkIdType
        VisitUtils<T>::to_single_index(const CoordinateSystem <T> *cs,
                                       int nx, int ny, int nz,
                                       int gx, int gy, int gz) {
            vtkIdType index = 0;

            if (cs->rank() == 1) {
                // 'x'
                index = gx;
            } else if (cs->rank() == 2) {
                // 'x' + 'y' * 'Nx'
                index = gx + gy * nx;
            } else {
                // 'x' + 'y' * 'Nx' + 'z' * 'Nx' * 'Ny'
                index = gx + gy * nx + gz * nx * ny;
            }

            return index;
        }

        /* ---------------------------------------------------------------- */
        /* Specific writing routines                                        */
        /* ---------------------------------------------------------------- */

        /** Write out the cluster list as list of points. The point's 'value' is the size of the cluster
         * @param full path to filename, including extension '.vtk'
         * @param cluster list
         */
        template<typename T>
        void
        VisitUtils<T>::write_cluster_modes_vtk(const string &filename, const typename Cluster<T>::list &list,
                                               bool spatial_only) {
            ofstream f(filename.c_str());
            f << fixed << setprecision(4);

            // Write Header

            f << "# vtk DataFile Version 3.0" << endl;
            f << "point list " << endl;
            f << "ASCII" << endl;
            f << "DATASET UNSTRUCTURED_GRID" << endl;
            f << "POINTS " << list.size() << " FLOAT" << endl;

            for (size_t ci = 0; ci < list.size(); ci++) {
                typename Cluster<T>::ptr c = list[ci];
                size_t dim_count = spatial_only ? c->spatial_rank() : c->rank();
                vector<T> mode = c->mode;
                size_t dims_plotted = 0;

                for (size_t vi = 0; vi < dim_count; vi++) {
                    size_t dim_index = vi;

                    if (vi < VTK_DIMENSION_INDEXES.size()) {
                        dim_index = VTK_DIMENSION_INDEXES.empty() ? vi : VTK_DIMENSION_INDEXES[vi];
                    }

                    f << mode[dim_index] << "\t";
                    dims_plotted++;
                }

                while (dims_plotted < 3) {
                    f << "0.0\t";
                    dims_plotted++;
                }

                f << endl;
            }

            f << endl;
            f << "POINT_DATA " << list.size() << endl;
            f << "SCALARS mode INT" << endl;
            f << "LOOKUP_TABLE default" << endl;
            for (size_t pi = 0; pi < list.size(); pi++) {
                typename Cluster<T>::ptr c = list[pi];
                size_t dim_count = spatial_only ? c->spatial_rank() : c->rank();

                if (spatial_only) {
                    f << c->id << endl;
                } else {
                    f << c->mode[dim_count - 1];
                }
            }

            f.close();
        }

        template<class T>
        void
        VisitUtils<T>::write_geometrical_cluster_centers_vtk(const string &filename,
                                                             const typename Cluster<T>::list &list,
                                                             bool at_max_height) {
            ofstream f(filename.c_str());
            f << fixed << setprecision(4);

            // determine the spatial dimension
            typename Cluster<T>::ptr c = NULL;
            typename Point<T>::ptr p = NULL;

            // Write Header

            f << "# vtk DataFile Version 3.0" << endl;
            f << "point list " << endl;
            f << "ASCII" << endl;
            f << "DATASET UNSTRUCTURED_GRID" << endl;
            f << "POINTS " << list.size() << " FLOAT" << endl;

            for (size_t ci = 0; ci < list.size(); ci++) {
                typename Cluster<T>::ptr c = list[ci];

                // obtain the geometrical center

                size_t spatial_dims = c->get_points().at(0)->coordinate.size();

                vector<T> mode = c->geometrical_center();

                if (spatial_dims == 3 && at_max_height) {
                    T max = 0;
                    for (size_t pi = 0; pi < c->size(); pi++) {
                        Point<T> *p = c->get_points().at(pi);
                        if (p->coordinate[0] > max) {
                            max = p->coordinate[0];
                        }
                    }

                    mode[0] = 1.5 * max;
                }

                size_t dims_plotted = 0;

                for (size_t vi = 0; vi < spatial_dims; vi++) {
                    size_t dim_index = vi;

                    if (vi < VTK_DIMENSION_INDEXES.size()) {
                        dim_index = VTK_DIMENSION_INDEXES.empty() ? vi : VTK_DIMENSION_INDEXES[vi];
                    }

                    f << mode[dim_index] << "\t";

                    dims_plotted++;
                }

                while (dims_plotted < 3) {
                    f << "0.0\t";

                    dims_plotted++;
                }

                f << endl;
            }

            f << endl;
            f << "POINT_DATA " << list.size() << endl;
            f << "SCALARS geometrical_center INT" << endl;
            f << "LOOKUP_TABLE default" << endl;
            for (size_t pi = 0; pi < list.size(); pi++) {
                typename Cluster<T>::ptr c = list[pi];

                f << c->id << endl;
            }

            f.close();
        }

        static vtkSmartPointer<vtkLookupTable> _vtk_cluster_table = NULL;

        template<typename T>
        vtkSmartPointer<vtkLookupTable>
        VisitUtils<T>::cluster_lookup_table() {
            if (_vtk_cluster_table == NULL) {
                // Lookup table
                _vtk_cluster_table = vtkSmartPointer<vtkLookupTable>::New();
                _vtk_cluster_table->SetNumberOfTableValues(6);

                // Red
                _vtk_cluster_table->SetTableValue(0, 255.0 / 255.0, 0.0 / 255.0, 0.0 / 255.0);

                // Purple
                _vtk_cluster_table->SetTableValue(1, 205.0 / 255.0, 255.0 / 255.0, 0.0 / 255.0);

                // Green
                _vtk_cluster_table->SetTableValue(2, 0.0 / 255.0, 255.0 / 255.0, 0.0 / 255.0);

                // Orange
                _vtk_cluster_table->SetTableValue(3, 255.0 / 255.0, 102.0 / 255.0, 0.0 / 255.0);

                // Blue
                _vtk_cluster_table->SetTableValue(4, 0.0 / 255.0, 187.0 / 255.0, 255.0 / 255.0);

                // Yellow
                _vtk_cluster_table->SetTableValue(5, 255.0 / 255.0, 255.0 / 255.0, 0.0 / 255.0);

                _vtk_cluster_table->Build();
            }

            return _vtk_cluster_table;
        }

        template<typename T>
        void
        VisitUtils<T>::write_clusters_vtu(const ClusterList <T> *list,
                                          const CoordinateSystem <T> *cs,
                                          const string &base_name,
                                          unsigned int max_colors,
                                          bool use_ids,
                                          bool include_boundary,
                                          bool write_xml) {
            // escape dangerous characters from basename
            string basename = boost::filesystem::path(base_name).stem().string();
            string mesh_filename = basename + "-clusters" + (write_xml ? ".vtu" : ".vtk");
            string poly_filename = basename + "-boundaries" + (write_xml ? ".vtu" : ".vtk");

            size_t num_points = 0;
            size_t point_dim = 0;

            cout << "Cluster list has " << list->clusters.size() << " clusters" << endl;
            for (size_t ci = 0; ci < list->clusters.size(); ci++) {
                num_points += list->clusters[ci]->size();
                if (point_dim == 0) {
                    point_dim = list->clusters[ci]->get_points()[0]->coordinate.size();
                }
            }
            // Only process 2D/3D for now
            assert(point_dim == 2 || point_dim == 3);

            vtkSmartPointer<vtkCellArray> cellArray = vtkSmartPointer<vtkCellArray>::New();
            vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();

            vtkSmartPointer<vtkDoubleArray> pointData = vtkSmartPointer<vtkDoubleArray>::New();
            pointData->SetName("point_data");

            vtkSmartPointer<vtkDoubleArray> cellData = vtkSmartPointer<vtkDoubleArray>::New();
            cellData->SetName("cell_data");

            vtkSmartPointer<vtkIntArray> pointColors = vtkSmartPointer<vtkIntArray>::New();
            pointColors->SetName("point_color");
            pointColors->SetLookupTable(cluster_lookup_table());

            vtkSmartPointer<vtkIntArray> cellColors = vtkSmartPointer<vtkIntArray>::New();
            cellColors->SetName("cell_color");
            cellColors->SetLookupTable(cluster_lookup_table());

            for (size_t ci = 0; ci < list->clusters.size(); ci++) {

                m3D::id_t id = use_ids ? list->clusters[ci]->id : ci;
                int color = id % 6;

                typename Cluster<T>::ptr cluster = list->clusters[ci];

                for (vtkIdType pi = 0; pi < cluster->size(); pi++) {
                    Point<T> *p = list->clusters[ci]->get_points()[pi];

                    double scalarValue = p->values[point_dim];
                    cellData->InsertNextValue(scalarValue);
                    cellColors->InsertNextValue(color);

                    T x, y, z;

                    x = y = z = 0.0;

                    VisitUtils<T>::get_vtk_coords(p->coordinate, x, y, z);

                    if (point_dim == 2) {
                        T rx = cs->resolution()[VisitUtils<T>::index_of(0)] / 2.0;
                        T ry = cs->resolution()[VisitUtils<T>::index_of(1)] / 2.0;

                        vtkIdType p1 = points->InsertNextPoint(x - rx, y - ry, 0);
                        pointData->InsertNextValue(scalarValue);
                        pointColors->InsertNextValue(color);

                        vtkIdType p2 = points->InsertNextPoint(x + rx, y - ry, 0);
                        pointData->InsertNextValue(scalarValue);
                        pointColors->InsertNextValue(color);

                        vtkIdType p3 = points->InsertNextPoint(x + rx, y + ry, 0);
                        pointData->InsertNextValue(scalarValue);
                        pointColors->InsertNextValue(color);

                        vtkIdType p4 = points->InsertNextPoint(x - rx, y + ry, 0);
                        pointData->InsertNextValue(scalarValue);
                        pointColors->InsertNextValue(color);

                        // Create a quad on the four points
                        vtkSmartPointer<vtkQuad> quad = vtkSmartPointer<vtkQuad>::New();
                        quad->GetPointIds()->SetId(0, p1);
                        quad->GetPointIds()->SetId(1, p2);
                        quad->GetPointIds()->SetId(2, p3);
                        quad->GetPointIds()->SetId(3, p4);

                        cellArray->InsertNextCell(quad);
                    } else {
                        T rx = cs->resolution()[VisitUtils<T>::index_of(0)] / 2.0;
                        T ry = cs->resolution()[VisitUtils<T>::index_of(1)] / 2.0;
                        T rz = cs->resolution()[VisitUtils<T>::index_of(2)] / 2.0;

                        vtkIdType p1 = points->InsertNextPoint(x - rx, y - ry, z - rz);
                        pointData->InsertNextValue(scalarValue);
                        pointColors->InsertNextValue(color);

                        vtkIdType p2 = points->InsertNextPoint(x + rx, y - ry, z - rz);
                        pointData->InsertNextValue(scalarValue);
                        pointColors->InsertNextValue(color);

                        vtkIdType p3 = points->InsertNextPoint(x + rx, y + ry, z - rz);
                        pointData->InsertNextValue(scalarValue);
                        pointColors->InsertNextValue(color);

                        vtkIdType p4 = points->InsertNextPoint(x - rx, y + ry, z - rz);
                        pointData->InsertNextValue(scalarValue);
                        pointColors->InsertNextValue(color);

                        vtkIdType p5 = points->InsertNextPoint(x - rx, y - ry, z + rz);
                        pointData->InsertNextValue(scalarValue);
                        pointColors->InsertNextValue(color);

                        vtkIdType p6 = points->InsertNextPoint(x + rx, y - ry, z + rz);
                        pointData->InsertNextValue(scalarValue);
                        pointColors->InsertNextValue(color);

                        vtkIdType p7 = points->InsertNextPoint(x + rx, y + ry, z + rz);
                        pointData->InsertNextValue(scalarValue);
                        pointColors->InsertNextValue(color);

                        vtkIdType p8 = points->InsertNextPoint(x - rx, y + ry, z + rz);
                        pointData->InsertNextValue(scalarValue);
                        pointColors->InsertNextValue(color);

                        // Create a voxel on the eight points
                        vtkSmartPointer<vtkHexahedron> voxel = vtkSmartPointer<vtkHexahedron>::New();
                        voxel->GetPointIds()->SetId(0, p1);
                        voxel->GetPointIds()->SetId(1, p2);
                        voxel->GetPointIds()->SetId(2, p3);
                        voxel->GetPointIds()->SetId(3, p4);

                        voxel->GetPointIds()->SetId(4, p5);
                        voxel->GetPointIds()->SetId(5, p6);
                        voxel->GetPointIds()->SetId(6, p7);
                        voxel->GetPointIds()->SetId(7, p8);

                        cellArray->InsertNextCell(voxel);
                    }
                }
            }

            // Create an unstructured grid and write it off
            vtkSmartPointer<vtkUnstructuredGrid> unstructuredGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();

            // Set point data
            unstructuredGrid->SetPoints(points);

            // Set cell data
            if (point_dim == 2) {
                unstructuredGrid->SetCells(VTK_QUAD, cellArray);
            } else {
                unstructuredGrid->SetCells(VTK_HEXAHEDRON, cellArray);
            }

            unstructuredGrid->GetPointData()->AddArray(pointData);
            unstructuredGrid->GetPointData()->AddArray(pointColors);
            unstructuredGrid->GetCellData()->AddArray(cellData);
            unstructuredGrid->GetCellData()->AddArray(cellColors);

            // Extract the envelope
            vtkSmartPointer<vtkAlgorithm> enveloper;
            if (include_boundary) {
                // Geometry filter
                vtkSmartPointer<vtkGeometryFilter> geometry = vtkSmartPointer<vtkGeometryFilter>::New();
                geometry->SetInputData(unstructuredGrid);

                vtkSmartPointer<vtkCleanPolyData> cleaner = vtkSmartPointer<vtkCleanPolyData>::New();
                cleaner->SetInputConnection(geometry->GetOutputPort());

                // Delauny 2D/3D

                if (point_dim == 2) {
                    vtkSmartPointer<vtkDelaunay2D> delauny = vtkSmartPointer<vtkDelaunay2D>::New();
                    delauny->SetInputConnection(cleaner->GetOutputPort());
                    enveloper = delauny;
                } else {
                    vtkSmartPointer<vtkDelaunay3D> delauny = vtkSmartPointer<vtkDelaunay3D>::New();
                    delauny->SetInputConnection(cleaner->GetOutputPort());
                    enveloper = delauny;
                }
            }

            // Write .vtu/.vtk file
            if (write_xml) {
                vtkSmartPointer<vtkXMLUnstructuredGridWriter> writer = vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
                writer->SetFileName(mesh_filename.c_str());
                writer->SetInputData(unstructuredGrid);
                writer->Write();
                if (include_boundary) {
                    writer->SetFileName(poly_filename.c_str());
                    writer->SetInputConnection(enveloper->GetOutputPort());
                    writer->Write();
                }
            } else {
                vtkSmartPointer<vtkUnstructuredGridWriter> writer = vtkSmartPointer<vtkUnstructuredGridWriter>::New();
                writer->SetFileName(mesh_filename.c_str());
                writer->SetInputData(unstructuredGrid);
                writer->Write();
                if (include_boundary) {
                    writer->SetFileName(poly_filename.c_str());
                    writer->SetInputConnection(enveloper->GetOutputPort());
                    writer->Write();
                }
            }
        }

        template<class T>
        void
        VisitUtils<T>::write_center_tracks_vtk(typename Track<T>::trackmap &track_map,
                                               const std::string &basename,
                                               size_t spatial_dimensions,
                                               bool exclude_degenerates) {
            typename Track<T>::trackmap::iterator tmi;

            for (tmi = track_map.begin(); tmi != track_map.end(); tmi++) {
                typename Track<T>::ptr track = tmi->second;

                if (exclude_degenerates && track->clusters.size() == 1) {
                    continue;
                }

                string filename = basename + "-track_" + boost::lexical_cast<string>(tmi->first) + ".vtk";

                ofstream f(filename.c_str());
                f << fixed << setprecision(4);

                // Write Header
                f << "# vtk DataFile Version 3.0" << endl;
                f << "Meanie3D Track" << endl;
                f << "ASCII" << endl;
                f << "DATASET UNSTRUCTURED_GRID" << endl;
                f << "POINTS " << track->size() << " FLOAT" << endl;

                // Write point coordinates out as unstructured grid

                typename std::list<typename Cluster<T>::ptr>::iterator ti;
                for (ti = track->clusters.begin(); ti != track->clusters.end(); ++ti) {
                    TrackCluster<T> *c = (TrackCluster<T> *) (*ti);

                    vector<T> center = c->geometrical_center();

                    for (size_t vi = 0; vi < center.size(); vi++) {
                        size_t index = VTK_DIMENSION_INDEXES.empty() ? vi : VTK_DIMENSION_INDEXES[vi];

                        f << center[index] << "\t";
                    }

                    if (center.size() < 3) {
                        f << "0.0";
                    }

                    f << endl;
                }

                // Write point data out. Only take the first value after coordinates

                f << endl;
                f << "POINT_DATA " << track->size() << endl;
                f << "SCALARS track_step FLOAT" << endl;
                f << "LOOKUP_TABLE default" << endl;

                size_t step = 0;

                for (ti = track->clusters.begin(); ti != track->clusters.end(); ti++) {
                    //f << ti->points.size() << endl;
                    f << step++ << endl;
                }

                f.close();
            }
        }

        template<class T>
        void
        VisitUtils<T>::write_center_tracks_vtk(typename ConradCluster<T>::trackmap_t &track_map,
                                               const std::string &basename,
                                               bool exclude_degenerates) {
            typename ConradCluster<T>::trackmap_t::const_iterator tmi;

            for (tmi = track_map.begin(); tmi != track_map.end(); tmi++) {
                typename ConradCluster<T>::track_t *track = tmi->second;

                if (exclude_degenerates && track->size() == 1) {
                    continue;
                }

                string filename = basename + "-track_" + boost::lexical_cast<string>(tmi->first) + ".vtk";

                ofstream f(filename.c_str());
                f << fixed << setprecision(4);

                // Write Header
                f << "# vtk DataFile Version 3.0" << endl;
                f << "Meanie3D Track" << endl;
                f << "ASCII" << endl;
                f << "DATASET UNSTRUCTURED_GRID" << endl;
                f << "POINTS " << track->size() << " FLOAT" << endl;

                // Write point coordinates out as unstructured grid

                typename ConradCluster<T>::track_t::const_iterator ti;

                for (ti = track->begin(); ti != track->end(); ti++) {
                    vector<T> center = ti->center();

                    for (size_t vi = 0; vi < center.size(); vi++) {
                        f << center[vi] << "\t";
                    }

                    if (center.size() < 3) {
                        f << "0.0";
                    }

                    f << endl;
                }

                // Write point data out. Only take the first value after coordinates

                f << endl;
                f << "POINT_DATA " << track->size() << endl;
                f << "SCALARS track_step FLOAT" << endl;
                f << "LOOKUP_TABLE default" << endl;

                size_t step = 0;

                for (ti = track->begin(); ti != track->end(); ti++) {
                    //f << ti->points.size() << endl;
                    f << step++ << endl;
                }

                f.close();
            }
        }

        template<class T>
        void
        VisitUtils<T>::write_cluster_weight_response_vtk(const string &base_name,
                                                         const typename Cluster<T>::list &clusters,
                                                         WeightFunction <T> *w,
                                                         bool useMode) {
            string basename(base_name);

            for (size_t ci = 0; ci < clusters.size(); ci++) {
                Cluster<T> *cluster = clusters[ci];

                vector<T> mode = cluster->mode;

                // Write cluster out

                boost::replace_all(basename, "/", "_");
                boost::replace_all(basename, "..", "");

                string filename = basename + "_" + boost::lexical_cast<string>(cluster->id) + ".vtk";

                ofstream f(filename.c_str());
                f << fixed << setprecision(4);

                // Write Header
                f << "# vtk DataFile Version 3.0" << endl;
                f << "Cluster weight function response" << endl;
                f << "ASCII" << endl;
                f << "DATASET UNSTRUCTURED_GRID" << endl;
                f << "POINTS " << cluster->size() << " FLOAT" << endl;

                // Write point coordinates out as unstructured grid

                size_t point_dim = cluster->at(0)->coordinate.size();

                for (size_t pi = 0; pi < cluster->size(); pi++) {
                    Point<T> *p = cluster->at(pi);

                    for (size_t vi = 0; vi < point_dim; vi++) {
                        size_t index = VTK_DIMENSION_INDEXES.empty() ? vi : VTK_DIMENSION_INDEXES[vi];

                        f << p->coordinate[index] << "\t";
                    }

                    for (size_t j = p->coordinate.size(); j < 3; j++) {
                        f << "0.0\t";
                    }

                    f << endl;
                }

                // Write point data out. Only take the first value after coordinates

                T wr = useMode ? cluster->modal_weight_response(w) : cluster->average_weight_response(w);

                f << endl;
                f << "POINT_DATA " << cluster->size() << endl;
                f << "SCALARS weight FLOAT" << endl;
                f << "LOOKUP_TABLE default" << endl;

                for (size_t pi = 0; pi < cluster->size() - 1; pi++) {
                    f << wr << endl;
                }

                f.close();
            }
        }

        template<class T>
        void
        VisitUtils<T>::write_cluster_meanshift_vtk(const string &base_name,
                                                   const typename Cluster<T>::list &clusters,
                                                   bool use_ids,
                                                   bool spatial_only) {
            std::string basename(base_name);
            boost::replace_all(basename, "/", "_");
            boost::replace_all(basename, "..", "");

            for (size_t ci = 0; ci < clusters.size(); ci++) {
                Cluster<T> *cluster = clusters[ci];

                typedef vector<vector<T> > vvector_t;

                vvector_t origins;

                vvector_t shifts;

                for (size_t pi = 0; pi < cluster->size(); pi++) {
                    typename Point<T>::ptr p = cluster->at(pi);

                    if (spatial_only) {
                        origins.push_back(p->coordinate);

                        vector<T> shift = p->shift;

                        shifts.push_back(vector<T>(&shift[0], &shift[p->coordinate.size()]));
                    } else {
                        origins.push_back(p->values);
                        shifts.push_back(p->shift);
                    }
                }

                string filename = basename + "_" + boost::lexical_cast<string>(use_ids ? cluster->id : ci) + ".vtk";

                VisitUtils<T>::write_vectors_vtk(filename, origins, shifts, "shift");
            }

        }

        /** Helper function for drawing an ellipse (representing bandwidth and somesuch)
         * in a .curve file format.
         * @param filename
         * @param half axis data
         * @param number of segments in the curve (default 1000)
         * @param pointer to origin vector, defaults to NULL = (0,0)
         */
        template<typename T>
        void
        VisitUtils<T>::write_ellipsis_2d(const string &filename, const vector<T> &half_axis, size_t number_of_segements,
                                         const vector<T> *origin) {
            ofstream fs(filename.c_str());
            // fs.imbue( locale("de_DE.UTF-8") );
            fs << "# bandwidth" /* << fixed << setprecision(0)*/ << endl;
            vector<T> x0 = (origin == NULL) ? vector<T>(2, 0.0) : *origin;
            for (size_t i = 0; i < number_of_segements; i++) {
                float phi = i * 2 * M_PI / ((float) number_of_segements);
                float x = x0[1] + half_axis[0] * cos(phi);
                float y = x0[0] + half_axis[1] * sin(phi);
                fs << y << "\t" << x << endl;
            }
            fs.close();
        }

        /** Helper function for drawing an ellipse (representing bandwidth and somesuch)
         * in a .curve file format.
         * @param filename
         * @param half axis data
         * @param number of segments in the curve (default 1000)
         * @param pointer to origin vector, defaults to NULL = (0,0,0)
         */
        template<typename T>
        void
        VisitUtils<T>::write_ellipsis_3d(const string &filename, const vector<T> &half_axis, size_t number_of_segements,
                                         const vector<T> *origin) {
            ofstream fs(filename.c_str());
            // fs.imbue( locale("de_DE.UTF-8") );
            fs << "x\ty\tz\tv" << endl;
            vector<T> x0 = (origin == NULL) ? vector<T>(2, 0.0) : *origin;
            for (size_t i = 0; i < number_of_segements; i++) {
                float u = i * 2 * M_PI / ((float) number_of_segements);
                for (size_t j = 0; j < number_of_segements; j++) {
                    float v = j * 2 * M_PI / ((float) number_of_segements);
                    float x = half_axis[0] * cos(u) * sin(v);
                    float y = half_axis[1] * sin(u) * sin(v);
                    float z = half_axis[2] * cos(v);
                    if (origin != NULL) {
                        x += origin->at(0);
                        y += origin->at(1);
                        z += origin->at(2);
                    }

                    fs << x << "\t" << y << "\t" << z << "\t" << 1.0 << endl;
                }
            }
            fs.close();
        }

        template<typename T>
        void
        VisitUtils<T>::write_featurespace_vtk(const string &filename, FeatureSpace <T> *fs, string variable_name) {
            ofstream f(filename.c_str());
            f << fixed << setprecision(8);

            // Write Header
            f << "# vtk DataFile Version 3.0" << endl;
            f << variable_name << endl;
            f << "ASCII" << endl;
            f << "DATASET UNSTRUCTURED_GRID" << endl;
            f << "POINTS " << fs->points.size() << " FLOAT" << endl;

            // Write point coordinates out as unstructured grid
            for (size_t pi = 0; pi < fs->points.size(); pi++) {
                typename Point<T>::ptr p = fs->points[pi];
                vector<T> c = p->values;
                for (size_t ri = 0; ri < c.size(); ri++) {
                    size_t index = ri;
                    if (ri < p->coordinate.size()) {
                        index = VTK_DIMENSION_INDEXES.empty() ? ri : VTK_DIMENSION_INDEXES[ri];
                    }
                    f << c[index] << "\t";
                }
                if (c.size() < 3) {
                    f << "0.0";
                }
                f << endl;
            }

            // use then LAST variable to colour the value
            f << endl;
            f << "POINT_DATA " << fs->points.size() << endl;
            f << "SCALARS " << variable_name << " FLOAT" << endl;
            f << "LOOKUP_TABLE default" << endl;
            for (size_t pi = 0; pi < fs->points.size(); pi++) {
                typename Point<T>::ptr p = fs->points[pi];
                vector<T> v = p->values;
                T value = v.back();
                f << value << endl;
            }
            f.close();
        }

        template<typename T>
        void
        VisitUtils<T>::write_featurespace_variables_vtk(const string &filename,
                                                        FeatureSpace <T> *fs,
                                                        const vector<string> &feature_variables,
                                                        const vector<string> &vtk_variables,
                                                        bool write_legacy) {
            const CoordinateSystem<T> *cs = fs->coordinate_system;

            int nx, ny, nz;
            VisitUtils<T>::get_vtk_image_dimensions(cs, nx, ny, nz);

            vector<vtkDoubleArray *> coords;
            vtkRectilinearGrid *rgrid = allocate_vtk_rectilinear_grid(cs, coords);
            rgrid->DebugOn();
            rgrid->CheckAttributes();

            for (size_t vi = 0; vi < vtk_variables.size(); vi++) {
                std::string var = vtk_variables[vi];
                size_t value_index = fs->spatial_rank() + vectors::index_of_first<string>(feature_variables, var);
                cout << "Writing variable " << var << " (index=" << value_index << ")" << endl;
                vtkDoubleArray *variable = vtkDoubleArray::New();
                variable->SetName(var.c_str());
                variable->SetNumberOfComponents(1); // scalar
                variable->SetNumberOfValues(nx * ny * nz);
                variable->FillComponent(0, 0);
                for (size_t i = 0; i < fs->points.size(); ++i) {
                    typename Point<T>::ptr p = fs->points.at(i);
                    double value = (double) p->values[value_index];
                    int gx, gy, gz;
                    VisitUtils<T>::get_vtk_gridpoint(p->gridpoint, gx, gy, gz);
                    int gridIndex = to_single_index(cs, nx, ny, nz, gx, gy, gz);
                    variable->SetValue(gridIndex, value);
                }

                rgrid->GetPointData()->AddArray(variable);
            }

            // Write out

            if (write_legacy) {
                // ASCII
                vtkSmartPointer<vtkRectilinearGridWriter>
                        writer = vtkSmartPointer<vtkRectilinearGridWriter>::New();
                std::string fn = filename + ".vtk";
                writer->SetFileName(fn.c_str());
#if VTK_MAJOR_VERSION <= 5
                writer->SetInput(rgrid);
#else
                writer->SetInputData(rgrid);
#endif
                writer->Write();
            } else {
                // XML
                vtkSmartPointer<vtkXMLRectilinearGridWriter>
                        xmlWriter = vtkSmartPointer<vtkXMLRectilinearGridWriter>::New();
                std::string xml_fn = filename + "." + xmlWriter->GetDefaultFileExtension();
                xmlWriter->SetFileName(xml_fn.c_str());

#if VTK_MAJOR_VERSION <= 5
                xmlWriter->SetInput(rgrid);
#else
                xmlWriter->SetInputData(rgrid);
#endif
                xmlWriter->Write();
            }

            // Clean up
            for (size_t ci = 0; ci < coords.size(); ci++) {
                coords.at(ci)->Delete();
            }
            rgrid->Delete();
        }

        template<typename T>
        void
        VisitUtils<T>::write_vectors_vtk(const string &filename,
                                         const vector<vector<T> > &origins,
                                         const vector<vector<T> > &vectors,
                                         string var_name) {
            assert(origins.size() == vectors.size());

            ofstream f(filename.c_str());
            f << fixed << setprecision(4);

            // Write Header
            f << "# vtk DataFile Version 3.0" << endl;
            f << "Vector List" << endl;
            f << "ASCII" << endl;
            f << "DATASET UNSTRUCTURED_GRID" << endl;
            f << "POINTS " << origins.size() << " FLOAT" << endl;

            // cap @ 3D

            size_t spatial_dims = origins.front().size();

            for (size_t index = 0; index < origins.size(); index++) {
                vector<T> v = origins[index];

                for (size_t ri = 0; ri < spatial_dims; ri++) {
                    size_t index = VisitUtils<T>::index_of(ri);

                    f << v[index] << "\t";
                }

                for (int i = spatial_dims; i < 3; i++) {
                    f << "0.0\t";
                }

                f << endl;
            }

            f << endl;
            f << "POINT_DATA " << origins.size() << endl;
            f << "VECTORS " << var_name << " FLOAT" << endl;
            for (size_t index = 0; index < vectors.size(); index++) {
                vector<T> v = vectors[index];

                for (size_t ri = 0; ri < spatial_dims; ri++) {
                    size_t index = VisitUtils<T>::index_of(ri);

                    f << v[index] << "\t";
                }

                for (int i = spatial_dims; i < 3; i++) {
                    f << "0.0\t";
                }

                f << endl;
            }
            f << endl;

        }

        template<typename T>
        void
        VisitUtils<T>::write_matrix_vtk(const string &filename, const boost::numeric::ublas::matrix<T> &matrix,
                                        string var_name) {
            ofstream f(filename.c_str());
            f << fixed << setprecision(4);

            // Write Header
            f << "# vtk DataFile Version 3.0" << endl;
            f << "Featurespace" << endl;
            f << "ASCII" << endl;
            f << "DATASET UNSTRUCTURED_GRID" << endl;
            f << "POINTS " << matrix.size1() << " FLOAT" << endl;

            // Write point coordinates out as unstructured grid

            for (size_t pi = 0; pi < matrix.size1(); pi++) {
                for (size_t ri = 0; ri < matrix.size2(); ri++) {
                    f << matrix.operator()(pi, ri) << "\t";
                }
                if (matrix.size2() < 3) {
                    f << "0.0";
                }

                f << endl;
            }

            // use then LAST variable to colour the value

            f << endl;
            f << "POINT_DATA " << matrix.size1() << endl;
            f << "SCALARS " << var_name << " FLOAT" << endl;
            f << "LOOKUP_TABLE default" << endl;
            for (size_t pi = 0; pi < matrix.size1(); pi++) {
                f << "0.0" << endl;
            }

            f.close();
        }

        template<typename T>
        void
        VisitUtils<T>::write_ublas_matrix_vtk(const string &filename, const vector<vector<T> > &origins,
                                              const vector<vector<T> > &vectors) {
            assert(origins.size() == vectors.size());

            ofstream f(filename.c_str());
            f << fixed << setprecision(4);

            // Write Header
            f << "# vtk DataFile Version 3.0" << endl;
            f << "Vector List" << endl;
            f << "ASCII" << endl;
            f << "DATASET UNSTRUCTURED_GRID" << endl;
            f << "POINTS " << origins.size() << " FLOAT" << endl;
            for (size_t index = 0; index < origins.size(); index++) {
                vector<T> v = origins[index];

                for (size_t ri = 0; ri < v.size(); ri++) {
                    f << v[ri] << "\t";
                }

                f << endl;
            }

            f << endl;
            f << "POINT_DATA " << origins.size() << endl;
            f << "FIELD FieldData 1" << endl;
            f << "vectors " << vectors.front().size() << " " << origins.size() << " FLOAT" << endl;
            for (size_t index = 0; index < vectors.size(); index++) {
                vector<T> v = vectors[index];

                for (size_t ri = 0; ri < v.size(); ri++) {
                    f << v[ri] << "\t";
                }

                f << endl;
            }
            f << endl;
        }

        template<typename T>
        void
        VisitUtils<T>::write_pointlist_vtk(const string &filename, typename Point<T>::list *list, size_t dim,
                                           string var_name) {
            ofstream f(filename.c_str());
            f << fixed << setprecision(4);

            // Write Header
            f << "# vtk DataFile Version 3.0" << endl;
            f << "point list " << endl;
            f << "ASCII" << endl;
            f << "DATASET UNSTRUCTURED_GRID" << endl;
            f << "POINTS " << list->size() << " FLOAT" << endl;

            // Write point coordinates out as unstructured grid
            for (size_t pi = 0; pi < list->size(); pi++) {
                Point<T> *p = list->at(pi);
                for (size_t ri = 0; ri < dim; ri++) {
                    f << p->values[get_vtk_index(ri)] << "\t";
                }
                if (dim < 3) {
                    f << "0.0";
                }
                f << endl;
            }

            f << endl;
            f << "POINT_DATA " << list->size() << endl;
            f << "SCALARS " << var_name << " FLOAT" << endl;
            f << "LOOKUP_TABLE default" << endl;

            for (size_t pi = 0; pi < list->size(); pi++) {
                Point<T> *p = list->at(pi);

                f << p->values[dim] << endl;
            }

            f.close();
        }

        template<typename T>
        void
        VisitUtils<T>::write_pointlist_all_vars_vtk(const string &filename, typename Point<T>::list *list,
                                                    const vector<string> &var_names) {
            ofstream f(filename.c_str());
            f << fixed << setprecision(4);

            // Write Header

            f << "# vtk DataFile Version 3.0" << endl;
            f << "point list " << endl;
            f << "ASCII" << endl;
            f << "DATASET UNSTRUCTURED_GRID" << endl;
            f << "POINTS " << list->size() << " FLOAT" << endl;

            // Write point coordinates out as unstructured grid

            Point<T> *p = NULL;

            for (size_t pi = 0; pi < list->size(); pi++) {
                p = list->at(pi);
                for (size_t ri = 0; ri < p->coordinate.size(); ri++) {
                    f << p->values[get_vtk_index(ri)] << "\t";
                }

                if (p->coordinate.size() < 3) {
                    f << "0.0";
                }

                f << endl;
            }

            for (size_t k = p->coordinate.size(); k < p->values.size(); k++) {
                std::string var_name = var_names.empty()
                                       ? "var_" + boost::lexical_cast<string>(k)
                                       : var_names[k - p->coordinate.size()];

                f << endl;
                f << "POINT_DATA " << list->size() << endl;
                f << "SCALARS " << var_name << " FLOAT" << endl;
                f << "LOOKUP_TABLE default" << endl;

                for (size_t pi = 0; pi < list->size(); pi++) {
                    Point<T> *vp = list->at(pi);

                    f << vp->values[k] << endl;
                }
            }

            f.close();
        }

        template<typename T>
        void
        VisitUtils<T>::write_pointlist_vtk(const string &filename, vector<vector<T> > *list, string var_name) {
            ofstream f(filename.c_str());
            f << fixed << setprecision(4);

            // Write Header

            f << "# vtk DataFile Version 3.0" << endl;
            f << "point list " << endl;
            f << "ASCII" << endl;
            f << "DATASET UNSTRUCTURED_GRID" << endl;
            f << "POINTS " << list->size() << " FLOAT" << endl;

            size_t dim = 0;

            if (list->size() > 0) {
                dim = list->front().size();
            }

            // Write point coordinates out as unstructured grid

            for (size_t pi = 0; pi < list->size(); pi++) {
                for (size_t ri = 0; ri < dim; ri++) {
                    f << list->at(pi)[get_vtk_index(ri)] << "\t";
                }

                f << endl;
            }

            // use then LAST dimension to 'colour' the point

            f << endl;
            f << "POINT_DATA " << list->size() << endl;
            f << "SCALARS " << var_name << " FLOAT" << endl;
            f << "LOOKUP_TABLE default" << endl;

            for (size_t pi = 0; pi < list->size(); pi++) {
                float value = static_cast<float> (pi) * 255.0f / static_cast<float> (list->size());

                f << value << endl;
            }

            f.close();
        }

        template<typename T>
        void
        VisitUtils<T>::write_modes_vtk(const string &filename, const vector<vector<T> > &list,
                                       const vector<size_t> &trajectory_lenghts, string var_name) {
            ofstream f(filename.c_str());
            f << fixed << setprecision(4);

            // Write Header

            f << "# vtk DataFile Version 3.0" << endl;
            f << "point list " << endl;
            f << "ASCII" << endl;
            f << "DATASET UNSTRUCTURED_GRID" << endl;
            f << "POINTS " << list.size() << " FLOAT" << endl;

            size_t dim = 0;
            if (list.size() > 0) {
                dim = list.front().size();
            }

            // Write point coordinates out as unstructured grid

            for (size_t pi = 0; pi < list.size(); pi++) {
                for (size_t ri = 0; ri < dim; ri++) {
                    f << list[pi][get_vtk_index(ri)] << "\t";
                }

                f << endl;
            }

            // use then LAST dimension to 'colour' the point

            f << endl;
            f << "POINT_DATA " << list.size() << endl;
            f << "SCALARS " << var_name << " FLOAT" << endl;
            f << "LOOKUP_TABLE default" << endl;

            for (size_t pi = 0; pi < list.size(); pi++) {
                float value = trajectory_lenghts[pi];

                f << value << endl;
            }

            f.close();
        }

        template<typename T>
        void
        VisitUtils<T>::write_radolan_vtk(const string &filename, const string &outfile,
                                         Radolan::RDDataType *threshold) {
            using namespace Radolan;

            RDScan *scan = RDAllocateScan();

            if (RDReadScan(filename.c_str(), scan, true) >= 0) {
                // figure out how many valid values we have

                size_t number_of_valid_points = 0;

                if (threshold == NULL) {
                    number_of_valid_points = scan->dimLat * scan->dimLon;
                } else {
                    for (size_t i = 0; i < (scan->dimLat * scan->dimLon); i++) {
                        RDDataType value = scan->data[i];
                        if (value >= *threshold) {
                            number_of_valid_points++;
                        }
                    }
                }

                ofstream f(outfile.c_str());
                f << fixed << setprecision(4);

                // Write Header

                f << "# vtk DataFile Version 3.0" << endl;
                f << "point list " << endl;
                f << "ASCII" << endl;
                f << "DATASET UNSTRUCTURED_GRID" << endl;
                f << "POINTS " << number_of_valid_points << " FLOAT" << endl;

                RDCoordinateSystem rcs(scan->header.scanType);

                int lat, lon;

                for (lat = 0; lat < scan->dimLat; lat++) {
                    for (lon = 0; lon < scan->dimLon; lon++) {
                        RDDataType value = scan->data[lat * scan->dimLon + lon];

                        if (threshold == NULL || (threshold != NULL && value >= *threshold)) {
                            RDCartesianPoint p = rcs.cartesianCoordinate(rdGridPoint(lon, lat));

                            f << p.x << "\t" << p.y << "\t0.0" << endl;
                        }
                    }
                }

                // use then LAST dimension to 'colour' the point

                f << endl;
                f << "POINT_DATA " << number_of_valid_points << endl;
                f << "SCALARS " << "reflectivity" << " FLOAT" << endl;
                f << "LOOKUP_TABLE default" << endl;

                for (size_t i = 0; i < scan->dimLat * scan->dimLon; i++) {
                    RDDataType value = scan->data[i];

                    if (threshold == NULL || (threshold != NULL && value >= *threshold)) {
                        f << value << endl;
                    }
                }

                f.close();
            }
        }

        template<typename T>
        void
        VisitUtils<T>::write_weights(const string &filename,
                                     const string &var_name,
                                     typename Point<T>::list *list,
                                     const vector<T> &weights,
                                     bool restrict_to_2D) {
            ofstream f(filename.c_str());
            f << fixed << setprecision(4);

            // Write Header

            f << "# vtk DataFile Version 3.0" << endl;
            f << "Weights" << endl;
            f << "ASCII" << endl;
            f << "DATASET UNSTRUCTURED_GRID" << endl;
            f << "POINTS " << list->size() << " FLOAT" << endl;

            size_t dim = 0;
            if (list->size() > 0) {
                dim = list->front()->values.size();
            }

            // Write point coordinates out as unstructured grid
            for (size_t pi = 0; pi < list->size(); pi++) {
                Point<T> *p = list->at(pi);
                // NOTE: modified to be put on top of 2D plots
                for (size_t ri = 0; ri < (restrict_to_2D ? 2 : dim); ri++) {
                    f << p->values[get_vtk_index(ri)] << "\t";
                }
                f << "0.0";
                f << endl;
            }

            // Write weights
            f << endl;
            f << "POINT_DATA " << list->size() << endl;
            f << "SCALARS " << var_name << " FLOAT" << endl;
            f << "LOOKUP_TABLE default" << endl;
            for (size_t pi = 0; pi < list->size(); pi++) {
                f << weights[pi] << endl;
            }
        }

        template<typename T>
        void
        VisitUtils<T>::write_shift_vectors(const string &filename,
                                           FeatureSpace <T> *fs,
                                           bool spatial_only) {
            vector<vector<T> > origins, vectors;

            // Write point coordinates out as unstructured grid

            for (size_t pi = 0; pi < fs->points.size(); pi++) {
                Point<T> *p = fs->points[pi];

                if (spatial_only) {
                    origins.push_back(p->coordinate);

                    vectors.push_back(fs->spatial_component(p->shift));
                } else {
                    origins.push_back(p->values);

                    vectors.push_back(p->shift);
                }
            }

            write_vectors_vtk(filename, origins, vectors);
        }

        template<typename T>
        void
        VisitUtils<T>::write_weight_function_response(const string &filename,
                                                      FeatureSpace <T> *fs,
                                                      WeightFunction <T> *weight_function,
                                                      bool write_legacy) {
            const CoordinateSystem<T> *cs = fs->coordinate_system;
            int nx, ny, nz;
            VisitUtils<T>::get_vtk_image_dimensions(cs, nx, ny, nz);
            vector<vtkDoubleArray *> coords;
            vtkRectilinearGrid *rgrid = allocate_vtk_rectilinear_grid(cs, coords);

            vtkDoubleArray *variable = vtkDoubleArray::New();
            variable->SetName("weight");
            variable->SetNumberOfComponents(1); // scalar
            variable->SetNumberOfValues(nx * ny * nz);
            variable->FillComponent(0, 0);

            for (size_t i = 0; i < fs->points.size(); ++i) {
                typename Point<T>::ptr p = fs->points.at(i);
                double value = (double) weight_function->operator()(p);
                int gx, gy, gz;
                VisitUtils<T>::get_vtk_gridpoint(p->gridpoint, gx, gy, gz);
                int gridIndex = to_single_index(cs, nx, ny, nz, gx, gy, gz);
                variable->SetValue(gridIndex, value);
            }
            rgrid->GetPointData()->AddArray(variable);

            // Write out
            if (write_legacy) {
                // ASCII
                vtkSmartPointer<vtkRectilinearGridWriter>
                        writer = vtkSmartPointer<vtkRectilinearGridWriter>::New();

                std::string fn = filename + ".vtk";
                writer->SetFileName(fn.c_str());
#if VTK_MAJOR_VERSION <= 5
                writer->SetInput(rgrid);
#else
                writer->SetInputData(rgrid);
#endif
                writer->Write();
            } else {
                // XML
                vtkSmartPointer<vtkXMLRectilinearGridWriter>
                        xmlWriter = vtkSmartPointer<vtkXMLRectilinearGridWriter>::New();
                std::string xml_fn = filename + "." + xmlWriter->GetDefaultFileExtension();
                xmlWriter->SetFileName(xml_fn.c_str());
#if VTK_MAJOR_VERSION <= 5
                xmlWriter->SetInput(rgrid);
#else
                xmlWriter->SetInputData(rgrid);
#endif
                xmlWriter->Write();
            }

            // Clean up
            for (size_t ci = 0; ci < coords.size(); ci++) {
                coords.at(ci)->Delete();
            }
            rgrid->Delete();
        }

        template<typename T>
        void
        VisitUtils<T>::write_multiarray_vtk(const std::string &filename,
                                            const std::string &variable_name,
                                            const CoordinateSystem <T> *cs,
                                            MultiArray <T> *array,
                                            bool write_legacy) {

            class Functor : public MultiArray<T>::ForEachFunctor
            {
            private:

                vtkDoubleArray *m_array;
                const CoordinateSystem<T> *m_cs;
                int nx, ny, nz;

            public:

                Functor(vtkDoubleArray *array, const CoordinateSystem<T> *cs) : m_array(array), m_cs(cs) {
                    VisitUtils<T>::get_vtk_image_dimensions(cs, nx, ny, nz);
                };

                void
                operator()(const vector<int> &index, const T value) {
                    int gx, gy, gz;
                    VisitUtils<T>::get_vtk_gridpoint(index, gx, gy, gz);
                    int gridIndex = VisitUtils<T>::to_single_index(m_cs, nx, ny, nz, gx, gy, gz);
                    m_array->SetValue(gridIndex, value);
                }
            };

            int nx, ny, nz;
            VisitUtils<T>::get_vtk_image_dimensions(cs, nx, ny, nz);

            vector<vtkDoubleArray *> coords;
            vtkRectilinearGrid *rgrid = allocate_vtk_rectilinear_grid(cs, coords);

            vtkDoubleArray *variable = vtkDoubleArray::New();
            variable->SetName(variable_name.c_str());
            variable->SetNumberOfComponents(1); // scalar
            variable->SetNumberOfValues(array->size());

            Functor f(variable, cs);
            array->for_each(&f);

            rgrid->GetPointData()->AddArray(variable);

            // Write out

            boost::filesystem::path path(filename);
            std::string basename = path.filename().stem().generic_string();

            if (write_legacy) {
                // ASCII

                vtkSmartPointer<vtkRectilinearGridWriter>
                        writer = vtkSmartPointer<vtkRectilinearGridWriter>::New();

                std::string fn = basename + ".vtk";
                writer->SetFileName(fn.c_str());

#if VTK_MAJOR_VERSION <= 5
                writer->SetInput(rgrid);
#else
                writer->SetInputData(rgrid);
#endif
                writer->Write();
            } else {
                // XML

                vtkSmartPointer<vtkXMLRectilinearGridWriter>
                        xmlWriter = vtkSmartPointer<vtkXMLRectilinearGridWriter>::New();
                std::string xml_fn = basename + "." + xmlWriter->GetDefaultFileExtension();

                xmlWriter->SetFileName(xml_fn.c_str());

#if VTK_MAJOR_VERSION <= 5
                xmlWriter->SetInput(rgrid);
#else
                xmlWriter->SetInputData(rgrid);
#endif
                xmlWriter->Write();
            }

            // Clean up

            for (size_t ci = 0; ci < coords.size(); ci++) {
                coords.at(ci)->Delete();
            }

            rgrid->Delete();
        };

        template<typename T>
        void
        VisitUtils<T>::write_multiarray_vtk(const std::string &filename,
                                            const std::string &variable_name,
                                            const CoordinateSystem <T> *cs,
                                            const MultiArray<bool> *array) {

            class Functor : public MultiArray<bool>::ForEachFunctor
            {
                std::ofstream &m_stream;
                const CoordinateSystem<T> *m_coord_system;
                bool m_write_coords;

            public:

                Functor(std::ofstream &stream,
                        const CoordinateSystem<T> *cs,
                        bool write_coords)
                        : m_stream(stream), m_coord_system(cs), m_write_coords(write_coords) {
                }

                void
                operator()(const vector<int> &index, const bool value) {
                    if (m_write_coords) {
                        for (size_t ri = 0; ri < 3; ri++) {
                            if (ri < index.size()) {
                                vector<T> coord(index.size());
                                m_coord_system->lookup(index, coord);
                                m_stream << coord[get_vtk_index(ri)] << "\t";
                            } else {
                                m_stream << 0.0 << "\t";
                            }
                        }
                        m_stream << endl;
                    } else {
                        m_stream << (value ? 1.0 : 0.0) << endl;
                    }
                }
            };

            ofstream f(filename.c_str());
            f << fixed << setprecision(4);

            // Write Header

            f << "# vtk DataFile Version 3.0" << endl;
            f << variable_name << endl;
            f << "ASCII" << endl;
            f << "DATASET UNSTRUCTURED_GRID" << endl;
            f << "POINTS " << array->size() << " FLOAT" << endl;

            // Write point coordinates out as unstructured grid

            Functor f1(f, cs, true);
            array->for_each(&f1);

            // Write weights

            f << endl;
            f << "POINT_DATA " << array->size() << endl;
            f << "SCALARS " << variable_name << " FLOAT" << endl;
            f << "LOOKUP_TABLE default" << endl;

            Functor f2(f, cs, false);
            array->for_each(&f2);
        };
    }
}

#endif
#endif

redpajama_set_name: RedPajamaGithub