<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "google/cloud/storage/client.h"
#include <functional>
#include <iostream>
#include <map>
#include <sstream>

namespace {
struct Usage {
  std::string msg;
};

char const* ConsumeArg(int& argc, char* argv[]) {
  if (argc < 2) {
    return nullptr;
  }
  char const* result = argv[1];
  std::copy(argv + 2, argv + argc, argv + 1);
  argc--;
  return result;
}

std::string command_usage;

void PrintUsage(int, char* argv[], std::string const& msg) {
  std::string const cmd = argv[0];
  auto last_slash = std::string(cmd).find_last_of('/');
  auto program = cmd.substr(last_slash + 1);
  std::cerr << msg << "\nUsage: " << program << " <command> [arguments]\n\n"
            << "Commands:\n"
            << command_usage << "\n";
}

void GetServiceAccount(google::cloud::storage::Client client, int& argc,
                       char*[]) {
  if (argc != 1) {
    throw Usage{"get-service-account"};
  }
  //! [get service account]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client) {
    StatusOr<gcs::ServiceAccount> service_account_details =
        client.GetServiceAccount();

    if (!service_account_details) {
      throw std::runtime_error(service_account_details.status().message());
    }
    std::cout << "The service account details are " << *service_account_details
              << "\n";
  }
  //! [get service account]
  (std::move(client));
}

void GetServiceAccountForProject(google::cloud::storage::Client client,
                                 int& argc, char* argv[]) {
  if (argc != 2) {
    throw Usage{"get-service-account-for-project <project-id>"};
  }
  auto project_id = ConsumeArg(argc, argv);
  //! [get service account for project]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string project_id) {
    StatusOr<gcs::ServiceAccount> service_account_details =
        client.GetServiceAccountForProject(project_id);

    if (!service_account_details) {
      throw std::runtime_error(service_account_details.status().message());
    }

    std::cout << "The service account details for project " << project_id
              << " are " << *service_account_details << "\n";
  }
  //! [get service account for project]
  (std::move(client), project_id);
}

void ListHmacKeys(google::cloud::storage::Client client, int& argc, char*[]) {
  if (argc != 1) {
    throw Usage{"list-hmac-keys"};
  }
  //! [list hmac keys] [START storage_list_hmac_keys]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client) {
    int count = 0;
    gcs::ListHmacKeysReader hmac_keys_list = client.ListHmacKeys();
    for (auto&& hmac_key_metadata : hmac_keys_list) {
      if (!hmac_key_metadata) {
        throw std::runtime_error(hmac_key_metadata.status().message());
      }
      std::cout << "service_account_email = "
                << hmac_key_metadata->service_account_email()
                << "\naccess_id = " << hmac_key_metadata->access_id() << "\n";
      ++count;
    }
    if (count == 0) {
      std::cout << "No HMAC keys in default project\n";
    }
  }
  //! [list hmac keys] [END storage_list_hmac_keys]
  (std::move(client));
}

void ListHmacKeysWithServiceAccount(google::cloud::storage::Client client,
                                    int& argc, char* argv[]) {
  if (argc != 2) {
    throw Usage{"list-hmac-keys-with-service-account <service-account>"};
  }
  //! [list hmac keys service account]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string service_account) {
    int count = 0;
    gcs::ListHmacKeysReader hmac_keys_list =
        client.ListHmacKeys(gcs::ServiceAccountFilter(service_account));
    for (auto&& hmac_key_metadata : hmac_keys_list) {
      if (!hmac_key_metadata) {
        throw std::runtime_error(hmac_key_metadata.status().message());
      }
      std::cout << "service_account_email = "
                << hmac_key_metadata->service_account_email()
                << "\naccess_id = " << hmac_key_metadata->access_id() << "\n";
      ++count;
    }
    if (count == 0) {
      std::cout << "No HMAC keys for service account " << service_account
                << " in default project\n";
    }
  }
  //! [list hmac keys service account]
  (std::move(client), argv[1]);
}

void CreateHmacKey(google::cloud::storage::Client client, int& argc,
                   char* argv[]) {
  if (argc != 2) {
    throw Usage{"create-hmac-key <service-account-email>"};
  }
  //! [create hmac key] [START storage_create_hmac_key]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string service_account_email) {
    StatusOr<std::pair<gcs::HmacKeyMetadata, std::string>> hmac_key_details =
        client.CreateHmacKey(service_account_email);

    if (!hmac_key_details) {
      throw std::runtime_error(hmac_key_details.status().message());
    }
    std::cout << "The base64 encoded secret is: " << hmac_key_details->second
              << "\nDo not miss that secret, there is no API to recover it."
              << "\nThe HMAC key metadata is: " << hmac_key_details->first
              << "\n";
  }
  //! [create hmac key] [END storage_create_hmac_key]
  (std::move(client), argv[1]);
}

void CreateHmacKeyForProject(google::cloud::storage::Client client, int& argc,
                             char* argv[]) {
  if (argc != 3) {
    throw Usage{
        "create-hmac-key-for-project <project-id> <service-account-email>"};
  }
  //! [create hmac key project]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string project_id,
     std::string service_account_email) {
    StatusOr<std::pair<gcs::HmacKeyMetadata, std::string>> hmac_key_details =
        client.CreateHmacKey(service_account_email,
                             gcs::OverrideDefaultProject(project_id));

    if (!hmac_key_details) {
      throw std::runtime_error(hmac_key_details.status().message());
    }
    std::cout << "The base64 encoded secret is: " << hmac_key_details->second
              << "\nDo not miss that secret, there is no API to recover it."
              << "\nThe HMAC key metadata is: " << hmac_key_details->first
              << "\n";
  }
  //! [create hmac key project]
  (std::move(client), argv[1], argv[2]);
}

void DeleteHmacKey(google::cloud::storage::Client client, int& argc,
                   char* argv[]) {
  if (argc != 2) {
    throw Usage{"delete-hmac-key <access-id>"};
  }
  //! [delete hmac key] [START storage_delete_hmac_key]
  namespace gcs = google::cloud::storage;
  [](gcs::Client client, std::string access_id) {
    google::cloud::Status status = client.DeleteHmacKey(access_id);

    if (!status.ok()) {
      throw std::runtime_error(status.message());
    }
    std::cout << "The key is deleted, though it may still appear"
              << " in ListHmacKeys() results.\n";
  }
  //! [delete hmac key] [END storage_delete_hmac_key]
  (std::move(client), argv[1]);
}

void GetHmacKey(google::cloud::storage::Client client, int& argc,
                char* argv[]) {
  if (argc != 2) {
    throw Usage{"get-hmac-key <access-id>"};
  }
  //! [get hmac key] [START storage_get_hmac_key]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string access_id) {
    StatusOr<gcs::HmacKeyMetadata> hmac_key_details =
        client.GetHmacKey(access_id);

    if (!hmac_key_details) {
      throw std::runtime_error(hmac_key_details.status().message());
    }
    std::cout << "The HMAC key metadata is: " << *hmac_key_details << "\n";
  }
  //! [get hmac key] [END storage_get_hmac_key]
  (std::move(client), argv[1]);
}

void UpdateHmacKey(google::cloud::storage::Client client, int& argc,
                   char* argv[]) {
  if (argc != 3) {
    throw Usage{"update-hmac-key <access-id> <state>"};
  }
  //! [update hmac key]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string access_id, std::string state) {
    StatusOr<gcs::HmacKeyMetadata> current_metadata =
        client.GetHmacKey(access_id);
    if (!current_metadata) {
      throw std::runtime_error(current_metadata.status().message());
    }

    StatusOr<gcs::HmacKeyMetadata> updated_metadata = client.UpdateHmacKey(
        access_id, gcs::HmacKeyMetadata().set_state(std::move(state)));

    if (!updated_metadata) {
      throw std::runtime_error(updated_metadata.status().message());
    }
    std::cout << "The updated HMAC key metadata is: " << *updated_metadata
              << "\n";
  }
  //! [update hmac key]
  (std::move(client), argv[1], argv[2]);
}

void ActivateHmacKey(google::cloud::storage::Client client, int& argc,
                     char* argv[]) {
  if (argc != 2) {
    throw Usage{"activate-hmac-key <access-id>"};
  }
  //! [START storage_activate_hmac_key]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string access_id) {
    StatusOr<gcs::HmacKeyMetadata> updated_metadata = client.UpdateHmacKey(
        access_id,
        gcs::HmacKeyMetadata().set_state(gcs::HmacKeyMetadata::state_active()));

    if (!updated_metadata) {
      throw std::runtime_error(updated_metadata.status().message());
    }
    if (updated_metadata->state() != gcs::HmacKeyMetadata::state_active()) {
      throw std::runtime_error(
          "The HMAC key is NOT active, this is unexpected");
    }
    std::cout << "The HMAC key is now active\nFull metadata: "
              << *updated_metadata << "\n";
  }
  //! [END storage_activate_hmac_key]
  (std::move(client), argv[1]);
}

void DeactivateHmacKey(google::cloud::storage::Client client, int& argc,
                       char* argv[]) {
  if (argc != 2) {
    throw Usage{"deactivate-hmac-key <access-id>"};
  }
  //! [START storage_deactivate_hmac_key]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string access_id) {
    StatusOr<gcs::HmacKeyMetadata> updated_metadata = client.UpdateHmacKey(
        access_id, gcs::HmacKeyMetadata().set_state(
                       gcs::HmacKeyMetadata::state_inactive()));

    if (!updated_metadata) {
      throw std::runtime_error(updated_metadata.status().message());
    }
    if (updated_metadata->state() != gcs::HmacKeyMetadata::state_inactive()) {
      throw std::runtime_error("The HMAC key is active, this is unexpected");
    }
    std::cout << "The HMAC key is now inactive\nFull metadata: "
              << *updated_metadata << "\n";
  }
  //! [END storage_deactivate_hmac_key]
  (std::move(client), argv[1]);
}

}  // anonymous namespace

int main(int argc, char* argv[]) try {
  // Create a client to communicate with Google Cloud Storage.
  google::cloud::StatusOr<google::cloud::storage::Client> client =
      google::cloud::storage::Client::CreateDefaultClient();
  if (!client) {
    std::cerr << "Failed to create Storage Client, status=" << client.status()
              << "\n";
    return 1;
  }

  using CommandType =
      std::function<void(google::cloud::storage::Client, int&, char*[])>;
  std::map<std::string, CommandType> commands = {
      {"get-service-account", &GetServiceAccount},
      {"get-service-account-for-project", &GetServiceAccountForProject},
      {"list-hmac-keys", &ListHmacKeys},
      {"list-hmac-keys-with-service-account", &ListHmacKeysWithServiceAccount},
      {"create-hmac-key-for-project", &CreateHmacKeyForProject},
      {"create-hmac-key", &CreateHmacKey},
      {"delete-hmac-key", &DeleteHmacKey},
      {"get-hmac-key", &GetHmacKey},
      {"update-hmac-key", &UpdateHmacKey},
      {"activate-hmac-key", &ActivateHmacKey},
      {"deactivate-hmac-key", &DeactivateHmacKey},
  };
  for (auto&& kv : commands) {
    try {
      int fake_argc = 0;
      kv.second(*client, fake_argc, argv);
    } catch (Usage const& u) {
      command_usage += "    ";
      command_usage += u.msg;
      command_usage += "\n";
    } catch (...) {
      // ignore other exceptions.
    }
  }

  if (argc < 2) {
    PrintUsage(argc, argv, "Missing command");
    return 1;
  }

  std::string const command = ConsumeArg(argc, argv);
  auto it = commands.find(command);
  if (commands.end() == it) {
    PrintUsage(argc, argv, "Unknown command: " + command);
    return 1;
  }

  it->second(*client, argc, argv);

  return 0;
} catch (Usage const& ex) {
  PrintUsage(argc, argv, ex.msg);
  return 1;
} catch (std::exception const& ex) {
  std::cerr << "Standard C++ exception raised: " << ex.what() << "\n";
  return 1;
}
<commit_msg>doc: add storage_get_service_account tag (#3278)<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "google/cloud/storage/client.h"
#include <functional>
#include <iostream>
#include <map>
#include <sstream>

namespace {
struct Usage {
  std::string msg;
};

char const* ConsumeArg(int& argc, char* argv[]) {
  if (argc < 2) {
    return nullptr;
  }
  char const* result = argv[1];
  std::copy(argv + 2, argv + argc, argv + 1);
  argc--;
  return result;
}

std::string command_usage;

void PrintUsage(int, char* argv[], std::string const& msg) {
  std::string const cmd = argv[0];
  auto last_slash = std::string(cmd).find_last_of('/');
  auto program = cmd.substr(last_slash + 1);
  std::cerr << msg << "\nUsage: " << program << " <command> [arguments]\n\n"
            << "Commands:\n"
            << command_usage << "\n";
}

void GetServiceAccount(google::cloud::storage::Client client, int& argc,
                       char*[]) {
  if (argc != 1) {
    throw Usage{"get-service-account"};
  }
  //! [START storage_get_service_account] [get service account]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client) {
    StatusOr<gcs::ServiceAccount> service_account_details =
        client.GetServiceAccount();

    if (!service_account_details) {
      throw std::runtime_error(service_account_details.status().message());
    }
    std::cout << "The service account details are " << *service_account_details
              << "\n";
  }
  //! [END storage_get_service_account] [get service account]
  (std::move(client));
}

void GetServiceAccountForProject(google::cloud::storage::Client client,
                                 int& argc, char* argv[]) {
  if (argc != 2) {
    throw Usage{"get-service-account-for-project <project-id>"};
  }
  auto project_id = ConsumeArg(argc, argv);
  //! [get service account for project]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string project_id) {
    StatusOr<gcs::ServiceAccount> service_account_details =
        client.GetServiceAccountForProject(project_id);

    if (!service_account_details) {
      throw std::runtime_error(service_account_details.status().message());
    }

    std::cout << "The service account details for project " << project_id
              << " are " << *service_account_details << "\n";
  }
  //! [get service account for project]
  (std::move(client), project_id);
}

void ListHmacKeys(google::cloud::storage::Client client, int& argc, char*[]) {
  if (argc != 1) {
    throw Usage{"list-hmac-keys"};
  }
  //! [list hmac keys] [START storage_list_hmac_keys]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client) {
    int count = 0;
    gcs::ListHmacKeysReader hmac_keys_list = client.ListHmacKeys();
    for (auto&& hmac_key_metadata : hmac_keys_list) {
      if (!hmac_key_metadata) {
        throw std::runtime_error(hmac_key_metadata.status().message());
      }
      std::cout << "service_account_email = "
                << hmac_key_metadata->service_account_email()
                << "\naccess_id = " << hmac_key_metadata->access_id() << "\n";
      ++count;
    }
    if (count == 0) {
      std::cout << "No HMAC keys in default project\n";
    }
  }
  //! [list hmac keys] [END storage_list_hmac_keys]
  (std::move(client));
}

void ListHmacKeysWithServiceAccount(google::cloud::storage::Client client,
                                    int& argc, char* argv[]) {
  if (argc != 2) {
    throw Usage{"list-hmac-keys-with-service-account <service-account>"};
  }
  //! [list hmac keys service account]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string service_account) {
    int count = 0;
    gcs::ListHmacKeysReader hmac_keys_list =
        client.ListHmacKeys(gcs::ServiceAccountFilter(service_account));
    for (auto&& hmac_key_metadata : hmac_keys_list) {
      if (!hmac_key_metadata) {
        throw std::runtime_error(hmac_key_metadata.status().message());
      }
      std::cout << "service_account_email = "
                << hmac_key_metadata->service_account_email()
                << "\naccess_id = " << hmac_key_metadata->access_id() << "\n";
      ++count;
    }
    if (count == 0) {
      std::cout << "No HMAC keys for service account " << service_account
                << " in default project\n";
    }
  }
  //! [list hmac keys service account]
  (std::move(client), argv[1]);
}

void CreateHmacKey(google::cloud::storage::Client client, int& argc,
                   char* argv[]) {
  if (argc != 2) {
    throw Usage{"create-hmac-key <service-account-email>"};
  }
  //! [create hmac key] [START storage_create_hmac_key]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string service_account_email) {
    StatusOr<std::pair<gcs::HmacKeyMetadata, std::string>> hmac_key_details =
        client.CreateHmacKey(service_account_email);

    if (!hmac_key_details) {
      throw std::runtime_error(hmac_key_details.status().message());
    }
    std::cout << "The base64 encoded secret is: " << hmac_key_details->second
              << "\nDo not miss that secret, there is no API to recover it."
              << "\nThe HMAC key metadata is: " << hmac_key_details->first
              << "\n";
  }
  //! [create hmac key] [END storage_create_hmac_key]
  (std::move(client), argv[1]);
}

void CreateHmacKeyForProject(google::cloud::storage::Client client, int& argc,
                             char* argv[]) {
  if (argc != 3) {
    throw Usage{
        "create-hmac-key-for-project <project-id> <service-account-email>"};
  }
  //! [create hmac key project]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string project_id,
     std::string service_account_email) {
    StatusOr<std::pair<gcs::HmacKeyMetadata, std::string>> hmac_key_details =
        client.CreateHmacKey(service_account_email,
                             gcs::OverrideDefaultProject(project_id));

    if (!hmac_key_details) {
      throw std::runtime_error(hmac_key_details.status().message());
    }
    std::cout << "The base64 encoded secret is: " << hmac_key_details->second
              << "\nDo not miss that secret, there is no API to recover it."
              << "\nThe HMAC key metadata is: " << hmac_key_details->first
              << "\n";
  }
  //! [create hmac key project]
  (std::move(client), argv[1], argv[2]);
}

void DeleteHmacKey(google::cloud::storage::Client client, int& argc,
                   char* argv[]) {
  if (argc != 2) {
    throw Usage{"delete-hmac-key <access-id>"};
  }
  //! [delete hmac key] [START storage_delete_hmac_key]
  namespace gcs = google::cloud::storage;
  [](gcs::Client client, std::string access_id) {
    google::cloud::Status status = client.DeleteHmacKey(access_id);

    if (!status.ok()) {
      throw std::runtime_error(status.message());
    }
    std::cout << "The key is deleted, though it may still appear"
              << " in ListHmacKeys() results.\n";
  }
  //! [delete hmac key] [END storage_delete_hmac_key]
  (std::move(client), argv[1]);
}

void GetHmacKey(google::cloud::storage::Client client, int& argc,
                char* argv[]) {
  if (argc != 2) {
    throw Usage{"get-hmac-key <access-id>"};
  }
  //! [get hmac key] [START storage_get_hmac_key]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string access_id) {
    StatusOr<gcs::HmacKeyMetadata> hmac_key_details =
        client.GetHmacKey(access_id);

    if (!hmac_key_details) {
      throw std::runtime_error(hmac_key_details.status().message());
    }
    std::cout << "The HMAC key metadata is: " << *hmac_key_details << "\n";
  }
  //! [get hmac key] [END storage_get_hmac_key]
  (std::move(client), argv[1]);
}

void UpdateHmacKey(google::cloud::storage::Client client, int& argc,
                   char* argv[]) {
  if (argc != 3) {
    throw Usage{"update-hmac-key <access-id> <state>"};
  }
  //! [update hmac key]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string access_id, std::string state) {
    StatusOr<gcs::HmacKeyMetadata> current_metadata =
        client.GetHmacKey(access_id);
    if (!current_metadata) {
      throw std::runtime_error(current_metadata.status().message());
    }

    StatusOr<gcs::HmacKeyMetadata> updated_metadata = client.UpdateHmacKey(
        access_id, gcs::HmacKeyMetadata().set_state(std::move(state)));

    if (!updated_metadata) {
      throw std::runtime_error(updated_metadata.status().message());
    }
    std::cout << "The updated HMAC key metadata is: " << *updated_metadata
              << "\n";
  }
  //! [update hmac key]
  (std::move(client), argv[1], argv[2]);
}

void ActivateHmacKey(google::cloud::storage::Client client, int& argc,
                     char* argv[]) {
  if (argc != 2) {
    throw Usage{"activate-hmac-key <access-id>"};
  }
  //! [START storage_activate_hmac_key]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string access_id) {
    StatusOr<gcs::HmacKeyMetadata> updated_metadata = client.UpdateHmacKey(
        access_id,
        gcs::HmacKeyMetadata().set_state(gcs::HmacKeyMetadata::state_active()));

    if (!updated_metadata) {
      throw std::runtime_error(updated_metadata.status().message());
    }
    if (updated_metadata->state() != gcs::HmacKeyMetadata::state_active()) {
      throw std::runtime_error(
          "The HMAC key is NOT active, this is unexpected");
    }
    std::cout << "The HMAC key is now active\nFull metadata: "
              << *updated_metadata << "\n";
  }
  //! [END storage_activate_hmac_key]
  (std::move(client), argv[1]);
}

void DeactivateHmacKey(google::cloud::storage::Client client, int& argc,
                       char* argv[]) {
  if (argc != 2) {
    throw Usage{"deactivate-hmac-key <access-id>"};
  }
  //! [START storage_deactivate_hmac_key]
  namespace gcs = google::cloud::storage;
  using ::google::cloud::StatusOr;
  [](gcs::Client client, std::string access_id) {
    StatusOr<gcs::HmacKeyMetadata> updated_metadata = client.UpdateHmacKey(
        access_id, gcs::HmacKeyMetadata().set_state(
                       gcs::HmacKeyMetadata::state_inactive()));

    if (!updated_metadata) {
      throw std::runtime_error(updated_metadata.status().message());
    }
    if (updated_metadata->state() != gcs::HmacKeyMetadata::state_inactive()) {
      throw std::runtime_error("The HMAC key is active, this is unexpected");
    }
    std::cout << "The HMAC key is now inactive\nFull metadata: "
              << *updated_metadata << "\n";
  }
  //! [END storage_deactivate_hmac_key]
  (std::move(client), argv[1]);
}

}  // anonymous namespace

int main(int argc, char* argv[]) try {
  // Create a client to communicate with Google Cloud Storage.
  google::cloud::StatusOr<google::cloud::storage::Client> client =
      google::cloud::storage::Client::CreateDefaultClient();
  if (!client) {
    std::cerr << "Failed to create Storage Client, status=" << client.status()
              << "\n";
    return 1;
  }

  using CommandType =
      std::function<void(google::cloud::storage::Client, int&, char*[])>;
  std::map<std::string, CommandType> commands = {
      {"get-service-account", &GetServiceAccount},
      {"get-service-account-for-project", &GetServiceAccountForProject},
      {"list-hmac-keys", &ListHmacKeys},
      {"list-hmac-keys-with-service-account", &ListHmacKeysWithServiceAccount},
      {"create-hmac-key-for-project", &CreateHmacKeyForProject},
      {"create-hmac-key", &CreateHmacKey},
      {"delete-hmac-key", &DeleteHmacKey},
      {"get-hmac-key", &GetHmacKey},
      {"update-hmac-key", &UpdateHmacKey},
      {"activate-hmac-key", &ActivateHmacKey},
      {"deactivate-hmac-key", &DeactivateHmacKey},
  };
  for (auto&& kv : commands) {
    try {
      int fake_argc = 0;
      kv.second(*client, fake_argc, argv);
    } catch (Usage const& u) {
      command_usage += "    ";
      command_usage += u.msg;
      command_usage += "\n";
    } catch (...) {
      // ignore other exceptions.
    }
  }

  if (argc < 2) {
    PrintUsage(argc, argv, "Missing command");
    return 1;
  }

  std::string const command = ConsumeArg(argc, argv);
  auto it = commands.find(command);
  if (commands.end() == it) {
    PrintUsage(argc, argv, "Unknown command: " + command);
    return 1;
  }

  it->second(*client, argc, argv);

  return 0;
} catch (Usage const& ex) {
  PrintUsage(argc, argv, ex.msg);
  return 1;
} catch (std::exception const& ex) {
  std::cerr << "Standard C++ exception raised: " << ex.what() << "\n";
  return 1;
}
<|endoftext|>


<commit_before>#include "tileManager.h"
#include "scene/scene.h"
#include "tile/mapTile.h"
#include "view/view.h"

#include <chrono>
#include <algorithm>

TileManager::TileManager() {

    // Instantiate workers
    for (size_t i = 0; i < MAX_WORKERS; i++) {
        m_workers.push_back(std::unique_ptr<TileWorker>(new TileWorker()));
    }
}

TileManager::TileManager(TileManager&& _other) :
    m_view(std::move(_other.m_view)),
    m_tileSet(std::move(_other.m_tileSet)),
    m_dataSources(std::move(_other.m_dataSources)),
    m_workers(std::move(_other.m_workers)),
    m_queuedTiles(std::move(_other.m_queuedTiles)) {
}

TileManager::~TileManager() {
    for (auto& worker : m_workers) {
        if (!worker->isFree()) {
            worker->abort();
            worker->getTileResult();
        }
        // We stop all workers before we destroy the resources they use.
        // TODO: This will wait for any pending network requests to finish,
        // which could delay closing of the application.
    }
    m_dataSources.clear();
    m_tileSet.clear();
}

void TileManager::updateTileSet() {

    m_tileSetChanged = false;

    // Check if any incoming tiles are finished
    for (auto& worker : m_workers) {

        if (!worker->isFree() && worker->isFinished()) {

            // Get result from worker and move it into tile set
            auto tile = worker->getTileResult();
            const TileID& id = tile->getID();
            logMsg("Tile [%d, %d, %d] finished loading\n", id.z, id.x, id.y);
            std::swap(m_tileSet[id], tile);
            cleanProxyTiles(id);
            m_tileSetChanged = true;

        }

    }

    if (! (m_view->changedOnLastUpdate() || m_tileSetChanged) ) {
        // No new tiles have come into view and no tiles have finished loading,
        // so the tileset is unchanged
        return;
    }

    const std::set<TileID>& visibleTiles = m_view->getVisibleTiles();

    // Loop over visibleTiles and add any needed tiles to tileSet
    {
        auto setTilesIter = m_tileSet.begin();
        auto visTilesIter = visibleTiles.begin();

        while (visTilesIter != visibleTiles.end()) {

            if (setTilesIter == m_tileSet.end() || *visTilesIter < setTilesIter->first) {
                // tileSet is missing an element present in visibleTiles
                addTile(*visTilesIter);
                m_tileSetChanged = true;
                ++visTilesIter;
            } else if (setTilesIter->first < *visTilesIter) {
                // visibleTiles is missing an element present in tileSet (handled below)
                ++setTilesIter;
            } else {
                // tiles in both sets match, move on
                ++setTilesIter;
                ++visTilesIter;
            }
        }
    }

    // Loop over tileSet and remove any tiles that are neither visible nor proxies
    {
        auto setTilesIter = m_tileSet.begin();
        auto visTilesIter = visibleTiles.begin();

        while (setTilesIter != m_tileSet.end()) {

            if (visTilesIter == visibleTiles.end() || setTilesIter->first < *visTilesIter) {
                // visibleTiles is missing an element present in tileSet
                if (setTilesIter->second->getProxyCounter() <= 0) {
                    removeTile(setTilesIter);
                    m_tileSetChanged = true;
                } else {
                    ++setTilesIter;
                }
            } else if (*visTilesIter < setTilesIter->first) {
                // tileSet is missing an element present in visibleTiles (shouldn't occur)
                ++visTilesIter;
            } else {
                // tiles in both sets match, move on
                ++setTilesIter;
                ++visTilesIter;
            }
        }
    }

    // Dispatch workers for queued tiles
    {
        auto workersIter = m_workers.begin();
        auto queuedTilesIter = m_queuedTiles.begin();

        while (workersIter != m_workers.end() && queuedTilesIter != m_queuedTiles.end()) {

            TileID id = *queuedTilesIter;
            auto& worker = *workersIter;

            if (worker->isFree()) {
                worker->load(id, m_dataSources, m_scene->getStyles(), *m_view);
                queuedTilesIter = m_queuedTiles.erase(queuedTilesIter);
            }

            ++workersIter;
        }
    }
}

void TileManager::addTile(const TileID& _tileID) {

    std::shared_ptr<MapTile> tile(new MapTile(_tileID, m_view->getMapProjection()));
    m_tileSet[_tileID] = std::move(tile);

    //Add Proxy if corresponding proxy MapTile ready
    updateProxyTiles(_tileID, m_view->isZoomIn());

    // Queue tile for workers
    m_queuedTiles.push_front(_tileID);

}

void TileManager::removeTile(std::map< TileID, std::shared_ptr<MapTile> >::iterator& _tileIter) {

    const TileID& id = _tileIter->first;

    // Remove tile from queue, if present
    const auto& found = std::find(m_queuedTiles.begin(), m_queuedTiles.end(), id);
    if (found != m_queuedTiles.end()) {
        m_queuedTiles.erase(found);
        cleanProxyTiles(id);
    }

    // If a worker is loading this tile, abort it
    for (const auto& worker : m_workers) {
        if (!worker->isFree() && worker->getTileID() == id) {
            worker->abort();
            // Proxy tiles will be cleaned in update loop
        }
    }

    // Remove labels for tile
    LabelContainer::GetInstance()->removeLabels(id);

    // Remove tile from set
    _tileIter = m_tileSet.erase(_tileIter);

}

void TileManager::updateProxyTiles(const TileID& _tileID, bool _zoomingIn) {
    if (_zoomingIn) {
        // zoom in - add parent
        const auto& parentID = _tileID.getParent();
        const auto& parentTileIter = m_tileSet.find(parentID);
        if (parentID.isValid() && parentTileIter != m_tileSet.end()) {
            parentTileIter->second->incProxyCounter();
        }
    } else {
        for(int i = 0; i < 4; i++) {
            const auto& childID = _tileID.getChild(i);
            const auto& childTileIter = m_tileSet.find(childID);
            if(childID.isValid(m_view->s_maxZoom) && childTileIter != m_tileSet.end()) {
                childTileIter->second->incProxyCounter();
            }
        }
    }
}

void TileManager::cleanProxyTiles(const TileID& _tileID) {
    // check if parent proxy is present
    const auto& parentID = _tileID.getParent();
    const auto& parentTileIter = m_tileSet.find(parentID);
    if (parentID.isValid() && parentTileIter != m_tileSet.end()) {
        parentTileIter->second->decProxyCounter();
    }

    // check if child proxies are present
    for(int i = 0; i < 4; i++) {
        const auto& childID = _tileID.getChild(i);
        const auto& childTileIter = m_tileSet.find(childID);
        if(childID.isValid(m_view->s_maxZoom) && childTileIter != m_tileSet.end()) {
            childTileIter->second->decProxyCounter();
        }
    }
}
<commit_msg>Fix an issue in tile queueing that reversed the preferred tile ordering<commit_after>#include "tileManager.h"
#include "scene/scene.h"
#include "tile/mapTile.h"
#include "view/view.h"

#include <chrono>
#include <algorithm>

TileManager::TileManager() {

    // Instantiate workers
    for (size_t i = 0; i < MAX_WORKERS; i++) {
        m_workers.push_back(std::unique_ptr<TileWorker>(new TileWorker()));
    }
}

TileManager::TileManager(TileManager&& _other) :
    m_view(std::move(_other.m_view)),
    m_tileSet(std::move(_other.m_tileSet)),
    m_dataSources(std::move(_other.m_dataSources)),
    m_workers(std::move(_other.m_workers)),
    m_queuedTiles(std::move(_other.m_queuedTiles)) {
}

TileManager::~TileManager() {
    for (auto& worker : m_workers) {
        if (!worker->isFree()) {
            worker->abort();
            worker->getTileResult();
        }
        // We stop all workers before we destroy the resources they use.
        // TODO: This will wait for any pending network requests to finish,
        // which could delay closing of the application.
    }
    m_dataSources.clear();
    m_tileSet.clear();
}

void TileManager::updateTileSet() {

    m_tileSetChanged = false;

    // Check if any incoming tiles are finished
    for (auto& worker : m_workers) {

        if (!worker->isFree() && worker->isFinished()) {

            // Get result from worker and move it into tile set
            auto tile = worker->getTileResult();
            const TileID& id = tile->getID();
            logMsg("Tile [%d, %d, %d] finished loading\n", id.z, id.x, id.y);
            std::swap(m_tileSet[id], tile);
            cleanProxyTiles(id);
            m_tileSetChanged = true;

        }

    }

    if (! (m_view->changedOnLastUpdate() || m_tileSetChanged) ) {
        // No new tiles have come into view and no tiles have finished loading,
        // so the tileset is unchanged
        return;
    }

    const std::set<TileID>& visibleTiles = m_view->getVisibleTiles();

    // Loop over visibleTiles and add any needed tiles to tileSet
    {
        auto setTilesIter = m_tileSet.begin();
        auto visTilesIter = visibleTiles.begin();

        while (visTilesIter != visibleTiles.end()) {

            if (setTilesIter == m_tileSet.end() || *visTilesIter < setTilesIter->first) {
                // tileSet is missing an element present in visibleTiles
                addTile(*visTilesIter);
                m_tileSetChanged = true;
                ++visTilesIter;
            } else if (setTilesIter->first < *visTilesIter) {
                // visibleTiles is missing an element present in tileSet (handled below)
                ++setTilesIter;
            } else {
                // tiles in both sets match, move on
                ++setTilesIter;
                ++visTilesIter;
            }
        }
    }

    // Loop over tileSet and remove any tiles that are neither visible nor proxies
    {
        auto setTilesIter = m_tileSet.begin();
        auto visTilesIter = visibleTiles.begin();

        while (setTilesIter != m_tileSet.end()) {

            if (visTilesIter == visibleTiles.end() || setTilesIter->first < *visTilesIter) {
                // visibleTiles is missing an element present in tileSet
                if (setTilesIter->second->getProxyCounter() <= 0) {
                    removeTile(setTilesIter);
                    m_tileSetChanged = true;
                } else {
                    ++setTilesIter;
                }
            } else if (*visTilesIter < setTilesIter->first) {
                // tileSet is missing an element present in visibleTiles (shouldn't occur)
                ++visTilesIter;
            } else {
                // tiles in both sets match, move on
                ++setTilesIter;
                ++visTilesIter;
            }
        }
    }

    // Dispatch workers for queued tiles
    {
        auto workersIter = m_workers.begin();
        auto queuedTilesIter = m_queuedTiles.begin();

        while (workersIter != m_workers.end() && queuedTilesIter != m_queuedTiles.end()) {

            TileID id = *queuedTilesIter;
            auto& worker = *workersIter;

            if (worker->isFree()) {
                worker->load(id, m_dataSources, m_scene->getStyles(), *m_view);
                queuedTilesIter = m_queuedTiles.erase(queuedTilesIter);
            }

            ++workersIter;
        }
    }
}

void TileManager::addTile(const TileID& _tileID) {

    std::shared_ptr<MapTile> tile(new MapTile(_tileID, m_view->getMapProjection()));
    m_tileSet[_tileID] = std::move(tile);

    //Add Proxy if corresponding proxy MapTile ready
    updateProxyTiles(_tileID, m_view->isZoomIn());

    // Queue tile for workers
    m_queuedTiles.push_back(_tileID);

}

void TileManager::removeTile(std::map< TileID, std::shared_ptr<MapTile> >::iterator& _tileIter) {

    const TileID& id = _tileIter->first;

    // Remove tile from queue, if present
    const auto& found = std::find(m_queuedTiles.begin(), m_queuedTiles.end(), id);
    if (found != m_queuedTiles.end()) {
        m_queuedTiles.erase(found);
        cleanProxyTiles(id);
    }

    // If a worker is loading this tile, abort it
    for (const auto& worker : m_workers) {
        if (!worker->isFree() && worker->getTileID() == id) {
            worker->abort();
            // Proxy tiles will be cleaned in update loop
        }
    }

    // Remove labels for tile
    LabelContainer::GetInstance()->removeLabels(id);

    // Remove tile from set
    _tileIter = m_tileSet.erase(_tileIter);

}

void TileManager::updateProxyTiles(const TileID& _tileID, bool _zoomingIn) {
    if (_zoomingIn) {
        // zoom in - add parent
        const auto& parentID = _tileID.getParent();
        const auto& parentTileIter = m_tileSet.find(parentID);
        if (parentID.isValid() && parentTileIter != m_tileSet.end()) {
            parentTileIter->second->incProxyCounter();
        }
    } else {
        for(int i = 0; i < 4; i++) {
            const auto& childID = _tileID.getChild(i);
            const auto& childTileIter = m_tileSet.find(childID);
            if(childID.isValid(m_view->s_maxZoom) && childTileIter != m_tileSet.end()) {
                childTileIter->second->incProxyCounter();
            }
        }
    }
}

void TileManager::cleanProxyTiles(const TileID& _tileID) {
    // check if parent proxy is present
    const auto& parentID = _tileID.getParent();
    const auto& parentTileIter = m_tileSet.find(parentID);
    if (parentID.isValid() && parentTileIter != m_tileSet.end()) {
        parentTileIter->second->decProxyCounter();
    }

    // check if child proxies are present
    for(int i = 0; i < 4; i++) {
        const auto& childID = _tileID.getChild(i);
        const auto& childTileIter = m_tileSet.find(childID);
        if(childID.isValid(m_view->s_maxZoom) && childTileIter != m_tileSet.end()) {
            childTileIter->second->decProxyCounter();
        }
    }
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2010 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id$

// mapnik
#include <mapnik/agg_renderer.hpp>
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/image_util.hpp>

// stl
#include <cmath>

namespace mapnik {

template <typename T>
void agg_renderer<T>::process(raster_symbolizer const& sym,
                              Feature const& feature,
                              proj_transform const& prj_trans)
{
    raster_ptr const& raster=feature.get_raster();
    if (raster)
    {
        // If there's a colorizer defined, use it to color the raster in-place
        raster_colorizer_ptr colorizer = sym.get_colorizer();
        if (colorizer)
            colorizer->colorize(raster);

        box2d<double> ext=t_.forward(raster->ext_);

        int start_x = (int)ext.minx();
        int start_y = (int)ext.miny();
        int end_x = (int)ceil(ext.maxx());
        int end_y = (int)ceil(ext.maxy());
        int raster_width = end_x - start_x;
        int raster_height = end_y - start_y;
        double err_offs_x = ext.minx() - start_x;
        double err_offs_y = ext.miny() - start_y;

        if ( raster_width > 0 && raster_height > 0)
        {
            double scale_factor = ext.width() / raster->data_.width();
            image_data_32 target(raster_width,raster_height);

            if (sym.get_scaling() == "bilinear8"){
                scale_image_bilinear8<image_data_32>(target,raster->data_, err_offs_x, err_offs_y);
            } else {
                scaling_method_e scaling_method = get_scaling_method_by_name(sym.get_scaling());
                std::clog << "scaling: " << scaling_method << "\n";
                scale_image_agg<image_data_32>(target,raster->data_, (scaling_method_e)scaling_method, scale_factor, err_offs_x, err_offs_y, sym.calculate_filter_factor());
            }

            if (sym.get_mode() == "normal"){
                if (sym.get_opacity() == 1.0) {
                    pixmap_.set_rectangle_alpha(start_x,start_y,target);
                } else {
                    pixmap_.set_rectangle_alpha2(target,start_x,start_y, sym.get_opacity());
                }
            } else if (sym.get_mode() == "grain_merge"){
                pixmap_.template merge_rectangle<MergeGrain> (target,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "grain_merge2"){
                pixmap_.template merge_rectangle<MergeGrain2> (target,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "multiply"){
                pixmap_.template merge_rectangle<Multiply> (target,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "multiply2"){
                pixmap_.template merge_rectangle<Multiply2> (target,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "divide"){
                pixmap_.template merge_rectangle<Divide> (target,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "divide2"){
                pixmap_.template merge_rectangle<Divide2> (target,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "screen"){
                pixmap_.template merge_rectangle<Screen> (target,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "hard_light"){
                pixmap_.template merge_rectangle<HardLight> (target,start_x,start_y, sym.get_opacity());
            } else {
                if (sym.get_opacity() == 1.0){
                    pixmap_.set_rectangle(start_x,start_y,target);
                } else {
                    pixmap_.set_rectangle_alpha2(target,start_x,start_y, sym.get_opacity());
                }
            }
            // TODO: other modes? (add,diff,sub,...)
        }
    }
}

template void agg_renderer<image_32>::process(raster_symbolizer const&,
                                              Feature const&,
                                              proj_transform const&);

}
<commit_msg>+ remove debug printout<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2010 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id$

// mapnik
#include <mapnik/agg_renderer.hpp>
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/image_util.hpp>

// stl
#include <cmath>

namespace mapnik {

template <typename T>
void agg_renderer<T>::process(raster_symbolizer const& sym,
                              Feature const& feature,
                              proj_transform const& prj_trans)
{
    raster_ptr const& raster=feature.get_raster();
    if (raster)
    {
        // If there's a colorizer defined, use it to color the raster in-place
        raster_colorizer_ptr colorizer = sym.get_colorizer();
        if (colorizer)
            colorizer->colorize(raster);

        box2d<double> ext=t_.forward(raster->ext_);

        int start_x = (int)ext.minx();
        int start_y = (int)ext.miny();
        int end_x = (int)ceil(ext.maxx());
        int end_y = (int)ceil(ext.maxy());
        int raster_width = end_x - start_x;
        int raster_height = end_y - start_y;
        double err_offs_x = ext.minx() - start_x;
        double err_offs_y = ext.miny() - start_y;

        if ( raster_width > 0 && raster_height > 0)
        {
            double scale_factor = ext.width() / raster->data_.width();
            image_data_32 target(raster_width,raster_height);

            if (sym.get_scaling() == "bilinear8"){
                scale_image_bilinear8<image_data_32>(target,raster->data_, err_offs_x, err_offs_y);
            } else {
                scaling_method_e scaling_method = get_scaling_method_by_name(sym.get_scaling());
                scale_image_agg<image_data_32>(target,raster->data_, (scaling_method_e)scaling_method, scale_factor, err_offs_x, err_offs_y, sym.calculate_filter_factor());
            }

            if (sym.get_mode() == "normal"){
                if (sym.get_opacity() == 1.0) {
                    pixmap_.set_rectangle_alpha(start_x,start_y,target);
                } else {
                    pixmap_.set_rectangle_alpha2(target,start_x,start_y, sym.get_opacity());
                }
            } else if (sym.get_mode() == "grain_merge"){
                pixmap_.template merge_rectangle<MergeGrain> (target,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "grain_merge2"){
                pixmap_.template merge_rectangle<MergeGrain2> (target,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "multiply"){
                pixmap_.template merge_rectangle<Multiply> (target,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "multiply2"){
                pixmap_.template merge_rectangle<Multiply2> (target,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "divide"){
                pixmap_.template merge_rectangle<Divide> (target,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "divide2"){
                pixmap_.template merge_rectangle<Divide2> (target,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "screen"){
                pixmap_.template merge_rectangle<Screen> (target,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "hard_light"){
                pixmap_.template merge_rectangle<HardLight> (target,start_x,start_y, sym.get_opacity());
            } else {
                if (sym.get_opacity() == 1.0){
                    pixmap_.set_rectangle(start_x,start_y,target);
                } else {
                    pixmap_.set_rectangle_alpha2(target,start_x,start_y, sym.get_opacity());
                }
            }
            // TODO: other modes? (add,diff,sub,...)
        }
    }
}

template void agg_renderer<image_32>::process(raster_symbolizer const&,
                                              Feature const&,
                                              proj_transform const&);

}
<|endoftext|>


<commit_before><commit_msg>Disabling flaky StatsTableTest.MultipleThreads on Linux too.<commit_after><|endoftext|>


<commit_before>#include <catch.hpp>

#include "fixtures.hpp"
#include "greens/KPM.hpp"
using namespace tbm;

Model make_test_model(bool is_double = false, bool is_complex = false) {
    auto model = Model(graphene::monolayer());
    model.set_shape(shape::rectangle(0.6f, 0.8f));
    model.add_onsite_modifier(field::constant_potential(1));
    if (is_double) {
        model.add_hopping_modifier(field::force_double_precision());
    }
    if (is_complex) {
        model.add_hopping_modifier(field::constant_magnetic_field(100));
    }
    return model;
}

TEST_CASE("OptimizedHamiltonian reordering", "[kpm]") {
    auto const model = make_test_model();
    auto const num_sites = model.system()->num_sites();

    using scalat_t = float;
    auto const matrix = ham::get_reference<scalat_t>(model.hamiltonian());
    auto bounds = kpm::Bounds<scalat_t>(&matrix, KPMConfig{}.lanczos_precision);

    auto size_indices = [](kpm::OptimizedHamiltonian<scalat_t> const& oh, int num_moments) {
        auto v = std::vector<int>(num_moments);
        for (auto n = 0; n < num_moments; ++n) {
            v[n] = oh.sizes().index(n, num_moments);
        }
        return v;
    };

    SECTION("Diagonal") {
        auto oh = kpm::OptimizedHamiltonian<scalat_t>(&matrix);
        auto const i = num_sites / 2;
        oh.optimize_for({i, i}, bounds.scaling_factors());

        REQUIRE(oh.idx().row == 0);
        REQUIRE(oh.idx().cols[0] == 0);
        REQUIRE(oh.sizes().get_data().front() == 1);
        REQUIRE(oh.sizes().get_data().back() == num_sites);
        REQUIRE(oh.sizes().get_offset() == 0);

        auto const expected6 = std::vector<int>{0, 1, 2, 2, 1, 0};
        REQUIRE(size_indices(oh, 6) == expected6);
        auto const expected9 = std::vector<int>{0, 1, 2, 3, 4, 3, 2, 1, 0};
        REQUIRE(size_indices(oh, 9) == expected9);
        auto const expected12 = std::vector<int>{0, 1, 2, 3, 4, 4, 4, 4, 3, 2, 1, 0};
        REQUIRE(size_indices(oh, 12) == expected12);
    }

    SECTION("Off-diagonal") {
        auto oh = kpm::OptimizedHamiltonian<scalat_t>(&matrix);
        auto const i = num_sites / 4;
        auto const j = num_sites / 2;
        oh.optimize_for({i, std::vector<int>{j, j+1, j+2}}, bounds.scaling_factors());

        REQUIRE(oh.idx().row != oh.idx().cols[0]);
        REQUIRE(oh.sizes().get_data().front() == 1);
        REQUIRE(oh.sizes().get_data().back() == num_sites);
        REQUIRE(oh.sizes().get_offset() > 0);

        auto const expected6 = std::vector<int>{0, 1, 2, 3, 3, 3};
        REQUIRE(size_indices(oh, 6) == expected6);
        auto const expected9 = std::vector<int>{0, 1, 2, 3, 4, 4, 4, 4, 3};
        REQUIRE(size_indices(oh, 9) == expected9);
        auto const expected12 = std::vector<int>{0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 4, 3};
        REQUIRE(size_indices(oh, 12) == expected12);
    }
}

TEST_CASE("KPM strategy", "[kpm]") {
    for (auto is_double_precision : {false, true}) {
        for (auto is_complex : {false, true}) {
            INFO("double: " << is_double_precision << ", complex: " << is_complex);
            auto const model = make_test_model(is_double_precision, is_complex);

            auto const num_sites = model.system()->num_sites();
            auto const i = num_sites / 2;
            auto const j = num_sites / 4;
            auto const energy_range = ArrayXd::LinSpaced(10, -0.3, 0.3);
            auto const broadening = 0.8;
            auto const cols = std::vector<int>{i, j, j+1, j+2};
            auto const precision = Eigen::NumTraits<float>::dummy_precision();

            struct Result { ArrayXcd g_ii, g_ij; };
            auto results = std::vector<Result>();

            for (auto opt_level = 0; opt_level <= 3; ++opt_level) {
                auto config = KPMConfig{};
                config.optimization_level = opt_level;
                auto kpm = make_greens_strategy<KPM>(model.hamiltonian(), config);

                auto const gs = kpm->calc_vector(i, cols, energy_range, broadening);
                REQUIRE(gs.size() == cols.size());
                REQUIRE_FALSE(gs[0].isApprox(gs[1], precision));
                REQUIRE_FALSE(gs[1].isApprox(gs[2], precision));

                kpm->change_hamiltonian(model.hamiltonian());
                auto const g_ii = kpm->calc(i, i, energy_range, broadening);
                REQUIRE(g_ii.isApprox(gs[0], precision));

                auto const g_ij = kpm->calc(i, j, energy_range, broadening);
                auto const g_ji = kpm->calc(j, i, energy_range, broadening);
                REQUIRE(g_ij.isApprox(g_ji, precision));
                REQUIRE(g_ij.isApprox(gs[1], precision));

                results.push_back({g_ii, g_ij});
            }

            REQUIRE(results[0].g_ii.isApprox(results[1].g_ii, precision));
            REQUIRE(results[0].g_ii.isApprox(results[2].g_ii, precision));

            REQUIRE(results[0].g_ij.isApprox(results[1].g_ij, precision));
            REQUIRE(results[0].g_ij.isApprox(results[2].g_ij, precision));
        }
    }
}

TEST_CASE("KPM optimization levels", "[kpm]") {
    for (auto is_double_precision : {false, true}) {
        for (auto is_complex : {false, true}) {
            INFO("double: " << is_double_precision << ", complex: " << is_complex);
            auto const model = make_test_model(is_double_precision, is_complex);

            auto const num_sites = model.system()->num_sites();
            auto calc_greens = [&](int i, int j, int opt_level) {
                auto config = KPMConfig{};
                config.optimization_level = opt_level;
                auto kpm = make_greens_strategy<KPM>(model.hamiltonian(), config);
                auto const g = kpm->calc(i, j, ArrayXd::LinSpaced(10, -0.3, 0.3), 0.8);
                return ArrayXcf{g.cast<std::complex<float>>()};
            };

            SECTION("Diagonal") {
                auto const i = num_sites / 2;
                auto const g0 = calc_greens(i, i, /*opt_level*/0);
                auto const g1 = calc_greens(i, i, /*opt_level*/1);
                auto const g2 = calc_greens(i, i, /*opt_level*/2);
                auto const g3 = calc_greens(i, i, /*opt_level*/3);

                REQUIRE(g0.isApprox(g1));
                REQUIRE(g0.isApprox(g2));
                REQUIRE(g0.isApprox(g3));
            }

            SECTION("Off-diagonal") {
                auto const i = num_sites / 2;
                auto const j = num_sites / 4;
                auto const g0 = calc_greens(i, j, /*opt_level*/0);
                auto const g1 = calc_greens(i, j, /*opt_level*/1);
                auto const g2 = calc_greens(i, j, /*opt_level*/2);
                auto const g3 = calc_greens(i, j, /*opt_level*/3);

                REQUIRE(g0.isApprox(g1));
                REQUIRE(g0.isApprox(g2));
                REQUIRE(g0.isApprox(g3));
            }
        }
    }
}
<commit_msg>Add workaround for intel compiler issue<commit_after>#include <catch.hpp>

#include "fixtures.hpp"
#include "greens/KPM.hpp"
using namespace tbm;

Model make_test_model(bool is_double = false, bool is_complex = false) {
    auto model = Model(graphene::monolayer());
    model.set_shape(shape::rectangle(0.6f, 0.8f));
    model.add_onsite_modifier(field::constant_potential(1));
    if (is_double) {
        model.add_hopping_modifier(field::force_double_precision());
    }
    if (is_complex) {
        model.add_hopping_modifier(field::constant_magnetic_field(100));
    }
    return model;
}

TEST_CASE("OptimizedHamiltonian reordering", "[kpm]") {
    auto const model = make_test_model();
    auto const num_sites = model.system()->num_sites();

    using scalat_t = float;
    auto const matrix = ham::get_reference<scalat_t>(model.hamiltonian());
    auto bounds = kpm::Bounds<scalat_t>(&matrix, KPMConfig{}.lanczos_precision);

    auto size_indices = [](kpm::OptimizedHamiltonian<scalat_t> const& oh, int num_moments) {
        auto v = std::vector<int>(num_moments);
        for (auto n = 0; n < num_moments; ++n) {
            v[n] = oh.sizes().index(n, num_moments);
        }
        return v;
    };

    SECTION("Diagonal") {
        auto oh = kpm::OptimizedHamiltonian<scalat_t>(&matrix);
        auto const i = num_sites / 2;
        oh.optimize_for({i, i}, bounds.scaling_factors());

        REQUIRE(oh.idx().row == 0);
        REQUIRE(oh.idx().cols[0] == 0);
        REQUIRE(oh.sizes().get_data().front() == 1);
        REQUIRE(oh.sizes().get_data().back() == num_sites);
        REQUIRE(oh.sizes().get_offset() == 0);

        auto const expected6 = std::vector<int>{0, 1, 2, 2, 1, 0};
        REQUIRE(size_indices(oh, 6) == expected6);
        auto const expected9 = std::vector<int>{0, 1, 2, 3, 4, 3, 2, 1, 0};
        REQUIRE(size_indices(oh, 9) == expected9);
        auto const expected12 = std::vector<int>{0, 1, 2, 3, 4, 4, 4, 4, 3, 2, 1, 0};
        REQUIRE(size_indices(oh, 12) == expected12);
    }

    SECTION("Off-diagonal") {
        auto oh = kpm::OptimizedHamiltonian<scalat_t>(&matrix);
        auto const i = num_sites / 4;
        auto const j = num_sites / 2;
        oh.optimize_for({i, std::vector<int>{j, j+1, j+2}}, bounds.scaling_factors());

        REQUIRE(oh.idx().row != oh.idx().cols[0]);
        REQUIRE(oh.sizes().get_data().front() == 1);
        REQUIRE(oh.sizes().get_data().back() == num_sites);
        REQUIRE(oh.sizes().get_offset() > 0);

        auto const expected6 = std::vector<int>{0, 1, 2, 3, 3, 3};
        REQUIRE(size_indices(oh, 6) == expected6);
        auto const expected9 = std::vector<int>{0, 1, 2, 3, 4, 4, 4, 4, 3};
        REQUIRE(size_indices(oh, 9) == expected9);
        auto const expected12 = std::vector<int>{0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 4, 3};
        REQUIRE(size_indices(oh, 12) == expected12);
    }
}

TEST_CASE("KPM strategy", "[kpm]") {
    for (auto is_double_precision : {false, true}) {
        for (auto is_complex : {false, true}) {
            INFO("double: " << is_double_precision << ", complex: " << is_complex);
            auto const model = make_test_model(is_double_precision, is_complex);

            auto const num_sites = model.system()->num_sites();
            auto const i = num_sites / 2;
            auto const j = num_sites / 4;
            auto const energy_range = ArrayXd::LinSpaced(10, -0.3, 0.3);
            auto const broadening = 0.8;
            auto const cols = std::vector<int>{i, j, j+1, j+2};
            auto precision = Eigen::NumTraits<float>::dummy_precision();
#ifdef __INTEL_COMPILER // workaround for ICC 16.0.1 on Linux
            precision *= 4;
#endif
            struct Result { ArrayXcd g_ii, g_ij; };
            auto results = std::vector<Result>();

            for (auto opt_level = 0; opt_level <= 3; ++opt_level) {
                INFO("opt_level: " << opt_level);
                auto config = KPMConfig{};
                config.optimization_level = opt_level;
                auto kpm = make_greens_strategy<KPM>(model.hamiltonian(), config);

                auto const gs = kpm->calc_vector(i, cols, energy_range, broadening);
                REQUIRE(gs.size() == cols.size());
                REQUIRE_FALSE(gs[0].isApprox(gs[1], precision));
                REQUIRE_FALSE(gs[1].isApprox(gs[2], precision));

                kpm->change_hamiltonian(model.hamiltonian());
                auto const g_ii = kpm->calc(i, i, energy_range, broadening);
                REQUIRE(g_ii.isApprox(gs[0], precision));

                auto const g_ij = kpm->calc(i, j, energy_range, broadening);
                auto const g_ji = kpm->calc(j, i, energy_range, broadening);
                REQUIRE(g_ij.isApprox(g_ji, precision));
                REQUIRE(g_ij.isApprox(gs[1], precision));

                results.push_back({g_ii, g_ij});
            }

            REQUIRE(results[0].g_ii.isApprox(results[1].g_ii, precision));
            REQUIRE(results[0].g_ii.isApprox(results[2].g_ii, precision));

            REQUIRE(results[0].g_ij.isApprox(results[1].g_ij, precision));
            REQUIRE(results[0].g_ij.isApprox(results[2].g_ij, precision));
        }
    }
}

TEST_CASE("KPM optimization levels", "[kpm]") {
    for (auto is_double_precision : {false, true}) {
        for (auto is_complex : {false, true}) {
            INFO("double: " << is_double_precision << ", complex: " << is_complex);
            auto const model = make_test_model(is_double_precision, is_complex);

            auto const num_sites = model.system()->num_sites();
            auto calc_greens = [&](int i, int j, int opt_level) {
                auto config = KPMConfig{};
                config.optimization_level = opt_level;
                auto kpm = make_greens_strategy<KPM>(model.hamiltonian(), config);
                auto const g = kpm->calc(i, j, ArrayXd::LinSpaced(10, -0.3, 0.3), 0.8);
                return ArrayXcf{g.cast<std::complex<float>>()};
            };

            SECTION("Diagonal") {
                auto const i = num_sites / 2;
                auto const g0 = calc_greens(i, i, /*opt_level*/0);
                auto const g1 = calc_greens(i, i, /*opt_level*/1);
                auto const g2 = calc_greens(i, i, /*opt_level*/2);
                auto const g3 = calc_greens(i, i, /*opt_level*/3);

                REQUIRE(g0.isApprox(g1));
                REQUIRE(g0.isApprox(g2));
                REQUIRE(g0.isApprox(g3));
            }

            SECTION("Off-diagonal") {
                auto const i = num_sites / 2;
                auto const j = num_sites / 4;
                auto const g0 = calc_greens(i, j, /*opt_level*/0);
                auto const g1 = calc_greens(i, j, /*opt_level*/1);
                auto const g2 = calc_greens(i, j, /*opt_level*/2);
                auto const g3 = calc_greens(i, j, /*opt_level*/3);

                REQUIRE(g0.isApprox(g1));
                REQUIRE(g0.isApprox(g2));
                REQUIRE(g0.isApprox(g3));
            }
        }
    }
}
<|endoftext|>


<commit_before>#ifndef LASKIN_NUMBERS_HPP_GUARD
#define LASKIN_NUMBERS_HPP_GUARD

#include "defines.hpp"
#include <stdexcept>

namespace laskin
{
    std::string int_to_string(integer, int = 10);
    std::string real_to_string(real);

    integer string_to_int(const std::string&, int = -1)
        throw(std::length_error);
    real string_to_real(const std::string&)
        throw(std::length_error);
}

#endif /* !LASKIN_NUMBERS_HPP_GUARD */
<commit_msg>fix compiling on freebsd<commit_after>#ifndef LASKIN_NUMBERS_HPP_GUARD
#define LASKIN_NUMBERS_HPP_GUARD

#include "defines.hpp"
#include <stdexcept>
#include <string>

namespace laskin
{
    std::string int_to_string(integer, int = 10);
    std::string real_to_string(real);

    integer string_to_int(const std::string&, int = -1)
        throw(std::length_error);
    real string_to_real(const std::string&)
        throw(std::length_error);
}

#endif /* !LASKIN_NUMBERS_HPP_GUARD */
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Library
  Module:    vtkSweptSurface.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkSweptSurface.hh"
#include "vtkActor.hh"
#include "vtkVoxel.hh"

// Description:
// Construct object with SampleDimensions = (50,50,50), FillValue =
// LARGE_FLOAT, ModelBounds=(0,0,0,0,0,0) (i.e, bounds will be
// computed automatically), and Capping turned on.
vtkSweptSurface::vtkSweptSurface()
{
  this->ModelBounds[0] = 0.0; //compute automatically
  this->ModelBounds[1] = 0.0;
  this->ModelBounds[2] = 0.0;
  this->ModelBounds[3] = 0.0;
  this->ModelBounds[4] = 0.0;
  this->ModelBounds[5] = 0.0;

  this->SampleDimensions[0] = 50;
  this->SampleDimensions[1] = 50;
  this->SampleDimensions[2] = 50;

  this->Interpolation = 0;
  this->FillValue = LARGE_FLOAT;
  this->Transforms = NULL;
  this->Capping = 1;
}

void vtkSweptSurface::SetModelBounds(float xmin, float xmax, float ymin,
                                     float ymax, float zmin, float zmax)
{
  float bounds[6];

  bounds[0] = xmin;
  bounds[1] = xmax;
  bounds[2] = ymin;
  bounds[3] = ymax;
  bounds[4] = zmin;
  bounds[5] = zmax;

  this->SetModelBounds(bounds);
}

void vtkSweptSurface::Execute()
{
  int i, numPts, numOutPts;
  vtkPointData *pd;
  vtkScalars *inScalars, *newScalars;
  vtkStructuredPoints *input=(vtkStructuredPoints *)this->Input;
  float inAr[3], inOrigin[3];
  int inDim[3];
  int numSteps, stepNum;
  int numTransforms, transNum;
  vtkActor a; //use the actor to do position/orientation stuff
  vtkTransform *transform1, *transform2, t;
  float time;
  float position[3], position1[3], position2[3];
  float orient[3], orient1[3], orient2[3];

  vtkDebugMacro(<<"Creating swept surface");
  this->Initialize();

  // make sure there is input
  pd = this->Input->GetPointData();
  inScalars = pd->GetScalars();
  if ( (numPts=this->Input->GetNumberOfPoints()) < 1 ||
  inScalars == NULL )
    {
    vtkErrorMacro(<<"No input scalars defined!");
    return;
    }

  // check that path is defined
  if ( this->Transforms == NULL )
    {
    vtkErrorMacro(<<"No path defined!");
    return;
    }

  if ( (numTransforms=this->Transforms->GetNumberOfItems()) < 2 )
    {
    vtkErrorMacro(<<"At least two transforms are required to define path!");
    return;
    }

  this->SetDimensions(this->SampleDimensions);
  this->ComputeBounds();

  input->GetDimensions(inDim);
  input->GetAspectRatio(inAr);
  input->GetOrigin(inOrigin);
//
// Allocate data.  Scalar "type" is same as input.
//
  numOutPts = this->Dimensions[0] * this->Dimensions[1] * this->Dimensions[2];
  newScalars = inScalars->MakeObject(numOutPts);
  for (i = 0; i < numOutPts; i++) newScalars->SetScalar(i,this->FillValue);
//
// Sample data at each point in path
//
  this->Transforms->InitTraversal();
  transform2 = this->Transforms->GetNextItem();
  transform2->GetInverse(t.GetMatrix());

  t.GetPosition(position2[0], position2[1], position2[2]);
  t.GetOrientation(orient2[0], orient2[1], orient2[2]);

  for (transNum=0; transNum < (numTransforms-1); transNum++)
    {
    vtkDebugMacro(<<"Injecting between transforms "<< transNum <<" and "
                  << transNum+1);
    transform1 = transform2;
    transform2 = this->Transforms->GetNextItem();
    transform2->GetInverse(t.GetMatrix());
//
// Loop over all points (i.e., voxels), transform into input coordinate system,
// and obtain interpolated value. Then perform union operation.
//
    if ( this->Interpolation > 0 ) numSteps = this->Interpolation;
    else if ( this->Interpolation < 0 ) numSteps = 1;
    else numSteps = this->ComputeNumberOfSteps(transform1,transform2);

    for (stepNum=0; stepNum < numSteps; stepNum++)
      {
      // linearly interpolate position and orientation
      time = (float) stepNum / numSteps;

      for (i=0; i<3; i++)
        {
        position1[i] = position2[i];
        orient1[i] = orient2[i];
        }
      t.GetPosition(position2[0], position2[1], position2[2]);
      t.GetOrientation(orient2[0], orient2[1], orient2[2]);

      for (i=0; i<3; i++)
        {
        position[i] = position1[i] + time*(position2[i] - position1[i]);
        orient[i] = orient1[i] + time*(orient2[i] - orient1[i]);
        }

      a.SetPosition(position);
      a.SetOrientation(orient);
      this->SampleInput(a.GetMatrix(), inDim, inOrigin, inAr,
                        inScalars, newScalars);
      }
    }

  //finish off last step
  a.SetPosition(position2);
  a.SetOrientation(orient2);
  this->SampleInput(a.GetMatrix(), inDim, inOrigin, inAr,
                    inScalars, newScalars);

  // Update ourselves and release memory
  this->PointData.SetScalars(newScalars);
  newScalars->Delete();
}

void vtkSweptSurface::SampleInput(vtkMatrix4x4& m, int inDim[3],
                                 float inOrigin[3], float inAr[3],
                                 vtkScalars *inScalars, vtkScalars *outScalars)
{
  int i, j, k, ii;
  int inSliceSize=inDim[0]*inDim[1];
  int sliceSize=this->SampleDimensions[0]*this->SampleDimensions[1];
  float x[4], loc[3], newScalar, scalar;
  static vtkVoxel voxel;
  static vtkIdList idList(8);
  static vtkFloatScalars voxelScalars(8);
  int kOffset, jOffset, dim[3], idx;
  float xTrans[4], weights[8];
  static vtkTransform t;

  t.SetMatrix(m); //we need to do this to pre-multiply
  t.Transpose();
  x[3] = 1.0; //homogeneous coordinates

  for (k=0; k<this->SampleDimensions[2]; k++)
    {
    kOffset = k*sliceSize;
    x[2] = this->Origin[2] + k * this->AspectRatio[2];
    for (j=0; j<this->SampleDimensions[1]; j++)
      {
      jOffset = j*this->SampleDimensions[0];
      x[1] = this->Origin[1] + j * this->AspectRatio[1];
      for (i=0; i<this->SampleDimensions[0]; i++)
        {
        x[0] = this->Origin[0] + i * this->AspectRatio[0];

        // transform into local space
        t.PointMultiply(x,xTrans);
        if ( xTrans[3] != 0.0 ) for (ii=0; ii<3; ii++) xTrans[ii] /= xTrans[3];

        // determine which voxel point falls in.
        for (ii=0; ii<3; ii++)
          {
          loc[ii] = (xTrans[ii]-inOrigin[ii]) / inAr[ii];
          dim[ii] = (int)loc[ii];
          }

        //check and make sure point is inside
        if ( loc[0] >= 0.0 && loc[1] >= 0.0 && loc[2] >= 0.0 &&
        dim[0] < inDim[0] && dim[1] < inDim[1] && dim[2] < inDim[2] )
          {
          //get scalar values
          idx = dim[0] + dim[1]*inDim[0] + dim[2]*inSliceSize;
          idList.SetId(0,idx);
          idList.SetId(1,idx+1);
          idList.SetId(2,idx+1 + inDim[0]);
          idList.SetId(3,idx + inDim[0]);
          idList.SetId(4,idx + inSliceSize);
          idList.SetId(5,idx+1 + inSliceSize);
          idList.SetId(6,idx+1 + inDim[0] + inSliceSize);
          idList.SetId(7,idx + inDim[0] + inSliceSize);

          inScalars->GetScalars(idList,voxelScalars);

          for (ii=0; ii<3; ii++) loc[ii] = loc[ii] - dim[ii];

          voxel.InterpolationFunctions(loc,weights);

          for (newScalar=0.0, ii=0; ii<8; ii++)
            newScalar += voxelScalars.GetScalar(ii) * weights[ii];

          scalar = outScalars->GetScalar((idx=i+jOffset+kOffset));
          if ( newScalar < scalar )  //union operation
            outScalars->SetScalar(idx,newScalar);
          }
        }
      }
    }
}

unsigned long int vtkSweptSurface::GetMTime()
{
  unsigned long mtime=vtkStructuredPointsToStructuredPointsFilter::GetMTime();
  unsigned long int transMtime;
  vtkTransform *t;

  for (this->Transforms->InitTraversal(); t = this->Transforms->GetNextItem(); )
    {
    transMtime = t->GetMTime();
    if ( transMtime > mtime ) mtime = transMtime;
    }

  return mtime;
}

// compute model bounds from geometry and path
void vtkSweptSurface::ComputeBounds()
{
  int i, dim;

  // if bounds are not specified, compute bounds from path
  if (this->ModelBounds[0] >= this->ModelBounds[1] ||
  this->ModelBounds[2] >= this->ModelBounds[3] ||
  this->ModelBounds[4] >= this->ModelBounds[5])
    {
    }
  else // else use what's specified
    {
    for (i=0; i<3; i++)
      {
      this->Origin[i] = this->ModelBounds[2*i];
      if ( (dim=this->SampleDimensions[i]) <= 1 )
        {
        vtkWarningMacro(<<"Dimensions don't specify volume");
        }
      this->AspectRatio[i] =(this->ModelBounds[2*i+1] - this->ModelBounds[2*i])
                             / (dim - 1);
      }
    }
}

// based on both path and bounding box of input, compute the number of
// steps between the specified transforms
int vtkSweptSurface::ComputeNumberOfSteps(vtkTransform *t1, vtkTransform *t2)
{
  return 1;
}

void vtkSweptSurface::Cap(vtkFloatScalars *s)
{
  int i,j,k;
  int idx;
  int d01=this->SampleDimensions[0]*this->SampleDimensions[1];

// i-j planes
  k = 0;
  for (j=0; j<this->SampleDimensions[1]; j++)
    for (i=0; i<this->SampleDimensions[0]; i++)
      s->SetScalar(i+j*this->SampleDimensions[1], this->FillValue);

  k = this->SampleDimensions[2] - 1;
  idx = k*d01;
  for (j=0; j<this->SampleDimensions[1]; j++)
    for (i=0; i<this->SampleDimensions[0]; i++)
      s->SetScalar(idx+i+j*this->SampleDimensions[1], this->FillValue);

// j-k planes
  i = 0;
  for (k=0; k<this->SampleDimensions[2]; k++)
    for (j=0; j<this->SampleDimensions[1]; j++)
      s->SetScalar(j*this->SampleDimensions[0]+k*d01, this->FillValue);

  i = this->SampleDimensions[0] - 1;
  for (k=0; k<this->SampleDimensions[2]; k++)
    for (j=0; j<this->SampleDimensions[1]; j++)
      s->SetScalar(i+j*this->SampleDimensions[0]+k*d01, this->FillValue);

// i-k planes
  j = 0;
  for (k=0; k<this->SampleDimensions[2]; k++)
    for (i=0; i<this->SampleDimensions[0]; i++)
      s->SetScalar(i+k*d01, this->FillValue);

  j = this->SampleDimensions[1] - 1;
  idx = j*this->SampleDimensions[0];
  for (k=0; k<this->SampleDimensions[2]; k++)
    for (i=0; i<this->SampleDimensions[0]; i++)
      s->SetScalar(idx+i+k*d01, this->FillValue);

}

void vtkSweptSurface::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkStructuredPointsToStructuredPointsFilter::PrintSelf(os,indent);

  os << indent << "Sample Dimensions: (" << this->SampleDimensions[0] << ", "
               << this->SampleDimensions[1] << ", "
               << this->SampleDimensions[2] << ")\n";
  os << indent << "ModelBounds: \n";
  os << indent << "  Xmin,Xmax: (" << this->ModelBounds[0] << ", " << this->ModelBounds[1] << ")\n";
  os << indent << "  Ymin,Ymax: (" << this->ModelBounds[2] << ", " << this->ModelBounds[3] << ")\n";
  os << indent << "  Zmin,Zmax: (" << this->ModelBounds[4] << ", " << this->ModelBounds[5] << ")\n";

  os << indent << "Fill Value:" << this->FillValue << "\n";
  os << indent << "Capping: " << (this->Capping ? "On\n" : "Off\n");

  if ( this->Transforms )
    {
    os << indent << "Number of Transforms: " << this->Transforms->GetNumberOfItems() << "\n";
    }
  else
    {
    os << indent << "No transform defined!\n";
    }
}

<commit_msg>ENH: Got it working for mace example.<commit_after>/*=========================================================================

  Program:   Visualization Library
  Module:    vtkSweptSurface.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkSweptSurface.hh"
#include "vtkActor.hh"
#include "vtkVoxel.hh"

// Description:
// Construct object with SampleDimensions = (50,50,50), FillValue =
// LARGE_FLOAT, ModelBounds=(0,0,0,0,0,0) (i.e, bounds will be
// computed automatically), and Capping turned on.
vtkSweptSurface::vtkSweptSurface()
{
  this->ModelBounds[0] = 0.0; //compute automatically
  this->ModelBounds[1] = 0.0;
  this->ModelBounds[2] = 0.0;
  this->ModelBounds[3] = 0.0;
  this->ModelBounds[4] = 0.0;
  this->ModelBounds[5] = 0.0;

  this->SampleDimensions[0] = 50;
  this->SampleDimensions[1] = 50;
  this->SampleDimensions[2] = 50;

  this->Interpolation = 0;
  this->FillValue = LARGE_FLOAT;
  this->Transforms = NULL;
  this->Capping = 1;
}

void vtkSweptSurface::SetModelBounds(float xmin, float xmax, float ymin,
                                     float ymax, float zmin, float zmax)
{
  float bounds[6];

  bounds[0] = xmin;
  bounds[1] = xmax;
  bounds[2] = ymin;
  bounds[3] = ymax;
  bounds[4] = zmin;
  bounds[5] = zmax;

  this->SetModelBounds(bounds);
}

void vtkSweptSurface::Execute()
{
  int i, numPts, numOutPts;
  vtkPointData *pd;
  vtkScalars *inScalars, *newScalars;
  vtkStructuredPoints *input=(vtkStructuredPoints *)this->Input;
  float inAr[3], inOrigin[3];
  int inDim[3];
  int numSteps, stepNum;
  int numTransforms, transNum;
  vtkActor a; //use the actor to do position/orientation stuff
  vtkTransform *transform1, *transform2, t;
  float time;
  float position[3], position1[3], position2[3];
  float orient[3], orient1[3], orient2[3];

  vtkDebugMacro(<<"Creating swept surface");
  this->Initialize();

  // make sure there is input
  pd = this->Input->GetPointData();
  inScalars = pd->GetScalars();
  if ( (numPts=this->Input->GetNumberOfPoints()) < 1 ||
  inScalars == NULL )
    {
    vtkErrorMacro(<<"No input scalars defined!");
    return;
    }

  // check that path is defined
  if ( this->Transforms == NULL )
    {
    vtkErrorMacro(<<"No path defined!");
    return;
    }

  if ( (numTransforms=this->Transforms->GetNumberOfItems()) < 2 )
    {
    vtkErrorMacro(<<"At least two transforms are required to define path!");
    return;
    }

  this->SetDimensions(this->SampleDimensions);
  this->ComputeBounds();

  input->GetDimensions(inDim);
  input->GetAspectRatio(inAr);
  input->GetOrigin(inOrigin);
//
// Allocate data.  Scalar "type" is same as input.
//
  numOutPts = this->Dimensions[0] * this->Dimensions[1] * this->Dimensions[2];
  newScalars = inScalars->MakeObject(numOutPts);
  for (i = 0; i < numOutPts; i++) newScalars->SetScalar(i,this->FillValue);
//
// Sample data at each point in path
//
  this->Transforms->InitTraversal();
  transform2 = this->Transforms->GetNextItem();
  transform2->GetInverse(t.GetMatrix());

  t.GetPosition(position2[0], position2[1], position2[2]);
  t.GetOrientation(orient2[0], orient2[1], orient2[2]);

  for (transNum=0; transNum < (numTransforms-1); transNum++)
    {
    vtkDebugMacro(<<"Injecting between transforms "<< transNum <<" and "
                  << transNum+1);
    transform1 = transform2;
    transform2 = this->Transforms->GetNextItem();
    transform2->GetInverse(t.GetMatrix());
//
// Loop over all points (i.e., voxels), transform into input coordinate system,
// and obtain interpolated value. Then perform union operation.
//
    if ( this->Interpolation > 0 ) numSteps = this->Interpolation;
    else if ( this->Interpolation < 0 ) numSteps = 1;
    else numSteps = this->ComputeNumberOfSteps(transform1,transform2);

    for (i=0; i<3; i++)
      {
      position1[i] = position2[i];
      orient1[i] = orient2[i];
      }
    t.GetPosition(position2[0], position2[1], position2[2]);
    t.GetOrientation(orient2[0], orient2[1], orient2[2]);

    for (stepNum=0; stepNum < numSteps; stepNum++)
      {
      // linearly interpolate position and orientation
      time = (float) stepNum / numSteps;

      for (i=0; i<3; i++)
        {
        position[i] = position1[i] + time*(position2[i] - position1[i]);
        orient[i] = orient1[i] + time*(orient2[i] - orient1[i]);
        }

      a.SetPosition(position);
      a.SetOrientation(orient);
      this->SampleInput(a.GetMatrix(), inDim, inOrigin, inAr,
                        inScalars, newScalars);
      }
    }

  //finish off last step
  a.SetPosition(position2);
  a.SetOrientation(orient2);
  this->SampleInput(a.GetMatrix(), inDim, inOrigin, inAr,
                    inScalars, newScalars);

  // Update ourselves and release memory
  this->PointData.SetScalars(newScalars);
  newScalars->Delete();
}

void vtkSweptSurface::SampleInput(vtkMatrix4x4& m, int inDim[3],
                                 float inOrigin[3], float inAr[3],
                                 vtkScalars *inScalars, vtkScalars *outScalars)
{
  int i, j, k, ii;
  int inSliceSize=inDim[0]*inDim[1];
  int sliceSize=this->SampleDimensions[0]*this->SampleDimensions[1];
  float x[4], loc[3], newScalar, scalar;
  static vtkVoxel voxel;
  static vtkIdList idList(8);
  static vtkFloatScalars voxelScalars(8);
  int kOffset, jOffset, dim[3], idx;
  float xTrans[4], weights[8];
  static vtkTransform t;

  t.SetMatrix(m); //we need to do this to pre-multiply
  t.Transpose();
  x[3] = 1.0; //homogeneous coordinates

  for (k=0; k<this->SampleDimensions[2]; k++)
    {
    kOffset = k*sliceSize;
    x[2] = this->Origin[2] + k * this->AspectRatio[2];
    for (j=0; j<this->SampleDimensions[1]; j++)
      {
      jOffset = j*this->SampleDimensions[0];
      x[1] = this->Origin[1] + j * this->AspectRatio[1];
      for (i=0; i<this->SampleDimensions[0]; i++)
        {
        x[0] = this->Origin[0] + i * this->AspectRatio[0];

        // transform into local space
        t.PointMultiply(x,xTrans);
        if ( xTrans[3] != 0.0 ) for (ii=0; ii<3; ii++) xTrans[ii] /= xTrans[3];

        // determine which voxel point falls in.
        for (ii=0; ii<3; ii++)
          {
          loc[ii] = (xTrans[ii]-inOrigin[ii]) / inAr[ii];
          dim[ii] = (int)loc[ii];
          }

        //check and make sure point is inside
        if ( loc[0] >= 0.0 && loc[1] >= 0.0 && loc[2] >= 0.0 &&
        dim[0] < inDim[0] && dim[1] < inDim[1] && dim[2] < inDim[2] )
          {
          //get scalar values
          idx = dim[0] + dim[1]*inDim[0] + dim[2]*inSliceSize;
          idList.SetId(0,idx);
          idList.SetId(1,idx+1);
          idList.SetId(2,idx+1 + inDim[0]);
          idList.SetId(3,idx + inDim[0]);
          idList.SetId(4,idx + inSliceSize);
          idList.SetId(5,idx+1 + inSliceSize);
          idList.SetId(6,idx+1 + inDim[0] + inSliceSize);
          idList.SetId(7,idx + inDim[0] + inSliceSize);

          inScalars->GetScalars(idList,voxelScalars);

          for (ii=0; ii<3; ii++) loc[ii] = loc[ii] - dim[ii];

          voxel.InterpolationFunctions(loc,weights);

          for (newScalar=0.0, ii=0; ii<8; ii++)
            newScalar += voxelScalars.GetScalar(ii) * weights[ii];

          scalar = outScalars->GetScalar((idx=i+jOffset+kOffset));
          if ( newScalar < scalar )  //union operation
            outScalars->SetScalar(idx,newScalar);
          }
        }
      }
    }
}

unsigned long int vtkSweptSurface::GetMTime()
{
  unsigned long mtime=vtkStructuredPointsToStructuredPointsFilter::GetMTime();
  unsigned long int transMtime;
  vtkTransform *t;

  for (this->Transforms->InitTraversal(); t = this->Transforms->GetNextItem(); )
    {
    transMtime = t->GetMTime();
    if ( transMtime > mtime ) mtime = transMtime;
    }

  return mtime;
}

// compute model bounds from geometry and path
void vtkSweptSurface::ComputeBounds()
{
  int i, dim;

  // if bounds are not specified, compute bounds from path
  if (this->ModelBounds[0] >= this->ModelBounds[1] ||
  this->ModelBounds[2] >= this->ModelBounds[3] ||
  this->ModelBounds[4] >= this->ModelBounds[5])
    {
    }
  else // else use what's specified
    {
    for (i=0; i<3; i++)
      {
      this->Origin[i] = this->ModelBounds[2*i];
      if ( (dim=this->SampleDimensions[i]) <= 1 )
        {
        vtkWarningMacro(<<"Dimensions don't specify volume");
        }
      this->AspectRatio[i] =(this->ModelBounds[2*i+1] - this->ModelBounds[2*i])
                             / (dim - 1);
      }
    }
}

// based on both path and bounding box of input, compute the number of
// steps between the specified transforms
int vtkSweptSurface::ComputeNumberOfSteps(vtkTransform *t1, vtkTransform *t2)
{
  return 1;
}

void vtkSweptSurface::Cap(vtkFloatScalars *s)
{
  int i,j,k;
  int idx;
  int d01=this->SampleDimensions[0]*this->SampleDimensions[1];

// i-j planes
  k = 0;
  for (j=0; j<this->SampleDimensions[1]; j++)
    for (i=0; i<this->SampleDimensions[0]; i++)
      s->SetScalar(i+j*this->SampleDimensions[1], this->FillValue);

  k = this->SampleDimensions[2] - 1;
  idx = k*d01;
  for (j=0; j<this->SampleDimensions[1]; j++)
    for (i=0; i<this->SampleDimensions[0]; i++)
      s->SetScalar(idx+i+j*this->SampleDimensions[1], this->FillValue);

// j-k planes
  i = 0;
  for (k=0; k<this->SampleDimensions[2]; k++)
    for (j=0; j<this->SampleDimensions[1]; j++)
      s->SetScalar(j*this->SampleDimensions[0]+k*d01, this->FillValue);

  i = this->SampleDimensions[0] - 1;
  for (k=0; k<this->SampleDimensions[2]; k++)
    for (j=0; j<this->SampleDimensions[1]; j++)
      s->SetScalar(i+j*this->SampleDimensions[0]+k*d01, this->FillValue);

// i-k planes
  j = 0;
  for (k=0; k<this->SampleDimensions[2]; k++)
    for (i=0; i<this->SampleDimensions[0]; i++)
      s->SetScalar(i+k*d01, this->FillValue);

  j = this->SampleDimensions[1] - 1;
  idx = j*this->SampleDimensions[0];
  for (k=0; k<this->SampleDimensions[2]; k++)
    for (i=0; i<this->SampleDimensions[0]; i++)
      s->SetScalar(idx+i+k*d01, this->FillValue);

}

void vtkSweptSurface::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkStructuredPointsToStructuredPointsFilter::PrintSelf(os,indent);

  os << indent << "Sample Dimensions: (" << this->SampleDimensions[0] << ", "
               << this->SampleDimensions[1] << ", "
               << this->SampleDimensions[2] << ")\n";
  os << indent << "ModelBounds: \n";
  os << indent << "  Xmin,Xmax: (" << this->ModelBounds[0] << ", " << this->ModelBounds[1] << ")\n";
  os << indent << "  Ymin,Ymax: (" << this->ModelBounds[2] << ", " << this->ModelBounds[3] << ")\n";
  os << indent << "  Zmin,Zmax: (" << this->ModelBounds[4] << ", " << this->ModelBounds[5] << ")\n";

  os << indent << "Fill Value:" << this->FillValue << "\n";
  os << indent << "Capping: " << (this->Capping ? "On\n" : "Off\n");

  if ( this->Transforms )
    {
    os << indent << "Number of Transforms: " << this->Transforms->GetNumberOfItems() << "\n";
    }
  else
    {
    os << indent << "No transform defined!\n";
    }
}

<|endoftext|>