python libclang, not finding template definition

245 views Asked by At

I have a header file I am trying to parse using python and libclang.

I made the following method:

def FindDeclaration(path, function_name):
    idx = clang.cindex.Index.create()
    tu = idx.parse(path)
    location = None
    for f in tu.cursor.walk_preorder():
            location = f.location
            print(f.spelling)

 def main():
    FindDeclaration("path to file", "function name")

And called it on a file:

#pragma once

/** @cond */
#include <iostream>
#include <queue>
#include <vector>

#include "Eigen/Dense"
/** @endcond */

#include "Helpers/FlotingPointArithmetic.hpp"

/**
 * @brief Shorthand to shorten code.
 *
 * @tparam S Scalar.
 */
template <typename S>
using Vec = Eigen::Matrix<S, 3, 1>;
/**
 * @brief Test collision of a line with a triangle.
 *
 * @param origin Start of the line.
 * @param ray Direction of the line.
 * @param triangle Triangle against which to test.
 * @return float Signed distance along the line at which the intersection happens.
 *  Infinity if no such value exists.
 */
float TriangleLineIntersection(
    const Eigen::Vector3d& origin,
    const Eigen::Vector3d& ray,
    const std::vector<Eigen::Vector3d>& triangle);
/**
 * @brief Calculate the intersection of 2 lines.
 *
 * This calculates the intersection of 2 lines, $P_1 + a V_1$ and $P_2 + b V_2$
 * in 3D if it exists.
 *
 * Proof:
 * $     P_1 + a V_1 = P_2 + b V_2$
 * $\iff a V_1 = (P_2 - P_1) + b V_2$
 * $\iff a V_1 \times V_2 = (P_2 - P_1) \times V_2$
 * $\iff a = \frac{((P_2 - P_1) \times V_2) \cdot (n)} {(V_1 \times V_2) \cdot n}$
 *
 * With $n = \frac{(V_1 \times V_2)} {|V_1 \times V_2|}$
 *
 * A solution exists if and only if the above is well deifned (no divisions by 0).
 *
 * The method will return 0 if the 2 origins are the same, and infinity if the 2 lines
 * are either parallel or not coplanar.
 *
 * @param origin1 Origin of the first line
 * @param ray1 Direction of the first line
 * @param origin2 Origin of the second line
 * @param ray2 Direction of the second line
 * @return double Distance in terms of `ray1` from `origin1` to the point of intersection.
 * i.e the intersection vertex is at `origin1 + return_value * ray1`
 */
// Taken from here: http://mathforum.org/library/drmath/view/62814.html
// (note there's a small error, the absolute value deletes the sign, I corrected it.)
double LineLineIntersection(
    const Eigen::Vector3d& origin1,
    const Eigen::Vector3d& ray1,
    const Eigen::Vector3d& origin2,
    const Eigen::Vector3d& ray2);
/**
 * @brief Test if a point is inside of a triangle. (The first 3 values of the array will
 * be used, all values threafter will be ignored).
 *
 * @param triangle The triangle against which to test.
 * @param point The point being tested.
 * @return true The point is inside the triangle.
 * @return false The point is outside the triangle.
 */
bool TestPointInTriangle(
    const std::vector<Eigen::Vector3d>& triangle,
    const Eigen::Vector3d& point);
/**
 * @brief Calculate the barycentric coordinates of a triangle.
 *
 * @param p Point to test.
 * @param a First point in the triangle.
 * @param b Second point in the triangle.
 * @param c Third point in the triangle.
 * @return std::tuple<float, float, float> u, v, w tuple.
 */
std::tuple<float, float, float> Barycentric(
    const Eigen::Vector3f& p,
    const Eigen::Vector3f& a,
    const Eigen::Vector3f& b,
    const Eigen::Vector3f& c);
/**
 * @brief Unproject a screen value onto world coordinates. For values that should be on
 * the screen plane in 3D, the z coordinate should be equal to the near plane of the
 * camera.
 *
 * @param screen 3 value position of screen coordinate (z is depth)
 * @param view_proj View projection matrix of the camera.
 * @return Eigen::Vector3d Unprojected coordinate.
 */
Eigen::Vector3d Unproject(
    const Eigen::Vector3d& screen,
    const Eigen::Matrix4d& view_proj);
/**
 * @brief Test that a point is in the segment described by $s_1$ and $s_2$.
 *
 * Segment inclusion means the point is both in the line and in between the 2 points.
 * If @include_boundary is true, the method returns true if $s_1 = p$ or $s_2 = p$, if
 * false it returns false in those cases.
 *
 * @param s1 First point in the segment.
 * @param s2 Second point in the segment.
 * @param p  Point to test.
 * @param include_boundary Whether to include the boundary points.
 * @return true The point is in the segment.
 * @return false The point is not in the segment.
 */
bool TestPointInSegment(
    const Eigen::Vector3d& s1,
    const Eigen::Vector3d& s2,
    const Eigen::Vector3d& p,
    bool include_boundary = true);
/**
 * @brief Get the signed angle between 2 unit directions. This function assumes all
 * preconditions are met. It should be given 2 unit directions and one of the 2 normals
 * defined by that plane. Other inputs are undefined behahoviour .
 *
 * @param d1 First unit direction.
 * @param d2 Second unit direction.
 * @param normal Normal to the plane.
 * @return double Signed angle from d1 to d2.
 */
double SignedAngle(
    const Eigen::Vector3d& d1,
    const Eigen::Vector3d& d2,
    const Eigen::Vector3d& normal);
/**
 * @brief Implementation of Dijkstra's shortest path algorithm. (Doesn't handle forests).
 *
 * @tparam T Type encapsulating a node in the graph.
 * @param node_list An array of nodes (all nodes should be present).
 * @param GetNeighbours Function returning an std::vector of the neighbours of a node.
 * @param GetId Function returning the id (index in the node_list) of a node.
 * @param GetDistance Function returning the weight of the edge connecting 2 nodes.
 * @param start The root node from which to start Dikstra's
 * @return std::pair<std::vector<uint>, std::vector<double>> The first value will be the
 *  ancestry table of the tree. i.e the value at return1[i] is the parent of node i.
 *  The second value will be the total distance of a node. i.e the value at return1[i] is
 *  the total distance from start onto the node i.
 */
template <typename T>
std::pair<std::vector<uint>, std::vector<double>> Dijkstra(
    const std::vector<T>& node_list,
    std::vector<T> (*GetNeighbours)(const T& t),
    uint (*GetId)(const T& t),
    double (*GetDistance)(const T& t1, const T& t2),
    uint start)
{
    std::vector<double> node_distance_map(node_list.size(), std::numeric_limits<double>::max());
    std::vector<uint> node_parent_map(node_list.size());
    std::vector<bool> node_visited_map(node_list.size(), false);

    typedef std::pair<double, uint> NodeInfo;
    std::priority_queue<NodeInfo, std::vector<NodeInfo>, std::greater<NodeInfo>> queue;

    node_distance_map[start] = 0;
    node_parent_map[start] = start;
    queue.push({0, start});

    uint current_node_index = start;
    while(!queue.empty())
    {
        auto[current_distance, current_node_index] = queue.top();
        queue.pop();
        auto current_node = node_list[current_node_index];

        node_visited_map[current_node_index] = true;

        auto neighbours = GetNeighbours(current_node);
        assert(neighbours.size() > 0);
        double shortest_distance = std::numeric_limits<double>::max();
        auto& shortest_neighbour = neighbours[0];
        for(auto& neighbour : neighbours)
        {
            uint neighbour_id = GetId(neighbour);
            // Skip any node that has already been visited
            if(node_visited_map[neighbour_id]) continue;
            double distance = GetDistance(current_node, neighbour);
            double total_distance = distance + current_distance;

            // Overwrite prior distances if the current distance is shorter
            if(total_distance < node_distance_map[neighbour_id])
            {
                node_parent_map[neighbour_id] = current_node_index;
                node_distance_map[neighbour_id] = total_distance;
                queue.push({total_distance, neighbour_id});
            }
        }
    }

    return {node_parent_map, node_distance_map};
}
/** ss
 * @brief Express a point given in the standard basis into an arbitrary orthonormal basis.
 *
 * @param e1 First orthonormal basis vector.
 * @param e2 Second orthonormal basis vector.
 * @param e3 Third orthonormal basis vector.
 * @param origin Origin of the basis.
 * @param point Point to re-express.
 * @return Eigen::Vector3d Coordinates of the point in the given basis.
 */
Eigen::Vector3d ExpressInBasis(
    const Eigen::Vector3d& e1,
    const Eigen::Vector3d& e2,
    const Eigen::Vector3d& e3,
    const Eigen::Vector3d& origin,
    const Eigen::Vector3d& point);
/**
 * @brief Unproject a point in screen coordinates into world coordinates.
 *
 * @tparam T Scalar type.
 * @param screen Point expressed in screen coordinates (including depth).
 * @param view_proj View Projection matrix.
 * @return Eigen::Matrix<S, 3, 1> Unprojected point.
 */
template <typename S>
Eigen::Matrix<S, 3, 1> Unproject(
    const Eigen::Matrix<S, 3, 1>& screen,
    const Eigen::Matrix<S, 4, 4>& view_proj)
{
    Eigen::Matrix<S, 4, 1> v =
          view_proj.inverse()
        * Eigen::Matrix<S, 4, 1>(screen[0], screen[1], screen[2], static_cast<S>(1));

    return Eigen::Matrix<S, 3, 1>{v[0], v[1], v[2]} * (static_cast<S>(1) / v[3]);
}
/**
 * @brief Compute the intersection of a line and a triangle when they are both in the same
 * plane.
 *
 * (Currently it is assumed the line starts inside the triangle)
 *
 * @tparam S Scalar type.
 * @param origin Start of the line.
 * @param dir Direction of the line.
 * @param t1 First point int he triangle.
 * @param t2 Second point int he triangle.
 * @param t3 Third point int he triangle.
 * @return std::tuple<Vec<S>, bool, int> Tuple of:
 *  - The intersection point.
 *  - True if the line hits, false otherwise.
 *  - The index of the first point in the collided edge (0 for t1, 1 for t2, 2 for t3).
 */
template <typename S>
std::tuple<Vec<S>, bool, int> CoPlanarLineTriangleIntersection(
    const Vec<S>& origin,
    const Vec<S>& dir,
    const Vec<S>& t1,
    const Vec<S>& t2,
    const Vec<S>& t3)
{
    const std::array<Vec<S>, 3> points = {t1, t2, t3};

    for(uint i=0; i < 3; i++)
    {
        Vec<S> v1 = points[i];
        Vec<S> v2 = points[(i + 1) % 3];

        Vec<S> edge = v2 - v1;
        float u = LineLineIntersection(
            {v1.x(), v1.y(), v1.z()},
            {edge.x(), edge.y(), edge.z()},
            {origin.x(), origin.y(), origin.z()},
            {dir.x(), dir.y(), dir.z()});
        Vec<S> intersection = v1 + edge * u;
        // u is the parameter of the first line. This will give the sign of the parameter
        // of the second line.
        float v = (intersection - origin).dot(dir);
        if(v >= 0 && u>=0 && u <= 1.f + 0.0000000001)
            return {intersection, true, i};
    }

    return {{}, false, -1};
}

template <typename S>
std::tuple<Vec<S>, bool, int> CoPlanarLinePolyLineIntersection(
    const Vec<S>& origin,
    const Vec<S>& dir,
    const std::vector<Vec<S>>& line,
    bool is_closed = false)
{
    const uint point_num = line.size();
    for(uint i=0; i < point_num + is_closed - 1; i++)
    {
        Vec<S> v1 = line[i];
        Vec<S> v2 = line[(i + 1) % point_num];

        Vec<S> edge = v2 - v1;
        float u = LineLineIntersection(
            {v1.x(), v1.y(), v1.z()},
            {edge.x(), edge.y(), edge.z()},
            {origin.x(), origin.y(), origin.z()},
            {dir.x(), dir.y(), dir.z()});
        Vec<S> intersection = v1 + edge * u;
        // u is the parameter of the first line. This will give the sign of the parameter
        // of the second line.
        float v = (intersection - origin).dot(dir);
        if(v >= 0 && IsInRange(u, 0.f, 1.f))
            return {intersection, true, i};
    }

    return {{}, false, -1};
}
/**
 * @brief Orthogonally project a point onto a line.
 *
 * @tparam S scalar type.
 * @param point Point to project.
 * @param origin Start of line.
 * @param edge Direction of the line.
 * @return constexpr Vec<S>
 */
template <typename S>
constexpr Vec<S> ProjectPointOntoLine(
    const Vec<S>& point,
    const Vec<S>& origin,
    const Vec<S>& edge)
{
    const Vec<S> dir = edge.normalized();
    const Vec<S> v = (point - origin);
    return origin + v.dot(dir) * dir;
}

The file itself is not particularily importnat, it's just data. I call my python function this way:

python3 Scripts/checker.py | grep <function name>

Only some functions get printed this way. For example Unproect is found, Dijkstra isn't, TestPointInTriangle is found, ExpressInBasis is not.

I don't see any pattern that explains why some functions are picked while others are ignored.

0

There are 0 answers