/*****************************************************************************
*
* Copyright (c) 2000 - 2018, Lawrence Livermore National Security, LLC
* Produced at the Lawrence Livermore National Laboratory
* LLNL-CODE-442911
* All rights reserved.
*
* This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The
* full copyright notice is contained in the file COPYRIGHT located at the root
* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.
*
* 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 disclaimer below.
*  - Redistributions in binary form must reproduce the above copyright notice,
*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the
*    documentation and/or other materials provided with the distribution.
*  - Neither the name of  the LLNS/LLNL 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 LAWRENCE  LIVERMORE NATIONAL  SECURITY,
* LLC, THE  U.S.  DEPARTMENT OF  ENERGY  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 <ExplodeAttributes.h>
#include <DataNode.h>
#include <ExplodeAttributes.h>

//
// Enum conversion methods for ExplodeAttributes::ExplodeType
//

static const char *ExplodeType_strings[] = {
"Point", "Plane", "Cylinder"
};

std::string
ExplodeAttributes::ExplodeType_ToString(ExplodeAttributes::ExplodeType t)
{
    int index = int(t);
    if(index < 0 || index >= 3) index = 0;
    return ExplodeType_strings[index];
}

std::string
ExplodeAttributes::ExplodeType_ToString(int t)
{
    int index = (t < 0 || t >= 3) ? 0 : t;
    return ExplodeType_strings[index];
}

bool
ExplodeAttributes::ExplodeType_FromString(const std::string &s, ExplodeAttributes::ExplodeType &val)
{
    val = ExplodeAttributes::Point;
    for(int i = 0; i < 3; ++i)
    {
        if(s == ExplodeType_strings[i])
        {
            val = (ExplodeType)i;
            return true;
        }
    }
    return false;
}

//
// Enum conversion methods for ExplodeAttributes::ExplosionPattern
//

static const char *ExplosionPattern_strings[] = {
"Impact", "Scatter"};

std::string
ExplodeAttributes::ExplosionPattern_ToString(ExplodeAttributes::ExplosionPattern t)
{
    int index = int(t);
    if(index < 0 || index >= 2) index = 0;
    return ExplosionPattern_strings[index];
}

std::string
ExplodeAttributes::ExplosionPattern_ToString(int t)
{
    int index = (t < 0 || t >= 2) ? 0 : t;
    return ExplosionPattern_strings[index];
}

bool
ExplodeAttributes::ExplosionPattern_FromString(const std::string &s, ExplodeAttributes::ExplosionPattern &val)
{
    val = ExplodeAttributes::Impact;
    for(int i = 0; i < 2; ++i)
    {
        if(s == ExplosionPattern_strings[i])
        {
            val = (ExplosionPattern)i;
            return true;
        }
    }
    return false;
}

//
// Enum conversion methods for ExplodeAttributes::SubsetType
//

static const char *SubsetType_strings[] = {
"Material", "Domain", "Group", 
"EnumScalar", "Unknown"};

std::string
ExplodeAttributes::SubsetType_ToString(ExplodeAttributes::SubsetType t)
{
    int index = int(t);
    if(index < 0 || index >= 5) index = 0;
    return SubsetType_strings[index];
}

std::string
ExplodeAttributes::SubsetType_ToString(int t)
{
    int index = (t < 0 || t >= 5) ? 0 : t;
    return SubsetType_strings[index];
}

bool
ExplodeAttributes::SubsetType_FromString(const std::string &s, ExplodeAttributes::SubsetType &val)
{
    val = ExplodeAttributes::Material;
    for(int i = 0; i < 5; ++i)
    {
        if(s == SubsetType_strings[i])
        {
            val = (SubsetType)i;
            return true;
        }
    }
    return false;
}

// ****************************************************************************
// Method: ExplodeAttributes::ExplodeAttributes
//
// Purpose: 
//   Init utility for the ExplodeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

void ExplodeAttributes::Init()
{
    explosionType = Point;
    explosionPoint[0] = 0;
    explosionPoint[1] = 0;
    explosionPoint[2] = 0;
    planePoint[0] = 0;
    planePoint[1] = 0;
    planePoint[2] = 0;
    planeNorm[0] = 0;
    planeNorm[1] = 0;
    planeNorm[2] = 0;
    cylinderPoint1[0] = 0;
    cylinderPoint1[1] = 0;
    cylinderPoint1[2] = 0;
    cylinderPoint2[0] = 0;
    cylinderPoint2[1] = 0;
    cylinderPoint2[2] = 0;
    materialExplosionFactor = 1;
    cylinderRadius = 0;
    explodeMaterialCells = false;
    cellExplosionFactor = 1;
    explosionPattern = Impact;
    explodeAllCells = false;
    subsetType = Unknown;

    ExplodeAttributes::SelectAll();
}

// ****************************************************************************
// Method: ExplodeAttributes::ExplodeAttributes
//
// Purpose: 
//   Copy utility for the ExplodeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

void ExplodeAttributes::Copy(const ExplodeAttributes &obj)
{
    AttributeGroupVector::const_iterator pos;

    explosionType = obj.explosionType;
    explosionPoint[0] = obj.explosionPoint[0];
    explosionPoint[1] = obj.explosionPoint[1];
    explosionPoint[2] = obj.explosionPoint[2];

    planePoint[0] = obj.planePoint[0];
    planePoint[1] = obj.planePoint[1];
    planePoint[2] = obj.planePoint[2];

    planeNorm[0] = obj.planeNorm[0];
    planeNorm[1] = obj.planeNorm[1];
    planeNorm[2] = obj.planeNorm[2];

    cylinderPoint1[0] = obj.cylinderPoint1[0];
    cylinderPoint1[1] = obj.cylinderPoint1[1];
    cylinderPoint1[2] = obj.cylinderPoint1[2];

    cylinderPoint2[0] = obj.cylinderPoint2[0];
    cylinderPoint2[1] = obj.cylinderPoint2[1];
    cylinderPoint2[2] = obj.cylinderPoint2[2];

    materialExplosionFactor = obj.materialExplosionFactor;
    material = obj.material;
    cylinderRadius = obj.cylinderRadius;
    explodeMaterialCells = obj.explodeMaterialCells;
    cellExplosionFactor = obj.cellExplosionFactor;
    explosionPattern = obj.explosionPattern;
    explodeAllCells = obj.explodeAllCells;
    boundaryNames = obj.boundaryNames;
    // *** Copy the explosions field ***
    // Delete the AttributeGroup objects and clear the vector.
    for(pos = explosions.begin(); pos != explosions.end(); ++pos)
        delete *pos;
    explosions.clear();
    if(obj.explosions.size() > 0)
        explosions.reserve(obj.explosions.size());
    // Duplicate the explosions from obj.
    for(pos = obj.explosions.begin(); pos != obj.explosions.end(); ++pos)
    {
        ExplodeAttributes *oldExplodeAttributes = (ExplodeAttributes *)(*pos);
        ExplodeAttributes *newExplodeAttributes = new ExplodeAttributes(*oldExplodeAttributes);
        explosions.push_back(newExplodeAttributes);
    }

    subsetType = obj.subsetType;

    ExplodeAttributes::SelectAll();
}

// Type map format string
const char *ExplodeAttributes::TypeMapFormatString = EXPLODEATTRIBUTES_TMFS;
const AttributeGroup::private_tmfs_t ExplodeAttributes::TmfsStruct = {EXPLODEATTRIBUTES_TMFS};


// ****************************************************************************
// Method: ExplodeAttributes::ExplodeAttributes
//
// Purpose: 
//   Default constructor for the ExplodeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

ExplodeAttributes::ExplodeAttributes() : 
    AttributeSubject(ExplodeAttributes::TypeMapFormatString)
{
    ExplodeAttributes::Init();
}

// ****************************************************************************
// Method: ExplodeAttributes::ExplodeAttributes
//
// Purpose: 
//   Constructor for the derived classes of ExplodeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

ExplodeAttributes::ExplodeAttributes(private_tmfs_t tmfs) : 
    AttributeSubject(tmfs.tmfs)
{
    ExplodeAttributes::Init();
}

// ****************************************************************************
// Method: ExplodeAttributes::ExplodeAttributes
//
// Purpose: 
//   Copy constructor for the ExplodeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

ExplodeAttributes::ExplodeAttributes(const ExplodeAttributes &obj) : 
    AttributeSubject(ExplodeAttributes::TypeMapFormatString)
{
    ExplodeAttributes::Copy(obj);
}

// ****************************************************************************
// Method: ExplodeAttributes::ExplodeAttributes
//
// Purpose: 
//   Copy constructor for derived classes of the ExplodeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

ExplodeAttributes::ExplodeAttributes(const ExplodeAttributes &obj, private_tmfs_t tmfs) : 
    AttributeSubject(tmfs.tmfs)
{
    ExplodeAttributes::Copy(obj);
}

// ****************************************************************************
// Method: ExplodeAttributes::~ExplodeAttributes
//
// Purpose: 
//   Destructor for the ExplodeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

ExplodeAttributes::~ExplodeAttributes()
{
    AttributeGroupVector::iterator pos;

    // Destroy the explosions field.
    for(pos = explosions.begin(); pos != explosions.end(); ++pos)
        delete *pos;
}

// ****************************************************************************
// Method: ExplodeAttributes::operator = 
//
// Purpose: 
//   Assignment operator for the ExplodeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

ExplodeAttributes& 
ExplodeAttributes::operator = (const ExplodeAttributes &obj)
{
    if (this == &obj) return *this;

    ExplodeAttributes::Copy(obj);

    return *this;
}

// ****************************************************************************
// Method: ExplodeAttributes::operator == 
//
// Purpose: 
//   Comparison operator == for the ExplodeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

bool
ExplodeAttributes::operator == (const ExplodeAttributes &obj) const
{
    // Compare the explosionPoint arrays.
    bool explosionPoint_equal = true;
    for(int i = 0; i < 3 && explosionPoint_equal; ++i)
        explosionPoint_equal = (explosionPoint[i] == obj.explosionPoint[i]);

    // Compare the planePoint arrays.
    bool planePoint_equal = true;
    for(int i = 0; i < 3 && planePoint_equal; ++i)
        planePoint_equal = (planePoint[i] == obj.planePoint[i]);

    // Compare the planeNorm arrays.
    bool planeNorm_equal = true;
    for(int i = 0; i < 3 && planeNorm_equal; ++i)
        planeNorm_equal = (planeNorm[i] == obj.planeNorm[i]);

    // Compare the cylinderPoint1 arrays.
    bool cylinderPoint1_equal = true;
    for(int i = 0; i < 3 && cylinderPoint1_equal; ++i)
        cylinderPoint1_equal = (cylinderPoint1[i] == obj.cylinderPoint1[i]);

    // Compare the cylinderPoint2 arrays.
    bool cylinderPoint2_equal = true;
    for(int i = 0; i < 3 && cylinderPoint2_equal; ++i)
        cylinderPoint2_equal = (cylinderPoint2[i] == obj.cylinderPoint2[i]);

    bool explosions_equal = (obj.explosions.size() == explosions.size());
    for(size_t i = 0; (i < explosions.size()) && explosions_equal; ++i)
    {
        // Make references to ExplodeAttributes from AttributeGroup *.
        const ExplodeAttributes &explosions1 = *((const ExplodeAttributes *)(explosions[i]));
        const ExplodeAttributes &explosions2 = *((const ExplodeAttributes *)(obj.explosions[i]));
        explosions_equal = (explosions1 == explosions2);
    }

    // Create the return value
    return ((explosionType == obj.explosionType) &&
            explosionPoint_equal &&
            planePoint_equal &&
            planeNorm_equal &&
            cylinderPoint1_equal &&
            cylinderPoint2_equal &&
            (materialExplosionFactor == obj.materialExplosionFactor) &&
            (material == obj.material) &&
            (cylinderRadius == obj.cylinderRadius) &&
            (explodeMaterialCells == obj.explodeMaterialCells) &&
            (cellExplosionFactor == obj.cellExplosionFactor) &&
            (explosionPattern == obj.explosionPattern) &&
            (explodeAllCells == obj.explodeAllCells) &&
            (boundaryNames == obj.boundaryNames) &&
            explosions_equal &&
            (subsetType == obj.subsetType));
}

// ****************************************************************************
// Method: ExplodeAttributes::operator != 
//
// Purpose: 
//   Comparison operator != for the ExplodeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

bool
ExplodeAttributes::operator != (const ExplodeAttributes &obj) const
{
    return !(this->operator == (obj));
}

// ****************************************************************************
// Method: ExplodeAttributes::TypeName
//
// Purpose: 
//   Type name method for the ExplodeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

const std::string
ExplodeAttributes::TypeName() const
{
    return "ExplodeAttributes";
}

// ****************************************************************************
// Method: ExplodeAttributes::CopyAttributes
//
// Purpose: 
//   CopyAttributes method for the ExplodeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

bool
ExplodeAttributes::CopyAttributes(const AttributeGroup *atts)
{
    if(TypeName() != atts->TypeName())
        return false;

    // Call assignment operator.
    const ExplodeAttributes *tmp = (const ExplodeAttributes *)atts;
    *this = *tmp;

    return true;
}

// ****************************************************************************
// Method: ExplodeAttributes::CreateCompatible
//
// Purpose: 
//   CreateCompatible method for the ExplodeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

AttributeSubject *
ExplodeAttributes::CreateCompatible(const std::string &tname) const
{
    AttributeSubject *retval = 0;
    if(TypeName() == tname)
        retval = new ExplodeAttributes(*this);
    // Other cases could go here too. 

    return retval;
}

// ****************************************************************************
// Method: ExplodeAttributes::NewInstance
//
// Purpose: 
//   NewInstance method for the ExplodeAttributes class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

AttributeSubject *
ExplodeAttributes::NewInstance(bool copy) const
{
    AttributeSubject *retval = 0;
    if(copy)
        retval = new ExplodeAttributes(*this);
    else
        retval = new ExplodeAttributes;

    return retval;
}

// ****************************************************************************
// Method: ExplodeAttributes::SelectAll
//
// Purpose: 
//   Selects all attributes.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

void
ExplodeAttributes::SelectAll()
{
    Select(ID_explosionType,           (void *)&explosionType);
    Select(ID_explosionPoint,          (void *)explosionPoint, 3);
    Select(ID_planePoint,              (void *)planePoint, 3);
    Select(ID_planeNorm,               (void *)planeNorm, 3);
    Select(ID_cylinderPoint1,          (void *)cylinderPoint1, 3);
    Select(ID_cylinderPoint2,          (void *)cylinderPoint2, 3);
    Select(ID_materialExplosionFactor, (void *)&materialExplosionFactor);
    Select(ID_material,                (void *)&material);
    Select(ID_cylinderRadius,          (void *)&cylinderRadius);
    Select(ID_explodeMaterialCells,    (void *)&explodeMaterialCells);
    Select(ID_cellExplosionFactor,     (void *)&cellExplosionFactor);
    Select(ID_explosionPattern,        (void *)&explosionPattern);
    Select(ID_explodeAllCells,         (void *)&explodeAllCells);
    Select(ID_boundaryNames,           (void *)&boundaryNames);
    Select(ID_explosions,              (void *)&explosions);
    Select(ID_subsetType,              (void *)&subsetType);
}

// ****************************************************************************
// Method: ExplodeAttributes::CreateSubAttributeGroup
//
// Purpose: 
//   This class contains attributes for the explode operator. 
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

AttributeGroup *
ExplodeAttributes::CreateSubAttributeGroup(int)
{
    return new ExplodeAttributes;
}

///////////////////////////////////////////////////////////////////////////////
// Persistence methods
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
// Method: ExplodeAttributes::CreateNode
//
// Purpose: 
//   This method creates a DataNode representation of the object so it can be saved to a config file.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

bool
ExplodeAttributes::CreateNode(DataNode *parentNode, bool completeSave, bool forceAdd)
{
    if(parentNode == 0)
        return false;

    ExplodeAttributes defaultObject;
    bool addToParent = false;
    // Create a node for ExplodeAttributes.
    DataNode *node = new DataNode("ExplodeAttributes");

    if(completeSave || !FieldsEqual(ID_explosionType, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("explosionType", ExplodeType_ToString(explosionType)));
    }

    if(completeSave || !FieldsEqual(ID_explosionPoint, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("explosionPoint", explosionPoint, 3));
    }

    if(completeSave || !FieldsEqual(ID_planePoint, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("planePoint", planePoint, 3));
    }

    if(completeSave || !FieldsEqual(ID_planeNorm, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("planeNorm", planeNorm, 3));
    }

    if(completeSave || !FieldsEqual(ID_cylinderPoint1, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("cylinderPoint1", cylinderPoint1, 3));
    }

    if(completeSave || !FieldsEqual(ID_cylinderPoint2, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("cylinderPoint2", cylinderPoint2, 3));
    }

    if(completeSave || !FieldsEqual(ID_materialExplosionFactor, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("materialExplosionFactor", materialExplosionFactor));
    }

    if(completeSave || !FieldsEqual(ID_material, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("material", material));
    }

    if(completeSave || !FieldsEqual(ID_cylinderRadius, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("cylinderRadius", cylinderRadius));
    }

    if(completeSave || !FieldsEqual(ID_explodeMaterialCells, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("explodeMaterialCells", explodeMaterialCells));
    }

    if(completeSave || !FieldsEqual(ID_cellExplosionFactor, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("cellExplosionFactor", cellExplosionFactor));
    }

    if(completeSave || !FieldsEqual(ID_explosionPattern, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("explosionPattern", ExplosionPattern_ToString(explosionPattern)));
    }

    if(completeSave || !FieldsEqual(ID_explodeAllCells, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("explodeAllCells", explodeAllCells));
    }

    if(completeSave || !FieldsEqual(ID_boundaryNames, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("boundaryNames", boundaryNames));
    }

    if(completeSave || !FieldsEqual(ID_explosions, &defaultObject))
    {
        addToParent = true;
        for(size_t i = 0; i < explosions.size(); ++i)
            explosions[i]->CreateNode(node, completeSave, true);
    }

    if(completeSave || !FieldsEqual(ID_subsetType, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("subsetType", SubsetType_ToString(subsetType)));
    }


    // Add the node to the parent node.
    if(addToParent || forceAdd)
        parentNode->AddNode(node);
    else
        delete node;

    return (addToParent || forceAdd);
}

// ****************************************************************************
// Method: ExplodeAttributes::SetFromNode
//
// Purpose: 
//   This method sets attributes in this object from values in a DataNode representation of the object.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

void
ExplodeAttributes::SetFromNode(DataNode *parentNode)
{
    if(parentNode == 0)
        return;

    DataNode *searchNode = parentNode->GetNode("ExplodeAttributes");
    if(searchNode == 0)
        return;

    DataNode *node;
    DataNode **children;
    if((node = searchNode->GetNode("explosionType")) != 0)
    {
        // Allow enums to be int or string in the config file
        if(node->GetNodeType() == INT_NODE)
        {
            int ival = node->AsInt();
            if(ival >= 0 && ival < 3)
                SetExplosionType(ExplodeType(ival));
        }
        else if(node->GetNodeType() == STRING_NODE)
        {
            ExplodeType value;
            if(ExplodeType_FromString(node->AsString(), value))
                SetExplosionType(value);
        }
    }
    if((node = searchNode->GetNode("explosionPoint")) != 0)
        SetExplosionPoint(node->AsDoubleArray());
    if((node = searchNode->GetNode("planePoint")) != 0)
        SetPlanePoint(node->AsDoubleArray());
    if((node = searchNode->GetNode("planeNorm")) != 0)
        SetPlaneNorm(node->AsDoubleArray());
    if((node = searchNode->GetNode("cylinderPoint1")) != 0)
        SetCylinderPoint1(node->AsDoubleArray());
    if((node = searchNode->GetNode("cylinderPoint2")) != 0)
        SetCylinderPoint2(node->AsDoubleArray());
    if((node = searchNode->GetNode("materialExplosionFactor")) != 0)
        SetMaterialExplosionFactor(node->AsDouble());
    if((node = searchNode->GetNode("material")) != 0)
        SetMaterial(node->AsString());
    if((node = searchNode->GetNode("cylinderRadius")) != 0)
        SetCylinderRadius(node->AsDouble());
    if((node = searchNode->GetNode("explodeMaterialCells")) != 0)
        SetExplodeMaterialCells(node->AsBool());
    if((node = searchNode->GetNode("cellExplosionFactor")) != 0)
        SetCellExplosionFactor(node->AsDouble());
    if((node = searchNode->GetNode("explosionPattern")) != 0)
    {
        // Allow enums to be int or string in the config file
        if(node->GetNodeType() == INT_NODE)
        {
            int ival = node->AsInt();
            if(ival >= 0 && ival < 2)
                SetExplosionPattern(ExplosionPattern(ival));
        }
        else if(node->GetNodeType() == STRING_NODE)
        {
            ExplosionPattern value;
            if(ExplosionPattern_FromString(node->AsString(), value))
                SetExplosionPattern(value);
        }
    }
    if((node = searchNode->GetNode("explodeAllCells")) != 0)
        SetExplodeAllCells(node->AsBool());
    if((node = searchNode->GetNode("boundaryNames")) != 0)
        SetBoundaryNames(node->AsStringVector());

    // Clear all the ExplodeAttributess if we got any.
    bool clearedExplosions = false;
    // Go through all of the children and construct a new
    // ExplodeAttributes for each one of them.
    children = searchNode->GetChildren();
    if(children != 0)
    {
        for(int i = 0; i < searchNode->GetNumChildren(); ++i)
        {
            if(children[i]->GetKey() == std::string("ExplodeAttributes"))
            {
                if (!clearedExplosions)
                {
                    ClearExplosions();
                    clearedExplosions = true;
                }
                ExplodeAttributes temp;
                temp.SetFromNode(children[i]);
                AddExplosions(temp);
            }
        }
    }

    if((node = searchNode->GetNode("subsetType")) != 0)
    {
        // Allow enums to be int or string in the config file
        if(node->GetNodeType() == INT_NODE)
        {
            int ival = node->AsInt();
            if(ival >= 0 && ival < 5)
                SetSubsetType(SubsetType(ival));
        }
        else if(node->GetNodeType() == STRING_NODE)
        {
            SubsetType value;
            if(SubsetType_FromString(node->AsString(), value))
                SetSubsetType(value);
        }
    }
}

///////////////////////////////////////////////////////////////////////////////
// Set property methods
///////////////////////////////////////////////////////////////////////////////

void
ExplodeAttributes::SetExplosionType(ExplodeAttributes::ExplodeType explosionType_)
{
    explosionType = explosionType_;
    Select(ID_explosionType, (void *)&explosionType);
}

void
ExplodeAttributes::SetExplosionPoint(const double *explosionPoint_)
{
    explosionPoint[0] = explosionPoint_[0];
    explosionPoint[1] = explosionPoint_[1];
    explosionPoint[2] = explosionPoint_[2];
    Select(ID_explosionPoint, (void *)explosionPoint, 3);
}

void
ExplodeAttributes::SetPlanePoint(const double *planePoint_)
{
    planePoint[0] = planePoint_[0];
    planePoint[1] = planePoint_[1];
    planePoint[2] = planePoint_[2];
    Select(ID_planePoint, (void *)planePoint, 3);
}

void
ExplodeAttributes::SetPlaneNorm(const double *planeNorm_)
{
    planeNorm[0] = planeNorm_[0];
    planeNorm[1] = planeNorm_[1];
    planeNorm[2] = planeNorm_[2];
    Select(ID_planeNorm, (void *)planeNorm, 3);
}

void
ExplodeAttributes::SetCylinderPoint1(const double *cylinderPoint1_)
{
    cylinderPoint1[0] = cylinderPoint1_[0];
    cylinderPoint1[1] = cylinderPoint1_[1];
    cylinderPoint1[2] = cylinderPoint1_[2];
    Select(ID_cylinderPoint1, (void *)cylinderPoint1, 3);
}

void
ExplodeAttributes::SetCylinderPoint2(const double *cylinderPoint2_)
{
    cylinderPoint2[0] = cylinderPoint2_[0];
    cylinderPoint2[1] = cylinderPoint2_[1];
    cylinderPoint2[2] = cylinderPoint2_[2];
    Select(ID_cylinderPoint2, (void *)cylinderPoint2, 3);
}

void
ExplodeAttributes::SetMaterialExplosionFactor(double materialExplosionFactor_)
{
    materialExplosionFactor = materialExplosionFactor_;
    Select(ID_materialExplosionFactor, (void *)&materialExplosionFactor);
}

void
ExplodeAttributes::SetMaterial(const std::string &material_)
{
    material = material_;
    Select(ID_material, (void *)&material);
}

void
ExplodeAttributes::SetCylinderRadius(double cylinderRadius_)
{
    cylinderRadius = cylinderRadius_;
    Select(ID_cylinderRadius, (void *)&cylinderRadius);
}

void
ExplodeAttributes::SetExplodeMaterialCells(bool explodeMaterialCells_)
{
    explodeMaterialCells = explodeMaterialCells_;
    Select(ID_explodeMaterialCells, (void *)&explodeMaterialCells);
}

void
ExplodeAttributes::SetCellExplosionFactor(double cellExplosionFactor_)
{
    cellExplosionFactor = cellExplosionFactor_;
    Select(ID_cellExplosionFactor, (void *)&cellExplosionFactor);
}

void
ExplodeAttributes::SetExplosionPattern(ExplodeAttributes::ExplosionPattern explosionPattern_)
{
    explosionPattern = explosionPattern_;
    Select(ID_explosionPattern, (void *)&explosionPattern);
}

void
ExplodeAttributes::SetExplodeAllCells(bool explodeAllCells_)
{
    explodeAllCells = explodeAllCells_;
    Select(ID_explodeAllCells, (void *)&explodeAllCells);
}

void
ExplodeAttributes::SetBoundaryNames(const stringVector &boundaryNames_)
{
    boundaryNames = boundaryNames_;
    Select(ID_boundaryNames, (void *)&boundaryNames);
}

void
ExplodeAttributes::SetSubsetType(ExplodeAttributes::SubsetType subsetType_)
{
    subsetType = subsetType_;
    Select(ID_subsetType, (void *)&subsetType);
}

///////////////////////////////////////////////////////////////////////////////
// Get property methods
///////////////////////////////////////////////////////////////////////////////

ExplodeAttributes::ExplodeType
ExplodeAttributes::GetExplosionType() const
{
    return ExplodeType(explosionType);
}

const double *
ExplodeAttributes::GetExplosionPoint() const
{
    return explosionPoint;
}

double *
ExplodeAttributes::GetExplosionPoint()
{
    return explosionPoint;
}

const double *
ExplodeAttributes::GetPlanePoint() const
{
    return planePoint;
}

double *
ExplodeAttributes::GetPlanePoint()
{
    return planePoint;
}

const double *
ExplodeAttributes::GetPlaneNorm() const
{
    return planeNorm;
}

double *
ExplodeAttributes::GetPlaneNorm()
{
    return planeNorm;
}

const double *
ExplodeAttributes::GetCylinderPoint1() const
{
    return cylinderPoint1;
}

double *
ExplodeAttributes::GetCylinderPoint1()
{
    return cylinderPoint1;
}

const double *
ExplodeAttributes::GetCylinderPoint2() const
{
    return cylinderPoint2;
}

double *
ExplodeAttributes::GetCylinderPoint2()
{
    return cylinderPoint2;
}

double
ExplodeAttributes::GetMaterialExplosionFactor() const
{
    return materialExplosionFactor;
}

const std::string &
ExplodeAttributes::GetMaterial() const
{
    return material;
}

std::string &
ExplodeAttributes::GetMaterial()
{
    return material;
}

double
ExplodeAttributes::GetCylinderRadius() const
{
    return cylinderRadius;
}

bool
ExplodeAttributes::GetExplodeMaterialCells() const
{
    return explodeMaterialCells;
}

double
ExplodeAttributes::GetCellExplosionFactor() const
{
    return cellExplosionFactor;
}

ExplodeAttributes::ExplosionPattern
ExplodeAttributes::GetExplosionPattern() const
{
    return ExplosionPattern(explosionPattern);
}

bool
ExplodeAttributes::GetExplodeAllCells() const
{
    return explodeAllCells;
}

const stringVector &
ExplodeAttributes::GetBoundaryNames() const
{
    return boundaryNames;
}

stringVector &
ExplodeAttributes::GetBoundaryNames()
{
    return boundaryNames;
}

const AttributeGroupVector &
ExplodeAttributes::GetExplosions() const
{
    return explosions;
}

AttributeGroupVector &
ExplodeAttributes::GetExplosions()
{
    return explosions;
}

ExplodeAttributes::SubsetType
ExplodeAttributes::GetSubsetType() const
{
    return SubsetType(subsetType);
}

///////////////////////////////////////////////////////////////////////////////
// Select property methods
///////////////////////////////////////////////////////////////////////////////

void
ExplodeAttributes::SelectExplosionPoint()
{
    Select(ID_explosionPoint, (void *)explosionPoint, 3);
}

void
ExplodeAttributes::SelectPlanePoint()
{
    Select(ID_planePoint, (void *)planePoint, 3);
}

void
ExplodeAttributes::SelectPlaneNorm()
{
    Select(ID_planeNorm, (void *)planeNorm, 3);
}

void
ExplodeAttributes::SelectCylinderPoint1()
{
    Select(ID_cylinderPoint1, (void *)cylinderPoint1, 3);
}

void
ExplodeAttributes::SelectCylinderPoint2()
{
    Select(ID_cylinderPoint2, (void *)cylinderPoint2, 3);
}

void
ExplodeAttributes::SelectMaterial()
{
    Select(ID_material, (void *)&material);
}

void
ExplodeAttributes::SelectBoundaryNames()
{
    Select(ID_boundaryNames, (void *)&boundaryNames);
}

void
ExplodeAttributes::SelectExplosions()
{
    Select(ID_explosions, (void *)&explosions);
}

///////////////////////////////////////////////////////////////////////////////
// AttributeGroupVector convenience methods.
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
// Method: ExplodeAttributes::AddExplosions
//
// Purpose: 
//   This class contains attributes for the explode operator. 
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

void
ExplodeAttributes::AddExplosions(const ExplodeAttributes &obj)
{
    ExplodeAttributes *newExplodeAttributes = new ExplodeAttributes(obj);
    explosions.push_back(newExplodeAttributes);

    // Indicate that things have changed by selecting it.
    Select(ID_explosions, (void *)&explosions);
}

// ****************************************************************************
// Method: ExplodeAttributes::ClearExplosions
//
// Purpose: 
//   This class contains attributes for the explode operator. 
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

void
ExplodeAttributes::ClearExplosions()
{
    AttributeGroupVector::iterator pos;

    for(pos = explosions.begin(); pos != explosions.end(); ++pos)
        delete *pos;
    explosions.clear();

    // Indicate that things have changed by selecting the list.
    Select(ID_explosions, (void *)&explosions);
}

// ****************************************************************************
// Method: ExplodeAttributes::RemoveExplosions
//
// Purpose: 
//   This class contains attributes for the explode operator. 
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

void
ExplodeAttributes::RemoveExplosions(int index)
{
    AttributeGroupVector::iterator pos = explosions.begin();

    // Iterate through the vector "index" times. 
    for(int i = 0; i < index; ++i)
        if(pos != explosions.end()) ++pos;

    // If pos is still a valid iterator, remove that element.
    if(pos != explosions.end())
    {
        delete *pos;
        explosions.erase(pos);
    }

    // Indicate that things have changed by selecting the list.
    Select(ID_explosions, (void *)&explosions);
}

// ****************************************************************************
// Method: ExplodeAttributes::GetNumExplosions
//
// Purpose: 
//   This class contains attributes for the explode operator. 
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

int
ExplodeAttributes::GetNumExplosions() const
{
    return (int)explosions.size();
}

// ****************************************************************************
// Method: ExplodeAttributes::GetExplosions
//
// Purpose: 
//   This class contains attributes for the explode operator. 
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

ExplodeAttributes &
ExplodeAttributes::GetExplosions(int i)
{
    return *((ExplodeAttributes *)explosions[i]);
}

// ****************************************************************************
// Method: ExplodeAttributes::GetExplosions
//
// Purpose: 
//   This class contains attributes for the explode operator. 
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

const ExplodeAttributes &
ExplodeAttributes::GetExplosions(int i) const
{
    return *((ExplodeAttributes *)explosions[i]);
}

// ****************************************************************************
// Method: ExplodeAttributes::operator []
//
// Purpose: 
//   This class contains attributes for the explode operator. 
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

ExplodeAttributes &
ExplodeAttributes::operator [] (int i)
{
    return *((ExplodeAttributes *)explosions[i]);
}

// ****************************************************************************
// Method: ExplodeAttributes::operator []
//
// Purpose: 
//   This class contains attributes for the explode operator. 
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

const ExplodeAttributes &
ExplodeAttributes::operator [] (int i) const
{
    return *((ExplodeAttributes *)explosions[i]);
}

///////////////////////////////////////////////////////////////////////////////
// Keyframing methods
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
// Method: ExplodeAttributes::GetFieldName
//
// Purpose: 
//   This method returns the name of a field given its index.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

std::string
ExplodeAttributes::GetFieldName(int index) const
{
    switch (index)
    {
    case ID_explosionType:           return "explosionType";
    case ID_explosionPoint:          return "explosionPoint";
    case ID_planePoint:              return "planePoint";
    case ID_planeNorm:               return "planeNorm";
    case ID_cylinderPoint1:          return "cylinderPoint1";
    case ID_cylinderPoint2:          return "cylinderPoint2";
    case ID_materialExplosionFactor: return "materialExplosionFactor";
    case ID_material:                return "material";
    case ID_cylinderRadius:          return "cylinderRadius";
    case ID_explodeMaterialCells:    return "explodeMaterialCells";
    case ID_cellExplosionFactor:     return "cellExplosionFactor";
    case ID_explosionPattern:        return "explosionPattern";
    case ID_explodeAllCells:         return "explodeAllCells";
    case ID_boundaryNames:           return "boundaryNames";
    case ID_explosions:              return "explosions";
    case ID_subsetType:              return "subsetType";
    default:  return "invalid index";
    }
}

// ****************************************************************************
// Method: ExplodeAttributes::GetFieldType
//
// Purpose: 
//   This method returns the type of a field given its index.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

AttributeGroup::FieldType
ExplodeAttributes::GetFieldType(int index) const
{
    switch (index)
    {
    case ID_explosionType:           return FieldType_enum;
    case ID_explosionPoint:          return FieldType_doubleArray;
    case ID_planePoint:              return FieldType_doubleArray;
    case ID_planeNorm:               return FieldType_doubleArray;
    case ID_cylinderPoint1:          return FieldType_doubleArray;
    case ID_cylinderPoint2:          return FieldType_doubleArray;
    case ID_materialExplosionFactor: return FieldType_double;
    case ID_material:                return FieldType_string;
    case ID_cylinderRadius:          return FieldType_double;
    case ID_explodeMaterialCells:    return FieldType_bool;
    case ID_cellExplosionFactor:     return FieldType_double;
    case ID_explosionPattern:        return FieldType_enum;
    case ID_explodeAllCells:         return FieldType_bool;
    case ID_boundaryNames:           return FieldType_stringVector;
    case ID_explosions:              return FieldType_attVector;
    case ID_subsetType:              return FieldType_enum;
    default:  return FieldType_unknown;
    }
}

// ****************************************************************************
// Method: ExplodeAttributes::GetFieldTypeName
//
// Purpose: 
//   This method returns the name of a field type given its index.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

std::string
ExplodeAttributes::GetFieldTypeName(int index) const
{
    switch (index)
    {
    case ID_explosionType:           return "enum";
    case ID_explosionPoint:          return "doubleArray";
    case ID_planePoint:              return "doubleArray";
    case ID_planeNorm:               return "doubleArray";
    case ID_cylinderPoint1:          return "doubleArray";
    case ID_cylinderPoint2:          return "doubleArray";
    case ID_materialExplosionFactor: return "double";
    case ID_material:                return "string";
    case ID_cylinderRadius:          return "double";
    case ID_explodeMaterialCells:    return "bool";
    case ID_cellExplosionFactor:     return "double";
    case ID_explosionPattern:        return "enum";
    case ID_explodeAllCells:         return "bool";
    case ID_boundaryNames:           return "stringVector";
    case ID_explosions:              return "attVector";
    case ID_subsetType:              return "enum";
    default:  return "invalid index";
    }
}

// ****************************************************************************
// Method: ExplodeAttributes::FieldsEqual
//
// Purpose: 
//   This method compares two fields and return true if they are equal.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   
// ****************************************************************************

bool
ExplodeAttributes::FieldsEqual(int index_, const AttributeGroup *rhs) const
{
    const ExplodeAttributes &obj = *((const ExplodeAttributes*)rhs);
    bool retval = false;
    switch (index_)
    {
    case ID_explosionType:
        {  // new scope
        retval = (explosionType == obj.explosionType);
        }
        break;
    case ID_explosionPoint:
        {  // new scope
        // Compare the explosionPoint arrays.
        bool explosionPoint_equal = true;
        for(int i = 0; i < 3 && explosionPoint_equal; ++i)
            explosionPoint_equal = (explosionPoint[i] == obj.explosionPoint[i]);

        retval = explosionPoint_equal;
        }
        break;
    case ID_planePoint:
        {  // new scope
        // Compare the planePoint arrays.
        bool planePoint_equal = true;
        for(int i = 0; i < 3 && planePoint_equal; ++i)
            planePoint_equal = (planePoint[i] == obj.planePoint[i]);

        retval = planePoint_equal;
        }
        break;
    case ID_planeNorm:
        {  // new scope
        // Compare the planeNorm arrays.
        bool planeNorm_equal = true;
        for(int i = 0; i < 3 && planeNorm_equal; ++i)
            planeNorm_equal = (planeNorm[i] == obj.planeNorm[i]);

        retval = planeNorm_equal;
        }
        break;
    case ID_cylinderPoint1:
        {  // new scope
        // Compare the cylinderPoint1 arrays.
        bool cylinderPoint1_equal = true;
        for(int i = 0; i < 3 && cylinderPoint1_equal; ++i)
            cylinderPoint1_equal = (cylinderPoint1[i] == obj.cylinderPoint1[i]);

        retval = cylinderPoint1_equal;
        }
        break;
    case ID_cylinderPoint2:
        {  // new scope
        // Compare the cylinderPoint2 arrays.
        bool cylinderPoint2_equal = true;
        for(int i = 0; i < 3 && cylinderPoint2_equal; ++i)
            cylinderPoint2_equal = (cylinderPoint2[i] == obj.cylinderPoint2[i]);

        retval = cylinderPoint2_equal;
        }
        break;
    case ID_materialExplosionFactor:
        {  // new scope
        retval = (materialExplosionFactor == obj.materialExplosionFactor);
        }
        break;
    case ID_material:
        {  // new scope
        retval = (material == obj.material);
        }
        break;
    case ID_cylinderRadius:
        {  // new scope
        retval = (cylinderRadius == obj.cylinderRadius);
        }
        break;
    case ID_explodeMaterialCells:
        {  // new scope
        retval = (explodeMaterialCells == obj.explodeMaterialCells);
        }
        break;
    case ID_cellExplosionFactor:
        {  // new scope
        retval = (cellExplosionFactor == obj.cellExplosionFactor);
        }
        break;
    case ID_explosionPattern:
        {  // new scope
        retval = (explosionPattern == obj.explosionPattern);
        }
        break;
    case ID_explodeAllCells:
        {  // new scope
        retval = (explodeAllCells == obj.explodeAllCells);
        }
        break;
    case ID_boundaryNames:
        {  // new scope
        retval = (boundaryNames == obj.boundaryNames);
        }
        break;
    case ID_explosions:
        {  // new scope
        bool explosions_equal = (obj.explosions.size() == explosions.size());
        for(size_t i = 0; (i < explosions.size()) && explosions_equal; ++i)
        {
            // Make references to ExplodeAttributes from AttributeGroup *.
            const ExplodeAttributes &explosions1 = *((const ExplodeAttributes *)(explosions[i]));
            const ExplodeAttributes &explosions2 = *((const ExplodeAttributes *)(obj.explosions[i]));
            explosions_equal = (explosions1 == explosions2);
        }

        retval = explosions_equal;
        }
        break;
    case ID_subsetType:
        {  // new scope
        retval = (subsetType == obj.subsetType);
        }
        break;
    default: retval = false;
    }

    return retval;
}

///////////////////////////////////////////////////////////////////////////////
// User-defined methods.
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
// Method: ExplodeAttributes::AttributesMatch
//
// Purpose: 
//     Compare two attributes, excluding their explosions list. 
//
// Programmer: Alister Maguire
// Creation:   Tue Feb 20 11:06:54 PST 2018
//
// Modifications:
//   
// ****************************************************************************

bool
ExplodeAttributes::AttributesMatch (const ExplodeAttributes &obj) const
{
    // Compare the explosionPoint arrays.
    bool explosionPoint_equal = true;
    for(int i = 0; i < 3 && explosionPoint_equal; ++i)
        explosionPoint_equal = (explosionPoint[i] == obj.explosionPoint[i]);

    // Compare the planePoint arrays.
    bool planePoint_equal = true;
    for(int i = 0; i < 3 && planePoint_equal; ++i)
        planePoint_equal = (planePoint[i] == obj.planePoint[i]);

    // Compare the planeNorm arrays.
    bool planeNorm_equal = true;
    for(int i = 0; i < 3 && planeNorm_equal; ++i)
        planeNorm_equal = (planeNorm[i] == obj.planeNorm[i]);

    // Compare the cylinderPoint1 arrays.
    bool cylinderPoint1_equal = true;
    for(int i = 0; i < 3 && cylinderPoint1_equal; ++i)
        cylinderPoint1_equal = (cylinderPoint1[i] == obj.cylinderPoint1[i]);

    // Compare the cylinderPoint2 arrays.
    bool cylinderPoint2_equal = true;
    for(int i = 0; i < 3 && cylinderPoint2_equal; ++i)
        cylinderPoint2_equal = (cylinderPoint2[i] == obj.cylinderPoint2[i]);

    // Create the return value
    return ((explosionType == obj.explosionType) &&
            explosionPoint_equal &&
            planePoint_equal &&
            planeNorm_equal &&
            cylinderPoint1_equal &&
            cylinderPoint2_equal &&
            (materialExplosionFactor == obj.materialExplosionFactor) &&
            (material == obj.material) &&
            (cylinderRadius == obj.cylinderRadius) &&
            (explodeMaterialCells == obj.explodeMaterialCells) &&
            (cellExplosionFactor == obj.cellExplosionFactor) &&
            (explosionPattern == obj.explosionPattern) &&
            (explodeAllCells == obj.explodeAllCells) &&
            (boundaryNames == obj.boundaryNames));
}

