<commit_before>/*
 * Copyright (c) 2006, Creative Labs Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided
 * that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice, this list of conditions and
 * 	     the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
 * 	     and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *     * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to endorse or
 * 	     promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "core/strings/stringFunctions.h"

#include "aldlist.h"
#if defined(TORQUE_OS_MAC)
#include <OpenAL/alc.h>
#elif defined(TORQUE_OS_LINUX)
#include <AL/alc.h>
#else
#include <al/alc.h>
#endif

/*
 * Init call
 */
ALDeviceList::ALDeviceList( const OPENALFNTABLE &oalft )
{
   VECTOR_SET_ASSOCIATION( vDeviceInfo );

	ALDEVICEINFO	ALDeviceInfo;
	char *devices;
	int index;
	const char *defaultDeviceName;
   const char *actualDeviceName;

   dMemcpy( &ALFunction, &oalft, sizeof( OPENALFNTABLE ) );

   // DeviceInfo vector stores, for each enumerated device, it's device name, selection status, spec version #, and extension support
   vDeviceInfo.clear();
   vDeviceInfo.reserve(10);

   defaultDeviceIndex = 0;

   // grab function pointers for 1.0-API functions, and if successful proceed to enumerate all devices
   if (ALFunction.alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) {
      devices = (char *)ALFunction.alcGetString(NULL, ALC_DEVICE_SPECIFIER);
      defaultDeviceName = (char *)ALFunction.alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
      index = 0;
      // go through device list (each device terminated with a single NULL, list terminated with double NULL)
      while (*devices != 0) {
         if (String::compare(defaultDeviceName, devices) == 0) {
            defaultDeviceIndex = index;
         }
         ALCdevice *device = ALFunction.alcOpenDevice(devices);
         if (device) {
            ALCcontext *context = ALFunction.alcCreateContext(device, NULL);
            if (context) {
               ALFunction.alcMakeContextCurrent(context);
               // if new actual device name isn't already in the list, then add it...
               actualDeviceName = ALFunction.alcGetString(device, ALC_DEVICE_SPECIFIER);
               bool bNewName = true;
               for (int i = 0; i < GetNumDevices(); i++) {
                  if (String::compare(GetDeviceName(i), actualDeviceName) == 0) {
                     bNewName = false;
                  }
               }
               if ((bNewName) && (actualDeviceName != NULL) && (dStrlen(actualDeviceName) > 0)) {
                  dMemset(&ALDeviceInfo, 0, sizeof(ALDEVICEINFO));
                  ALDeviceInfo.bSelected = true;
                  dStrncpy(ALDeviceInfo.strDeviceName, actualDeviceName, sizeof(ALDeviceInfo.strDeviceName));
                  ALFunction.alcGetIntegerv(device, ALC_MAJOR_VERSION, sizeof(int), &ALDeviceInfo.iMajorVersion);
                  ALFunction.alcGetIntegerv(device, ALC_MINOR_VERSION, sizeof(int), &ALDeviceInfo.iMinorVersion);

                  ALDeviceInfo.iCapsFlags = 0;

                  // Check for ALC Extensions
                  if (ALFunction.alcIsExtensionPresent(device, "ALC_EXT_CAPTURE") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALCapture;
                  if (ALFunction.alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALEFX;

                  // Check for AL Extensions
                  if (ALFunction.alIsExtensionPresent("AL_EXT_OFFSET") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALOffset;

                  if (ALFunction.alIsExtensionPresent("AL_EXT_LINEAR_DISTANCE") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALLinearDistance;
                  if (ALFunction.alIsExtensionPresent("AL_EXT_EXPONENT_DISTANCE") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALExponentDistance;

                  if (ALFunction.alIsExtensionPresent("EAX2.0") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALEAX2;
                  if (ALFunction.alIsExtensionPresent("EAX3.0") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALEAX3;
                  if (ALFunction.alIsExtensionPresent("EAX4.0") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALEAX4;
                  if (ALFunction.alIsExtensionPresent("EAX5.0") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALEAX5;

                  if (ALFunction.alIsExtensionPresent("EAX-RAM") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALEAXRAM;

                  // Get Source Count
                  ALDeviceInfo.uiSourceCount = GetMaxNumSources();

                  vDeviceInfo.push_back(ALDeviceInfo);
               }
               ALFunction.alcMakeContextCurrent(NULL);
               ALFunction.alcDestroyContext(context);
            }
            ALFunction.alcCloseDevice(device);
         }
         devices += dStrlen(devices) + 1;
         index += 1;
      }
   }

	ResetFilters();
}

/*
 * Exit call
 */
ALDeviceList::~ALDeviceList()
{
}

/*
 * Returns the number of devices in the complete device list
 */
int ALDeviceList::GetNumDevices()
{
	return (int)vDeviceInfo.size();
}

/*
 * Returns the device name at an index in the complete device list
 */
const char *ALDeviceList::GetDeviceName(int index)
{
	if (index < GetNumDevices())
		return vDeviceInfo[index].strDeviceName;
	else
		return NULL;
}

/*
 * Returns the major and minor version numbers for a device at a specified index in the complete list
 */
void ALDeviceList::GetDeviceVersion(int index, int *major, int *minor)
{
	if (index < GetNumDevices()) {
		if (major)
			*major = vDeviceInfo[index].iMajorVersion;
		if (minor)
			*minor = vDeviceInfo[index].iMinorVersion;
	}
	return;
}

/*
 * Returns the maximum number of Sources that can be generate on the given device
 */
U32 ALDeviceList::GetMaxNumSources(S32 index)
{
	if (index < GetNumDevices())
		return vDeviceInfo[index].uiSourceCount;
	else
		return 0;
}

/*
 * Checks if the extension is supported on the given device
 */
bool ALDeviceList::IsExtensionSupported(int index, SFXALCaps cap)
{
	bool bReturn = false;

	if (index < GetNumDevices())
      bReturn = vDeviceInfo[index].iCapsFlags & cap;

	return bReturn;
}

/*
 * returns the index of the default device in the complete device list
 */
int ALDeviceList::GetDefaultDevice()
{
	return defaultDeviceIndex;
}

/*
 * Deselects devices which don't have the specified minimum version
 */
void ALDeviceList::FilterDevicesMinVer(S32 major, S32 minor)
{
	int dMajor, dMinor;
	for (U32 i = 0; i < vDeviceInfo.size(); i++) {
		GetDeviceVersion(i, &dMajor, &dMinor);
		if ((dMajor < major) || ((dMajor == major) && (dMinor < minor))) {
			vDeviceInfo[i].bSelected = false;
		}
	}
}

/*
 * Deselects devices which don't have the specified maximum version
 */
void ALDeviceList::FilterDevicesMaxVer(S32 major, S32 minor)
{
	S32 dMajor, dMinor;
	for (U32 i = 0; i < vDeviceInfo.size(); i++) {
		GetDeviceVersion(i, &dMajor, &dMinor);
		if ((dMajor > major) || ((dMajor == major) && (dMinor > minor))) {
			vDeviceInfo[i].bSelected = false;
		}
	}
}

/*
 * Deselects device which don't support the given extension name
 */
void ALDeviceList::FilterDevicesExtension(SFXALCaps cap)
{
	for (U32 i = 0; i < vDeviceInfo.size(); i++)
		vDeviceInfo[i].bSelected = vDeviceInfo[i].iCapsFlags & cap;
}

/*
 * Resets all filtering, such that all devices are in the list
 */
void ALDeviceList::ResetFilters()
{
	for (S32 i = 0; i < GetNumDevices(); i++) {
		vDeviceInfo[i].bSelected = true;
	}
	filterIndex = 0;
}

/*
 * Gets index of first filtered device
 */
int ALDeviceList::GetFirstFilteredDevice()
{
	int i;

	for (i = 0; i < GetNumDevices(); i++) {
		if (vDeviceInfo[i].bSelected == true) {
			break;
		}
	}
	filterIndex = i + 1;
	return i;
}

/*
 * Gets index of next filtered device
 */
int ALDeviceList::GetNextFilteredDevice()
{
	int i;

	for (i = filterIndex; i < GetNumDevices(); i++) {
		if (vDeviceInfo[i].bSelected == true) {
			break;
		}
	}
	filterIndex = i + 1;
	return i;
}

/*
 * Internal function to detemine max number of Sources that can be generated
 */
unsigned int ALDeviceList::GetMaxNumSources()
{
	ALuint uiSources[256];
	U32 iSourceCount = 0;

	// Clear AL Error Code
	ALFunction.alGetError();

	// Generate up to 256 Sources, checking for any errors
	for (iSourceCount = 0; iSourceCount < 256; iSourceCount++)
	{
		ALFunction.alGenSources(1, &uiSources[iSourceCount]);
		if (ALFunction.alGetError() != AL_NO_ERROR)
			break;
	}

	// Release the Sources
	ALFunction.alDeleteSources(iSourceCount, uiSources);
	if (ALFunction.alGetError() != AL_NO_ERROR)
	{
		for (U32 i = 0; i < 256; i++)
		{
			ALFunction.alDeleteSources(1, &uiSources[i]);
		}
	}

	return iSourceCount;
}<commit_msg>* BugFix: Fix AL device listing so that functions like sfxGetAvailableDevices return the actual devices on the system.<commit_after>/*
 * Copyright (c) 2006, Creative Labs Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided
 * that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice, this list of conditions and
 * 	     the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
 * 	     and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *     * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to endorse or
 * 	     promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "core/strings/stringFunctions.h"

#include "aldlist.h"
#if defined(TORQUE_OS_MAC)
#include <OpenAL/alc.h>
#elif defined(TORQUE_OS_LINUX)
#include <AL/alc.h>
#else
#include <al/alc.h>
#endif

/*
 * Init call
 */
ALDeviceList::ALDeviceList( const OPENALFNTABLE &oalft )
{
   VECTOR_SET_ASSOCIATION( vDeviceInfo );

	ALDEVICEINFO	ALDeviceInfo;
	char *devices;
	int index;
	const char *defaultDeviceName;
   const char *actualDeviceName;

   dMemcpy( &ALFunction, &oalft, sizeof( OPENALFNTABLE ) );

   // DeviceInfo vector stores, for each enumerated device, it's device name, selection status, spec version #, and extension support
   vDeviceInfo.clear();
   vDeviceInfo.reserve(10);

   defaultDeviceIndex = 0;

   // grab function pointers for 1.0-API functions, and if successful proceed to enumerate all devices
   if (ALFunction.alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) {
      devices = (char *)ALFunction.alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
      defaultDeviceName = (char *)ALFunction.alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
      index = 0;
      // go through device list (each device terminated with a single NULL, list terminated with double NULL)
      while (*devices != 0) {
         if (String::compare(defaultDeviceName, devices) == 0) {
            defaultDeviceIndex = index;
         }
         ALCdevice *device = ALFunction.alcOpenDevice(devices);
         if (device) {
            ALCcontext *context = ALFunction.alcCreateContext(device, NULL);
            if (context) {
               ALFunction.alcMakeContextCurrent(context);
               // if new actual device name isn't already in the list, then add it...
               actualDeviceName = devices;
               bool bNewName = true;
               for (int i = 0; i < GetNumDevices(); i++) {
                  if (String::compare(GetDeviceName(i), actualDeviceName) == 0) {
                     bNewName = false;
                  }
               }
               if ((bNewName) && (actualDeviceName != NULL) && (dStrlen(actualDeviceName) > 0)) {
                  dMemset(&ALDeviceInfo, 0, sizeof(ALDEVICEINFO));
                  ALDeviceInfo.bSelected = true;
                  dStrncpy(ALDeviceInfo.strDeviceName, actualDeviceName, sizeof(ALDeviceInfo.strDeviceName));
                  ALFunction.alcGetIntegerv(device, ALC_MAJOR_VERSION, sizeof(int), &ALDeviceInfo.iMajorVersion);
                  ALFunction.alcGetIntegerv(device, ALC_MINOR_VERSION, sizeof(int), &ALDeviceInfo.iMinorVersion);

                  ALDeviceInfo.iCapsFlags = 0;

                  // Check for ALC Extensions
                  if (ALFunction.alcIsExtensionPresent(device, "ALC_EXT_CAPTURE") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALCapture;
                  if (ALFunction.alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALEFX;

                  // Check for AL Extensions
                  if (ALFunction.alIsExtensionPresent("AL_EXT_OFFSET") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALOffset;

                  if (ALFunction.alIsExtensionPresent("AL_EXT_LINEAR_DISTANCE") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALLinearDistance;
                  if (ALFunction.alIsExtensionPresent("AL_EXT_EXPONENT_DISTANCE") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALExponentDistance;

                  if (ALFunction.alIsExtensionPresent("EAX2.0") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALEAX2;
                  if (ALFunction.alIsExtensionPresent("EAX3.0") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALEAX3;
                  if (ALFunction.alIsExtensionPresent("EAX4.0") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALEAX4;
                  if (ALFunction.alIsExtensionPresent("EAX5.0") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALEAX5;

                  if (ALFunction.alIsExtensionPresent("EAX-RAM") == AL_TRUE)
                     ALDeviceInfo.iCapsFlags |= SFXALEAXRAM;

                  // Get Source Count
                  ALDeviceInfo.uiSourceCount = GetMaxNumSources();

                  vDeviceInfo.push_back(ALDeviceInfo);
               }
               ALFunction.alcMakeContextCurrent(NULL);
               ALFunction.alcDestroyContext(context);
            }
            ALFunction.alcCloseDevice(device);
         }
         devices += dStrlen(devices) + 1;
         index += 1;
      }
   }

	ResetFilters();
}

/*
 * Exit call
 */
ALDeviceList::~ALDeviceList()
{
}

/*
 * Returns the number of devices in the complete device list
 */
int ALDeviceList::GetNumDevices()
{
	return (int)vDeviceInfo.size();
}

/*
 * Returns the device name at an index in the complete device list
 */
const char *ALDeviceList::GetDeviceName(int index)
{
	if (index < GetNumDevices())
		return vDeviceInfo[index].strDeviceName;
	else
		return NULL;
}

/*
 * Returns the major and minor version numbers for a device at a specified index in the complete list
 */
void ALDeviceList::GetDeviceVersion(int index, int *major, int *minor)
{
	if (index < GetNumDevices()) {
		if (major)
			*major = vDeviceInfo[index].iMajorVersion;
		if (minor)
			*minor = vDeviceInfo[index].iMinorVersion;
	}
	return;
}

/*
 * Returns the maximum number of Sources that can be generate on the given device
 */
U32 ALDeviceList::GetMaxNumSources(S32 index)
{
	if (index < GetNumDevices())
		return vDeviceInfo[index].uiSourceCount;
	else
		return 0;
}

/*
 * Checks if the extension is supported on the given device
 */
bool ALDeviceList::IsExtensionSupported(int index, SFXALCaps cap)
{
	bool bReturn = false;

	if (index < GetNumDevices())
      bReturn = vDeviceInfo[index].iCapsFlags & cap;

	return bReturn;
}

/*
 * returns the index of the default device in the complete device list
 */
int ALDeviceList::GetDefaultDevice()
{
	return defaultDeviceIndex;
}

/*
 * Deselects devices which don't have the specified minimum version
 */
void ALDeviceList::FilterDevicesMinVer(S32 major, S32 minor)
{
	int dMajor, dMinor;
	for (U32 i = 0; i < vDeviceInfo.size(); i++) {
		GetDeviceVersion(i, &dMajor, &dMinor);
		if ((dMajor < major) || ((dMajor == major) && (dMinor < minor))) {
			vDeviceInfo[i].bSelected = false;
		}
	}
}

/*
 * Deselects devices which don't have the specified maximum version
 */
void ALDeviceList::FilterDevicesMaxVer(S32 major, S32 minor)
{
	S32 dMajor, dMinor;
	for (U32 i = 0; i < vDeviceInfo.size(); i++) {
		GetDeviceVersion(i, &dMajor, &dMinor);
		if ((dMajor > major) || ((dMajor == major) && (dMinor > minor))) {
			vDeviceInfo[i].bSelected = false;
		}
	}
}

/*
 * Deselects device which don't support the given extension name
 */
void ALDeviceList::FilterDevicesExtension(SFXALCaps cap)
{
	for (U32 i = 0; i < vDeviceInfo.size(); i++)
		vDeviceInfo[i].bSelected = vDeviceInfo[i].iCapsFlags & cap;
}

/*
 * Resets all filtering, such that all devices are in the list
 */
void ALDeviceList::ResetFilters()
{
	for (S32 i = 0; i < GetNumDevices(); i++) {
		vDeviceInfo[i].bSelected = true;
	}
	filterIndex = 0;
}

/*
 * Gets index of first filtered device
 */
int ALDeviceList::GetFirstFilteredDevice()
{
	int i;

	for (i = 0; i < GetNumDevices(); i++) {
		if (vDeviceInfo[i].bSelected == true) {
			break;
		}
	}
	filterIndex = i + 1;
	return i;
}

/*
 * Gets index of next filtered device
 */
int ALDeviceList::GetNextFilteredDevice()
{
	int i;

	for (i = filterIndex; i < GetNumDevices(); i++) {
		if (vDeviceInfo[i].bSelected == true) {
			break;
		}
	}
	filterIndex = i + 1;
	return i;
}

/*
 * Internal function to detemine max number of Sources that can be generated
 */
unsigned int ALDeviceList::GetMaxNumSources()
{
	ALuint uiSources[256];
	U32 iSourceCount = 0;

	// Clear AL Error Code
	ALFunction.alGetError();

	// Generate up to 256 Sources, checking for any errors
	for (iSourceCount = 0; iSourceCount < 256; iSourceCount++)
	{
		ALFunction.alGenSources(1, &uiSources[iSourceCount]);
		if (ALFunction.alGetError() != AL_NO_ERROR)
			break;
	}

	// Release the Sources
	ALFunction.alDeleteSources(iSourceCount, uiSources);
	if (ALFunction.alGetError() != AL_NO_ERROR)
	{
		for (U32 i = 0; i < 256; i++)
		{
			ALFunction.alDeleteSources(1, &uiSources[i]);
		}
	}

	return iSourceCount;
}
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2018-2021 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/basegl/datavisualizer/volumeraycastvisualizer.h>
#include <modules/base/processors/volumesource.h>
#include <modules/base/processors/cubeproxygeometryprocessor.h>
#include <modules/base/processors/volumeboundingbox.h>
#include <modules/basegl/processors/volumeraycaster.h>
#include <modules/basegl/processors/entryexitpointsprocessor.h>
#include <modules/basegl/processors/background.h>
#include <modules/basegl/processors/meshrenderprocessorgl.h>
#include <modules/basegl/processors/linerendererprocessor.h>
#include <modules/opengl/canvasprocessorgl.h>
#include <inviwo/core/processors/processorutils.h>
#include <inviwo/core/ports/volumeport.h>

#include <inviwo/core/properties/ordinalproperty.h>
#include <inviwo/core/properties/ordinalrefproperty.h>
#include <inviwo/core/properties/optionproperty.h>
#include <inviwo/core/io/datareaderfactory.h>

namespace inviwo {

using GP = util::GridPos;

VolumeRaycastVisualizer::VolumeRaycastVisualizer(InviwoApplication* app)
    : DataVisualizer{}, app_(app) {}

std::string VolumeRaycastVisualizer::getName() const { return "Volume Raycaster"; }

Document VolumeRaycastVisualizer::getDescription() const {
    Document doc;
    auto b = doc.append("html").append("body");
    b.append("", "Construct a standard volume raycaster");
    return doc;
}

std::vector<FileExtension> VolumeRaycastVisualizer::getSupportedFileExtensions() const {
    auto rf = app_->getDataReaderFactory();
    auto exts = rf->getExtensionsForType<Volume>();
    auto exts2 = rf->getExtensionsForType<VolumeSequence>();
    exts.insert(exts.end(), exts2.begin(), exts2.end());
    return exts;
}

bool VolumeRaycastVisualizer::isOutportSupported(const Outport* port) const {
    return dynamic_cast<const VolumeOutport*>(port) != nullptr;
}

bool VolumeRaycastVisualizer::hasSourceProcessor() const { return true; }
bool VolumeRaycastVisualizer::hasVisualizerNetwork() const { return true; }

std::pair<Processor*, Outport*> VolumeRaycastVisualizer::addSourceProcessor(
    const std::string& filename, ProcessorNetwork* net) const {

    auto source = net->addProcessor(util::makeProcessor<VolumeSource>(GP{0, 0}, app_, filename));
    auto outport = source->getOutports().front();
    return {source, outport};
}

std::vector<Processor*> VolumeRaycastVisualizer::addVisualizerNetwork(Outport* outport,
                                                                      ProcessorNetwork* net) const {

    auto cpg = net->addProcessor(util::makeProcessor<CubeProxyGeometry>(GP{1, 3}));
    auto eep = net->addProcessor(util::makeProcessor<EntryExitPoints>(GP{1, 6}));
    auto vrc = net->addProcessor(util::makeProcessor<VolumeRaycaster>(GP{0, 9}));
    auto bak = net->addProcessor(util::makeProcessor<Background>(GP{0, 12}));
    auto cvs = net->addProcessor(util::makeProcessor<CanvasProcessorGL>(GP{0, 15}));

    auto vbb = net->addProcessor(util::makeProcessor<VolumeBoundingBox>(GP{8, 3}));
    auto lrp = net->addProcessor(util::makeProcessor<LineRendererProcessor>(GP{8, 6}));

    dynamic_cast<FloatVec4Property*>(bak->getPropertyByIdentifier("bgColor1"))
        ->set(vec4(0.443f, 0.482f, 0.6f, 1.0f));
    dynamic_cast<FloatVec4Property*>(bak->getPropertyByIdentifier("bgColor2"))
        ->set(vec4(0.831f, 0.831f, 0.831f, 1.0f));

    // set shading mode in volume raycaster to 'no shading'
    dynamic_cast<OptionPropertyInt*>(vrc->getPropertyByIdentifier("shadingMode", true))->set(0);

    dynamic_cast<FloatProperty*>(lrp->getPropertyByPath("lineSettings.lineWidth"))->set(1.5f);
    dynamic_cast<FloatVec3RefProperty*>(vrc->getPropertyByIdentifier("lookFrom", true))
        ->set(vec3(0.0f, 0.0f, 30.0f));

    net->addConnection(outport, cpg->getInports()[0]);
    net->addConnection(cpg->getOutports()[0], eep->getInports()[0]);

    net->addConnection(eep->getOutports()[0], vrc->getInports()[1]);
    net->addConnection(eep->getOutports()[1], vrc->getInports()[2]);

    net->addConnection(outport, vrc->getInports()[0]);
    net->addConnection(vrc->getOutports()[0], bak->getInports()[0]);
    net->addConnection(bak->getOutports()[0], cvs->getInports()[0]);

    net->addConnection(outport, vbb->getInports()[0]);
    net->addConnection(vbb->getOutports()[0], lrp->getInports()[0]);
    net->addConnection(lrp->getOutports()[0], vrc->getInports()[3]);

    net->addLink(eep->getPropertyByIdentifier("camera"), vrc->getPropertyByIdentifier("camera"));
    net->addLink(vrc->getPropertyByIdentifier("camera"), eep->getPropertyByIdentifier("camera"));

    net->addLink(eep->getPropertyByIdentifier("camera"), lrp->getPropertyByIdentifier("camera"));
    net->addLink(lrp->getPropertyByIdentifier("camera"), eep->getPropertyByIdentifier("camera"));

    net->evaluateLinksFromProperty(vrc->getPropertyByIdentifier("camera"));

    return {cpg, eep, vrc, cvs, vbb, bak, lrp};
}

std::vector<Processor*> VolumeRaycastVisualizer::addSourceAndVisualizerNetwork(
    const std::string& filename, ProcessorNetwork* net) const {

    auto sourceAndOutport = addSourceProcessor(filename, net);
    auto processors = addVisualizerNetwork(sourceAndOutport.second, net);

    processors.push_back(sourceAndOutport.first);
    return processors;
}

}  // namespace inviwo
<commit_msg>BaseGL: fixes a property type change<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2018-2021 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/basegl/datavisualizer/volumeraycastvisualizer.h>
#include <modules/base/processors/volumesource.h>
#include <modules/base/processors/cubeproxygeometryprocessor.h>
#include <modules/base/processors/volumeboundingbox.h>
#include <modules/basegl/processors/volumeraycaster.h>
#include <modules/basegl/processors/entryexitpointsprocessor.h>
#include <modules/basegl/processors/background.h>
#include <modules/basegl/processors/meshrenderprocessorgl.h>
#include <modules/basegl/processors/linerendererprocessor.h>
#include <modules/opengl/canvasprocessorgl.h>
#include <inviwo/core/processors/processorutils.h>
#include <inviwo/core/ports/volumeport.h>

#include <inviwo/core/properties/ordinalproperty.h>
#include <inviwo/core/properties/ordinalrefproperty.h>
#include <inviwo/core/properties/optionproperty.h>
#include <inviwo/core/io/datareaderfactory.h>

namespace inviwo {

using GP = util::GridPos;

VolumeRaycastVisualizer::VolumeRaycastVisualizer(InviwoApplication* app)
    : DataVisualizer{}, app_(app) {}

std::string VolumeRaycastVisualizer::getName() const { return "Volume Raycaster"; }

Document VolumeRaycastVisualizer::getDescription() const {
    Document doc;
    auto b = doc.append("html").append("body");
    b.append("", "Construct a standard volume raycaster");
    return doc;
}

std::vector<FileExtension> VolumeRaycastVisualizer::getSupportedFileExtensions() const {
    auto rf = app_->getDataReaderFactory();
    auto exts = rf->getExtensionsForType<Volume>();
    auto exts2 = rf->getExtensionsForType<VolumeSequence>();
    exts.insert(exts.end(), exts2.begin(), exts2.end());
    return exts;
}

bool VolumeRaycastVisualizer::isOutportSupported(const Outport* port) const {
    return dynamic_cast<const VolumeOutport*>(port) != nullptr;
}

bool VolumeRaycastVisualizer::hasSourceProcessor() const { return true; }
bool VolumeRaycastVisualizer::hasVisualizerNetwork() const { return true; }

std::pair<Processor*, Outport*> VolumeRaycastVisualizer::addSourceProcessor(
    const std::string& filename, ProcessorNetwork* net) const {

    auto source = net->addProcessor(util::makeProcessor<VolumeSource>(GP{0, 0}, app_, filename));
    auto outport = source->getOutports().front();
    return {source, outport};
}

template <typename T, typename V>
T& trySetProperty(Processor* proc, std::string_view identifier, V&& val, bool recursive = false) {

    if (auto* p = recursive ? proc->getPropertyByIdentifier(identifier, true)
                            : proc->getPropertyByPath(identifier)) {
        if (auto* tp = dynamic_cast<T*>(p)) {
            tp->set(std::forward<V>(val));
            return *tp;
        } else {
            throw Exception(
                fmt::format("Property '{}' not of type '{}'", identifier, typeid(T).name()),
                IVW_CONTEXT_CUSTOM("VolumeRaycastVisualizer"));
        }
    } else {
        throw Exception(fmt::format("Could not find property: '{}'", identifier),
                        IVW_CONTEXT_CUSTOM("VolumeRaycastVisualizer"));
    }
}

std::vector<Processor*> VolumeRaycastVisualizer::addVisualizerNetwork(Outport* outport,
                                                                      ProcessorNetwork* net) const {

    auto cpg = net->addProcessor(util::makeProcessor<CubeProxyGeometry>(GP{1, 3}));
    auto eep = net->addProcessor(util::makeProcessor<EntryExitPoints>(GP{1, 6}));
    auto vrc = net->addProcessor(util::makeProcessor<VolumeRaycaster>(GP{0, 9}));
    auto bak = net->addProcessor(util::makeProcessor<Background>(GP{0, 12}));
    auto cvs = net->addProcessor(util::makeProcessor<CanvasProcessorGL>(GP{0, 15}));

    auto vbb = net->addProcessor(util::makeProcessor<VolumeBoundingBox>(GP{8, 3}));
    auto lrp = net->addProcessor(util::makeProcessor<LineRendererProcessor>(GP{8, 6}));

    trySetProperty<FloatVec4Property>(bak, "bgColor1", vec4(0.443f, 0.482f, 0.600f, 1.0f));
    trySetProperty<FloatVec4Property>(bak, "bgColor2", vec4(0.831f, 0.831f, 0.831f, 1.0f));

    trySetProperty<TemplateOptionProperty<ShadingMode>>(vrc, "shadingMode", ShadingMode::None,
                                                        true);
    trySetProperty<FloatVec3RefProperty>(vrc, "lookFrom", vec3(0.0f, 0.0f, 30.0f), true);
    trySetProperty<FloatProperty>(lrp, "lineSettings.lineWidth", 1.5f);

    net->addConnection(outport, cpg->getInports()[0]);
    net->addConnection(cpg->getOutports()[0], eep->getInports()[0]);

    net->addConnection(eep->getOutports()[0], vrc->getInports()[1]);
    net->addConnection(eep->getOutports()[1], vrc->getInports()[2]);

    net->addConnection(outport, vrc->getInports()[0]);
    net->addConnection(vrc->getOutports()[0], bak->getInports()[0]);
    net->addConnection(bak->getOutports()[0], cvs->getInports()[0]);

    net->addConnection(outport, vbb->getInports()[0]);
    net->addConnection(vbb->getOutports()[0], lrp->getInports()[0]);
    net->addConnection(lrp->getOutports()[0], vrc->getInports()[3]);

    net->addLink(eep->getPropertyByIdentifier("camera"), vrc->getPropertyByIdentifier("camera"));
    net->addLink(vrc->getPropertyByIdentifier("camera"), eep->getPropertyByIdentifier("camera"));

    net->addLink(eep->getPropertyByIdentifier("camera"), lrp->getPropertyByIdentifier("camera"));
    net->addLink(lrp->getPropertyByIdentifier("camera"), eep->getPropertyByIdentifier("camera"));

    net->evaluateLinksFromProperty(vrc->getPropertyByIdentifier("camera"));

    return {cpg, eep, vrc, cvs, vbb, bak, lrp};
}

std::vector<Processor*> VolumeRaycastVisualizer::addSourceAndVisualizerNetwork(
    const std::string& filename, ProcessorNetwork* net) const {

    auto sourceAndOutport = addSourceProcessor(filename, net);
    auto processors = addVisualizerNetwork(sourceAndOutport.second, net);

    processors.push_back(sourceAndOutport.first);
    return processors;
}

}  // namespace inviwo
<|endoftext|>


<commit_before>
#include <string>
#include <fstream>
#include <iostream>
#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImageRegionIterator.h"
#include "itkRGBPixel.h"
#include "itkRGBAPixel.h"

#include "itkRedColormapFunctor.h"
#include "itkGreenColormapFunctor.h"
#include "itkBlueColormapFunctor.h"
#include "itkGreyColormapFunctor.h"
#include "itkHotColormapFunctor.h"
#include "itkCoolColormapFunctor.h"
#include "itkSpringColormapFunctor.h"
#include "itkSummerColormapFunctor.h"
#include "itkAutumnColormapFunctor.h"
#include "itkWinterColormapFunctor.h"
#include "itkCopperColormapFunctor.h"
#include "itkHSVColormapFunctor.h"
#include "itkJetColormapFunctor.h"
#include "itkCustomColormapFunctor.h"
#include "itkOverUnderColormapFunctor.h"

#include "itkScalarToRGBColormapImageFilter.h"

template <unsigned int ImageDimension>
int ConvertScalarImageToRGB( int argc, char *argv[] )
{
  typedef unsigned int PixelType;
//  typedef itk::RGBPixel<unsigned char> RGBPixelType;
  typedef itk::RGBAPixel<unsigned char> RGBPixelType;

  typedef float RealType;

  typedef itk::Image<PixelType, ImageDimension> ImageType;
  typedef itk::Image<float, ImageDimension> RealImageType;
  typedef itk::Image<RGBPixelType, ImageDimension> RGBImageType;

  typedef itk::ImageFileReader<RealImageType> ReaderType;
  typename ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName( argv[2] );
  reader->Update();

  typedef itk::Image<unsigned char, ImageDimension> MaskImageType;
  typename MaskImageType::Pointer maskImage = MaskImageType::New();
  typedef itk::ImageFileReader<MaskImageType> MaskReaderType;
  typename MaskReaderType::Pointer maskreader = MaskReaderType::New();
  maskreader->SetFileName( argv[4] );
  try
    {
    maskreader->Update();
    maskImage = maskreader->GetOutput();
    }
  catch(...)
    {
    maskImage = NULL;
    };

  std::string colormapString( argv[5] );

  typedef itk::ScalarToRGBColormapImageFilter<RealImageType,
    RGBImageType> RGBFilterType;
  typename RGBFilterType::Pointer rgbfilter = RGBFilterType::New();
  rgbfilter->SetInput( reader->GetOutput() );

  if ( colormapString == "red" )
    {
    rgbfilter->SetColormap( RGBFilterType::Red );
    }
  else if ( colormapString == "green"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Green );
    }
  else if ( colormapString == "blue"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Blue );
    }
  else if ( colormapString == "grey"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Grey );
    }
  else if ( colormapString == "cool"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Cool );
    }
  else if ( colormapString == "hot"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Hot );
    }
  else if ( colormapString == "spring"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Spring );
    }
  else if ( colormapString == "autumn"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Autumn );
    }
  else if ( colormapString == "winter"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Winter );
    }
  else if ( colormapString == "copper"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Copper );
    }
  else if ( colormapString == "summer"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Summer );
    }
  else if ( colormapString == "jet"  )
    {
//    rgbfilter->SetColormap( RGBFilterType::Jet );
    typedef itk::Functor::JetColormapFunctor<typename RealImageType::PixelType,
      typename RGBImageType::PixelType> ColormapType;
    typename ColormapType::Pointer colormap = ColormapType::New();
    rgbfilter->SetColormap( colormap );
    }
  else if ( colormapString == "hsv"  )
    {
//    rgbfilter->SetColormap( RGBFilterType::HSV );
    typedef itk::Functor::HSVColormapFunctor<typename RealImageType::PixelType,
      typename RGBImageType::PixelType> ColormapType;
    typename ColormapType::Pointer colormap = ColormapType::New();
    rgbfilter->SetColormap( colormap );
    }
  else if ( colormapString == "overunder"  )
    {
    rgbfilter->SetColormap( RGBFilterType::OverUnder );
    }
  else if ( colormapString == "custom"  )
    {
    typedef itk::Functor::CustomColormapFunctor<typename RealImageType::PixelType,
      typename RGBImageType::PixelType> ColormapType;
    typename ColormapType::Pointer colormap = ColormapType::New();

    std::ifstream str( argv[6] );
    std::string line;

    // Get red values
    {
    std::getline( str, line );
    std::istringstream iss( line );
    float value;
    typename ColormapType::ChannelType channel;
    while ( iss >> value )
      {
      channel.push_back( value );
      }
    colormap->SetRedChannel( channel );
    }

    // Get green values
    {
    std::getline( str, line );
    std::istringstream iss( line );
    float value;
    typename ColormapType::ChannelType channel;
    while ( iss >> value )
      {
      channel.push_back( value );
      }
    colormap->SetGreenChannel( channel );
    }
    // Get blue values
    {
    std::getline( str, line );
    std::istringstream iss( line );
    float value;
    typename ColormapType::ChannelType channel;
    while ( iss >> value )
      {
      channel.push_back( value );
      }
    colormap->SetBlueChannel( channel );
    }
    rgbfilter->SetColormap( colormap );
    }

  if( maskImage )
    {

    RealType maskMinimumValue = itk::NumericTraits<RealType>::max();
    RealType maskMaximumValue = itk::NumericTraits<RealType>::NonpositiveMin();

    itk::ImageRegionIterator<MaskImageType> ItM( maskImage,
      maskImage->GetLargestPossibleRegion() );
    itk::ImageRegionIterator<RealImageType> ItS( reader->GetOutput(),
      reader->GetOutput()->GetLargestPossibleRegion() );
    for( ItM.GoToBegin(), ItS.GoToBegin(); !ItM.IsAtEnd(); ++ItM, ++ItS )
      {
      if( ItM.Get() != 0 )
        {
        if( maskMinimumValue >= ItS.Get() )
          {
          maskMinimumValue = ItS.Get();
          }
        if( maskMaximumValue <= ItS.Get() )
          {
          maskMaximumValue = ItS.Get();
          }
        }
      }

    rgbfilter->SetUseInputImageExtremaForScaling( false );
    rgbfilter->GetColormap()->SetMinimumInputValue( maskMinimumValue );
    rgbfilter->GetColormap()->SetMaximumInputValue( maskMaximumValue );
    }

  rgbfilter->GetColormap()->SetMinimumRGBComponentValue(
    ( argc > 9 ) ? static_cast<
    typename RGBPixelType::ComponentType>( atof( argv[9] ) ) : 0 );
  rgbfilter->GetColormap()->SetMaximumRGBComponentValue(
    ( argc > 10 ) ? static_cast<
    typename RGBPixelType::ComponentType>( atof( argv[10] ) ) : 255 );

  if( argc > 8 )
    {
    rgbfilter->SetUseInputImageExtremaForScaling( false );
    rgbfilter->GetColormap()->SetMinimumInputValue(
      static_cast<RealType>( atof( argv[7] ) ) );
    rgbfilter->GetColormap()->SetMaximumInputValue(
      static_cast<RealType>( atof( argv[8] ) ) );
    }

  try
    {
    rgbfilter->Update();
    }
  catch (...)
    {
    return EXIT_FAILURE;
    }

  if( maskImage )
    {
    itk::ImageRegionIterator<MaskImageType> ItM( maskImage,
      maskImage->GetLargestPossibleRegion() );
    itk::ImageRegionIterator<RGBImageType> ItC( rgbfilter->GetOutput(),
      rgbfilter->GetOutput()->GetLargestPossibleRegion() );
    itk::ImageRegionIterator<RealImageType> ItS( reader->GetOutput(),
      reader->GetOutput()->GetLargestPossibleRegion() );

    ItM.GoToBegin();
    ItC.GoToBegin();
    ItS.GoToBegin();

    while( !ItM.IsAtEnd() )
      {
      if( ItM.Get() == 0 )
        {
        RGBPixelType rgbpixel;

//        RealType minimumValue = rgbfilter->GetColormap()->GetMinimumInputValue();
//        RealType maximumValue = rgbfilter->GetColormap()->GetMaximumInputValue();
//
//        RealType minimumRGBValue
//          = rgbfilter->GetColormap()->GetMinimumRGBComponentValue();
//        RealType maximumRGBValue
//          = rgbfilter->GetColormap()->GetMaximumRGBComponentValue();
//
//        RealType ratio = ( ItS.Get() - minimumValue ) / ( maximumValue - minimumValue );
//
//        rgbpixel.Fill( ratio * ( maximumRGBValue - minimumRGBValue )
//          + minimumRGBValue );
        rgbpixel.Fill( itk::NumericTraits<typename RGBPixelType::ComponentType>::Zero );

        ItC.Set( rgbpixel );
        }
      ++ItM;
      ++ItC;
      ++ItS;
      }
    }

  typedef itk::ImageFileWriter<RGBImageType> WriterType;
  typename WriterType::Pointer writer = WriterType::New();
  writer->SetInput( rgbfilter->GetOutput() );
  writer->SetFileName( argv[3] );
  writer->Update();

  return 0;
}

int main( int argc, char *argv[] )
{
  if ( argc < 6 )
    {
    std::cout << "Usage: " << argv[0] << " imageDimension inputImage outputImage "
      << "mask colormap [customColormapFile] [minimumInput] [maximumInput] "
      << "[minimumRGBOutput] [maximumRGBOutput]" << std::endl;
    std::cout << "  Possible colormaps: grey, red, green, blue, copper, jet, hsv, ";
    std::cout << "spring, summer, autumn, winter, hot, cool, overunder, custom" << std::endl;
    exit( 1 );
    }

  switch( atoi( argv[1] ) )
   {
   case 2:
     ConvertScalarImageToRGB<2>( argc, argv );
     break;
   case 3:
     ConvertScalarImageToRGB<3>( argc, argv );
     break;
   default:
      std::cerr << "Unsupported dimension" << std::endl;
      exit( EXIT_FAILURE );
   }
}

<commit_msg>PERF: Changed the RGB pixel type due to compatibility issues with itk-snap 1.9.9.<commit_after>
#include <string>
#include <fstream>
#include <iostream>
#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImageRegionIterator.h"
#include "itkRGBPixel.h"
#include "itkRGBAPixel.h"

#include "itkRedColormapFunctor.h"
#include "itkGreenColormapFunctor.h"
#include "itkBlueColormapFunctor.h"
#include "itkGreyColormapFunctor.h"
#include "itkHotColormapFunctor.h"
#include "itkCoolColormapFunctor.h"
#include "itkSpringColormapFunctor.h"
#include "itkSummerColormapFunctor.h"
#include "itkAutumnColormapFunctor.h"
#include "itkWinterColormapFunctor.h"
#include "itkCopperColormapFunctor.h"
#include "itkHSVColormapFunctor.h"
#include "itkJetColormapFunctor.h"
#include "itkCustomColormapFunctor.h"
#include "itkOverUnderColormapFunctor.h"

#include "itkScalarToRGBColormapImageFilter.h"

template <unsigned int ImageDimension>
int ConvertScalarImageToRGB( int argc, char *argv[] )
{
  typedef unsigned int PixelType;
  typedef itk::RGBPixel<unsigned char> RGBPixelType;
//  typedef itk::RGBAPixel<unsigned char> RGBPixelType;

  typedef float RealType;

  typedef itk::Image<PixelType, ImageDimension> ImageType;
  typedef itk::Image<float, ImageDimension> RealImageType;
  typedef itk::Image<RGBPixelType, ImageDimension> RGBImageType;

  typedef itk::ImageFileReader<RealImageType> ReaderType;
  typename ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName( argv[2] );
  reader->Update();

  typedef itk::Image<unsigned char, ImageDimension> MaskImageType;
  typename MaskImageType::Pointer maskImage = MaskImageType::New();
  typedef itk::ImageFileReader<MaskImageType> MaskReaderType;
  typename MaskReaderType::Pointer maskreader = MaskReaderType::New();
  maskreader->SetFileName( argv[4] );
  try
    {
    maskreader->Update();
    maskImage = maskreader->GetOutput();
    }
  catch(...)
    {
    maskImage = NULL;
    };

  std::string colormapString( argv[5] );

  typedef itk::ScalarToRGBColormapImageFilter<RealImageType,
    RGBImageType> RGBFilterType;
  typename RGBFilterType::Pointer rgbfilter = RGBFilterType::New();
  rgbfilter->SetInput( reader->GetOutput() );

  if ( colormapString == "red" )
    {
    rgbfilter->SetColormap( RGBFilterType::Red );
    }
  else if ( colormapString == "green"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Green );
    }
  else if ( colormapString == "blue"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Blue );
    }
  else if ( colormapString == "grey"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Grey );
    }
  else if ( colormapString == "cool"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Cool );
    }
  else if ( colormapString == "hot"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Hot );
    }
  else if ( colormapString == "spring"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Spring );
    }
  else if ( colormapString == "autumn"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Autumn );
    }
  else if ( colormapString == "winter"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Winter );
    }
  else if ( colormapString == "copper"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Copper );
    }
  else if ( colormapString == "summer"  )
    {
    rgbfilter->SetColormap( RGBFilterType::Summer );
    }
  else if ( colormapString == "jet"  )
    {
//    rgbfilter->SetColormap( RGBFilterType::Jet );
    typedef itk::Functor::JetColormapFunctor<typename RealImageType::PixelType,
      typename RGBImageType::PixelType> ColormapType;
    typename ColormapType::Pointer colormap = ColormapType::New();
    rgbfilter->SetColormap( colormap );
    }
  else if ( colormapString == "hsv"  )
    {
//    rgbfilter->SetColormap( RGBFilterType::HSV );
    typedef itk::Functor::HSVColormapFunctor<typename RealImageType::PixelType,
      typename RGBImageType::PixelType> ColormapType;
    typename ColormapType::Pointer colormap = ColormapType::New();
    rgbfilter->SetColormap( colormap );
    }
  else if ( colormapString == "overunder"  )
    {
    rgbfilter->SetColormap( RGBFilterType::OverUnder );
    }
  else if ( colormapString == "custom"  )
    {
    typedef itk::Functor::CustomColormapFunctor<typename RealImageType::PixelType,
      typename RGBImageType::PixelType> ColormapType;
    typename ColormapType::Pointer colormap = ColormapType::New();

    std::ifstream str( argv[6] );
    std::string line;

    // Get red values
    {
    std::getline( str, line );
    std::istringstream iss( line );
    float value;
    typename ColormapType::ChannelType channel;
    while ( iss >> value )
      {
      channel.push_back( value );
      }
    colormap->SetRedChannel( channel );
    }

    // Get green values
    {
    std::getline( str, line );
    std::istringstream iss( line );
    float value;
    typename ColormapType::ChannelType channel;
    while ( iss >> value )
      {
      channel.push_back( value );
      }
    colormap->SetGreenChannel( channel );
    }
    // Get blue values
    {
    std::getline( str, line );
    std::istringstream iss( line );
    float value;
    typename ColormapType::ChannelType channel;
    while ( iss >> value )
      {
      channel.push_back( value );
      }
    colormap->SetBlueChannel( channel );
    }
    rgbfilter->SetColormap( colormap );
    }

  if( maskImage )
    {

    RealType maskMinimumValue = itk::NumericTraits<RealType>::max();
    RealType maskMaximumValue = itk::NumericTraits<RealType>::NonpositiveMin();

    itk::ImageRegionIterator<MaskImageType> ItM( maskImage,
      maskImage->GetLargestPossibleRegion() );
    itk::ImageRegionIterator<RealImageType> ItS( reader->GetOutput(),
      reader->GetOutput()->GetLargestPossibleRegion() );
    for( ItM.GoToBegin(), ItS.GoToBegin(); !ItM.IsAtEnd(); ++ItM, ++ItS )
      {
      if( ItM.Get() != 0 )
        {
        if( maskMinimumValue >= ItS.Get() )
          {
          maskMinimumValue = ItS.Get();
          }
        if( maskMaximumValue <= ItS.Get() )
          {
          maskMaximumValue = ItS.Get();
          }
        }
      }

    rgbfilter->SetUseInputImageExtremaForScaling( false );
    rgbfilter->GetColormap()->SetMinimumInputValue( maskMinimumValue );
    rgbfilter->GetColormap()->SetMaximumInputValue( maskMaximumValue );
    }

  rgbfilter->GetColormap()->SetMinimumRGBComponentValue(
    ( argc > 9 ) ? static_cast<
    typename RGBPixelType::ComponentType>( atof( argv[9] ) ) : 0 );
  rgbfilter->GetColormap()->SetMaximumRGBComponentValue(
    ( argc > 10 ) ? static_cast<
    typename RGBPixelType::ComponentType>( atof( argv[10] ) ) : 255 );

  if( argc > 8 )
    {
    rgbfilter->SetUseInputImageExtremaForScaling( false );
    rgbfilter->GetColormap()->SetMinimumInputValue(
      static_cast<RealType>( atof( argv[7] ) ) );
    rgbfilter->GetColormap()->SetMaximumInputValue(
      static_cast<RealType>( atof( argv[8] ) ) );
    }

  try
    {
    rgbfilter->Update();
    }
  catch (...)
    {
    return EXIT_FAILURE;
    }

  if( maskImage )
    {
    itk::ImageRegionIterator<MaskImageType> ItM( maskImage,
      maskImage->GetLargestPossibleRegion() );
    itk::ImageRegionIterator<RGBImageType> ItC( rgbfilter->GetOutput(),
      rgbfilter->GetOutput()->GetLargestPossibleRegion() );
    itk::ImageRegionIterator<RealImageType> ItS( reader->GetOutput(),
      reader->GetOutput()->GetLargestPossibleRegion() );

    ItM.GoToBegin();
    ItC.GoToBegin();
    ItS.GoToBegin();

    while( !ItM.IsAtEnd() )
      {
      if( ItM.Get() == 0 )
        {
        RGBPixelType rgbpixel;

//        RealType minimumValue = rgbfilter->GetColormap()->GetMinimumInputValue();
//        RealType maximumValue = rgbfilter->GetColormap()->GetMaximumInputValue();
//
//        RealType minimumRGBValue
//          = rgbfilter->GetColormap()->GetMinimumRGBComponentValue();
//        RealType maximumRGBValue
//          = rgbfilter->GetColormap()->GetMaximumRGBComponentValue();
//
//        RealType ratio = ( ItS.Get() - minimumValue ) / ( maximumValue - minimumValue );
//
//        rgbpixel.Fill( ratio * ( maximumRGBValue - minimumRGBValue )
//          + minimumRGBValue );
        rgbpixel.Fill( itk::NumericTraits<typename RGBPixelType::ComponentType>::Zero );

        ItC.Set( rgbpixel );
        }
      ++ItM;
      ++ItC;
      ++ItS;
      }
    }

  typedef itk::ImageFileWriter<RGBImageType> WriterType;
  typename WriterType::Pointer writer = WriterType::New();
  writer->SetInput( rgbfilter->GetOutput() );
  writer->SetFileName( argv[3] );
  writer->Update();

  return 0;
}

int main( int argc, char *argv[] )
{
  if ( argc < 6 )
    {
    std::cout << "Usage: " << argv[0] << " imageDimension inputImage outputImage "
      << "mask colormap [customColormapFile] [minimumInput] [maximumInput] "
      << "[minimumRGBOutput] [maximumRGBOutput]" << std::endl;
    std::cout << "  Possible colormaps: grey, red, green, blue, copper, jet, hsv, ";
    std::cout << "spring, summer, autumn, winter, hot, cool, overunder, custom" << std::endl;
    exit( 1 );
    }

  switch( atoi( argv[1] ) )
   {
   case 2:
     ConvertScalarImageToRGB<2>( argc, argv );
     break;
   case 3:
     ConvertScalarImageToRGB<3>( argc, argv );
     break;
   default:
      std::cerr << "Unsupported dimension" << std::endl;
      exit( EXIT_FAILURE );
   }
}

<|endoftext|>


<commit_before>#include "catch.hpp"

#include "DPAG.h"
#include <cstdio>
#include <vector>
#include <fstream>
using namespace std;

typedef unsigned int uint;

TEST_CASE("Basic DPAG usage", "[dpag]") {
  uint num_nodes = 10;
  DPAG d(num_nodes);

  CHECK(boost::num_vertices(d) == num_nodes);

  Vertex_d v;
  VertexId vertex_id = boost::get(boost::vertex_index, d);
  vertexIt v_i, v_end;
  outIter out_i, out_end, out_i1;
  EdgeId edge_id = boost::get(boost::edge_index, d);

  // access vertices with iterators and indices
  SECTION("accessing vertices") {
    boost::tie(v_i, v_end) = boost::vertices(d);
    SECTION("first vertex") {
      CHECK(vertex_id[*v_i] == 0);
    }
    SECTION("another vertex") {
      v_i++; v_i++; v_i++;
      CHECK(vertex_id[*v_i] == 3);
    }
  }

  // check looping over edges
  // add edges, check results with iterators
  SECTION("add some edges") {
    boost::add_edge(2,3, EdgeProperty(0), d);
    boost::add_edge(2,8, EdgeProperty(1), d);
    CHECK(boost::num_edges(d) == 2);

    // we've added the right edge
    v = boost::vertex(2, d);
    boost::tie(out_i, out_end)=boost::out_edges(v, d);
    SECTION("accessing first edge") {
      CHECK(target(*out_i, d) == 3);
      CHECK(edge_id[*out_i] == 0);
    }

    SECTION("accessing second and last edge") {
      CHECK(target(*(++out_i), d) == 8);
      CHECK(edge_id[*out_i] == 1);
      CHECK(++out_i == out_end);
    }
  }
}

class DPAGGenerator {
  DPAG** dpags;

public:

  // build a sequence of T steps
  DPAG make_sequence(uint T) {
    DPAG s(T);

    // make the connections go from right to left
    // to emulate RNN unfolding from right to left,
    // i.e. reverse topological sort
    for(uint i=T-1; i>0; --i)
      boost::add_edge(i, i-1, s);

    return s;
  }

  DPAG make_dpag(const char* fname) {
    // ifstream is(fname);
    // if(!is) {
    //   fprintf(stderr, "Could not open file %s\n", fname);
    //   exit(1);
    // }

    DPAG d;

    return d;
  }

  DPAG make_grid(uint N) {
    DPAG grid(N);

    return grid;
  }
};

TEST_CASE("DPAG functions with various data structures", "[dpag]") {
  //Vertex_d v;
  vertexIt v_i, v_end;
  outIter out_i, out_end;
  ieIter in_i, in_end;

  DPAGGenerator dg;

  int T = 10;
  DPAG sequence = dg.make_sequence(T);

  CHECK(boost::num_vertices(sequence) == T);

  DPAG dpag = dg.make_dpag("../data/test_dpag.gph");

  int N = T;
  DPAG grid = dg.make_grid(N);
  CHECK(boost::num_vertices(grid) == N);

  SECTION("equal - same skeleton") {
    DPAG sequence1 = dg.make_sequence(T);
    CHECK(equal(sequence, sequence1));

    DPAG dpag1 = dg.make_dpag("../data/test_dpag.gph");
    CHECK(equal(dpag, dpag1));

    DPAG grid1 = dg.make_grid(N);
    CHECK(equal(grid, grid1));

    SECTION("different edge properties") {
      DPAG sequence2 = dg.make_sequence(T);

      VertexId vertex_id = boost::get(boost::vertex_index, sequence2);
      Vertex_d v = boost::vertex(3, sequence2);
      outIter out_i = boost::out_edges(v, sequence2).first;
      EdgeId edge_id = boost::get(boost::edge_index, sequence2);
      edge_id[*out_i] = 2;
      CHECK_FALSE(equal(sequence, sequence2));
    }
  }

  SECTION("equal - different skeleton") {
    CHECK_FALSE(equal(sequence, dpag));
    CHECK_FALSE(equal(sequence, grid));
    CHECK_FALSE(equal(dpag, grid));
  }

  SECTION("Linear sequence") {
    CHECK(max_indegree(sequence) == 1);
    CHECK(max_outdegree(sequence) == 1);

    VertexId vertex_id = boost::get(boost::vertex_index, sequence);
    EdgeId edge_id = boost::get(boost::edge_index, sequence);

    for(boost::tie(v_i, v_end) = boost::vertices(sequence); v_i!=v_end; ++v_i) {
      boost::tie(out_i, out_end)=boost::out_edges(*v_i, sequence);
      boost::tie(in_i, in_end)=boost::in_edges(*v_i, sequence);

      int id = vertex_id[*v_i];
      if(id == 0) {
	CHECK(boost::source(*in_i, sequence) == vertex_id[*(v_i+1)]);
	CHECK(++in_i == in_end);
	CHECK(out_i == out_end);
      } else if(id < T-1) {
	CHECK(boost::target(*out_i, sequence) == vertex_id[*(v_i-1)]);
	CHECK(++out_i == out_end);
	CHECK(boost::source(*in_i, sequence) == vertex_id[*(v_i+1)]);
	CHECK(++in_i == in_end);
      } else {
	CHECK(id == T-1);
	CHECK(boost::target(*out_i, sequence) == vertex_id[*(v_i-1)]);
	CHECK(++out_i == out_end);
	CHECK(in_i == in_end);
      }
    }

    SECTION("topological sort") {
      std::vector<int> top_sort = topological_sort(sequence);
      CHECK(top_sort.size() == T);
      for(int i=0; i<T; ++i)
	CHECK(top_sort[i] == T-i-1);
    }
  }

  SECTION("DPAG") {

    SECTION("topological sort") {
    }
  }

  SECTION("Grid") {

    SECTION("topological sort") {
    }
  }
}
<commit_msg>Added DPAG tests.<commit_after>#include "catch.hpp"

#include "DPAG.h"
#include <cstdio>
#include <vector>
#include <fstream>
using namespace std;

typedef unsigned int uint;

TEST_CASE("Basic DPAG usage", "[dpag]") {
  uint num_nodes = 10;
  DPAG d(num_nodes);

  CHECK(boost::num_vertices(d) == num_nodes);

  Vertex_d v;
  VertexId vertex_id = boost::get(boost::vertex_index, d);
  vertexIt v_i, v_end;
  outIter out_i, out_end, out_i1;
  EdgeId edge_id = boost::get(boost::edge_index, d);

  // access vertices with iterators and indices
  SECTION("accessing vertices") {
    boost::tie(v_i, v_end) = boost::vertices(d);
    SECTION("first vertex") {
      CHECK(vertex_id[*v_i] == 0);
    }
    SECTION("another vertex") {
      v_i++; v_i++; v_i++;
      CHECK(vertex_id[*v_i] == 3);
    }
  }

  // check looping over edges
  // add edges, check results with iterators
  SECTION("add some edges") {
    boost::add_edge(2,3, EdgeProperty(0), d);
    boost::add_edge(2,8, EdgeProperty(1), d);
    CHECK(boost::num_edges(d) == 2);

    // we've added the right edge
    v = boost::vertex(2, d);
    boost::tie(out_i, out_end)=boost::out_edges(v, d);
    SECTION("accessing first edge") {
      CHECK(target(*out_i, d) == 3);
      CHECK(edge_id[*out_i] == 0);
    }

    SECTION("accessing second and last edge") {
      CHECK(target(*(++out_i), d) == 8);
      CHECK(edge_id[*out_i] == 1);
      CHECK(++out_i == out_end);
    }
  }
}

class DPAGGenerator {
  DPAG** dpags;

public:

  // build a sequence of T steps
  DPAG make_sequence(uint T) {
    DPAG s(T);

    // make the connections go from right to left
    // to emulate RNN unfolding from right to left,
    // i.e. reverse topological sort
    for(uint i=T-1; i>0; --i)
      boost::add_edge(i, i-1, s);

    return s;
  }

  DPAG make_dpag(const char* fname) {
    ifstream is(fname);
    if(!is) {
      fprintf(stderr, "Could not open file %s\n", fname);
      exit(1);
    }

    string line;
    getline(is, line);
    istringstream iss(line);
    int V;
    iss >> V;
    DPAG d(V);

    for(int i=0; i<V; ++i) {
      getline(is, line);
      istringstream iss1(line);
      int v;
      iss1 >> v;
      int target;
      int eindex = 0;
      while(iss1 >> target)
	boost::add_edge(v, target, EdgeProperty(eindex++), d);
    }

    return d;
  }

  DPAG make_grid(uint N) {
    DPAG grid(N);

    return grid;
  }
};

TEST_CASE("DPAG functions with various data structures", "[dpag]") {
  //Vertex_d v;
  vertexIt v_i, v_end;
  outIter out_i, out_end;
  ieIter in_i, in_end;

  DPAGGenerator dg;

  int T = 10;
  DPAG sequence = dg.make_sequence(T);

  CHECK(boost::num_vertices(sequence) == T);

  DPAG dpag = dg.make_dpag("data/test_dpag.gph");

  int N = T;
  DPAG grid = dg.make_grid(N);
  CHECK(boost::num_vertices(grid) == N);

  SECTION("equal - same skeleton") {
    DPAG sequence1 = dg.make_sequence(T);
    CHECK(equal(sequence, sequence1));

    DPAG dpag1 = dg.make_dpag("data/test_dpag.gph");
    CHECK(equal(dpag, dpag1));

    DPAG grid1 = dg.make_grid(N);
    CHECK(equal(grid, grid1));

    SECTION("different edge properties") {
      DPAG sequence2 = dg.make_sequence(T);

      VertexId vertex_id = boost::get(boost::vertex_index, sequence2);
      Vertex_d v = boost::vertex(3, sequence2);
      outIter out_i = boost::out_edges(v, sequence2).first;
      EdgeId edge_id = boost::get(boost::edge_index, sequence2);
      edge_id[*out_i] = 2;
      CHECK_FALSE(equal(sequence, sequence2));
    }
  }

  SECTION("equal - different skeleton") {
    CHECK_FALSE(equal(sequence, dpag));
    CHECK_FALSE(equal(sequence, grid));
    CHECK_FALSE(equal(dpag, grid));
  }

  SECTION("linear sequence") {
    CHECK(max_indegree(sequence) == 1);
    CHECK(max_outdegree(sequence) == 1);

    VertexId vertex_id = boost::get(boost::vertex_index, sequence);
    EdgeId edge_id = boost::get(boost::edge_index, sequence);

    for(boost::tie(v_i, v_end) = boost::vertices(sequence); v_i!=v_end; ++v_i) {
      boost::tie(out_i, out_end)=boost::out_edges(*v_i, sequence);
      boost::tie(in_i, in_end)=boost::in_edges(*v_i, sequence);

      int id = vertex_id[*v_i];
      if(id == 0) {
	CHECK(boost::source(*in_i, sequence) == vertex_id[*(v_i+1)]);
	CHECK(++in_i == in_end);
	CHECK(out_i == out_end);
      } else if(id < T-1) {
	CHECK(boost::target(*out_i, sequence) == vertex_id[*(v_i-1)]);
	CHECK(++out_i == out_end);
	CHECK(boost::source(*in_i, sequence) == vertex_id[*(v_i+1)]);
	CHECK(++in_i == in_end);
      } else {
	CHECK(id == T-1);
	CHECK(boost::target(*out_i, sequence) == vertex_id[*(v_i-1)]);
	CHECK(++out_i == out_end);
	CHECK(in_i == in_end);
      }
    }

    SECTION("topological sort") {
      std::vector<int> top_sort = topological_sort(sequence);
      CHECK(top_sort.size() == boost::num_vertices(sequence));
      for(int i=0; i<boost::num_vertices(sequence); ++i)
	CHECK(top_sort[i] == T-i-1);
    }
  }

  SECTION("DPAG") {
    CHECK(max_indegree(dpag) == 2);
    CHECK(max_outdegree(dpag) == 2);

    VertexId vertex_id = boost::get(boost::vertex_index, dpag);
    EdgeId edge_id = boost::get(boost::edge_index, dpag);

    Vertex_d v = boost::vertex(0, dpag);
    boost::tie(out_i, out_end)=boost::out_edges(v, dpag);
    boost::tie(in_i, in_end)=boost::in_edges(v, dpag);

    CHECK(in_i == in_end);
    CHECK(boost::target(*out_i, dpag) == 1);
    CHECK(edge_id[*out_i] == 0);
    CHECK(boost::target(*(++out_i), dpag) == 3);
    CHECK(edge_id[*out_i] == 1);
    CHECK(++out_i == out_end);

    v = boost::vertex(1, dpag);
    boost::tie(out_i, out_end)=boost::out_edges(v, dpag);
    boost::tie(in_i, in_end)=boost::in_edges(v, dpag);
    CHECK(boost::source(*in_i, dpag) == 0);
    CHECK(++in_i == in_end);
    CHECK(boost::target(*out_i, dpag) == 2);
    CHECK(edge_id[*out_i] == 0);
    CHECK(boost::target(*(++out_i), dpag) == 3);
    CHECK(edge_id[*out_i] == 1);
    CHECK(++out_i == out_end);

    v = boost::vertex(2, dpag);
    boost::tie(out_i, out_end)=boost::out_edges(v, dpag);
    boost::tie(in_i, in_end)=boost::in_edges(v, dpag);
    CHECK(boost::source(*in_i, dpag) == 1);
    CHECK(++in_i == in_end);
    CHECK(out_i == out_end);

    v = boost::vertex(3, dpag);
    boost::tie(out_i, out_end)=boost::out_edges(v, dpag);
    boost::tie(in_i, in_end)=boost::in_edges(v, dpag);
    CHECK(boost::source(*in_i, dpag) == 0);
    CHECK(boost::source(*(++in_i), dpag) == 1);
    CHECK(++in_i == in_end);
    CHECK(out_i == out_end);

    SECTION("topological sort") {
      vector<int> top_sort = topological_sort(dpag);
      int V = boost::num_vertices(dpag);
      CHECK(top_sort.size() == V);

      CHECK(top_sort[0] == 0);
      CHECK(top_sort[1] == 1);
      // TODO:: cannot check with complex expressions
      CHECK(0);
      // CHECK(top_sort[2] == 2 || top_sort[2] == 3);
      // CHECK(top_sort[3] == 2 || top_sort[3] == 3);
    }
  }

  SECTION("Grid") {

    SECTION("topological sort") {
    }
  }
}
<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "PorousFlowAddMaterialAction.h"
#include "AddKernelAction.h"
#include "AddMaterialAction.h"
#include "AddPostprocessorAction.h"
#include "AddUserObjectAction.h"
#include "PorousFlowActionBase.h"
#include "ActionWarehouse.h"
#include "ActionFactory.h"
#include "FEProblem.h"
#include "MooseObjectAction.h"
#include "Conversion.h"

registerMooseAction("PorousFlowApp", PorousFlowAddMaterialAction, "meta_action");

template <>
InputParameters
validParams<PorousFlowAddMaterialAction>()
{
  InputParameters params = validParams<Action>();
  params.addClassDescription(
      "Makes sure that the correct nodal and/or qp materials are added for each property");
  return params;
}

PorousFlowAddMaterialAction::PorousFlowAddMaterialAction(const InputParameters & params)
  : Action(params), PorousFlowDependencies()
{
}

void
PorousFlowAddMaterialAction::act()
{
  // Create the list of kernels, auxkernels, actions etc that each material may be
  // required by
  createDependencyList();

  // Get the list of materials that have been added
  auto actions = _awh.getActions<AddMaterialAction>();

  for (auto & action : actions)
    _ama_materials.push_back(const_cast<AddMaterialAction *>(action));

  for (auto & material : _ama_materials)
  {
    InputParameters & pars = material->getObjectParams();

    // Check if the material is a PorousFlow material
    if (pars.isParamValid("pf_material_type"))
    {
      const std::string pf_material_type = pars.get<std::string>("pf_material_type");

      // PorousFlowJoiner materials are added automatically by the PorousFlowAddMaterialJoiner
      // action, so no need to check these here
      if (pf_material_type != "joiner")
      {
        // There are two possibilities that must be considered:
        // 1) The parameter at_nodes has been set by the user. In this case, the material will
        // be added as normal by AddMaterialAction
        // 2) The parameter at_nodes has not been set by the user. In this case, this action
        // will check to see if the material is required at the qps, at the nodes, or possibly both

        // Only chech the second possibility
        if (!pars.isParamSetByUser("at_nodes"))
        {
          bool qp_material_required = false;

          // First, check the case at_nodes = false, as this is the default behaviour for the
          // at_nodes parameter. Note: the local variable at_nodes is set to true, so the material
          // is at the qps when !at_nodes
          const bool at_nodes = true;

          if (isPFMaterialRequired(pf_material_type, !at_nodes))
          {
            // This material is required at the qps, so add it as normal (setting the paramter
            // at_nodes = false for clarity)
            pars.set<bool>("at_nodes") = !at_nodes;
            qp_material_required = true;
          }

          // Check if the material is required at the nodes as well and that it isn't already
          // added in the input file. If it is needed and not already supplied, then it is added
          // in one of two ways: 1) If the material wasn't also required at the qps (checked above),
          // then we can simply set the at_nodes parameter to true. 2) If it was also required at
          // the qps, then a new material action is required to be added to the action warehouse
          if (isPFMaterialRequired(pf_material_type, at_nodes) &&
              !isPFMaterialPresent(material, at_nodes))
          {
            if (!qp_material_required)
              pars.set<bool>("at_nodes") = at_nodes;
            else
              addPFMaterial(material, at_nodes);
          }
        }
      }
    }
  }
}

void
PorousFlowAddMaterialAction::createDependencyList()
{
  // Unique list of kernels added in input file
  auto kernels = _awh.getActions<AddKernelAction>();
  for (auto & kernel : kernels)
    _dependency_list.insert(kernel->getMooseObjectType());

  // Unique list of PorousFlowActions added in input file
  auto actions = _awh.getActions<PorousFlowActionBase>();
  for (auto & action : actions)
    _dependency_list.insert(action->name());

  // Unique list of auxkernels added in input file
  auto auxkernels = _awh.getActions<AddKernelAction>();
  for (auto & auxkernel : auxkernels)
    _dependency_list.insert(auxkernel->getMooseObjectType());

  // Unique list of postprocessors added in input file
  auto postprocessors = _awh.getActions<AddPostprocessorAction>();
  for (auto & postprocessor : postprocessors)
    _dependency_list.insert(postprocessor->getMooseObjectType());

  // Unique list of userojects added in input file
  auto userobjects = _awh.getActions<AddUserObjectAction>();
  for (auto & userobject : userobjects)
    _dependency_list.insert(userobject->getMooseObjectType());
}

bool
PorousFlowAddMaterialAction::isPFMaterialRequired(std::string pf_material_type, bool at_nodes)
{
  const std::string nodal_ext = at_nodes ? "_nodal" : "_qp";

  // Check if this material is required by looping through the list of dependencies
  bool required = false;
  for (auto item : _dependency_list)
  {
    required = _deps.dependsOn(item, pf_material_type + nodal_ext);
    if (required)
      break;
  }

  return required;
}

bool
PorousFlowAddMaterialAction::isPFMaterialPresent(AddMaterialAction * material, bool at_nodes)
{
  // Need to check that it hasn't been added in the input file also to
  // avoid a duplicate material property error
  for (auto & ama_material : _ama_materials)
  {
    if (ama_material->name() != material->name() &&
        ama_material->getMooseObjectType() == material->getMooseObjectType())
    {
      InputParameters & mat_params = ama_material->getObjectParams();
      const bool mat_at_nodes = mat_params.get<bool>("at_nodes");

      InputParameters & pars = material->getObjectParams();

      // If the material isn't related to a fluid phase, it is present if
      // its at_nodes parameter is equal to the given at_nodes
      if (mat_at_nodes == at_nodes && !pars.isParamValid("phase"))
        return true;

      // If the material is related to a fluid phase, it is present if
      // its at_nodes parameter is equal to the given at_nodes, and its
      // phase is equal to phase
      if (pars.isParamValid("phase"))
      {
        const unsigned int phase = pars.get<unsigned int>("phase");

        if (mat_params.isParamValid("phase") && mat_params.get<unsigned int>("phase") == phase)
          return true;
      }
    }
  }

  // If all of these conditions aren't satisfied, then the material is already present
  return false;
}

void
PorousFlowAddMaterialAction::addPFMaterial(AddMaterialAction * material, bool at_nodes)
{
  const std::string nodal_ext = at_nodes ? "_nodal" : "_qp";

  // Input parameters for the material that is being added
  InputParameters & pars = material->getObjectParams();

  // PorousFlowMaterial type
  const std::string pf_material_type = pars.get<std::string>("pf_material_type");
  const std::string moose_object_type = material->getMooseObjectType();

  // If it is a material that also has a fluid phase, then extract that to add to name
  std::string phase_str;
  if (pars.isParamValid("phase"))
  {
    unsigned int phase = pars.get<unsigned int>("phase");
    phase_str = "_phase" + Moose::stringify(phase);
  }

  // Add material to the action warehouse
  InputParameters action_params = _action_factory.getValidParams("AddMaterialAction");
  action_params.set<ActionWarehouse *>("awh") = &_awh;

  // Setup action for passed in material type
  action_params.set<std::string>("type") = moose_object_type;

  const std::string material_name = material->name() + phase_str + nodal_ext;

  auto action = MooseSharedNamespace::dynamic_pointer_cast<MooseObjectAction>(
      _action_factory.create("AddMaterialAction", material_name, action_params));

  action->getObjectParams().applyParameters(pars);
  action->getObjectParams().set<bool>("at_nodes") = at_nodes;

  _awh.addActionBlock(action);
}
<commit_msg>Add BCs to dependency list<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "PorousFlowAddMaterialAction.h"
#include "AddKernelAction.h"
#include "AddMaterialAction.h"
#include "AddPostprocessorAction.h"
#include "AddUserObjectAction.h"
#include "AddBCAction.h"
#include "PorousFlowActionBase.h"
#include "ActionWarehouse.h"
#include "ActionFactory.h"
#include "FEProblem.h"
#include "MooseObjectAction.h"
#include "Conversion.h"

registerMooseAction("PorousFlowApp", PorousFlowAddMaterialAction, "meta_action");

template <>
InputParameters
validParams<PorousFlowAddMaterialAction>()
{
  InputParameters params = validParams<Action>();
  params.addClassDescription(
      "Makes sure that the correct nodal and/or qp materials are added for each property");
  return params;
}

PorousFlowAddMaterialAction::PorousFlowAddMaterialAction(const InputParameters & params)
  : Action(params), PorousFlowDependencies()
{
}

void
PorousFlowAddMaterialAction::act()
{
  // Create the list of kernels, auxkernels, actions etc that each material may be
  // required by
  createDependencyList();

  // Get the list of materials that have been added
  auto actions = _awh.getActions<AddMaterialAction>();

  for (auto & action : actions)
    _ama_materials.push_back(const_cast<AddMaterialAction *>(action));

  for (auto & material : _ama_materials)
  {
    InputParameters & pars = material->getObjectParams();

    // Check if the material is a PorousFlow material
    if (pars.isParamValid("pf_material_type"))
    {
      const std::string pf_material_type = pars.get<std::string>("pf_material_type");

      // PorousFlowJoiner materials are added automatically by the PorousFlowAddMaterialJoiner
      // action, so no need to check these here
      if (pf_material_type != "joiner")
      {
        // There are two possibilities that must be considered:
        // 1) The parameter at_nodes has been set by the user. In this case, the material will
        // be added as normal by AddMaterialAction
        // 2) The parameter at_nodes has not been set by the user. In this case, this action
        // will check to see if the material is required at the qps, at the nodes, or possibly both

        // Only chech the second possibility
        if (!pars.isParamSetByUser("at_nodes"))
        {
          bool qp_material_required = false;

          // First, check the case at_nodes = false, as this is the default behaviour for the
          // at_nodes parameter. Note: the local variable at_nodes is set to true, so the material
          // is at the qps when !at_nodes
          const bool at_nodes = true;

          if (isPFMaterialRequired(pf_material_type, !at_nodes))
          {
            // This material is required at the qps, so add it as normal (setting the paramter
            // at_nodes = false for clarity)
            pars.set<bool>("at_nodes") = !at_nodes;
            qp_material_required = true;
          }

          // Check if the material is required at the nodes as well and that it isn't already
          // added in the input file. If it is needed and not already supplied, then it is added
          // in one of two ways: 1) If the material wasn't also required at the qps (checked above),
          // then we can simply set the at_nodes parameter to true. 2) If it was also required at
          // the qps, then a new material action is required to be added to the action warehouse
          if (isPFMaterialRequired(pf_material_type, at_nodes) &&
              !isPFMaterialPresent(material, at_nodes))
          {
            if (!qp_material_required)
              pars.set<bool>("at_nodes") = at_nodes;
            else
              addPFMaterial(material, at_nodes);
          }
        }
      }
    }
  }
}

void
PorousFlowAddMaterialAction::createDependencyList()
{
  // Unique list of kernels added in input file
  auto kernels = _awh.getActions<AddKernelAction>();
  for (auto & kernel : kernels)
    _dependency_list.insert(kernel->getMooseObjectType());

  // Unique list of PorousFlowActions added in input file
  auto actions = _awh.getActions<PorousFlowActionBase>();
  for (auto & action : actions)
    _dependency_list.insert(action->name());

  // Unique list of auxkernels added in input file
  auto auxkernels = _awh.getActions<AddKernelAction>();
  for (auto & auxkernel : auxkernels)
    _dependency_list.insert(auxkernel->getMooseObjectType());

  // Unique list of postprocessors added in input file
  auto postprocessors = _awh.getActions<AddPostprocessorAction>();
  for (auto & postprocessor : postprocessors)
    _dependency_list.insert(postprocessor->getMooseObjectType());

  // Unique list of userojects added in input file
  auto userobjects = _awh.getActions<AddUserObjectAction>();
  for (auto & userobject : userobjects)
    _dependency_list.insert(userobject->getMooseObjectType());

  // Unique list of BCs added in input file
  auto bcs = _awh.getActions<AddBCAction>();
  for (auto & bc : bcs)
    _dependency_list.insert(bc->getMooseObjectType());
}

bool
PorousFlowAddMaterialAction::isPFMaterialRequired(std::string pf_material_type, bool at_nodes)
{
  const std::string nodal_ext = at_nodes ? "_nodal" : "_qp";

  // Check if this material is required by looping through the list of dependencies
  bool required = false;
  for (auto item : _dependency_list)
  {
    required = _deps.dependsOn(item, pf_material_type + nodal_ext);
    if (required)
      break;
  }

  return required;
}

bool
PorousFlowAddMaterialAction::isPFMaterialPresent(AddMaterialAction * material, bool at_nodes)
{
  // Need to check that it hasn't been added in the input file also to
  // avoid a duplicate material property error
  for (auto & ama_material : _ama_materials)
  {
    if (ama_material->name() != material->name() &&
        ama_material->getMooseObjectType() == material->getMooseObjectType())
    {
      InputParameters & mat_params = ama_material->getObjectParams();
      const bool mat_at_nodes = mat_params.get<bool>("at_nodes");

      InputParameters & pars = material->getObjectParams();

      // If the material isn't related to a fluid phase, it is present if
      // its at_nodes parameter is equal to the given at_nodes
      if (mat_at_nodes == at_nodes && !pars.isParamValid("phase"))
        return true;

      // If the material is related to a fluid phase, it is present if
      // its at_nodes parameter is equal to the given at_nodes, and its
      // phase is equal to phase
      if (pars.isParamValid("phase"))
      {
        const unsigned int phase = pars.get<unsigned int>("phase");

        if (mat_params.isParamValid("phase") && mat_params.get<unsigned int>("phase") == phase)
          return true;
      }
    }
  }

  // If all of these conditions aren't satisfied, then the material is already present
  return false;
}

void
PorousFlowAddMaterialAction::addPFMaterial(AddMaterialAction * material, bool at_nodes)
{
  const std::string nodal_ext = at_nodes ? "_nodal" : "_qp";

  // Input parameters for the material that is being added
  InputParameters & pars = material->getObjectParams();

  // PorousFlowMaterial type
  const std::string pf_material_type = pars.get<std::string>("pf_material_type");
  const std::string moose_object_type = material->getMooseObjectType();

  // If it is a material that also has a fluid phase, then extract that to add to name
  std::string phase_str;
  if (pars.isParamValid("phase"))
  {
    unsigned int phase = pars.get<unsigned int>("phase");
    phase_str = "_phase" + Moose::stringify(phase);
  }

  // Add material to the action warehouse
  InputParameters action_params = _action_factory.getValidParams("AddMaterialAction");
  action_params.set<ActionWarehouse *>("awh") = &_awh;

  // Setup action for passed in material type
  action_params.set<std::string>("type") = moose_object_type;

  const std::string material_name = material->name() + phase_str + nodal_ext;

  auto action = MooseSharedNamespace::dynamic_pointer_cast<MooseObjectAction>(
      _action_factory.create("AddMaterialAction", material_name, action_params));

  action->getObjectParams().applyParameters(pars);
  action->getObjectParams().set<bool>("at_nodes") = at_nodes;

  _awh.addActionBlock(action);
}
<|endoftext|>


<commit_before>#include "pqrs/xml_compiler.hpp"

namespace pqrs {
  void
  xml_compiler::extracted_ptree::extracted_ptree_iterator::increment(void)
  {
    if (stack_.empty()) return;

    auto& top = stack_.top();
    if (top.it == top.end) return;

    ++(top.it);
    collapse_();
    extract_include_();
  }

  const xml_compiler::extracted_ptree::node
  xml_compiler::extracted_ptree::extracted_ptree_iterator::dereference(void) const
  {
    if (stack_.empty()) {
      throw xml_compiler_logic_error("stack_.empty() in extracted_ptree_iterator.");
    }

    auto& top = stack_.top();
    if (top.it == top.end) {
      throw xml_compiler_logic_error("it == end in extracted_ptree_iterator.");
    }

    return node(*(top.it), extracted_ptree_, top.parent_replacement);
  }

  bool
  xml_compiler::extracted_ptree::extracted_ptree_iterator::equal(const extracted_ptree_iterator const& other) const
  {
    if (stack_.empty() && other.stack_.empty()) {
      return true;
    }
    if (stack_.empty() || other.stack_.empty()) {
      return false;
    }

    auto& top1 = stack_.top();
    auto& top2 = other.stack_.top();
    return top1.it == top2.it;
  }

  void
  xml_compiler::extracted_ptree::extracted_ptree_iterator::extract_include_(void)
  {
    if (stack_.empty()) return;

    auto& xml_compiler = extracted_ptree_.xml_compiler_;

    auto& top = stack_.top();
    auto& it = *(top.it);

    if (it.first != "include") return;

    // ----------------------------------------
    // replacement
    std::tr1::shared_ptr<pqrs::string::replacement> replacement_ptr(new pqrs::string::replacement);
    if (! it.second.empty()) {
      replacement_loader loader(xml_compiler, *replacement_ptr);
      loader.traverse(extracted_ptree(extracted_ptree_, top.parent_replacement, it.second));
    }

    auto end = replacement_ptr->end();
    for (auto& i : top.parent_replacement) {
      if (replacement_ptr->find(i.first) == end) {
        (*replacement_ptr)[i.first] = i.second;
      }
    }

    // ----------------------------------------
    std::string xml_file_path;
    {
      auto path = it.second.get_optional<std::string>("<xmlattr>.path");
      if (path) {
        if (extracted_ptree_.included_files_.empty()) {
          throw xml_compiler_logic_error("included_files_.empty() in extracted_ptree_iterator::extract_include_.");
        }
        xml_file_path = xml_compiler.make_file_path(pqrs::file_path::dirname(extracted_ptree_.included_files_.back()),
                                                    *path);
      }
    }
    {
      auto path = it.second.get_optional<std::string>("<xmlattr>.system_xml_path");
      if (path) {
        xml_file_path = xml_compiler.make_file_path(xml_compiler.system_xml_directory_, *path);
      }
    }

    if (! xml_file_path.empty()) {
      for (auto& i : extracted_ptree_.included_files_) {
        if (i == xml_file_path) {
          xml_compiler.error_information_.set("An infinite include loop is detected:\n" + xml_file_path);
          return;
        }
      }

      ptree_ptr pt_ptr;
      xml_compiler.read_xml_(pt_ptr,
                             xml_file_path,
                             *replacement_ptr);

      if (pt_ptr) {
        // Skip <include> next time.
        ++(top.it);
        // Do not call collapse_ here.
        // (Keep included_files_ to detect an infinite include loop.)

        if (! pt_ptr->empty()) {
          auto root_node = pt_ptr->begin();
          auto& root_children = root_node->second;
          if (! root_children.empty()) {
            stack_.push(stack_data(pt_ptr, replacement_ptr, root_children));
            extracted_ptree_.included_files_.push_back(xml_file_path);
            extract_include_();
          }
        }

        collapse_();
      }
    }
  }

  void
  xml_compiler::extracted_ptree::extracted_ptree_iterator::collapse_(void)
  {
    for (;;) {
      if (stack_.empty()) break;

      auto& top = stack_.top();
      if (top.it != top.end) {
        break;
      }

      if (top.extracted()) {
        if (extracted_ptree_.included_files_.empty()) {
          throw xml_compiler_logic_error("included_files_.empty() in extracted_ptree_iterator::collapse_.");
        }
        extracted_ptree_.included_files_.pop_back();
      }
      stack_.pop();
    }
  }
}
<commit_msg>cleanup xml_compiler<commit_after>#include "pqrs/xml_compiler.hpp"

namespace pqrs {
  void
  xml_compiler::extracted_ptree::extracted_ptree_iterator::increment(void)
  {
    if (stack_.empty()) return;

    auto& top = stack_.top();
    if (top.it == top.end) return;

    ++(top.it);
    collapse_();
    extract_include_();
  }

  const xml_compiler::extracted_ptree::node
  xml_compiler::extracted_ptree::extracted_ptree_iterator::dereference(void) const
  {
    if (stack_.empty()) {
      throw xml_compiler_logic_error("stack_.empty() in extracted_ptree_iterator.");
    }

    auto& top = stack_.top();
    if (top.it == top.end) {
      throw xml_compiler_logic_error("it == end in extracted_ptree_iterator.");
    }

    return node(*(top.it), extracted_ptree_, top.parent_replacement);
  }

  bool
  xml_compiler::extracted_ptree::extracted_ptree_iterator::equal(const extracted_ptree_iterator const& other) const
  {
    if (stack_.empty() && other.stack_.empty()) {
      return true;
    }
    if (stack_.empty() || other.stack_.empty()) {
      return false;
    }

    auto& top1 = stack_.top();
    auto& top2 = other.stack_.top();
    return top1.it == top2.it;
  }

  void
  xml_compiler::extracted_ptree::extracted_ptree_iterator::extract_include_(void)
  {
    if (stack_.empty()) return;

    auto& xml_compiler = extracted_ptree_.xml_compiler_;

    auto& top = stack_.top();
    auto& it = *(top.it);

    if (it.first != "include") return;

    // ----------------------------------------
    // replacement
    std::tr1::shared_ptr<pqrs::string::replacement> replacement_ptr(new pqrs::string::replacement);
    if (! it.second.empty()) {
      replacement_loader loader(xml_compiler, *replacement_ptr);
      loader.traverse(extracted_ptree(extracted_ptree_, top.parent_replacement, it.second));
    }

    auto end = replacement_ptr->end();
    for (auto& i : top.parent_replacement) {
      if (replacement_ptr->find(i.first) == end) {
        (*replacement_ptr)[i.first] = i.second;
      }
    }

    // ----------------------------------------
    std::string xml_file_path;
    {
      auto path = it.second.get_optional<std::string>("<xmlattr>.path");
      if (path) {
        if (extracted_ptree_.included_files_.empty()) {
          throw xml_compiler_logic_error("included_files_.empty() in extracted_ptree_iterator::extract_include_.");
        }
        xml_file_path = xml_compiler.make_file_path(pqrs::file_path::dirname(extracted_ptree_.included_files_.back()),
                                                    *path);
      }
    }

    if (! xml_file_path.empty()) {
      for (auto& i : extracted_ptree_.included_files_) {
        if (i == xml_file_path) {
          xml_compiler.error_information_.set("An infinite include loop is detected:\n" + xml_file_path);
          return;
        }
      }

      ptree_ptr pt_ptr;
      xml_compiler.read_xml_(pt_ptr,
                             xml_file_path,
                             *replacement_ptr);

      if (pt_ptr) {
        // Skip <include> next time.
        ++(top.it);
        // Do not call collapse_ here.
        // (Keep included_files_ to detect an infinite include loop.)

        if (! pt_ptr->empty()) {
          auto root_node = pt_ptr->begin();
          auto& root_children = root_node->second;
          if (! root_children.empty()) {
            stack_.push(stack_data(pt_ptr, replacement_ptr, root_children));
            extracted_ptree_.included_files_.push_back(xml_file_path);
            extract_include_();
          }
        }

        collapse_();
      }
    }
  }

  void
  xml_compiler::extracted_ptree::extracted_ptree_iterator::collapse_(void)
  {
    for (;;) {
      if (stack_.empty()) break;

      auto& top = stack_.top();
      if (top.it != top.end) {
        break;
      }

      if (top.extracted()) {
        if (extracted_ptree_.included_files_.empty()) {
          throw xml_compiler_logic_error("included_files_.empty() in extracted_ptree_iterator::collapse_.");
        }
        extracted_ptree_.included_files_.pop_back();
      }
      stack_.pop();
    }
  }
}
<|endoftext|>