DHART
Loading...
Searching...
No Matches
ViewAnalysis

Functions

vector< std::array< float, 3 > > HF::ViewAnalysis::FibbonacciDistributePoints (int num_points, float upwards_fov=50.0f, float downward_fov=70.0f)
 Evenly distribute a set of points around a sphere centered at the origin. More...
 
template<typename RES , typename RT , typename N >
std::vector< RES > HF::ViewAnalysis::SphericalViewAnalysis (RT &ray_tracer, const std::vector< N > &Nodes, int num_rays, float upward_limit=50.0f, float downward_limit=70.0f, float height=1.7f)
 Conduct view analysis with any Raytracer in parallel. More...
 
template<typename RT , typename N >
std::vector< float > HF::ViewAnalysis::SphericalRayshootWithAnyRTForDistance (RT &ray_tracer, const std::vector< N > &Nodes, int num_rays, float upward_limit=50.0f, float downward_limit=70.0f, float height=1.7f, const AGGREGATE_TYPE aggregation=AGGREGATE_TYPE::SUM)
 Conduct view analysis and recieve a summarized set of results for each node. More...
 
C_INTERFACE SphereicalViewAnalysisAggregate (HF::RayTracer::EmbreeRayTracer *ERT, HF::SpatialStructures::Node *node_ptr, int node_size, int max_rays, float upward_fov, float downward_fov, float height, AGGREGATE_TYPE AT, std::vector< float > **out_scores, float **out_scores_ptr, int *out_scores_size)
 Conduct view analysis, then aggregate the results. More...
 
C_INTERFACE SphereicalViewAnalysisAggregateFlat (HF::RayTracer::EmbreeRayTracer *ERT, const float *node_ptr, int node_size, int max_rays, float upward_fov, float downward_fov, float height, AGGREGATE_TYPE AT, std::vector< float > **out_scores, float **out_scores_ptr, int *out_scores_size)
 Conduct view analysis, and aggregate the results. More...
 
C_INTERFACE SphericalViewAnalysisNoAggregate (HF::RayTracer::EmbreeRayTracer *ERT, const HF::SpatialStructures::Node *node_ptr, int node_size, int *max_rays, float upward_fov, float downward_fov, float height, std::vector< RayResult > **out_results, RayResult **out_results_ptr)
 Perform view analysis, then get the distance and meshid for each individual ray casted. More...
 
C_INTERFACE SphericalViewAnalysisNoAggregateFlat (HF::RayTracer::EmbreeRayTracer *ERT, const float *node_ptr, int node_size, int *max_rays, float upward_fov, float downward_fov, float height, std::vector< RayResult > **out_results, RayResult **out_results_ptr)
 Perform view analysis, and get the distance and meshid for each individual ray casted. More...
 
C_INTERFACE SphericalDistribute (int *num_rays, std::vector< float > **out_direction_vector, float **out_direction_data, float upward_fov, float downward_fov)
 Equally distribute points around a unit sphere. More...
 

Detailed Description

Analyze the view from points in the environment.

Function Documentation

◆ FibbonacciDistributePoints()

std::vector< std::array< float, 3 > > HF::ViewAnalysis::FibbonacciDistributePoints ( int  num_points,
float  upwards_fov = 50.0f,
float  downward_fov = 70.0f 
)

#include <Cpp/analysismethods/src/view_analysis.cpp>

Evenly distribute a set of points around a sphere centered at the origin.

Parameters
num_pointsMaximum number of points to distribute.
upward_limitMaximum angle in degrees to cast rays above the viewpoint.
downward_limitMaximum angle in degrees to cast rays below the viewpoint.
Returns
A vector of arrays containing the x, y, and z coordinates of each point on the sphere.
Note
The number of points returned by this function will not exactly equal the amount of points specified by num_points depending on the values of upwards_fov and downward fov. More information is available below.
How FOV is implemented
Every point is equally distributed on a sphere using a formula based on this stack overflow answer: https://stackoverflow.com/questions/9600801/evenly-distributing-n-points-on-a-sphere. This formula cannot easily be mapped to a specific vertical fov or cone, so instead this function will remove points that don't meet the constraints. Discarding points causes the number of points generated to be less than the num_rays argument, so the percentage of points discarded is calculated and a second run is performed with an adjusted num_rays value to get as close as possible to the value specified in the argument. This approach will not result in an exact match to the num_rays argument, and will run FibbonacciDist twice.
Example
// Requires #include "view_analysis.h"
// For brevity
// Prepare maximum number of points to distribute
int size = 8;
// Generate points without any limitations on fov
auto points = FibbonacciDistributePoints(size, 90.0f, 90.0f);
// Print number of points
std::cout << "Number of Points:" << points.size() << std::endl;
// Iterate through results and print every point.
std::cout << "[";
for (int i = 0; i < size; i++) {
const auto& point = points[i];
std::cout << "(" << point[0] << ", " << point[1] << ", " << point[2] << ")";
if (i != size - 1) std::cout << ", ";
}
std::cout << "]" << std::endl;
vector< std::array< float, 3 > > FibbonacciDistributePoints(int num_points, float upwards_fov, float downward_fov)
Evenly distribute a set of points around a sphere centered at the origin.

>>> Number of Points:8
>>> [(-0, -1, 0), (-0.304862, -0.75, -0.586992), (0.813476, -0.5, 0.29708), (-0.894994, -0.25, 0.369441), (0.423846, 0, -0.905734), (0.289781, 0.25, 0.923865), (-0.749296, 0.5, -0.43423), (0.64601, 0.75, -0.142025)]

Definition at line 121 of file view_analysis.cpp.

References HF::ViewAnalysis::FibbonacciDist().

Referenced by SphericalDistribute(), HF::ViewAnalysis::SphericalRayshootWithAnyRTForDistance(), and HF::ViewAnalysis::SphericalViewAnalysis().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ SphereicalViewAnalysisAggregate()

C_INTERFACE SphereicalViewAnalysisAggregate ( HF::RayTracer::EmbreeRayTracer ERT,
HF::SpatialStructures::Node node_ptr,
int  node_size,
int  max_rays,
float  upward_fov,
float  downward_fov,
float  height,
AGGREGATE_TYPE  AT,
std::vector< float > **  out_scores,
float **  out_scores_ptr,
int *  out_scores_size 
)

#include <Cinterface/view_analysis_C.h>

Conduct view analysis, then aggregate the results.

Parameters
ERTRaytracer containing the geometry to use for ray intersections.
node_ptrObserver points for the view analysis.
node_sizeNumber of nodes in the array pointed to by node_ptr.
max_raysNumber of rays to cast for each node in node_ptr. Note that this may cast fewer rays than max_rays, depending on FOV restrictions.
upward_fovMaximum degrees upward from the viewer's eye level to consider.
downward_fovMaximum degrees downward from the viewer's eye level to consider.
heightHeight to offset nodes from the ground (+Z direction).
ATType of aggregation method to use.
out_scoresOutput parameter for node scores.
out_scores_ptrPointer to the data of out_scores.
out_scores_sizeSize of output_scores_ptr.
Returns
HF::Status::OK on completion.
Caller's Responsibility
The caller must call DestroyFloatVector with out_scores to free the memory allocated by this function.
Precondition
1) ERT points to a valid raytracer created by CreateRaytracer
2) node_ptr contains a valid array of nodes with length equal to node_size
3) out_scores, out_scores_ptr, and out_score_size are not null
Postcondition
1) out_scores contains a pointer to score for every node in nodes in order
2) out_scores_ptr cpoints to a valid array of scores
3) out_scores_size is updated to the length of the data held by out_scores_ptr
Todo:
Is there any situation where out_scores_size is smaller than node_size?
See also
Mesh setup (how to create a mesh), Mesh teardown (how to destroy a mesh)
Raytracer setup (how to create a BVH), Raytracer teardown (how to destroy a BVH)
SphericalViewAnalysis for an algorithm that returns the results of every ray casted instead of aggregating the results.
SphericalViewAnalysisAggregateFlat for a function that works on a flat array of floats instead of an array of nodes.

Begin by loading an .obj file (Mesh setup).
Then, create a BVH (Raytracer setup) using the mesh.

Example Code

Set up the parameters for the view analysis.

// Preparing the parameters for SphereicalViewAnalysisAggregate
// Define point to start ray
// These are Cartesian coordinates.
std::array<Node, 3> p1{ Node(0.0f, 0.0f, 2.0f) };
// Define direction to cast ray
// These are vector components, not Cartesian coordinates.
std::array<float, 3> dir { 0.0f, 0.0f, -1.0f };
// This is a container of nodes to be analyzed.
// SphereicalViewAnalysisAggregate accepts a (Node *) parameter,
// so a raw stack-allocated array will suffice.
//
// This may also be a pointer to a heap-allocated buffer
// (which is owned by a vector<Node>, accessed via the vector<Node>::data() method).
//
// ...or, it can be a pointer to memory allocated by the caller via operator new[node_count]
// (if this route is taken, be sure to release the memory with operator delete[] after use)
const int node_count = static_cast<int>(p1.size()); // should be the element count in nodes
int ray_count = 1000; // will be mutated by SphereicalViewAnalysisAggregate
const float height = 1.7f; // height to offset nodes from the ground, in meters
const float upward_fov = 50.0f; // default parameter is 50.0f in Python code
const float downward_fov = 70.0f; // default parameter is 70.0f in Python code

Now you must prepare a pointer to a std::vector<float>, where the aggregation results will be stored.
You must also select the aggregate type.

// Declare a pointer to vector<float>, named aggregate_results.
// This pointer will point to memory on the free store,
// allocated within SphereicalViewAnalysisAggregate.
//
// aggregate_results_data will point to the underlying buffer within *aggregate_results,
// which will be assigned inside SphereicalViewAnalysisAggregate.
//
// Note that we must call operator delete on aggregate_results when we are finished with it.
std::vector<float>* aggregate_results = nullptr;
float* aggregate_results_data = nullptr;
// Will be equal to aggregate_results->size();
int aggregate_results_size = -1;
// Select the aggregate type.
// This determines how to aggregate the edges within the results of the view analysis.
//
// AGGREGATE_TYPE::AVERAGE means that the edges will be aggregated
// by the maximum distance from the origin point to its hit points.
AGGREGATE_TYPE
Determines how to aggregate edges from the results of view analysis.
@ AVERAGE
Average distance of origin to its hit points.

Now we are ready to call SphereicalViewAnalysisAggregate .

p1.data(), node_count, ray_count,
upward_fov, downward_fov, height,
agg_type,
&aggregate_results, &aggregate_results_data, &aggregate_results_size);
if (status != 1) {
// Error!
std::cerr << "Error at SphereicalViewAnalysisAggregate, code: " << status << std::endl;
}
C_INTERFACE SphereicalViewAnalysisAggregate(EmbreeRayTracer *ERT, Node *node_ptr, int node_size, int max_rays, float upward_fov, float downward_fov, float height, AGGREGATE_TYPE AT, vector< float > **out_scores, float **out_scores_ptr, int *out_scores_size)
Conduct view analysis, then aggregate the results.

We can output the contents of the aggregate results vector to stdout .

// Print aggregate results vector (vector<float>)
std::cout << "[";
int i = 0;
for (auto agg_result : *aggregate_results) {
std::cout << agg_result;
if (i < aggregate_results->size() - 1) {
std::cout << ", ";
}
++i;
}
std::cout << "]" << std::endl;

After using the view analysis results, its resources must be relinquished .

//
// Memory resource cleanup.
//
// destroy vector<float>
if (aggregate_results) {
delete aggregate_results;
}

From here, please review the example at Raytracer teardown for instructions
on how to free the remainder of the resources used for the view analysis –
which are the (vector<HF::Geometry::MeshInfo> *) and (HF::Raytracer::EmbreeRayTracer *) instances.

>>> LoadOBJ loaded mesh successfully into loaded_obj at address 00000293CC9C8650, code: 1
>>> CreateRaytracer created EmbreeRayTracer successfully into bvh at address 00000293C3012D20, code: 1
>>> [7.43102, 0, 0]

Definition at line 17 of file view_analysis_C.cpp.

References HF::Exceptions::OK, and HF::ViewAnalysis::SphericalRayshootWithAnyRTForDistance().

+ Here is the call graph for this function:

◆ SphereicalViewAnalysisAggregateFlat()

C_INTERFACE SphereicalViewAnalysisAggregateFlat ( HF::RayTracer::EmbreeRayTracer ERT,
const float *  node_ptr,
int  node_size,
int  max_rays,
float  upward_fov,
float  downward_fov,
float  height,
AGGREGATE_TYPE  AT,
std::vector< float > **  out_scores,
float **  out_scores_ptr,
int *  out_scores_size 
)

#include <Cinterface/view_analysis_C.h>

Conduct view analysis, and aggregate the results.

Parameters
ERTRaytracer containing the geometry to use for ray intersections.
node_ptrObserver points for the view analysis. Each 3 floats represent the {x, y, z} of a new node.
node_sizeNumber of nodes in the array pointed to by node_ptr.
max_raysNumber of rays to cast for each node in node_ptr. Note that this may cast fewer rays than max_rays depending on fov restrictions.
upward_fovMaximum degrees upward from the viewer's eye level to consider.
downward_fovMaximum degrees downward from the viewer's eye level to consider.
heightHeight to offset nodes from the ground (+Z direction).
ATType of aggregation method to use.
out_scoresOutput parameter for node scores.
out_scores_ptrPointer to the data of out_scores.
out_scores_sizeSize of out_scores_ptr.
Returns
HF::OK on completion.

Similar to SphericalViewAnalysis but uses a flat array of floats instead of an array of nodes. This is to make the SphericalViewAnalysis function more accessible.

Caller's Responsibility
The caller must call DestroyFloatVector with out_scores to free the memory allocated by this function.
Precondition
1) ERT points to a valid raytracer created by CreateRaytracer.
2) node_ptr contains a valid array of floats with length equal to node_size * 3.
3) out_scores, out_scores_ptr, and out_score_size are not null.
Postcondition
1) out_scores contains a pointer to score for every node in nodes in order.
2) out_scores_ptr cpoints to a valid array of scores.
3) out_scores_size is updated to the length of the data held by out_scores_ptr.
Todo:
Is there any situation where out_scores_size is smaller than node_size?
See also
Mesh setup (how to create a mesh), Mesh teardown (how to destroy a mesh)
Raytracer setup (how to create a BVH), Raytracer teardown (how to destroy a BVH)

Begin by loading an .obj file (Mesh setup).
Then, create a BVH (Raytracer setup) using the mesh.

Example

Set up the parameters for the view analysis.

// Preparing the parameters for SphericalViewAnalysisAggregateFlat
// Define point to start ray
// These are Cartesian coordinates.
std::array<float, 3> p1 { 0.0f, 0.0f, 2.0f };
// Define direction to cast ray
// These are vector components, not Cartesian coordinates.
std::array<float, 3> dir { 0.0f, 0.0f, -1.0f };
// This is a container of nodes to be analyzed.
// SphericalViewAnalysisAggregateFlat accepts a (Node *) parameter,
// so a raw stack-allocated array will suffice.
//
// This may also be a pointer to a heap-allocated buffer
// (which is owned by a vector<Node>, accessed via the vector<Node>::data() method).
//
// ...or, it can be a pointer to memory allocated by the caller via operator new[node_count]
// (if this route is taken, be sure to release the memory with operator delete[] after use)
const int node_count = 1; // should be the element count in nodes
int ray_count = 1000; // will be mutated by SphericalViewAnalysisAggregateFlat
const float height = 1.7f; // height to offset nodes from the ground, in meters
const float upward_fov = 50.0f; // default parameter is 50.0f in Python code
const float downward_fov = 70.0f; // default parameter is 70.0f in Python code

Now you must prepare a pointer to a std::vector<float>, where the aggregation results will be stored.
You must also select the aggregate type.

// Declare a pointer to vector<float>, named aggregate_results.
// This pointer will point to memory on the free store,
// allocated within SphericalViewAnalysisAggregateFlat.
//
// aggregate_results_data will point to the underlying buffer within *aggregate_results,
// which will be assigned inside SphericalViewAnalysisNoAggregateFlat.
//
// Note that we must call operator delete on aggregate_results when we are finished with it.
std::vector<float>* aggregate_results = nullptr;
float* aggregate_results_data = nullptr;
// Will be equal to aggregate_results->size();
int aggregate_results_size = -1;
// Select the aggregate type.
// This determines how to aggregate the edges within the results of the view analysis.
//
// AGGREGATE_TYPE::AVERAGE means that the edges will be aggregated
// by the maximum distance from the origin point to its hit points.

Now we are ready to call SphericalViewAnalysisAggregateFlat .

p1.data(), node_count, ray_count,
upward_fov, downward_fov, height,
agg_type,
&aggregate_results, &aggregate_results_data, &aggregate_results_size);
if (status != 1) {
// Error!
std::cerr << "Error at SphereicalViewAnalysisAggregateFlat, code: " << status << std::endl;
}
C_INTERFACE SphereicalViewAnalysisAggregateFlat(HF::RayTracer::EmbreeRayTracer *ERT, const float *node_ptr, int node_size, int max_rays, float upward_fov, float downward_fov, float height, AGGREGATE_TYPE AT, std::vector< float > **out_scores, float **out_scores_ptr, int *out_scores_size)
Conduct view analysis, and aggregate the results.

We can output the contents of the aggregate results vector to stdout.

// Print aggregate results vector (vector<float>)
std::cout << "[";
int i = 0;
for (auto agg_result : *aggregate_results) {
std::cout << agg_result;
if (i < aggregate_results->size() - 1) {
std::cout << ", ";
}
++i;
}
std::cout << "]" << std::endl;

After using the view analysis results, its resources must be relinquished.

//
// Memory resource cleanup.
//
// destroy vector<float>
if (aggregate_results) {
delete aggregate_results;
}

From here, please review the example at Raytracer teardown for instructions
on how to free the remainder of the resources used for the view analysis –
which are the (vector<HF::Geometry::MeshInfo> *) and (HF::Raytracer::EmbreeRayTracer *) instances.

>>> LoadOBJ loaded mesh successfully into loaded_obj at address 00000293CC9C84D0, code: 1
>>> CreateRaytracer created EmbreeRayTracer successfully into bvh at address 00000293C3012D20, code: 1
>>> [7.43102]

Definition at line 50 of file view_analysis_C.cpp.

References ConvertRawFloatArrayToPoints(), HF::Exceptions::OK, and HF::ViewAnalysis::SphericalRayshootWithAnyRTForDistance().

+ Here is the call graph for this function:

◆ SphericalDistribute()

C_INTERFACE SphericalDistribute ( int *  num_rays,
std::vector< float > **  out_direction_vector,
float **  out_direction_data,
float  upward_fov,
float  downward_fov 
)

#include <Cinterface/view_analysis_C.h>

Equally distribute points around a unit sphere.

Parameters
num_raysNumber of points to distribute.
out_direction_vectorOutput parameter for points generated. Every 3 floats represents a new point.
out_direction_datapointer to the data of out_direction_vector
upward_fovMaximum degrees upward from the viewer's eye level to consider.
downward_fovMaximum degrees downward from the viewer's eye level to consider.
Returns
HF::OK on completion.
Caller's Responsibility
The caller must call DestroyFloatVector with out_direction_vector to free the memory allocated by this function.
Remarks
This function is used internally by all view analysis functions to equally distribute the directions each ray will be casted in.
Precondition
out_direction_vector and out_direction_data must not be null, but the pointers they hold can be null.
Postcondition
1) The pointer pointed to by out_direction_vector contains a vector of directions.
2) num_rays contains the number of points distributed by this function. This may be more or less than the original number depending on the limitations specified by upward and downward fov.
See also
Raytracer teardown (how to destroy a BVH)
Mesh teardown (how to destroy a mesh)
Example

Begin by initializing input values:

//
// Set arguments
//
int num_rays = 10; // number of points to distribute
std::vector<float>* out_float = nullptr; // output parameter for points generated
float* out_float_data; // pointer to buffer within *out_float
float up_fov = 90.0f; // max degrees upward from viewer's eye level to consider
float down_fov = 90.0f; // max degrees downward from viewer's eye level to consider

We are now ready to call SphericalDistribute .

//
// Call function
//
auto status = SphericalDistribute(
&num_rays,
&out_float,
&out_float_data,
up_fov,
down_fov
);
if (status != 1) {
std::cerr << "Error at SphericalDistribute, code: " << status << std::endl;
}
C_INTERFACE SphericalDistribute(int *num_rays, vector< float > **out_direction_vector, float **out_direction_data, float upward_fov, float downward_fov)
Equally distribute points around a unit sphere.

Let's output the result, stored in out_float_data (you can also access *out_float).

//
// Print results
//
std::cout << "Number of rays: " << num_rays << std::endl;
for (int i = 0; i < num_rays; i++) {
int os = i * 3;
std::cout << "("
<< out_float_data[os] << ", "
<< out_float_data[os + 1] << ", "
<< out_float_data[os + 2] << ")"
<< std::endl;
}

Make sure to destroy the resources addressed by out_float when you are finished with it.

//
// Deallocate Memory
//
DestroyFloatVector(out_float);
C_INTERFACE DestroyFloatVector(std::vector< float > *float_vector)
Delete a float vector that's pointed to by float_vector

>>> Number of rays: 10
>>> (-0, -1, 0)
>>> (-0.276545, -0.8, -0.532469)
>>> (0.751457, -0.6, 0.27443)
>>> (-0.847177, -0.4, 0.349703)
>>> (0.415282, -0.2, -0.887435)
>>> (0.299284, 0, 0.954164)
>>> (-0.847731, 0.2, -0.491275)
>>> (0.895138, 0.4, -0.196795)
>>> (-0.460102, 0.6, 0.654451)
>>> (-0.0771074, 0.8, -0.595025)

Definition at line 126 of file view_analysis_C.cpp.

References HF::ViewAnalysis::FibbonacciDistributePoints(), and HF::Exceptions::OK.

+ Here is the call graph for this function:

◆ SphericalRayshootWithAnyRTForDistance()

template<typename RT , typename N >
std::vector< float > HF::ViewAnalysis::SphericalRayshootWithAnyRTForDistance ( RT &  ray_tracer,
const std::vector< N > &  Nodes,
int  num_rays,
float  upward_limit = 50.0f,
float  downward_limit = 70.0f,
float  height = 1.7f,
const AGGREGATE_TYPE  aggregation = AGGREGATE_TYPE::SUM 
)

#include <Cpp/analysismethods/src/view_analysis.h>

Conduct view analysis and recieve a summarized set of results for each node.

Parameters
ray_tracerA valid raytracer that already has the geometry loaded.
NodesPoints to perform analysis from.
num_raysThe number of rays to cast from each point in nodes. The actual amount of rays cast may be less or more than this number. Due to how the spherical ray distribution is calculated.
Parameters
upward_limitMaximum angle in degrees to cast rays above the viewpoint.
downward_limitMaximum angle in degrees to cast rays below the viewpoint.
heightHeight off the ground to cast from. All points in Nodes will be offset this distance from the ground (+Z) before calculations are performed
aggregationThe type of aggregation to use.
Template Parameters
RTA Raytracer with IntersectOutputArguments defined for the type of N.
NA point that overloads [] for 0, 1 and 2.
Returns
A Nodes.size() long array of results for each node in Nodes.

The analysis performed by this function is identical to that described in SphericalViewAnalysis, but results are summarized over the course of the analysis for every observer point instead of recording each individual intersection. The memory usage for this function is drastically lower than that of SphericalViewAnalysis, resulting in lower execution times at the cost of being restricted to a set of predefined aggregation methods.

Exceptions
std::bad_array_new_lengthThe number of rays is larger than that which can be stored in a std::vector.
See also
FibbonacciDistributePoints For details on how the directions are calculated from num_rays.
SphericalViewAnalysis to get the result of every ray cast instead of summarizing the results.
AGGREGATE_TYPE for a list of aggregation methods.
Aggregate for the implementation of all aggregation methods.
Example
// Requires #include "view_analysis.h"
// Use this so we can fit within 80 characters
// Create Plane
const std::vector<float> plane_vertices{
-10.0f, 10.0f, 0.0f,
-10.0f, -10.0f, 0.0f,
10.0f, 10.0f, 0.0f,
10.0f, -10.0f, 0.0f,
};
const std::vector<int> plane_indices{ 3, 1, 0, 2, 3, 0 };
// Create RayTracer
EmbreeRayTracer ert(std::vector<MeshInfo>{
MeshInfo(plane_vertices, plane_indices, 0, " ")}
);
// Define observer points
std::vector<std::array<float, 3>> points{
{0,0,0}, {10,10,0}, {20,20,0}, {30, 30, 0}
};
// Perform View Analysis and sum the distance to all intersections
// for every node
int num_rays = 2000;
ert, points, num_rays, 90.0f, 90.0f, 1.7f, AGGREGATE_TYPE::SUM
);
// Print Results
std::cerr << "(";
for (int i = 0; i < results.size(); i++) {
std::cerr << results[i];
if (i != results.size() - 1) std::cerr << ", ";
}
std::cerr << ")" << std::endl;
HF::Geometry::MeshInfo< float > MeshInfo
Definition: raytracer_C.cpp:11
std::vector< float > SphericalRayshootWithAnyRTForDistance(RT &ray_tracer, const std::vector< N > &Nodes, int num_rays, float upward_limit=50.0f, float downward_limit=70.0f, float height=1.7f, const AGGREGATE_TYPE aggregation=AGGREGATE_TYPE::SUM)
Conduct view analysis and recieve a summarized set of results for each node.
AGGREGATE_TYPE
The type of aggregation to use for ViewAnalysisAggregate
Definition: view_analysis.h:49
@ SUM
Sum of the distance from the origin to all intersections.
A collection of vertices and indices representing geometry.
Definition: meshinfo.h:124
A wrapper for Intel's Embree Library.

>>> (2746.72, 932.565, 170.858, 76.8413)

Todo:
Should this have a height check like the one in the VisibilityGraph?
Todo:
Rename this to ViewAnalysisAggregate.
Todo:
Potential speed up here by using a Raytracer function that doesn't return the point of intersection.

Definition at line 484 of file view_analysis.h.

References HF::ViewAnalysis::Aggregate(), HF::ViewAnalysis::FibbonacciDistributePoints(), and HF::ViewAnalysis::MIN.

Referenced by SphereicalViewAnalysisAggregate(), and SphereicalViewAnalysisAggregateFlat().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ SphericalViewAnalysis()

template<typename RES , typename RT , typename N >
std::vector< RES > HF::ViewAnalysis::SphericalViewAnalysis ( RT &  ray_tracer,
const std::vector< N > &  Nodes,
int  num_rays,
float  upward_limit = 50.0f,
float  downward_limit = 70.0f,
float  height = 1.7f 
)

#include <Cpp/analysismethods/src/view_analysis.h>

Conduct view analysis with any Raytracer in parallel.

Parameters
ray_tracerA valid raytracer that already has the geometry loaded.
NodesPoints to perform analysis from.
num_raysThe number of rays to cast from each point in nodes. The actual amount of rays cast may be less or more than this number. Due to how the spherical ray distribution is calculated.
upward_limitMaximum angle in degrees to cast rays above the viewpoint.
downward_limitMaximum angle in degrees to cast rays below the viewpoint.
heightHeight off the ground to cast from. All points in Nodes will be offset this distance from the ground (+Z) before calculations are performed
Template Parameters
RESA class or struct that has a .SetHit() function. This function will be called with the node, direction, distance to intersection, and MeshID intersected for every ray that intersects geometry.
RTA Raytracer with IntersectOutputArguments defined for the type of N.
NA point that overloads [] for 0, 1 and 2.
Returns
An approximately num_rays * Nodes.size() long vector of RES with one element for every ray cast. Results will be laid out in order with the first node's results first, then the second, etc. Every ray that intersected something, and all elements that didn't result in an intersection will left at their default values.

ViewAnalysis is calculated by casting a series of rays equally distributed in a sphere from each point in Nodes. This function will run in parallel using all available cores. Depending on RES, this function's complexity and results can vary.

Exceptions
std::bad_array_new_lengthThe number of rays is larger than that which can be stored in a std::vector.
See also
FibbonacciDistributePoints For details on how the directions are calculated from num_rays.
SphericalRayshootWithAnyRTForDistance for a more efficent method of getting a summary of the results.
Example
// Requires #include "view_analysis.h"
// Use this so we can fit within 80 characters
// Create Plane
const std::vector<float> plane_vertices{
-10.0f, 10.0f, 0.0f,
-10.0f, -10.0f, 0.0f,
10.0f, 10.0f, 0.0f,
10.0f, -10.0f, 0.0f,
};
const std::vector<int> plane_indices{ 3, 1, 0, 2, 3, 0 };
// Create RayTracer
EmbreeRayTracer ert(std::vector<MeshInfo>{
MeshInfo(plane_vertices, plane_indices, 0, " ")}
);
// Define a struct that only stores the distance when sethit is called.
struct SampleResults {
float dist = -1.0f;
inline void SetHit(
const std::array<float, 3> & node,
const std::array<float, 3> & direction,
float distance,
int meshID
) {
dist = distance;
}
};
// Define observer points
std::vector<std::array<float, 3>> points{
{0,0,0}, {1,1,0}, {1,2,0}, {1000, 1000, 0}
};
// Perform View Analysis
int num_rays = 50;
auto results = SphericalViewAnalysis<SampleResults>(ert, points, num_rays);
// Determine how many directions there were since there may have been less than
// what we specified
int num_directions = results.size() / points.size();
// Construct a vector from the results of the first node
std::vector<SampleResults> first_results(
results.begin(), results.begin() + num_directions
);
// Print Results
std::cerr << "(";
for (int i = 0; i < first_results.size(); i++) {
const auto & result = first_results[i];
std::cerr << result.dist;
if (i != first_results.size() - 1) std::cerr << ", ";
}
std::cerr << ")" << std::endl;
std::vector< RES > SphericalViewAnalysis(RT &ray_tracer, const std::vector< N > &Nodes, int num_rays, float upward_limit=50.0f, float downward_limit=70.0f, float height=1.7f)
Conduct view analysis with any Raytracer in parallel.

>>> (-1, 7.35812, -1, -1, 3.70356, -1, 5.56647, 12.1517, -1, 2.36725, -1, -1, 2.97477, 2.58713, -1, -1, 1.91404, 5.95885, 4.26368, 1.86167, -1, -1, 2.0406, 2.78304, -1, -1, -1, -1, 2.83909, 2.05302, -1, -1, 1.90724, 4.29017, 6.3381, 1.98544, -1, -1, 2.75554, 3.15929, -1, -1, 2.6345, -1, -1, 6.80486, -1, 5.12012, -1)

Todo:
Should this have a height check like the one in the VisibilityGraph?

Definition at line 335 of file view_analysis.h.

References HF::ViewAnalysis::FibbonacciDistributePoints().

+ Here is the call graph for this function:

◆ SphericalViewAnalysisNoAggregate()

C_INTERFACE SphericalViewAnalysisNoAggregate ( HF::RayTracer::EmbreeRayTracer ERT,
const HF::SpatialStructures::Node node_ptr,
int  node_size,
int *  max_rays,
float  upward_fov,
float  downward_fov,
float  height,
std::vector< RayResult > **  out_results,
RayResult **  out_results_ptr 
)

#include <Cinterface/view_analysis_C.h>

Perform view analysis, then get the distance and meshid for each individual ray casted.

Parameters
ERTRaytracer containing the geometry to use for ray intersections.
node_ptrObserver points for the view analysis.
node_sizeNumber of nodes in the array pointed to by node_ptr.
max_raysNumber of rays to cast for each node in node_ptr. This will be updated with the actual number of rays casted upon completion.
upward_fovMaximum degrees upward from the viewer's eye level to consider.
downward_fovMaximum degrees downward from the viewer's eye level to consider.
heightHeight to offset nodes from the ground (+Z direction).
out_resultsPointer to the vector containing the results of every ray casted.
out_results_ptrPointer to the data of out_results.
Returns
HF::OK on completion.

Rays that do not intersect with any geometry will have a meshid of -1.

Caller's Responsibility
The caller must call DestroyRayResultVector with out_results to free the memory allocated by this function.
Precondition
1) ERT points to a valid raytracer created by CreateRaytracer.
2) node_ptr contains a valid array of nodes with length equal to node_size.
3) node_ptr, max_rays, and ERT are not null.
Postcondition
1) out_results contains a pointer to score for every node in nodes in order.
2) out_results_ptr points to a valid array of scores.
3) max_rays is updated to the number of rays casted in the view analysis.
See also
Mesh setup (how to create a mesh), Mesh teardown (how to destroy a mesh)
Raytracer setup (how to create a BVH), Raytracer teardown (how to destroy a BVH)
SphericalDistribute to get the direction of every ray casted by this function. Can be useful to determine the point of intersection for every ray casted.
Example

Begin by loading an .obj file (Mesh setup).
Then, create a BVH (Raytracer setup) using the mesh.

Set up the parameters for the view analysis.

// Preparing the parameters for SphericalViewAnalysisNoAggregate
// Define point to start ray
// These are Cartesian coordinates.
std::array<Node, 1> p1{ Node(0.0f, 0.0f, 2.0f) };
// Define direction to cast ray
// These are vector components, not Cartesian coordinates.
std::array<float, 3> dir { 0.0f, 0.0f, -1.0f };
// This is a container of nodes to be analyzed.
// SphericalViewAnalysisNoAggregate accepts a (Node *) parameter,
// so a raw stack-allocated array will suffice.
//
// This may also be a pointer to a heap-allocated buffer
// (which is owned by a vector<Node>, accessed via the vector<Node>::data() method).
//
// ...or, it can be a pointer to memory allocated by the caller via operator new[node_count]
// (if this route is taken, be sure to release the memory with operator delete[] after use)
const int node_count = static_cast<int>(p1.size()); // should be the element count in nodes
int ray_count = 1000; // will be mutated by SphericalViewAnalysisNoAggregate
const float height = 1.7f; // height to offset nodes from the ground, in meters
const float upward_fov = 50.0f; // default parameter is 50.0f in Python code
const float downward_fov = 70.0f; // default parameter is 70.0f in Python code

Now you must prepare a pointer to a std::vector<RayResult>.
View analysis results will be stored at the memory addressed by this pointer.

// Declare a pointer to vector<RayResult>, named results.
// This pointer will point to memory on the free store,
// allocated within SphericalViewAnalysisNoAggregate.
//
// results_data will point to the underlying buffer within *results,
// which will be assigned inside SphericalViewAnalysisNoAggregate.
//
// Note that we must call operator delete on results when we are finished with it.
std::vector<RayResult>* results = nullptr;
RayResult* results_data = nullptr;
The result of casting a ray at an object. Contains distance to the hitpoint and the ID of the mesh.
Definition: raytracer_C.h:89

Now we are ready to call SphericalViewAnalysisNoAggregate .

// Conducting a view analysis on the node at position p1.
p1.data(), node_count, &ray_count,
upward_fov, downward_fov, height,
&results, &results_data);
if (status != 1) {
// Error!
std::cerr << "Error at SphericalViewAnalysisNoAggregate, code: " << status << std::endl;
}
C_INTERFACE SphericalViewAnalysisNoAggregate(HF::RayTracer::EmbreeRayTracer *ERT, const HF::SpatialStructures::Node *node_ptr, int node_size, int *max_rays, float upward_fov, float downward_fov, float height, std::vector< RayResult > **out_results, RayResult **out_results_ptr)
Perform view analysis, then get the distance and meshid for each individual ray casted.

We can output the contents of the aggregate results vector to stdout.

// Print results vector (vector<RayResult>)
const int start_range = 15;
const int end_range = 20;
std::cout << "[";
for (int i = start_range; i < end_range; i++) {
auto result = (*results)[i];
std::cout << "(" << result.distance << ", " << result.meshid << ")";
if (i < end_range - 1) {
std::cout << ", ";
}
}
std::cout << "]" << std::endl;

After using the view analysis results, its resources must be relinquished.

//
// Memory resource cleanup.
//
// destroy vector<RayResult>
if (results) {
delete results;
}

From here, please review the example at Raytracer teardown for instructions
on how to free the remainder of the resources used for the view analysis –
which are the (vector<HF::Geometry::MeshInfo> *) and (HF::Raytracer::EmbreeRayTracer *) instances.

>>> LoadOBJ loaded mesh successfully into loaded_obj at address 00000293CC9C84D0, code: 1
>>> CreateRaytracer created EmbreeRayTracer successfully into bvh at address 00000293C3012500, code: 1
>>> [(-1, -1), (-1, -1), (15.8334, 0), (-1, -1), (-1, -1)]

Definition at line 73 of file view_analysis_C.cpp.

References HF::Exceptions::OK.

◆ SphericalViewAnalysisNoAggregateFlat()

C_INTERFACE SphericalViewAnalysisNoAggregateFlat ( HF::RayTracer::EmbreeRayTracer ERT,
const float *  node_ptr,
int  node_size,
int *  max_rays,
float  upward_fov,
float  downward_fov,
float  height,
std::vector< RayResult > **  out_results,
RayResult **  out_results_ptr 
)

#include <Cinterface/view_analysis_C.h>

Perform view analysis, and get the distance and meshid for each individual ray casted.

Parameters
ERTRaytracer containing the geometry to use for ray intersections.
node_ptrobserver points for the view analysis. Every 3 elements represents the x,y,z coordinates of a new point.
node_sizenumber of nodes in the array pointed to by node_ptr. Should be equal to the length of the array contained by node_ptr * 3.
max_raysnumber of rays to cast for each node in node_ptr. This will be updated with the actual number of rays casted upon completion.
upward_fovMaximum degrees upward from the viewer's eye level to consider.
downward_fovMaximum degrees downward from the viewer's eye level to consider.
heightHeight to offset nodes from the ground (+Z direction).
out_resultsPointer to the vector containing the results of every ray casted.
out_results_ptrPointer to the data of out_results.
Returns
HF::OK on completion.

Rays that do not intersect with any geometry will have a meshid of -1.

Caller's Responsibility
The caller must call DestroyRayResultVector with out_results to free the memory allocated by this function.
Precondition
1) ERT points to a valid raytracer created by CreateRaytracer.
2) node_ptr contains a valid array of floats with length equal to node_size *3 .
3) node_ptr, max_rays, and ERT are not null.
Postcondition
1) out_scores contains a pointer to score for every node in nodes in order.
2) out_scores_ptr cpoints to a valid array of scores.
3) max_rays is updated to the number of rays casted in the view analysis.
See also
Mesh setup (how to create a mesh), Mesh teardown (how to destroy a mesh)
Raytracer setup (how to create a BVH), Raytracer teardown (how to destroy a BVH)
SphericalDistribute to get the direction of every ray casted by this function. Can be useful to determine the point of intersection for every ray casted.
Example

Begin by loading an .obj file (Mesh setup).
Then, create a BVH (Raytracer setup) using the mesh.

Set up the parameters for the view analysis.

// Preparing the parameters for SphericalViewAnalysisNoAggregateFlat
// Define point to start ray
// These are Cartesian coordinates.
std::array<float, 3> p1 { 0.0f, 0.0f, 2.0f };
// Define direction to cast ray
// These are vector components, not Cartesian coordinates.
std::array<float, 3> dir { 0.0f, 0.0f, -1.0f };
// This is a container of nodes to be analyzed.
// SphericalViewAnalysisNoAggregateFlat accepts a (Node *) parameter,
// so a raw stack-allocated array will suffice.
//
// This may also be a pointer to a heap-allocated buffer
// (which is owned by a vector<Node>, accessed via the vector<Node>::data() method).
//
// ...or, it can be a pointer to memory allocated by the caller via operator new[node_count]
// (if this route is taken, be sure to release the memory with operator delete[] after use)
const int node_count = 1; // should be the element count in nodes
int ray_count = 1000; // will be mutated by SphericalViewAnalysisNoAggregateFlat
const float height = 1.7f; // height to offset nodes from the ground, in meters
const float upward_fov = 50.0f; // default parameter is 50.0f in Python code
const float downward_fov = 70.0f; // default parameter is 70.0f in Python code

Now you must prepare a pointer to a std::vector<RayResult>.
View analysis results will be stored at the memory addressed by this pointer.

// Declare a pointer to vector<RayResult>, named results.
// This pointer will point to memory on the free store,
// allocated within SphericalViewAnalysisNoAggregateFlat.
//
// results_data will point to the underlying buffer within *results,
// which will be assigned inside SphericalViewAnalysisNoAggregateFlat.
//
// Note that we must call operator delete on results when we are finished with it.
std::vector<RayResult>* results = nullptr;
RayResult* results_data = nullptr;

We are now ready to call SphericalViewAnalysisNoAggregateFlat.

// Conducting a view analysis on the node at position p1.
p1.data(), node_count, &ray_count,
upward_fov, downward_fov, height,
&results, &results_data);
if (status != 1) {
// Error!
std::cerr << "Error at SphericalViewAnalysisNoAggregateFlat, code: " << status << std::endl;
}
C_INTERFACE SphericalViewAnalysisNoAggregateFlat(HF::RayTracer::EmbreeRayTracer *ERT, const float *node_ptr, int node_size, int *max_rays, float upward_fov, float downward_fov, float height, std::vector< RayResult > **out_results, RayResult **out_results_ptr)
Perform view analysis, and get the distance and meshid for each individual ray casted.

We can output the contents of the results vector to stdout.

// Print results vector (vector<RayResult>)
const int start_range = 15;
const int end_range = 20;
std::cout << "[";
for (int i = start_range; i < end_range; i++) {
auto result = (*results)[i];
std::cout << "(" << result.distance << ", " << result.meshid << ")";
if (i < end_range - 1) {
std::cout << ", ";
}
}
std::cout << "]" << std::endl;

After using the view analysis results, its resources must be relinquished.

//
// Memory resource cleanup.
//
// destroy vector<RayResult>
if (results) {
delete results;
}

From here, please review the example at Raytracer teardown for instructions
on how to free the remainder of the resources used for the view analysis –
which are the (vector<HF::Geometry::MeshInfo> *) and (HF::Raytracer::EmbreeRayTracer *) instances.

>>> LoadOBJ loaded mesh successfully into loaded_obj at address 00000293CC9C8290, code: 1
>>> CreateRaytracer created EmbreeRayTracer successfully into bvh at address 00000293C3012D20, code: 1
>>> [(-1, -1), (-1, -1), (15.8334, 0), (-1, -1), (-1, -1)]

Definition at line 106 of file view_analysis_C.cpp.

References ConvertRawFloatArrayToPoints(), and HF::Exceptions::OK.

+ Here is the call graph for this function: