Attached goes new code with the changes I mentioned. Only tested once on a
simple case.
Should give you an idea of what I meant with Saturdays mail.
Feedback is as always very welcome.
I will now test it more thoroughly and then move on to revamp the first
step too, which is severely flawed still.
I have yet to come up with a more elegant way of checking which 'tiles' our
segment will cross and which not.
Back with more tomorrow.
Mario.
On 23 September 2017 at 20:20, Mario Meissner <mr.rash....@gmail.com> wrote:
> Hello everyone.
>
> I wrote this on my log a few hours ago but I thought it's a good idea to
> go into more detail here since it's major change in direction.
>
> First, I will get rid of the projection structure, which is now just a
> contribution. Its projection is now just something secondary that can be
> used to predict if we need to skip the point or not.
>
> So, my new approach will be clearly separated into three steps:
> -Create a list of contributions. This stage is completely recycled from my
> current code, and for now the methodology to detect points that will
> contribute to our segment will remain the same. It will be the weakest part
> of the implementation once this major revamp is done, and may require some
> work.
> -Compute the boundaries between the contributions. This means computing
> when each contribution starts and ends within the segment. They are stored
> inside the contribution structure.
> -Loop through the contributions and take average density proportional to
> how big each intersection is.
>
> Notice how much simpler the average_density computation is now. Stage two
> is also simple because I have already implemented the intersection function.
>
> As this is a major change it will take me a few days to implement. I've
> spent most of my time today to refactor step 1 to use contributions instead
> of projections. I hope by tomorrow I can send an in-progress version with
> some cases working.
>
> I really think this new version cleans up the mess quite a lot, simplifies
> the concepts, makes it all more readable, and most importantly, will
> support more situations than before, removing several flaws.
>
> Mario.
>
> On 23 September 2017 at 18:01, Mario Meissner <mr.rash....@gmail.com>
> wrote:
>
>> I'm passing two arguments to my segment_density, which are inhit and
>>> outhit points.
>>> I now realize that these are pointers and could change unexpectedly
>>> within the call if we run multiple threads.
>>> How can I make this safe? Should I BU_GET safe heap memory to store the
>>> points for the call, or pass the coordinates one by one as actual numbers?
>>>
>>
>> I guess I should just do the same I did with intersection, since in the
>> end it's the same issue.
>>
>> For debugging purposes I would like to set only one thread for rtweight,
>> how can I do that? The fact that I get 4 or more threads running my
>> segment_density at the same time makes it difficult to track down issues.
>>
>
>
Index: src/rt/rtexample.c
===================================================================
--- src/rt/rtexample.c (リビジョン 70336)
+++ src/rt/rtexample.c (作業コピー)
@@ -1,65 +1,65 @@
/* R T E X A M P L E . C
- * BRL-CAD
- *
- * Copyright (c) 2004-2016 United States Government as represented by
- * the U.S. Army Research Laboratory.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this file; see the file named COPYING for more
- * information.
- */
+* BRL-CAD
+*
+* Copyright (c) 2004-2016 United States Government as represented by
+* the U.S. Army Research Laboratory.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public License
+* version 2.1 as published by the Free Software Foundation.
+*
+* 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this file; see the file named COPYING for more
+* information.
+*/
/** @file rt/rtexample.c
- *
- * This is a heavily commented example of a program that uses librt to
- * shoot a single ray at some geometry in a .g database.
- *
- * The primary BRL-CAD ray-tracing API consists of calls to the
- * function rt_shootray(). This function takes a single argument, the
- * address of a data structure called the "application" structure.
- * This data structure contains crucial information, such as the
- * origin and direction of the ray to be traced, what to do if the ray
- * hits geometry, or what to do if it misses everything. While the
- * application struct is a large and somewhat complex looking, (it is
- * defined in the raytrace.h header) there are really very few items
- * in it which the application programmer must know about. These are:
- *
- * a_rt_i The "raytrace instance" obtained via rt_dirbuild()
- * a_ray The ray origin and direction to be shot
- * a_hit A callback function for when the ray encounters geometry
- * a_miss A callback function for when the ray misses everything
- *
- * Most of the work an application performs will be done in the "hit"
- * routine. This user-supplied routine gets called deep inside the
- * raytracing library via the rt_shootray() function. It is provided
- * with 3 parameters:
- *
- * ap Pointer to the application structure passed to
rt_shootray()
- * PartHeadp List of ray "partitions" which represent geometry hit
- * segp List of ray "segments" that comprised partitions
- *
- * Most applications can ignore the last parameter. The PartHeadp
- * parameter is a linked-list of "partition" structures (defined in
- * the raytrace.h header). It is the job of the "hit" routine to
- * process these ray/object intersections to do the work of the
- * application.
- *
- * This file is part of the default compile in source distributions of
- * BRL-CAD and is usually installed or provided via binary and source
- * distributions. To compile this example from a binary install:
- *
- * cc -I/usr/brlcad/include/brlcad -L/usr/brlcad/lib -o rtexample rtexample.c
-lbu -lrt -lm
- *
- * Jump to the START HERE section below for main().
- */
+*
+* This is a heavily commented example of a program that uses librt to
+* shoot a single ray at some geometry in a .g database.
+*
+* The primary BRL-CAD ray-tracing API consists of calls to the
+* function rt_shootray(). This function takes a single argument, the
+* address of a data structure called the "application" structure.
+* This data structure contains crucial information, such as the
+* origin and direction of the ray to be traced, what to do if the ray
+* hits geometry, or what to do if it misses everything. While the
+* application struct is a large and somewhat complex looking, (it is
+* defined in the raytrace.h header) there are really very few items
+* in it which the application programmer must know about. These are:
+*
+* a_rt_i The "raytrace instance" obtained via rt_dirbuild()
+* a_ray The ray origin and direction to be shot
+* a_hit A callback function for when the ray encounters geometry
+* a_miss A callback function for when the ray misses everything
+*
+* Most of the work an application performs will be done in the "hit"
+* routine. This user-supplied routine gets called deep inside the
+* raytracing library via the rt_shootray() function. It is provided
+* with 3 parameters:
+*
+* ap Pointer to the application structure passed to rt_shootray()
+* PartHeadp List of ray "partitions" which represent geometry hit
+* segp List of ray "segments" that comprised partitions
+*
+* Most applications can ignore the last parameter. The PartHeadp
+* parameter is a linked-list of "partition" structures (defined in
+* the raytrace.h header). It is the job of the "hit" routine to
+* process these ray/object intersections to do the work of the
+* application.
+*
+* This file is part of the default compile in source distributions of
+* BRL-CAD and is usually installed or provided via binary and source
+* distributions. To compile this example from a binary install:
+*
+* cc -I/usr/brlcad/include/brlcad -L/usr/brlcad/lib -o rtexample rtexample.c
-lbu -lrt -lm
+*
+* Jump to the START HERE section below for main().
+*/
#include "common.h"
@@ -67,264 +67,549 @@
#include <math.h>
#include <string.h>
#include <stdio.h>
+#include <string.h>
#include "vmath.h" /* vector math macros */
#include "raytrace.h" /* librt interface definitions */
-/**
- * rt_shootray() was told to call this on a hit.
- *
- * This callback routine utilizes the application structure which
- * describes the current state of the raytrace.
- *
- * This callback routine is provided a circular linked list of
- * partitions, each one describing one in and out segment of one
- * region for each region encountered.
- *
- * The 'segs' segment list is unused in this example.
- */
+fastf_t MARGIN = 0.0001;
+struct density_point {
+ struct bu_list l;
+ point_t point;
+ fastf_t density;
+};
+
+struct density_vector {
+ struct bu_list l;
+ vect_t vector;
+ point_t origin;
+ fastf_t factor;
+};
+
+/* One possible way of defining vectors is doing it over already defined
points.
+Here we can specify what kind of transition happens between two points. */
+struct transition {
+ struct bu_list l;
+ struct density_point * origin;
+ struct density_point * termination;
+ fastf_t coefficient;
+};
+
+struct contribution {
+ struct density_point * density_point;
+ point_t projection_point;
+ vect_t projection_vect;
+ fastf_t inhit_dist;
+ //fastf_t prev_dist;
+ fastf_t projection_dist;
+ point_t left_boundary;
+ point_t right_boundary;
+};
+
+struct intersection_t {
+ int intersect;
+ point_t intersection_point;
+};
+
+struct density_point * user_plist;
+const int MAX_POINTS = 99;
+
+int compare_dpoints(const void *, const void *);
+fastf_t absolute(fastf_t value) {
+ if (value < 0) {
+ return -value;
+ }
+ else {
+ return value;
+ }
+}
+
+/* Check if c is between a and b */
+int isBetween(point_t c, point_t a, point_t b) {
+ vect_t c_minus_a, b_minus_a;
+ VSUB2(c_minus_a, c, a);
+ VSUB2(b_minus_a, b, a);
+ fastf_t dot_product = VDOT(c_minus_a, b_minus_a);
+ fastf_t squared_length_ba = MAGNITUDE(b_minus_a)*MAGNITUDE(b_minus_a);
+ return dot_product > 0 && dot_product < squared_length_ba;
+}
+
+void compute_intersection(struct intersection_t * intersection, point_t
line_point0,
+ point_t line_point1, point_t plane_point, vect_t plane_normal) {
+ fastf_t epsilon = 1e-6;
+ fastf_t fac;
+ vect_t u, w;
+
+ VSUB2(u, line_point1, line_point0);
+ fastf_t dot = VDOT(plane_normal, u);
+ if (abs(dot) > epsilon) {
+ intersection->intersect = 1;
+ VSUB2(w, line_point0, plane_point);
+ fac = -VDOT(plane_normal, w) / dot;
+ VSCALE(u, u, fac);
+ VADD2(intersection->intersection_point, line_point0, u);
+ intersection->intersect = 1;
+ }
+ else {
+ intersection->intersect = 0;
+ }
+}
+
+
+/*
+Reads density points from stdin and stores them into density_point structs
+Receives the head of a bu_list of density_point structs
+and appends all points generated during the reading session to the list
+Returns the number of successfully read points
+*/
int
-hit(struct application *ap, struct partition *PartHeadp, struct seg
*UNUSED(segs))
+read_density_points(struct density_point * dplist_head)
{
- /* iterating over partitions, this will keep track of the current
- * partition we're working on.
- */
- struct partition *pp;
- /* will serve as a pointer for the entry and exit hitpoints */
- struct hit *hitp;
+ /* If we are given no proper bu_lists ... */
+ if (!BU_LIST_IS_INITIALIZED(&(dplist_head->l))) {
+ bu_log("No valid head of bu_list has been provided.\n");
+ /* Maybe also check if bu_list is of correct type? */
+ }
- /* will serve as a pointer to the solid primitive we hit */
- struct soltab *stp;
+ /* Local variables */
+ int count = 0;
+ struct density_point * entry;
+ short int origin;
+ short int termination;
+ fastf_t coeff;
+ int correct;
+ int reading = 1;
+ char input[30];
+ struct density_point * entries[99]; //Hardcoded max for now
- /* will contain surface curvature information at the entry */
- struct curvature cur = RT_CURVATURE_INIT_ZERO;
+
/* Outer loop. We come back here whenever user inputs wrong format
+
and until he types exit */
+ while (reading) {
+ bu_log("Please insert density points in the format:");
+ bu_log(" X Y Z density_value(in g / cm3). \n");
+ bu_log("Type 'exit' to finish. \n");
+ correct = 1;
- /* will contain our hit point coordinate */
- point_t pt;
+ /* Inner loop. While user inputs points in correct format we
loop here */
+ while (correct) {
+ bu_fgets(input, 30, stdin);
+ /* If user typed continue we need to exit both loops */
+ if (!strcmp(input, "exit\n")) {
+ bu_log("Finished inserting points.\n");
+ correct = 0;
+ reading = 0;
+ }
- /* will contain normal vector where ray enters geometry */
- vect_t inormal;
+ /* User didn't type continue */
+ else {
- /* will contain normal vector where ray exits geometry */
- vect_t onormal;
+ /* Set up new entry */
+ BU_GET(entry, struct density_point);
- /* iterate over each partition until we get back to the head.
- * each partition corresponds to a specific homogeneous region of
- * material.
- */
- for (pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw) {
+ /* If the input is in correct format we load it
and continue */
+ if (sscanf(input, "%lf %lf %lf %lf",
&entry->point[0],
+ &entry->point[1], &entry->point[2],
&entry->density) == 4) {
+ BU_LIST_PUSH(&(dplist_head->l),
&(entry->l));
+ entries[count] = entry;
+ count++;
+ }
- /* print the name of the region we hit as well as the name of
- * the primitives encountered on entry and exit.
- */
- bu_log("\n--- Hit region %s (in %s, out %s)\n",
- pp->pt_regionp->reg_name,
- pp->pt_inseg->seg_stp->st_name,
- pp->pt_outseg->seg_stp->st_name );
+ /* Otherwise we dont load it and jump back to
outer loop
+ to print usage again */
+ else {
+ correct = 0;
+ }
+ }
+ } /* Close inner loop */
+ } /* Close outer loop */
- /* entry hit point, so we type less */
- hitp = pp->pt_inhit;
- /* construct the actual (entry) hit-point from the ray and the
- * distance to the intersection point (i.e., the 't' value).
- */
- VJOIN1(pt, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir);
- /* primitive we encountered on entry */
- stp = pp->pt_inseg->seg_stp;
+ return count;
+}
- /* compute the normal vector at the entry point, flipping the
- * normal if necessary.
- */
- RT_HIT_NORMAL(inormal, hitp, stp, &(ap->a_ray), pp->pt_inflip);
+point_t * intersection(point_t p0, point_t p1, point_t p_co, vect_t p_no) {
+ fastf_t epsilon = 1e-6;
+ fastf_t fac;
+ vect_t u, w;
+ point_t intersect;
+ VSUB2(u, p1, p0);
+ fastf_t dot = VDOT(p_no, u);
+ if (absolute(dot) > epsilon) {
+ VSUB2(w, p0, p_co);
+ fac = -VDOT(p_no, w) / dot;
+ VSCALE(u, u, fac);
+ VADD2(intersect, p0, u);
+ return &intersect;
+ }
+ else {
+ return NULL;
+ }
+}
- /* print the entry hit point info */
- rt_pr_hit(" In", hitp);
- VPRINT( " Ipoint", pt);
- VPRINT( " Inormal", inormal);
- /* This next macro fills in the curvature information which
- * consists on a principle direction vector, and the inverse
- * radii of curvature along that direction and perpendicular
- * to it. Positive curvature bends toward the outward
- * pointing normal.
- */
- RT_CURVATURE(&cur, hitp, pp->pt_inflip, stp);
+/* Receives a segment and returns average density
+Uses memory pointer to user point list */
+fastf_t segment_density(point_t inhit, point_t outhit) {
- /* print the entry curvature information */
- VPRINT("PDir", cur.crv_pdir);
- bu_log(" c1=%g\n", cur.crv_c1);
- bu_log(" c2=%g\n", cur.crv_c2);
+ /* If no points, mass is 0 */
+ if (BU_LIST_IS_EMPTY(&(user_plist->l))) {
+ bu_log("No points were provided, thus object has no mass.\n");
+ return 0;
+ }
- /* exit point, so we type less */
- hitp = pp->pt_outhit;
+ /* DEBUG */
+ //VPRINT("inhit", inhit);
+ //VPRINT("outhit", outhit);
- /* construct the actual (exit) hit-point from the ray and the
- * distance to the intersection point (i.e., the 't' value).
- */
- VJOIN1(pt, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir);
+ /* If there is only one point we skip the paraphernalia */
+ if (bu_list_len(&user_plist->l) == 1) {
+ struct density_point * dp;
+ dp = (struct density_point *)user_plist->l.forw;
+ return dp->density;
+ }
- /* primitive we exited from */
- stp = pp->pt_outseg->seg_stp;
+ vect_t full_segment_vector;
+ VSUB2(full_segment_vector, outhit, inhit);
+ fastf_t full_segment_length = MAGNITUDE(full_segment_vector);
- /* compute the normal vector at the exit point, flipping the
- * normal if necessary.
- */
- RT_HIT_NORMAL(onormal, hitp, stp, &(ap->a_ray), pp->pt_outflip);
+ /* Projections Loop prep */
+ struct contribution * new_contribution;
+ struct density_point * dpoint_iter_ext; //External
+ struct density_point * dpoint_iter_mid; //Middle
+ struct density_point * dpoint_iter_int; //Internal
+ vect_t dpoint_vect;
+ vect_t prev_to_current_vect;
+ vect_t dpoint_to_projection_vect;
+ vect_t temp;
+ vect_t paral_projection; //I need this to VPROJECT doesn't complain?
+ int i = 0;
+ int is_valid;
- /* print the exit hit point info */
- rt_pr_hit(" Out", hitp);
- VPRINT( " Opoint", pt);
- VPRINT( " Onormal", onormal);
- }
+ /* Bu_calloc has given me some problems, so temporary hardcoded max */
+ /* FIXME: I should be allocating space dynamically */
+ struct contribution * contrib_array[99];
- /* A more complicated application would probably fill in a new
- * local application structure and describe, for example, a
- * reflected or refracted ray, and then call rt_shootray() for
- * those rays.
- */
+ /* Loop through points and project them onto segment if they need to be
*/
+ for (BU_LIST_FOR(dpoint_iter_ext, density_point, &(user_plist->l))) {
+ is_valid = 1;
+ BU_GET(new_contribution, struct contribution);
- /* Hit routine callbacks generally return 1 on hit or 0 on miss.
- * This value is returned by rt_shootray().
- */
- return 1;
+ /* TEST */
+ VSET(new_contribution->right_boundary, 0.0, 0.0, 0.0);
+
+ /* Create userpoint vector */
+ VSUB2(dpoint_vect, dpoint_iter_ext->point, inhit);
+ new_contribution->density_point = dpoint_iter_ext;
+ /* Project vector onto segment and compute absolute point of
the projection.
+ This will be necessary to evaluate if this contribution will
contribute or not. */
+ VPROJECT(dpoint_vect, full_segment_vector,
+ new_contribution->projection_vect, paral_projection);
+ VADD2(new_contribution->projection_point,
new_contribution->projection_vect, inhit);
+ new_contribution->inhit_dist =
MAGNITUDE(new_contribution->projection_vect);
+ //bu_log("inhit_dist: %lf \n", new_projection->inhit_dist);
+ /* Compute distance to the projection */
+ VSUB2(dpoint_to_projection_vect,
new_contribution->density_point->point,
+ new_contribution->projection_point);
+ new_contribution->projection_dist =
MAGNITUDE(dpoint_to_projection_vect);
+
+ /* Check if we need to project or not based on distance to all
other points */
+ for (BU_LIST_FOR(dpoint_iter_mid, density_point,
&(user_plist->l))) {
+ VSUB2(temp, new_contribution->projection_point,
dpoint_iter_mid->point);
+ /* If distance to some user point is shorter than to
the origin then we need to check boundaries */
+ if (dpoint_iter_ext != dpoint_iter_mid &&
+ MAGNITUDE(temp) <
new_contribution->projection_dist) {
+
+ /* If we are here it means the projection has
closer neighbor than original,
+ we now check if intersection falls inside
segment and has closer neighbor.
+ Also it should not be our first point. */
+ if (i > 0) {
+ //puts("array pointer bigger than
zero");
+ vect_t prev_to_curr;
+ point_t plane_point;
+ struct contribution * previous =
contrib_array[i - 1];
+ //VPRINT("previous",
previous->original->point);
+ //VPRINT("current",
new_projection->original->point);
+ //puts("read current and previous, now
computing plane");
+ VSUB2(prev_to_curr,
new_contribution->density_point->point, previous->density_point->point);
+ struct intersection_t * intersection;
+ BU_GET(intersection, struct
intersection_t);
+ vect_t intersect_to_original;
+ fastf_t distance_to_originals;
+ VSCALE(prev_to_curr, prev_to_curr, 0.5);
+ //puts("computing intersection");
+ VADD2(plane_point,
previous->projection_point, prev_to_curr);
+ compute_intersection(intersection,
inhit, outhit, plane_point, prev_to_curr);
+ if (intersection->intersect == 0) {
+ bu_log("Error: No intersection
happened. \n");
+ return 0;
+ }
+ VSUB2(intersect_to_original,
intersection->intersection_point, new_contribution->density_point->point);
+ BU_FREE(intersection, struct
intersection_t);
+ distance_to_originals =
MAGNITUDE(intersect_to_original);
+ /* Look for points closer to
intersection than the two original ones */
+ //puts("arrived at inner for");
+ for (BU_LIST_FOR(dpoint_iter_int,
density_point, &(user_plist->l))) {
+ VSUB2(temp,
new_contribution->projection_point, dpoint_iter_int->point);
+ if (dpoint_iter_ext !=
dpoint_iter_int &&
+ MAGNITUDE(temp) <
distance_to_originals + MARGIN) {
+ //puts("inner loop
found something");
+ /* FIXME: Deallocate
space we used for new_projection */
+ is_valid = 0;
+ //bu_log("Skipped
projection. \n");
+ break;
+ }
+ }
+
+ }
+ }
+ /* We are at the end of one iteration on the outer
check loop.
+ If we detected a nonvalid point we should stop looking.
*/
+ if (!is_valid) break;
+ }
+ if (is_valid) {
+
+ /* FIXME: Maybe I don't need all this
+ if (i == 0) {
+ new_contribution->prev_dist =
new_contribution->inhit_dist;
+ }
+ else {
+ VSUB2(prev_to_current_vect,
new_contribution->projection_vect,
+ contrib_array[i - 1]->projection);
+ new_contribution->prev_dist =
MAGNITUDE(prev_to_current_vect);
+ }
+ */
+ contrib_array[i] = new_contribution;
+ i++;
+ /* DEBUG */
+ //VPRINT("projection vector", new_projection->vect);
+ }
+
+ }
+
+ /* Sort projection list based on distance to inhit */
+ /* DEBUG */
+ //puts("Unordered Projection distances:");
+ for (int i = 0; i < i; i++) {
+ //bu_log("Point at distance %lf \n",
contrib_array[i]->inhit_dist);
+ }
+
+ qsort(contrib_array, i, sizeof(struct contribution *), compare_dpoints);
+
+ /* DEBUG */
+ //puts("Ordered projection distances:");
+ for (int i = 0; i < i; i++) {
+ //bu_log("Point at distance %lf \n",
contrib_array[i]->inhit_dist);
+ }
+
+ int num_contributions = i;
+
+ /* STAGE TWO: COMPUTE BOUNDARIES */
+
+ /* First contribution starts at inhit */
+ VMOVE(contrib_array[0]->left_boundary, inhit);
+ /* Go through remaining points (second to last) and compute boundary to
it's left neigbor */
+ vect_t curr_to_prev;
+ point_t plane_point;
+ struct intersection_t * intersection;
+ for (i = 1; i < num_contributions; i++) {
+ /* This will be the boundary between previous contribution and
the current one */
+ BU_GET(intersection, struct intersection_t);
+ /* Compute the vector that connects the two points */
+ VSUB2(curr_to_prev, contrib_array[i-1]->density_point->point,
+ contrib_array[i]->density_point->point);
+ /* Divide it in half and add it to the current to get the
middle point between them */
+ VSCALE(curr_to_prev, curr_to_prev, 0.5);
+ VADD2(plane_point, contrib_array[i]->density_point->point,
curr_to_prev);
+ /* Get the intersection and check if it's correct */
+ compute_intersection(intersection, inhit, outhit, plane_point,
curr_to_prev);
+ if (intersection->intersect == 0) {
+ bu_log("No intersection happened while calculating
boundaries, aborting.\n ");
+ return 0;
+ }
+ /* Copy the data to out contributions structures */
+ VMOVE(contrib_array[i]->left_boundary,
intersection->intersection_point);
+ VMOVE(contrib_array[i - 1]->right_boundary,
intersection->intersection_point);
+ }
+ /* Add the outhit point as right boundary for the last point */
+ VMOVE(contrib_array[i-1]->right_boundary, outhit);
+
+
+ /* STAGE THREE: COMPUTE MASS ACCORDING TO CONTRIBUTION DISTRIBUTION */
+ vect_t contribution_segment;
+ fastf_t average_density, contribution_segment_len;
+ average_density = 0.0;
+
+
+ /* Loop through contributions and compute average density */
+ for (int i = 0; i<num_contributions; i++) {
+ VSUB2(contribution_segment, contrib_array[i]->left_boundary,
contrib_array[i]->right_boundary);
+ contribution_segment_len = MAGNITUDE(contribution_segment);
+ average_density += contrib_array[i]->density_point->density *
contribution_segment_len / full_segment_length;
+ }
+ return average_density;
}
+int
+hit(struct application *ap, struct partition *PartHeadp, struct seg
*UNUSED(segs))
+{
+ struct partition *pp;
+ struct hit *hitp;
+ struct soltab *stp;
+ struct curvature cur = RT_CURVATURE_INIT_ZERO;
+ point_t pt;
+ vect_t inormal;
+ vect_t onormal;
+
+ /* Area that the ray covers, in mm^2 */
+ const fastf_t RAY_AREA = 0.2 * 0.2; //0.2cm height, 0.2cm width
+
+ for (pp = PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw) {
+ bu_log("\n--- Hit region %s (in %s, out %s)\n",
+ pp->pt_regionp->reg_name,
+ pp->pt_inseg->seg_stp->st_name,
+ pp->pt_outseg->seg_stp->st_name);
+
+ hitp = pp->pt_inhit;
+
+ VJOIN1(pt, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir);
+
+ stp = pp->pt_inseg->seg_stp;
+ RT_HIT_NORMAL(inormal, hitp, stp, &(ap->a_ray), pp->pt_inflip);
+
+ rt_pr_hit(" In", hitp);
+ VPRINT(" Ipoint", pt);
+ VPRINT(" Inormal", inormal);
+
+ hitp = pp->pt_outhit;
+
+ VJOIN1(pt, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir);
+
+ stp = pp->pt_outseg->seg_stp;
+ RT_HIT_NORMAL(onormal, hitp, stp, &(ap->a_ray), pp->pt_outflip);
+
+ rt_pr_hit(" Out", hitp);
+ VPRINT(" Opoint", pt);
+ VPRINT(" Onormal", onormal);
+
+ /* Now we compute the total mass this element saw while
crossing the region */
+ fastf_t mass, volume, length, avg_density;
+
+ /*Here we query the avg density of a segment */
+ avg_density = segment_density(pp->pt_inhit->hit_point,
pp->pt_outhit->hit_point);
+
+ /* Get the length */
+ length = pp->pt_outhit->hit_dist - pp->pt_inhit->hit_dist;
+ length = length / 10.0; //mm to cm
+
+ /*We also need to know the volume */
+ volume = length * RAY_AREA;
+
+ mass = volume * avg_density;
+ bu_log(" Segment length: %lf cm, volume crossed: %lf \n",
length, volume);
+ bu_log(" Average density through the segment: %lf \n",
avg_density);
+ bu_log(" Mass the ray saw through this region: %lf g \n",
mass);
+ }
+ return 1;
+}
+
+
/**
- * This is a callback routine that is invoked for every ray that
- * entirely misses hitting any geometry. This function is invoked by
- * rt_shootray() if the ray encounters nothing.
- */
+* This is a callback routine that is invoked for every ray that
+* entirely misses hitting any geometry. This function is invoked by
+* rt_shootray() if the ray encounters nothing.
+*/
int
miss(struct application *UNUSED(ap))
{
- bu_log("missed\n");
- return 0;
+ bu_log("missed\n");
+ return 0;
}
-
-/**
- * START HERE
- *
- * This is where it all begins.
- */
int
main(int argc, char **argv)
{
- /* Every application needs one of these. The "application"
- * structure carries information about how the ray-casting should
- * be performed. Defined in the raytrace.h header.
- */
- struct application ap;
+ /* Prepare user point list and let user fill it */
+ BU_GET(user_plist, struct density_point);
+ BU_LIST_INIT(&(user_plist->l));
+ struct transition * trans_list;
+ BU_GET(trans_list, struct transition);
+ BU_LIST_INIT(&(trans_list->l));
+ read_density_points(user_plist);
- /* The "raytrace instance" structure contains definitions for
- * librt which are specific to the particular model being
- * processed. One copy exists for each model. Defined in
- * the raytrace.h header and is returned by rt_dirbuild().
- */
- static struct rt_i *rtip;
+ //DEBUG
+ struct density_point * user_plist_iter;
+ struct transition * trans_iter;
+ puts("Main after user input. These are the loaded points:");
+ for (BU_LIST_FOR(user_plist_iter, density_point, &(user_plist->l))) {
+ VPRINT("density_point", user_plist_iter->point);
+ }
+ for (BU_LIST_FOR(trans_iter, transition, &(trans_list->l))) {
+ VPRINT("transition origin: ", trans_iter->origin->point);
+ VPRINT("transition termination: ",
trans_iter->termination->point);
+ printf("With coeff: %lf", trans_iter->coefficient);
- /* optional parameter to rt_dirbuild() that can be used to capture
- * a title if the geometry database has one set.
- */
- char title[1024] = {0};
+ }
+ //END DEBUG
- /* Check for command-line arguments. Make sure we have at least a
- * geometry file and one geometry object on the command line.
- */
- if (argc < 3) {
- bu_exit(1, "Usage: %s model.g objects...\n", argv[0]);
- }
- /* Load the specified geometry database (i.e., a ".g" file).
- * rt_dirbuild() returns an "instance" pointer which describes the
- * database to be raytraced. It also gives you back the title
- * string if you provide a buffer. This builds a directory of the
- * geometry (i.e., a table of contents) in the file.
- */
- rtip = rt_dirbuild(argv[1], title, sizeof(title));
- if (rtip == RTI_NULL) {
- bu_exit(2, "Building the database directory for [%s] FAILED\n",
argv[1]);
- }
+ /* Prep raytracing and launch one ray */
+ struct application ap;
+ static struct rt_i *rtip;
+ char title[1024] = { 0 };
+ if (argc < 3) {
+ bu_exit(1, "Usage: %s model.g objects...\n", argv[0]);
+ }
- /* Display the geometry database title obtained during
- * rt_dirbuild if a title is set.
- */
- if (title[0]) {
- bu_log("Title:\n%s\n", title);
- }
+ rtip = rt_dirbuild(argv[1], title, sizeof(title));
+ if (rtip == RTI_NULL) {
+ bu_exit(2, "Building the database directory for [%s] FAILED\n",
argv[1]);
+ }
- /* Walk the geometry trees. Here you identify any objects in the
- * database that you want included in the ray trace by iterating
- * of the object names that were specified on the command-line.
- */
- while (argc > 2) {
- if (rt_gettree(rtip, argv[2]) < 0)
- bu_log("Loading the geometry for [%s] FAILED\n", argv[2]);
- argc--;
- argv++;
- }
+ if (title[0]) {
+ bu_log("Title:\n%s\n", title);
+ }
- /* This next call gets the database ready for ray tracing. This
- * causes some values to be precomputed, sets up space
- * partitioning, computes bounding volumes, etc.
- */
- rt_prep_parallel(rtip, 1);
+ while (argc > 2) {
+ if (rt_gettree(rtip, argv[2]) < 0)
+ bu_log("Loading the geometry for [%s] FAILED\n",
argv[2]);
+ argc--;
+ argv++;
+ }
- /* initialize all values in application structure to zero */
- RT_APPLICATION_INIT(&ap);
+ rt_prep_parallel(rtip, 1);
+ RT_APPLICATION_INIT(&ap);
+ ap.a_rt_i = rtip;
+ ap.a_onehit = 0;
+ VSET(ap.a_ray.r_pt, -2000, -2000, -2000);
+ VSET(ap.a_ray.r_dir, 1.0, 1.0, 1.0);
+ VPRINT("Pnt", ap.a_ray.r_pt);
+ VPRINT("Dir", ap.a_ray.r_dir);
+ ap.a_hit = hit;
+ ap.a_miss = miss;
+ (void)rt_shootray(&ap);
- /* your application uses the raytrace instance containing the
- * geometry we loaded. this describes what we're shooting at.
- */
- ap.a_rt_i = rtip;
+ return 0;
+}
- /* stop at the first point of intersection or shoot all the way
- * through (defaults to 0 to shoot all the way through).
- */
- ap.a_onehit = 0;
- /* Set the ray start point and direction rt_shootray() uses these
- * two to determine what ray to fire. In this case we simply
- * shoot down the z axis toward the origin from 10 meters away.
- *
- * It's worth nothing that librt assumes units of millimeters.
- * All geometry is stored as millimeters regardless of the units
- * set during editing. There are libbu routines for performing
- * unit conversions if desired.
- */
- VSET(ap.a_ray.r_pt, 0.0, 0.0, 10000.0);
- VSET(ap.a_ray.r_dir, 0.0, 0.0, -1.0);
+int compare_dpoints(const void *a, const void *b) {
+ struct contribution *x = *(struct contribution **)a;
+ struct contribution *y = *(struct contribution **)b;
+ return x->inhit_dist - y->inhit_dist;
+}
- /* Simple debug printing */
- VPRINT("Pnt", ap.a_ray.r_pt);
- VPRINT("Dir", ap.a_ray.r_dir);
- /* This is what callback to perform on a hit. */
- ap.a_hit = hit;
- /* This is what callback to perform on a miss. */
- ap.a_miss = miss;
-
- /* Shoot the ray. */
- (void)rt_shootray(&ap);
-
- /* A real application would probably set up another ray and fire
- * again or do something a lot more complex in the callbacks.
- */
-
- return 0;
-}
-
/*
- * Local Variables:
- * mode: C
- * tab-width: 8
- * indent-tabs-mode: t
- * c-file-style: "stroustrup"
- * End:
- * ex: shiftwidth=4 tabstop=8
- */
+* Local Variables:
+* mode: C
+* tab-width: 8
+* indent-tabs-mode: t
+* c-file-style: "stroustrup"
+* End:
+* ex: shiftwidth=4 tabstop=8
+*/
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
BRL-CAD Developer mailing list
brlcad-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/brlcad-devel