Skip to content

Commit

Permalink
Add Transform<FromEndpoint, ToEndpoint>
Browse files Browse the repository at this point in the history
  • Loading branch information
r-owen committed Feb 28, 2017
1 parent 7654934 commit d7daa91
Show file tree
Hide file tree
Showing 6 changed files with 559 additions and 0 deletions.
139 changes: 139 additions & 0 deletions include/lsst/afw/geom/Transform.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// -*- lsst-c++ -*-
/*
* LSST Data Management System
* Copyright 2008-2017 LSST Corporation.
*
* This product includes software developed by the
* LSST Project (http://www.lsst.org/).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the LSST License Statement and
* the GNU General Public License along with this program. If not,
* see <http://www.lsstcorp.org/LegalNotices/>.
*/

#ifndef LSST_AFW_GEOM_TRANSFORM_H
#define LSST_AFW_GEOM_TRANSFORM_H

#include <memory>
#include <vector>

#include "astshim.h"
#include "ndarray.h"

#include "lsst/afw/geom/Endpoint.h"

namespace lsst {
namespace afw {
namespace geom {

/**
Transform LSST spatial data, such as Point2D and SpherePoint, using an AST transform.
This class contains two Endpoints, to specify the "from" and "to" LSST data type,
and an astshim::FrameSet or astshim::Mapping to specify the transformation.
The endpoints convert the data between the LSST Form (e.g. Point2D) and the form used by astshim.
@note You gain some safety by constructing a Transform from an astshim::FrameSet,
since the base and current frames in the FrameSet can be checked against by the appropriate endpoint.
@note "In place" versions of `tranForward` and `tranInverse` are not available
because data must be copied when converting from LSST data types to the type used by astshim,
so it didn't seem worth the bother.
*/
template <typename FromEndpoint, typename ToEndpoint>
class Transform {
public:
using FromArray = typename FromEndpoint::Array;
using FromPoint = typename FromEndpoint::Point;
using ToArray = typename ToEndpoint::Array;
using ToPoint = typename ToEndpoint::Point;

/**
Construct a Transform from a deep copy of an ast::Mapping
The internal FrameSet consists of a frame constructed by each endpoint
connected by the mapping.
@param[in] mapping ast::Mapping describing the desired transformation
@param[in] simplify Simplify the mapping?
*/
explicit Transform(ast::Mapping const &mapping, bool simplify=true);

/**
Constructor a Transform from a deep copy of a FrameSet.
The result transforms from the "base" frame to the "current" frame.
The "from" endpoint is used to normalize the "base" frame
and the "to" endpoint is used to normalize the "current" frame.
This is pickier than the constructor that takes an ast::Mapping in that:
- SphereEndpoint must be associated with an ast::SkyFrame and the SkyFrame axes
are swapped if necessary to the standard order: longitude, latitude.
- Point2Endpoint must be associated with an ast::Frame (not a subclass),
because Frame is the only kind of Frame that is sure to be Cartesian.
@param[in] frameSet ast::FrameSet describing the desired transformation in the usual way:
from "base" frame to "current" frame
@param[in] simplify Simplify the frame set? Note that this simplifies each mapping
in the frame set without removing any frames.
*/
explicit Transform(ast::FrameSet const & frameSet, bool simplify=true);

~Transform(){};

/**
Get the "from" endpoint
*/
FromEndpoint getFromEndpoint() const { return _fromEndpoint; }

/**
Get the contained frameset
*/
std::shared_ptr<const ast::FrameSet> getFrameSet() const { return _frameSet; }

/**
Get the "to" endpoint
*/
ToEndpoint getToEndpoint() const { return _toEndpoint; }

/**
Transform one point in the forward direction ("from" to "to")
*/
ToPoint tranForward(FromPoint const & point) const;

/**
Transform an array of points in the forward direction ("from" to "to")
*/
ToArray tranForward(FromArray const &array) const;

/**
Transform one point in the inverse direction ("to" to "from")
*/
FromPoint tranInverse(ToPoint const & point) const;

/**
Transform an array of points in the inverse direction ("to" to "from")
*/
FromArray tranInverse(ToArray const & array) const;

private:
FromEndpoint const _fromEndpoint;
std::shared_ptr<const ast::FrameSet> _frameSet;
ToEndpoint const _toEndpoint;
};

} // geom
} // afw
} // lsst

#endif
1 change: 1 addition & 0 deletions python/lsst/afw/geom/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ scripts.BasicSConscript.pybind11([
'linearTransform',
'xYTransform',
"endpoint",
"transform",
])
1 change: 1 addition & 0 deletions python/lsst/afw/geom/geomLib.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@
from .linearTransform import *
from ._spanSet import *
from ._endpoint import *
from ._transform import *
105 changes: 105 additions & 0 deletions python/lsst/afw/geom/transform.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* LSST Data Management System
* See COPYRIGHT file at the top of the source tree.
*
* This product includes software developed by the
* LSST Project (http://www.lsst.org/).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the LSST License Statement and
* the GNU General Public License along with this program. If not,
* see <http://www.lsstcorp.org/LegalNotices/>.
*/
#include <memory>

#include "astshim.h"
#include "pybind11/pybind11.h"
#include "pybind11/stl.h"
#include "numpy/arrayobject.h"
#include "ndarray/pybind11.h"

#include "lsst/utils/pybind11.h"
#include "lsst/afw/geom/Endpoint.h"
#include "lsst/afw/geom/Point.h"
#include "lsst/afw/geom/SpherePoint.h"
#include "lsst/afw/geom/Transform.h"

namespace py = pybind11;
using namespace py::literals;

namespace lsst {
namespace afw {
namespace geom {

namespace {

// Declare Transform<FromEndpoint, ToEndpoint>
template <typename FromEndpoint, typename ToEndpoint>
void declareTransform(py::module& mod, std::string const & fromName, std::string const & toName) {
using Class = Transform<FromEndpoint, ToEndpoint>;
using ToPoint = typename ToEndpoint::Point;
using ToArray = typename ToEndpoint::Array;
using FromPoint = typename FromEndpoint::Point;
using FromArray = typename FromEndpoint::Array;

py::class_<Class, std::shared_ptr<Class>> cls(mod, ("TransformFrom" + fromName + "To" + toName).c_str());

cls.def(py::init<ast::Mapping const &, bool>(), "mapping"_a, "simplify"_a=true);
cls.def(py::init<ast::FrameSet const &, bool>(), "frameSet"_a, "simplify"_a=true);

cls.def("getFromEndpoint", &Class::getFromEndpoint);
cls.def("getFrameSet", &Class::getFrameSet);
cls.def("getToEndpoint", &Class::getToEndpoint);

cls.def("tranForward", (ToArray (Class::*)(FromArray const &) const) &Class::tranForward, "array"_a);
cls.def("tranForward", (ToPoint (Class::*)(FromPoint const &) const) &Class::tranForward, "point"_a);
cls.def("tranInverse", (FromArray (Class::*)(ToArray const &) const) &Class::tranInverse, "array"_a);
cls.def("tranInverse", (FromPoint (Class::*)(ToPoint const &) const) &Class::tranInverse, "point"_a);
}

} // <anonymous>

PYBIND11_PLUGIN(_transform) {
// TODO uncomment these import(s) during the cleanup pass
// py::module::import("lsst.afw.geom.endpoint");

py::module mod("_transform");

// Need to import numpy for ndarray and eigen conversions
if (_import_array() < 0) {
PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import");
return nullptr;
}

declareTransform<GenericEndpoint, GenericEndpoint>(mod, "Generic", "Generic");
declareTransform<GenericEndpoint, Point2Endpoint>(mod, "Generic", "Point2");
declareTransform<GenericEndpoint, Point3Endpoint>(mod, "Generic", "Point3");
declareTransform<GenericEndpoint, SpherePointEndpoint>(mod, "Generic", "SpherePoint");
declareTransform<Point2Endpoint, GenericEndpoint>(mod, "Point2", "Generic");
declareTransform<Point2Endpoint, Point2Endpoint>(mod, "Point2", "Point2");
declareTransform<Point2Endpoint, Point3Endpoint>(mod, "Point2", "Point3");
declareTransform<Point2Endpoint, SpherePointEndpoint>(mod, "Point2", "SpherePoint");
declareTransform<Point3Endpoint, GenericEndpoint>(mod, "Point3", "Generic");
declareTransform<Point3Endpoint, Point2Endpoint>(mod, "Point3", "Point2");
declareTransform<Point3Endpoint, Point3Endpoint>(mod, "Point3", "Point3");
declareTransform<Point3Endpoint, SpherePointEndpoint>(mod, "Point3", "SpherePoint");
declareTransform<SpherePointEndpoint, GenericEndpoint>(mod, "SpherePoint", "Generic");
declareTransform<SpherePointEndpoint, Point2Endpoint>(mod, "SpherePoint", "Point2");
declareTransform<SpherePointEndpoint, Point3Endpoint>(mod, "SpherePoint", "Point3");
declareTransform<SpherePointEndpoint, SpherePointEndpoint>(mod, "SpherePoint", "SpherePoint");

return mod.ptr();
}

} // geom
} // afw
} // lsst
126 changes: 126 additions & 0 deletions src/geom/Transform.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* LSST Data Management System
* Copyright 2008-2017 LSST Corporation.
*
* This product includes software developed by the
* LSST Project (http://www.lsst.org/).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the LSST License Statement and
* the GNU General Public License along with this program. If not,
* see <http://www.lsstcorp.org/LegalNotices/>.
*/

#include <memory>
#include <vector>

#include "astshim.h"
#include "lsst/afw/geom/Endpoint.h"
#include "lsst/afw/geom/Point.h"
#include "lsst/afw/geom/SpherePoint.h"
#include "lsst/afw/geom/Transform.h"

namespace lsst {
namespace afw {
namespace geom {

template <typename FromEndpoint, typename ToEndpoint>
Transform<FromEndpoint, ToEndpoint>::Transform(ast::Mapping const &mapping, bool simplify)
: _fromEndpoint(mapping.getNin()), _frameSet(), _toEndpoint(mapping.getNout()) {
auto fromFrame = _fromEndpoint.makeFrame();
auto toFrame = _toEndpoint.makeFrame();
if (simplify) {
_frameSet = std::make_shared<ast::FrameSet>(*fromFrame, *(mapping.simplify()), *toFrame);
} else {
_frameSet = std::make_shared<ast::FrameSet>(*fromFrame, mapping, *toFrame);
}
}

template <typename FromEndpoint, typename ToEndpoint>
Transform<FromEndpoint, ToEndpoint>::Transform(ast::FrameSet const &frameSet, bool simplify)
: _fromEndpoint(frameSet.getNin()), _frameSet(), _toEndpoint(frameSet.getNout()) {
// Normalize the base and current frame in a way that affects its behavior as a mapping.
// To do this one must set the current frame to the frame to be normalized
// and normalize the frame set as a frame (i.e. normalize the frame "in situ").
// The obvious alternative of normalizing a shallow copy of the frame does not work;
// the frame is altered but not the associated mapping!
auto frameSetCopy = simplify ? std::dynamic_pointer_cast<ast::FrameSet>(frameSet.simplify())
: frameSet.copy();

// Normalize the current frame by normalizing the frameset as a frame
_toEndpoint.normalizeFrame(frameSetCopy);

// Normalize the base frame by temporarily making it the current frame,
// normalizing the frameset as a frame, then making it the base frame again
const int currIndex = frameSetCopy->getCurrent();
const int baseIndex = frameSetCopy->getBase();
frameSetCopy->setCurrent(baseIndex);
_fromEndpoint.normalizeFrame(frameSetCopy);
frameSetCopy->setBase(baseIndex);
frameSetCopy->setCurrent(currIndex);
// assign after modifying the frame set, since _frameSet points to a const frame set
_frameSet = frameSetCopy;
}

template <typename FromEndpoint, typename ToEndpoint>
typename ToEndpoint::Point Transform<FromEndpoint, ToEndpoint>::tranForward(
typename FromEndpoint::Point const &point) const {
auto const rawFromData = _fromEndpoint.dataFromPoint(point);
auto rawToData = _frameSet->tranForward(rawFromData);
return _toEndpoint.pointFromData(rawToData);
}

template <typename FromEndpoint, typename ToEndpoint>
typename ToEndpoint::Array Transform<FromEndpoint, ToEndpoint>::tranForward(
typename FromEndpoint::Array const &array) const {
auto const rawFromData = _fromEndpoint.dataFromArray(array);
auto rawToData = _frameSet->tranForward(rawFromData);
return _toEndpoint.arrayFromData(rawToData);
}

template <typename FromEndpoint, typename ToEndpoint>
typename FromEndpoint::Point Transform<FromEndpoint, ToEndpoint>::tranInverse(
typename ToEndpoint::Point const &point) const {
auto const rawFromData = _toEndpoint.dataFromPoint(point);
auto rawToData = _frameSet->tranInverse(rawFromData);
return _fromEndpoint.pointFromData(rawToData);
}

template <typename FromEndpoint, typename ToEndpoint>
typename FromEndpoint::Array Transform<FromEndpoint, ToEndpoint>::tranInverse(
typename ToEndpoint::Array const &array) const {
auto const rawFromData = _toEndpoint.dataFromArray(array);
auto rawToData = _frameSet->tranInverse(rawFromData);
return _fromEndpoint.arrayFromData(rawToData);
}

// explicit instantiations
template class Transform<GenericEndpoint, GenericEndpoint>;
template class Transform<GenericEndpoint, Point2Endpoint>;
template class Transform<GenericEndpoint, Point3Endpoint>;
template class Transform<GenericEndpoint, SpherePointEndpoint>;
template class Transform<Point2Endpoint, GenericEndpoint>;
template class Transform<Point2Endpoint, Point2Endpoint>;
template class Transform<Point2Endpoint, Point3Endpoint>;
template class Transform<Point2Endpoint, SpherePointEndpoint>;
template class Transform<Point3Endpoint, GenericEndpoint>;
template class Transform<Point3Endpoint, Point2Endpoint>;
template class Transform<Point3Endpoint, Point3Endpoint>;
template class Transform<Point3Endpoint, SpherePointEndpoint>;
template class Transform<SpherePointEndpoint, GenericEndpoint>;
template class Transform<SpherePointEndpoint, Point2Endpoint>;
template class Transform<SpherePointEndpoint, Point3Endpoint>;
template class Transform<SpherePointEndpoint, SpherePointEndpoint>;

} // geom
} // afw
} // lsst

0 comments on commit d7daa91

Please sign in to comment.