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.