/* See {rdo_solid.h}. */ #define rdo_solid_C_COPYRIGHT "Copyright © 2008 Danillo Pereira and J. Stolfi, UNICAMP" /* Last edited on 2024-12-21 11:51:21 by stolfi */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include vec_typeimpl(solid_vec_t, solid_vec, solid_t); void rdo_solid_write(FILE *wr, solid_t *sd) { fprintf(wr, "%-12s ", sd->name); if (sd->type == solid_type_Ovoid) { fprintf(wr, "Ovoid"); } else if (sd->type == solid_type_Brick) { fprintf(wr, "Brick"); } else { demand(FALSE, "invalid solid object type"); fprintf(wr, "!!!"); } int k; for (k = 0; k < 2; k++) { r3_gen_print(wr, &(sd->corner[k]), "%9.3f", " ( ", " ", " )"); } } solid_t rdo_solid_read(FILE *rd) { solid_t sd; /* Read the solid object's group name: */ sd.name = fget_string(rd); /* Read the solid object's type: */ char *str = fget_string(rd); if (strcmp(str, "Ovoid") == 0) { sd.type = solid_type_Ovoid; } else if (strcmp(str, "Brick") == 0) { sd.type = solid_type_Brick; } else { demand(FALSE, "invalid solid object type"); sd.type = solid_type_None; } /* Read the solid object's corners: */ int k; for (k = 0; k < 2; k++) { fget_skip_spaces_and_match(rd, "("); sd.corner[k] = fget_r3(rd); fget_skip_spaces_and_match(rd, ")"); } return sd; } #define solid_vec_FILE_VERSION "2008-07-14" void rdo_solid_vec_write(FILE *wr, solid_vec_t *sds) { /* Writes the header line: */ filefmt_write_header(wr, "solid_vec_t", solid_vec_FILE_VERSION); /* Here we should write comments provided by the client. */ /* Writes the number of solids: */ fprintf(wr, "num_solids = %d\n", sds->ne); /* Writes the solids: */ int i; for(i = 0; i < sds->ne; i++) { rdo_solid_write(wr, &(sds->e[i])); fprintf(wr, "\n"); } /* Writes the footer line, and synchronizes the file: */ filefmt_write_footer(wr, "solid_vec_t"); fflush(wr); } solid_vec_t rdo_solid_vec_read(FILE *rd) { /* Reads the header line, and comments (if any): */ filefmt_read_header(rd, "solid_vec_t", solid_vec_FILE_VERSION); char *cmt = filefmt_read_comment(rd, '#'); free(cmt); //por enquanto. /* Reads the number of solids in the list: */ int nob = nget_int32(rd, "num_solids"); fget_eol(rd); /* Reads the solids: */ solid_vec_t sds = solid_vec_new(nob); int i; for(i = 0; i < nob; i++) { sds.e[i] = rdo_solid_read(rd); fget_eol(rd); } /* Reads the footer line: */ filefmt_read_footer(rd, "solid_vec_t"); return sds; } void rdo_solid_get_normal(solid_t *sd, point3_t *position, vector3_t *normal) { switch (sd->type) { case solid_type_Ovoid: rdo_solid_get_normal_ovoid(sd->corner, position, normal); break; case solid_type_Brick: rdo_solid_get_normal_brick(sd->corner, position, normal); break; default: /* There should be no other type of intersection: */ assert(FALSE); } } void rdo_solid_get_normal_ovoid(point3_t corner[], point3_t *position, vector3_t *normal) { /* Get the center {ctr} of the ovoid: */ point3_t ctr; r3_mix(+0.5, &(corner[0]), +0.5, &(corner[1]), &ctr); /* Get the semidiameters {rad[0..2]} of the ovoid: */ vector3_t rad; r3_mix(-0.5, &(corner[0]), +0.5, &(corner[1]), &rad); /* Set {normal} to the displacement from {ctr} to {position}: */ r3_sub(position, &ctr, normal); /* Compute the gradient as the displacement divided by {rad} squared: */ int k; for (k = 0; k < 3; k++) { normal->c[k] /= (rad.c[k]*rad.c[k]); } /* Normalize to unit length: */ r3_dir(normal, normal); } void rdo_solid_get_normal_brick(point3_t corner[], point3_t *position, vector3_t *normal) { /* Find the axis {imax} perpendicular to the point's face: */ int imax = -1; double rmax = 0; /* Signed displacement with max abs value. */ int i; for (i = 0; i < 3; i++) { //* Get box data about axis {i}: */ double c0 = corner[0].c[i]; /* One end of the box. */ double c1 = corner[1].c[i]; /* The other end. */ double center = (c0 + c1)/2; /* Box center. */ double radius = fabs(c0 - c1)/2; /* Box half-width. */ assert(radius > 0); double dist = position->c[i] - center; /* Displacement from center to point. */ double r = dist/radius; /* Relative displacement. */ if (fabs(r) > fabs(rmax)) { rmax = r; imax = i; } } assert(rmax != 0); /* Otherwise the point is the box center! */ assert(imax >= 0); /* Ditto. */ /* The normal is the direction of axis {imax} with the sign of {rmax}: */ (*normal) = (vector3_t){{ 0,0,0 }}; normal->c[imax] = copysign(1.0, rmax); } void rdo_solid_vec_bounding_box(solid_vec_t *sds, point3_t corner[]) { int k; for (k = 0; k < 3; k++) { corner[0].c[k] = +INF; corner[1].c[k] = -INF; } int i; for (i = 0; i < sds->ne; i++) { solid_t *sdP = &(sds->e[i]); for (k = 0; k < 3; k++) { double c0 = sdP->corner[0].c[k]; double c1 = sdP->corner[1].c[k]; double cLo = fmin(c0,c1); double cHi = fmax(c0,c1); if (cLo < corner[0].c[k]) { corner[0].c[k] = cLo; } if (cHi > corner[1].c[k]) { corner[1].c[k] = cHi; } } } /* Enlarge the box a tiny bit: */ for (k = 0; k < 3; k++) { double c0 = corner[0].c[k]; double c1 = corner[1].c[k]; if (c1 > c0) { double dk = fmax(fabs(c0), fabs(c1)); corner[0].c[k] += 1.0e-8*dk; corner[1].c[k] -= 1.0e-8*dk; } } }