// Copyright (c) 2000, 2001, 2002, 2003 by David Scherer and others. // See the file license.txt for complete license terms. // See the file authors.txt for a complete list of contributors. #include #include #include "util/errors.hpp" #include "util/gl_enable.hpp" #include "python/slice.hpp" #include "python/curve.hpp" #include #include #include #include // Recall that the default constructor for object() is a reference to None. namespace cvisual { namespace python { curve::curve() : antialias( true), radius(0.0), sides(4) { for (size_t i=0; iradius = radius; } void curve::set_antialias( bool aa) { this->antialias = aa; } bool curve::degenerate() const { return count < 2; } bool curve::monochrome(float* tcolor, size_t pcount) { rgb first_color( tcolor[0], tcolor[1], tcolor[2]); size_t nn; for(nn=0; nn diff && rhs*frac > diff; } } // !namespace (unnamed) vector curve::get_center() const { // TODO: Optimize this by only recomputing the center when the checksum of // the entire object has changed. // TODO: Only add the "optimization" if the checksum is actually faster than // computing the average value every time... if (degenerate()) return vector(); vector ret; const double* pos_i = pos.data(); const double* pos_end = pos.end(); while (pos_i < pos_end) { ret.x += pos_i[0]; ret.y += pos_i[1]; ret.z += pos_i[2]; pos_i += 3; } ret /= count; return ret; } void curve::gl_pick_render( const view& scene) { // Aack, I can't think of any obvious optimizations here. // But since Visual 3 didn't permit picking of curves, omit for now. // We can't afford it; serious impact on performance. //gl_render( scene); } void curve::grow_extent( extent& world) { if (degenerate()) return; const double* pos_i = pos.data(); const double* pos_end = pos.end(); if (radius == 0.0) for ( ; pos_i < pos_end; pos_i += 3) world.add_point( vector(pos_i)); else for ( ; pos_i < pos_end; pos_i += 3) world.add_sphere( vector(pos_i), radius); world.add_body(); } bool curve::adjust_colors( const view& scene, float* tcolor, size_t pcount) { rgb rendered_color; bool mono = monochrome(tcolor, pcount); if (mono) { // We can get away without using a color array. rendered_color = rgb( tcolor[0], tcolor[1], tcolor[2]); if (scene.anaglyph) { if (scene.coloranaglyph) rendered_color.desaturate().gl_set(opacity); else rendered_color.grayscale().gl_set(opacity); } else rendered_color.gl_set(opacity); } else { glEnableClientState( GL_COLOR_ARRAY); if (scene.anaglyph) { // Must desaturate or grayscale the color. for (size_t i = 0; i < pcount; ++i) { rendered_color = rgb( tcolor[3*i], tcolor[3*i+1], tcolor[3*i+2]); if (scene.coloranaglyph) rendered_color = rendered_color.desaturate(); else rendered_color = rendered_color.grayscale(); tcolor[3*i] = rendered_color.red; tcolor[3*i+1] = rendered_color.green; tcolor[3*i+2] = rendered_color.blue; } } } return mono; } namespace { template struct converter { T data[3]; }; } // !namespace (anonymous) void curve::thickline( const view& scene, double* spos, float* tcolor, size_t pcount, double scaled_radius) { float *cost = curve_sc; float *sint = cost + sides; vector lastA; // unit vector of previous segment if (pcount < 2) return; bool closed = vector(&spos[0]) == vector(&spos[(pcount-1)*3]); size_t vcount = pcount*2 - closed; // The number of vertices along each edge of the curve std::vector projected( vcount*sides ); std::vector normals( vcount*sides ); std::vector light( vcount*sides ); // pos and color iterators const double* v_i = spos; const float* c_i = tcolor; size_t i = closed ? 0 : sides; bool mono = adjust_colors( scene, tcolor, pcount); for (size_t corner=0; corner < pcount; ++corner, v_i += 3, c_i += 3) { vector current( &v_i[0] ); vector next, A, bisecting_plane_normal; double sectheta; if (corner != pcount-1) { next = vector( &v_i[3] ); // The next vector in spos A = (next - current).norm(); if (!A) { if (corner == 0) { const double* tv_i = v_i; for (size_t tcorner=0; tcorner < pcount; ++tcorner, tv_i += 3) { A = (vector( &tv_i[3] ) - current).norm(); if (!A) continue; } if (!A) { // all the points of this curve are at the same location; abort return; } lastA = A; } else { A = lastA; } } bisecting_plane_normal = (A + lastA).norm(); if (!bisecting_plane_normal) { //< Exactly 180 degree bend bisecting_plane_normal = vector(0,0,1).cross(A); if (!bisecting_plane_normal) bisecting_plane_normal = vector(0,1,0).cross(A); } sectheta = bisecting_plane_normal.dot( lastA ); if (sectheta) sectheta = 1.0 / sectheta; } if (corner == 0) { vector y = vector(0,1,0); vector x = A.cross(y).norm(); if (!x) { x = A.cross( vector(0, 0, 1)).norm(); } y = x.cross(A).norm(); if (!x || !y || x == y) { std::ostringstream msg; msg << "Degenerate curve case! please report the following " "information to visualpython-users@lists.sourceforge.net: "; msg << "current:" << current << " next:" << next << " A:" << A << " x:" << x << " y:" << y << std::endl; VPYTHON_WARNING( msg.str()); } // scale radii x *= scaled_radius; y *= scaled_radius; for (size_t a=0; a < sides; a++) { vector rel = x*sint[a] + y*cost[a]; // first point is "up" normals[a+i] = rel.norm(); projected[a+i] = current + rel; if (!mono) light[a+i] = rgb( c_i ); if (!closed) { // Cap start of curve projected[a] = current; normals[a] = -A; if (!mono) light[a] = light[a+i]; } } i += sides; } else { double Adot = A.dot(next - current); for (size_t a=0; a < sides; a++) { vector prev_start = projected[i+a-sides]; vector rel = current - prev_start; double t = rel.dot(lastA); if (corner != pcount-1 && sectheta > 0.0) { double t1 = (rel.dot(bisecting_plane_normal)) * sectheta; t1 = std::max( t1, t - Adot ); t = std::max( 0.0, std::min( t, t1 ) ); } vector prev_end = prev_start + t*lastA; projected[i+a] = prev_end; normals[i+a] = normals[i+a-sides]; if (!mono) light[i+a] = rgb( c_i ); if (corner != pcount-1) { vector next_start = prev_end - 2*(prev_end-current).dot(bisecting_plane_normal)*bisecting_plane_normal; rel = next_start - current; projected[i+a+sides] = next_start; normals[i+a+sides] = (rel - A.dot(next_start-current)*A).norm(); if (!mono) light[i+a+sides] = light[i+a]; } else if (!closed) { // Cap end of curve for (size_t a=0; a < sides; a++) { projected[i+a+sides] = current; normals[i+a+sides] = lastA; if (!mono) light[i+a+sides] = light[a+i]; } } } i += 2*sides; } lastA = A; } if (closed) { // Connect the end of the curve to the start... can be ugly because the basis has gotten // twisted around! size_t i = (vcount - 1)*sides; for(size_t a=0; a max_extent[j]) max_extent[j] = *pos_i; pos_i++; } min_extent -= vector(radius,radius,radius); max_extent += vector(radius,radius,radius); out.translate( vector(.5,.5,.5) ); out.scale( vector(1,1,1) * (.999 / (v.gcf * std::max(max_extent.x-min_extent.x, std::max(max_extent.y-min_extent.y, max_extent.z-min_extent.z)))) ); out.translate( -.5 * v.gcf * (min_extent + max_extent) ); } } } // !namespace cvisual::python