Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/feature/7970_alternative_cuboid_…
Browse files Browse the repository at this point in the history
…xml_definition'
  • Loading branch information
gesnerpassos committed Oct 22, 2013
2 parents a1ca321 + 8c07b44 commit 99e3f8e
Show file tree
Hide file tree
Showing 6 changed files with 289 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ namespace Mantid
{
class Surface;
class Object;

struct CuboidCorners
{
Kernel::V3D lfb;
Kernel::V3D lft;
Kernel::V3D lbb;
Kernel::V3D rfb;
};

/**
Expand Down Expand Up @@ -79,6 +87,8 @@ namespace Mantid
std::string parseInfiniteCylinder(Poco::XML::Element* pElem, std::map<int, Surface*>& prim, int& l_id);
std::string parseCylinder(Poco::XML::Element* pElem, std::map<int, Surface*>& prim, int& l_id);
std::string parseSegmentedCylinder(Poco::XML::Element* pElem, std::map<int, Surface*>& prim, int& l_id);

CuboidCorners parseCuboid(Poco::XML::Element* pElem);
std::string parseCuboid(Poco::XML::Element* pElem, std::map<int, Surface*>& prim, int& l_id);
std::string parseInfiniteCone(Poco::XML::Element* pElem, std::map<int, Surface*>& prim, int& l_id);
std::string parseCone(Poco::XML::Element* pElem, std::map<int, Surface*>& prim, int& l_id);
Expand Down
134 changes: 106 additions & 28 deletions Code/Mantid/Framework/Geometry/src/Objects/ShapeFactory.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidKernel/Quat.h"

#include "MantidGeometry/Objects/ShapeFactory.h"
#include "MantidGeometry/Objects/Object.h"
#include "MantidGeometry/Surfaces/Quadratic.h"
Expand Down Expand Up @@ -30,6 +32,7 @@ using Poco::XML::NodeIterator;
using Poco::XML::NodeFilter;
using Poco::XML::DOMWriter;


namespace Mantid
{
namespace Geometry
Expand Down Expand Up @@ -525,6 +528,97 @@ std::string ShapeFactory::parseSegmentedCylinder(Poco::XML::Element* pElem, std:
return retAlgebraMatch.str();
}

/**
* Get the four corners of a cuboid from an XML element. The XML may consist
* of one of the two available syntaxes. We disallow a mixture of syntaxes.
*
* @param pElem :: XML 'cuboid' element from instrument definition file.
* @return The four corners of the cuboid.
*
* @throw std::invalid_argument if XML string is invalid.
*/
CuboidCorners ShapeFactory::parseCuboid(Poco::XML::Element* pElem)
{
// Users have two syntax options when defining cuboids:

// A - "Point" syntax.
Element* pElem_lfb = getOptionalShapeElement(pElem, "left-front-bottom-point");
Element* pElem_lft = getOptionalShapeElement(pElem, "left-front-top-point");
Element* pElem_lbb = getOptionalShapeElement(pElem, "left-back-bottom-point");
Element* pElem_rfb = getOptionalShapeElement(pElem, "right-front-bottom-point");

// B - "Alternate" syntax.
Element* pElem_height = getOptionalShapeElement(pElem, "height");
Element* pElem_width = getOptionalShapeElement(pElem, "width");
Element* pElem_depth = getOptionalShapeElement(pElem, "depth");
Element* pElem_centre = getOptionalShapeElement(pElem, "centre");
Element* pElem_axis = getOptionalShapeElement(pElem, "axis");

const bool usingPointSyntax = pElem_lfb && pElem_lft && pElem_lbb && pElem_rfb;
const bool usingAlternateSyntax = pElem_height && pElem_width && pElem_depth;

const bool usedPointSyntaxField = pElem_lfb || pElem_lft || pElem_lbb || pElem_rfb;
const bool usedAlternateSyntaxField = pElem_height || pElem_width || pElem_depth || pElem_centre || pElem_axis;

const std::string SYNTAX_ERROR_MSG = "XML element: <" + pElem->tagName() +
"> may contain EITHER corner points (LFB, LFT, LBB and RFB) OR " +
"height, width, depth, centre and axis values.";

CuboidCorners result;

if( usingPointSyntax && !usingAlternateSyntax )
{
if( usedAlternateSyntaxField )
throw std::invalid_argument(SYNTAX_ERROR_MSG);

result.lfb = parsePosition(pElem_lfb);
result.lft = parsePosition(pElem_lft);
result.lbb = parsePosition(pElem_lbb);
result.rfb = parsePosition(pElem_rfb);
}
else if( usingAlternateSyntax && !usingPointSyntax )
{
if( usedPointSyntaxField )
throw std::invalid_argument(SYNTAX_ERROR_MSG);

const double deltaH = getDoubleAttribute(pElem_height, "val") / 2;
const double deltaW = getDoubleAttribute(pElem_width, "val") / 2;
const double deltaD = getDoubleAttribute(pElem_depth, "val") / 2;

const V3D centre = pElem_centre ? parsePosition(pElem_centre) : V3D(0, 0, 0);

result.lfb = V3D(-deltaW,-deltaH,-deltaD);
result.lft = V3D(-deltaW, deltaH,-deltaD);
result.lbb = V3D(-deltaW,-deltaH, deltaD);
result.rfb = V3D( deltaW,-deltaH,-deltaD);

if( pElem_axis )
{
// Use a quarternion to do a rotation for us, with respect to the default
// axis. Our "Quat" implementation requires that the vectors passed to
// it be normalised.
V3D axis = parsePosition(pElem_axis);
axis.normalize();
const V3D DEFAULT_AXIS(0, 0, 1);
const Quat rotation(axis, DEFAULT_AXIS);

rotation.rotate(result.lfb);
rotation.rotate(result.lft);
rotation.rotate(result.lbb);
rotation.rotate(result.rfb);
}

result.lfb += centre;
result.lft += centre;
result.lbb += centre;
result.rfb += centre;
}
else
throw std::invalid_argument(SYNTAX_ERROR_MSG);

return result;
}

/** Parse XML 'cuboid' element
*
* @param pElem :: XML 'cuboid' element from instrument def. file
Expand All @@ -536,22 +630,14 @@ std::string ShapeFactory::parseSegmentedCylinder(Poco::XML::Element* pElem, std:
*/
std::string ShapeFactory::parseCuboid(Poco::XML::Element* pElem, std::map<int, Surface*>& prim, int& l_id)
{
Element* pElem_lfb = getShapeElement(pElem, "left-front-bottom-point");
Element* pElem_lft = getShapeElement(pElem, "left-front-top-point");
Element* pElem_lbb = getShapeElement(pElem, "left-back-bottom-point");
Element* pElem_rfb = getShapeElement(pElem, "right-front-bottom-point");

V3D lfb = parsePosition(pElem_lfb); // left front bottom
V3D lft = parsePosition(pElem_lft); // left front top
V3D lbb = parsePosition(pElem_lbb); // left back bottom
V3D rfb = parsePosition(pElem_rfb); // right front bottom
auto corners = parseCuboid(pElem);

V3D pointTowardBack = lbb-lfb;
V3D pointTowardBack = corners.lbb-corners.lfb;
pointTowardBack.normalize();

// add front plane cutoff
Plane* pPlaneFrontCutoff = new Plane();
pPlaneFrontCutoff->setPlane(lfb, pointTowardBack);
pPlaneFrontCutoff->setPlane(corners.lfb, pointTowardBack);
prim[l_id] = pPlaneFrontCutoff;

std::stringstream retAlgebraMatch;
Expand All @@ -560,43 +646,43 @@ std::string ShapeFactory::parseCuboid(Poco::XML::Element* pElem, std::map<int, S

// add back plane cutoff
Plane* pPlaneBackCutoff = new Plane();
pPlaneBackCutoff->setPlane(lbb, pointTowardBack);
pPlaneBackCutoff->setPlane(corners.lbb, pointTowardBack);
prim[l_id] = pPlaneBackCutoff;
retAlgebraMatch << "-" << l_id << " ";
l_id++;


V3D pointTowardRight = rfb-lfb;
V3D pointTowardRight = corners.rfb-corners.lfb;
pointTowardRight.normalize();

// add left plane cutoff
Plane* pPlaneLeftCutoff = new Plane();
pPlaneLeftCutoff->setPlane(lfb, pointTowardRight);
pPlaneLeftCutoff->setPlane(corners.lfb, pointTowardRight);
prim[l_id] = pPlaneLeftCutoff;
retAlgebraMatch << "" << l_id << " ";
l_id++;

// add right plane cutoff
Plane* pPlaneRightCutoff = new Plane();
pPlaneRightCutoff->setPlane(rfb, pointTowardRight);
pPlaneRightCutoff->setPlane(corners.rfb, pointTowardRight);
prim[l_id] = pPlaneRightCutoff;
retAlgebraMatch << "-" << l_id << " ";
l_id++;


V3D pointTowardTop = lft-lfb;
V3D pointTowardTop = corners.lft-corners.lfb;
pointTowardTop.normalize();

// add bottom plane cutoff
Plane* pPlaneBottomCutoff = new Plane();
pPlaneBottomCutoff->setPlane(lfb, pointTowardTop);
pPlaneBottomCutoff->setPlane(corners.lfb, pointTowardTop);
prim[l_id] = pPlaneBottomCutoff;
retAlgebraMatch << "" << l_id << " ";
l_id++;

// add top plane cutoff
Plane* pPlaneTopCutoff = new Plane();
pPlaneTopCutoff->setPlane(lft, pointTowardTop);
pPlaneTopCutoff->setPlane(corners.lft, pointTowardTop);
prim[l_id] = pPlaneTopCutoff;
retAlgebraMatch << "-" << l_id << ")";
l_id++;
Expand Down Expand Up @@ -1050,16 +1136,8 @@ void ShapeFactory::createGeometryHandler(Poco::XML::Element* pElem,boost::shared
{
boost::shared_ptr<GeometryHandler> handler(new GluGeometryHandler(Obj));
Obj->setGeometryHandler(handler);
Element* pElem_lfb = getShapeElement(pElem, "left-front-bottom-point");
Element* pElem_lft = getShapeElement(pElem, "left-front-top-point");
Element* pElem_lbb = getShapeElement(pElem, "left-back-bottom-point");
Element* pElem_rfb = getShapeElement(pElem, "right-front-bottom-point");

V3D lfb = parsePosition(pElem_lfb); // left front bottom
V3D lft = parsePosition(pElem_lft); // left front top
V3D lbb = parsePosition(pElem_lbb); // left back bottom
V3D rfb = parsePosition(pElem_rfb); // right front bottom
((GluGeometryHandler*)(handler.get()))->setCuboid(lfb,lft,lbb,rfb);
auto corners = parseCuboid(pElem);
((GluGeometryHandler*)(handler.get()))->setCuboid(corners.lfb,corners.lft,corners.lbb,corners.rfb);
}
else if(pElem->tagName()=="sphere")
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,26 @@ class InstrumentDefinitionParserTest : public CxxTest::TestSuite
TS_ASSERT( !ptrDet1001->isValid(V3D(0.0,-0.01,0.05)+ptrDet1001->getPos()) );
TS_ASSERT( !ptrDet1001->isValid(V3D(0.0,-0.01,-0.05)+ptrDet1001->getPos()) );

// test for "cuboid-alternate-test".
boost::shared_ptr<const IDetector> ptrDet18 = i->getDetector(18);

TS_ASSERT( ptrDet18->isValid(V3D( 1.05, 1.10, 1.20)+ptrDet18->getPos()) );
TS_ASSERT( ptrDet18->isValid(V3D( 1.05, 1.10, 0.80)+ptrDet18->getPos()) );
TS_ASSERT( ptrDet18->isValid(V3D( 1.05, 0.90, 1.20)+ptrDet18->getPos()) );
TS_ASSERT( ptrDet18->isValid(V3D( 1.05, 0.90, 0.80)+ptrDet18->getPos()) );
TS_ASSERT( ptrDet18->isValid(V3D( 0.95, 1.10, 1.20)+ptrDet18->getPos()) );
TS_ASSERT( ptrDet18->isValid(V3D( 0.95, 1.10, 0.80)+ptrDet18->getPos()) );
TS_ASSERT( ptrDet18->isValid(V3D( 0.95, 0.90, 1.20)+ptrDet18->getPos()) );
TS_ASSERT( ptrDet18->isValid(V3D( 0.95, 0.90, 0.80)+ptrDet18->getPos()) );

TS_ASSERT( !ptrDet18->isValid(V3D( 1.06, 1.11, 1.21)+ptrDet18->getPos()) );
TS_ASSERT( !ptrDet18->isValid(V3D( 1.06, 1.11, 0.79)+ptrDet18->getPos()) );
TS_ASSERT( !ptrDet18->isValid(V3D( 1.06, 0.89, 1.21)+ptrDet18->getPos()) );
TS_ASSERT( !ptrDet18->isValid(V3D( 1.06, 0.89, 0.79)+ptrDet18->getPos()) );
TS_ASSERT( !ptrDet18->isValid(V3D( 0.94, 1.11, 1.21)+ptrDet18->getPos()) );
TS_ASSERT( !ptrDet18->isValid(V3D( 0.94, 1.11, 0.79)+ptrDet18->getPos()) );
TS_ASSERT( !ptrDet18->isValid(V3D( 0.94, 0.89, 1.21)+ptrDet18->getPos()) );
TS_ASSERT( !ptrDet18->isValid(V3D( 0.94, 0.89, 0.79)+ptrDet18->getPos()) );

// test for "infinite-cylinder-test".
boost::shared_ptr<const IDetector> ptrDet12 = i->getDetector(12);
Expand Down
97 changes: 97 additions & 0 deletions Code/Mantid/Framework/Geometry/test/ShapeFactoryTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,103 @@ class ShapeFactoryTest : public CxxTest::TestSuite
TS_ASSERT( shape_sptr->isValid(V3D(0.0,0.09, 0.00001)) );
}

void testAlternateCuboid()
{
std::string xmlShape;
xmlShape += "<cuboid id=\"some-shape\">";
xmlShape += "<height val=\"0.2\" />";
xmlShape += "<width val=\"0.1\" />";
xmlShape += "<depth val=\"0.4\" />";
xmlShape += "<centre x=\"1.0\" y=\"1.0\" z=\"1.0\" />";
xmlShape += "<axis x=\"1\" y=\"0\" z=\"0\" />"; // Note non-default axis.
xmlShape += "</cuboid>";
xmlShape += "<algebra val=\"some-shape\" />";

auto cuboid = getObject(xmlShape);

TS_ASSERT( cuboid->isValid(V3D(1.20, 1.10, 0.95)) );
TS_ASSERT( cuboid->isValid(V3D(0.80, 1.10, 0.95)) );
TS_ASSERT( cuboid->isValid(V3D(1.20, 0.90, 0.95)) );
TS_ASSERT( cuboid->isValid(V3D(0.80, 0.90, 0.95)) );
TS_ASSERT( cuboid->isValid(V3D(1.20, 1.10, 1.05)) );
TS_ASSERT( cuboid->isValid(V3D(0.80, 1.10, 1.05)) );
TS_ASSERT( cuboid->isValid(V3D(1.20, 0.90, 1.05)) );
TS_ASSERT( cuboid->isValid(V3D(0.80, 0.90, 1.05)) );

TS_ASSERT( !cuboid->isValid(V3D(1.21, 1.11, 0.94)) );
TS_ASSERT( !cuboid->isValid(V3D(0.79, 1.11, 0.94)) );
TS_ASSERT( !cuboid->isValid(V3D(1.21, 0.89, 0.94)) );
TS_ASSERT( !cuboid->isValid(V3D(0.79, 0.89, 0.94)) );
TS_ASSERT( !cuboid->isValid(V3D(1.21, 1.11, 1.06)) );
TS_ASSERT( !cuboid->isValid(V3D(0.79, 1.11, 1.06)) );
TS_ASSERT( !cuboid->isValid(V3D(1.21, 0.89, 1.06)) );
TS_ASSERT( !cuboid->isValid(V3D(0.79, 0.89, 1.06)) );
}

void testAlternateCuboidDefaultAxis()
{
std::string xmlShape;
xmlShape += "<cuboid id=\"some-shape\">";
xmlShape += "<height val=\"0.2\" />";
xmlShape += "<width val=\"0.1\" />";
xmlShape += "<depth val=\"0.4\" />";
xmlShape += "<centre x=\"1.0\" y=\"1.0\" z=\"1.0\" />";
xmlShape += "</cuboid>";
xmlShape += "<algebra val=\"some-shape\" />";

auto cuboid = getObject(xmlShape);

TS_ASSERT( cuboid->isValid(V3D( 1.05, 1.10, 1.20)) );
TS_ASSERT( cuboid->isValid(V3D( 1.05, 1.10, 0.80)) );
TS_ASSERT( cuboid->isValid(V3D( 1.05, 0.90, 1.20)) );
TS_ASSERT( cuboid->isValid(V3D( 1.05, 0.90, 0.80)) );
TS_ASSERT( cuboid->isValid(V3D( 0.95, 1.10, 1.20)) );
TS_ASSERT( cuboid->isValid(V3D( 0.95, 1.10, 0.80)) );
TS_ASSERT( cuboid->isValid(V3D( 0.95, 0.90, 1.20)) );
TS_ASSERT( cuboid->isValid(V3D( 0.95, 0.90, 0.80)) );

TS_ASSERT( !cuboid->isValid(V3D( 1.06, 1.11, 1.21)) );
TS_ASSERT( !cuboid->isValid(V3D( 1.06, 1.11, 0.79)) );
TS_ASSERT( !cuboid->isValid(V3D( 1.06, 0.89, 1.21)) );
TS_ASSERT( !cuboid->isValid(V3D( 1.06, 0.89, 0.79)) );
TS_ASSERT( !cuboid->isValid(V3D( 0.94, 1.11, 1.21)) );
TS_ASSERT( !cuboid->isValid(V3D( 0.94, 1.11, 0.79)) );
TS_ASSERT( !cuboid->isValid(V3D( 0.94, 0.89, 1.21)) );
TS_ASSERT( !cuboid->isValid(V3D( 0.94, 0.89, 0.79)) );
}

void testAlternateCuboidDefaultCentre()
{
std::string xmlShape;
xmlShape += "<cuboid id=\"some-shape\">";
xmlShape += "<height val=\"0.2\" />";
xmlShape += "<width val=\"0.1\" />";
xmlShape += "<depth val=\"0.4\" />";
xmlShape += "<axis x=\"0\" y=\"0\" z=\"1\" />";
xmlShape += "</cuboid>";
xmlShape += "<algebra val=\"some-shape\" />";

auto cuboid = getObject(xmlShape);

TS_ASSERT( cuboid->isValid(V3D( 0.05, 0.10, 0.20)) );
TS_ASSERT( cuboid->isValid(V3D( 0.05, 0.10,-0.20)) );
TS_ASSERT( cuboid->isValid(V3D( 0.05,-0.10, 0.20)) );
TS_ASSERT( cuboid->isValid(V3D( 0.05,-0.10,-0.20)) );
TS_ASSERT( cuboid->isValid(V3D(-0.05, 0.10, 0.20)) );
TS_ASSERT( cuboid->isValid(V3D(-0.05, 0.10,-0.20)) );
TS_ASSERT( cuboid->isValid(V3D(-0.05,-0.10, 0.20)) );
TS_ASSERT( cuboid->isValid(V3D(-0.05,-0.10,-0.20)) );

TS_ASSERT( !cuboid->isValid(V3D( 0.06, 0.11, 0.21)) );
TS_ASSERT( !cuboid->isValid(V3D( 0.06, 0.11,-0.21)) );
TS_ASSERT( !cuboid->isValid(V3D( 0.06,-0.11, 0.21)) );
TS_ASSERT( !cuboid->isValid(V3D( 0.06,-0.11,-0.21)) );
TS_ASSERT( !cuboid->isValid(V3D(-0.06, 0.11, 0.21)) );
TS_ASSERT( !cuboid->isValid(V3D(-0.06, 0.11,-0.21)) );
TS_ASSERT( !cuboid->isValid(V3D(-0.06,-0.11, 0.21)) );
TS_ASSERT( !cuboid->isValid(V3D(-0.06,-0.11,-0.21)) );
}

void testRelayShapeXML()
{
//Create a cuboid.
Expand Down

0 comments on commit 99e3f8e

Please sign in to comment.