diff options
Diffstat (limited to 'graphics/epix/facet.cc')
-rw-r--r-- | graphics/epix/facet.cc | 505 |
1 files changed, 505 insertions, 0 deletions
diff --git a/graphics/epix/facet.cc b/graphics/epix/facet.cc new file mode 100644 index 0000000000..3b808d1b59 --- /dev/null +++ b/graphics/epix/facet.cc @@ -0,0 +1,505 @@ +/* + * facet.cc -- Utility classes for shaded surface plotting + * + * This file is part of ePiX, a C++ library for creating high-quality + * figures in LaTeX + * + * Version 1.2.0-2 + * Last Change: September 26, 2007 + */ + +/* + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 + * Andrew D. Hwang <rot 13 nujnat at zngupf dot ubylpebff dot rqh> + * Department of Mathematics and Computer Science + * College of the Holy Cross + * Worcester, MA, 01610-2395, USA + */ + +/* + * ePiX is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ePiX 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 General Public + * License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ePiX; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <cmath> + +#include "constants.h" +#include "errors.h" +#include "functions.h" + +#include "frame.h" +#include "camera.h" + +#include "Color.h" +#include "paint_style.h" + +#include "facet.h" + +namespace ePiX { + + facet::facet(P f(double, double), + double u0, double v0, + double du, double dv, + const unsigned int N1, const unsigned int N2) + : m_tint(the_paint_style().fill_color()), + m_line(the_paint_style().line_pen()), + m_fill(the_paint_style().fill_flag()), + pt1(f(u0, v0)), + pt2(f(u0 + N1*du, v0)), + pt3(f(u0 + N1*du, v0 + N2*dv)), + pt4(f(u0, v0 + N2*dv)), + center(0.25*(pt1 + pt2 + pt3 + pt4)), + direction(center-cam().viewpt()), + distance(norm(direction)) + { + perp = ((pt2 - center)*(pt1 - center)); + + if (norm(perp) < EPIX_EPSILON) + perp = (pt4 - center)*(pt3 - center); + + perp *= recip(norm(perp)); + + // bottom edge + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + i*du, v0)); + + // right edge + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0 + N1*du, v0 + j*dv)); + + // top edge (backward) + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + (N1-i)*du, v0 + N2*dv)); + + // left edge (downward) + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0, v0 + (N2-j)*dv)); + + bd.close().fill(!m_tint.is_unset()); + } + + + // facet constructor for f(double, double, double) + facet::facet(P f(double, double, double), + double u0, double v0, double w0, + double du, double dv, double dw, + const unsigned int N1, const unsigned int N2) + : m_tint(the_paint_style().fill_color()), + m_line(the_paint_style().line_pen()), + m_fill(the_paint_style().fill_flag()), + pt1(f(u0, v0, w0)) + { + if (du == 0) // (y,z) + { + // bottom edge + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0, v0 + i*dv, w0)); + + // right edge + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0, v0 + N1*dv, w0 + j*dw)); + + // top edge (backward) + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0, v0 + (N1-i)*dv, w0 + N2*dw)); + + // left edge (downward) + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0, v0, w0 + (N2-j)*dw)); + + // use corners to approximate distance to camera + pt2 = f(u0, v0 + N1*dv, w0); + pt3 = f(u0, v0 + N1*dv, w0 + N2*dw); + pt4 = f(u0, v0, w0 + N2*dw); + } + + else if (dv == 0) // (x,z) + { + // bottom edge + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + i*du, v0, w0)); + + // right edge + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0 + N1*du, v0, w0 + j*dw)); + + // top edge (backward) + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + (N1-i)*du, v0, w0 + N2*dw)); + + // left edge (downward) + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0, v0, w0 + (N2-j)*dw)); + + // use corners to approximate distance to camera + pt2 = f(u0 + N1*du, v0, w0); + pt3 = f(u0 + N1*du, v0, w0 + N2*dw); + pt4 = f(u0, v0, w0 + N2*dw); + } + + else if (dw == 0) // (x,y) + { + // bottom edge + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + i*du, v0, w0)); + + // right edge + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0 + N1*du, v0 + j*dv, w0)); + + // top edge (backward) + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + (N1-i)*du, v0 + N2*dv, w0)); + + // left edge (downward) + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0, v0 + (N2-j)*dv, w0)); + + // use corners to approximate distance to camera + pt2 = f(u0 + N1*du, v0, w0); + pt3 = f(u0 + N1*du, v0 + N2*dv, w0); + pt4 = f(u0, v0 + N2*dv, w0); + } + + else + epix_error("Bad call to facet constructor"); // exits + + bd.close().fill(!m_tint.is_unset()); + + center = 0.25*(pt1 + pt2 + pt3 + pt4); + + direction = center-cam().viewpt(); + distance = norm(direction); + + perp = ((pt2 - center)*(pt1 - center)); + + if (norm(perp) < EPIX_EPSILON) + perp = (pt4 - center)*(pt3 - center); + + perp *= recip(norm(perp)); + + } // end of facet(f(double, double, double), ...) + + + // for surface of rotation + facet::facet(double f(double), double g(double), + double u0, double v0, + double du, double dv, + const unsigned int N1, const unsigned int N2, + const frame& coords) + : m_tint(the_paint_style().fill_color()), + m_line(the_paint_style().line_pen()), + m_fill(the_paint_style().fill_flag()), + pt1(f(u0)*coords.sea() + + g(u0)*Cos(v0)*coords.sky() + + g(u0)*Sin(v0)*coords.eye()), + pt2(f(u0 + N1*du)*coords.sea() + + g(u0 + N1*du)*Cos(v0)*coords.sky() + + g(u0 + N1*du)*Sin(v0)*coords.eye()), + pt3(f(u0 + N1*du)*coords.sea() + + g(u0 + N1*du)*Cos(v0 + N2*dv)*coords.sky() + + g(u0 + N1*du)*Sin(v0 + N2*dv)*coords.eye()), + pt4(f(u0)*coords.sea() + + g(u0)*Cos(v0 + N2*dv)*coords.sky() + + g(u0)*Sin(v0 + N2*dv)*coords.eye()), + center(0.25*(pt1 + pt2 + pt3 + pt4)), + direction(center-cam().viewpt()), distance(norm(direction)) + { + perp = ((pt2 - center)*(pt1 - center)); + + if (norm(perp) < EPIX_EPSILON) + perp = (pt4 - center)*(pt3 - center); + + perp *= recip(norm(perp)); + + // bottom edge + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + i*du)*coords.sea() + + g(u0 + i*du)*Cos(v0)*coords.sky() + + g(u0 + i*du)*Sin(v0)*coords.eye()); + + // right edge + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0 + N1*du)*coords.sea() + + g(u0 + N1*du)*Cos(v0 + j*dv)*coords.sky() + + g(u0 + N1*du)*Sin(v0 + j*dv)*coords.eye()); + + // top edge (backward) + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + (N1-i)*du)*coords.sea() + + g(u0 + (N1-i)*du)*Cos(v0 + N2*dv)*coords.sky() + + g(u0 + (N1-i)*du)*Sin(v0 + N2*dv)*coords.eye()); + + // left edge (downward) + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0)*coords.sea() + + g(u0)*Cos(v0 + (N2-j)*dv)*coords.sky() + + g(u0)*Sin(v0 + (N2-j)*dv)*coords.eye()); + + bd.close().fill(!m_tint.is_unset()); + } + + //// Color-dependent constructors + facet::facet(P f(double, double), + double u0, double v0, + double du, double dv, + const unsigned int N1, const unsigned int N2, + const Color& tint) + : m_tint(tint), m_line(the_paint_style().line_pen()), + m_fill(the_paint_style().fill_flag()), + pt1(f(u0, v0)), + pt2(f(u0 + N1*du, v0)), + pt3(f(u0 + N1*du, v0 + N2*dv)), + pt4(f(u0, v0 + N2*dv)), + center(0.25*(pt1 + pt2 + pt3 + pt4)), + direction(center-cam().viewpt()), + distance(norm(direction)) + { + perp = ((pt2 - center)*(pt1 - center)); + + if (norm(perp) < EPIX_EPSILON) + perp = (pt4 - center)*(pt3 - center); + + perp *= recip(norm(perp)); + + // bottom edge + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + i*du, v0)); + + // right edge + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0 + N1*du, v0 + j*dv)); + + // top edge (backward) + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + (N1-i)*du, v0 + N2*dv)); + + // left edge (downward) + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0, v0 + (N2-j)*dv)); + + bd.close().fill(!m_tint.is_unset()); + } + + + // facet constructor for f(double, double, double) + facet::facet(P f(double, double, double), + double u0, double v0, double w0, + double du, double dv, double dw, + const unsigned int N1, const unsigned int N2, + const Color& tint) + : m_tint(tint), m_line(the_paint_style().line_pen()), + m_fill(the_paint_style().fill_flag()), + pt1(f(u0, v0, w0)) + { + if (du == 0) // (y,z) + { + // bottom edge + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0, v0 + i*dv, w0)); + + // right edge + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0, v0 + N1*dv, w0 + j*dw)); + + // top edge (backward) + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0, v0 + (N1-i)*dv, w0 + N2*dw)); + + // left edge (downward) + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0, v0, w0 + (N2-j)*dw)); + + // use corners to approximate distance to camera + pt2 = f(u0, v0 + N1*dv, w0); + pt3 = f(u0, v0 + N1*dv, w0 + N2*dw); + pt4 = f(u0, v0, w0 + N2*dw); + } + + else if (dv == 0) // (x,z) + { + // bottom edge + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + i*du, v0, w0)); + + // right edge + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0 + N1*du, v0, w0 + j*dw)); + + // top edge (backward) + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + (N1-i)*du, v0, w0 + N2*dw)); + + // left edge (downward) + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0, v0, w0 + (N2-j)*dw)); + + // use corners to approximate distance to camera + pt2 = f(u0 + N1*du, v0, w0); + pt3 = f(u0 + N1*du, v0, w0 + N2*dw); + pt4 = f(u0, v0, w0 + N2*dw); + } + + else if (dw == 0) // (x,y) + { + // bottom edge + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + i*du, v0, w0)); + + // right edge + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0 + N1*du, v0 + j*dv, w0)); + + // top edge (backward) + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + (N1-i)*du, v0 + N2*dv, w0)); + + // left edge (downward) + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0, v0 + (N2-j)*dv, w0)); + + // use corners to approximate distance to camera + pt2 = f(u0 + N1*du, v0, w0); + pt3 = f(u0 + N1*du, v0 + N2*dv, w0); + pt4 = f(u0, v0 + N2*dv, w0); + } + + else + epix_error("Bad call to facet constructor"); // exits + + bd.close().fill(!m_tint.is_unset()); + + center = 0.25*(pt1 + pt2 + pt3 + pt4); + + direction = center-cam().viewpt(); + distance = norm(direction); + + perp = ((pt2 - center)*(pt1 - center)); + + if (norm(perp) < EPIX_EPSILON) + perp = (pt4 - center)*(pt3 - center); + + perp *= recip(norm(perp)); + + } // end of facet(f(double, double, double), ...) + + + // for surface of rotation + facet::facet(double f(double), double g(double), + double u0, double v0, + double du, double dv, + const unsigned int N1, const unsigned int N2, + const Color& tint, const frame& coords) + : m_tint(tint), m_line(the_paint_style().line_pen()), + m_fill(the_paint_style().fill_flag()), + pt1(f(u0)*coords.sea() + + g(u0)*Cos(v0)*coords.sky() + + g(u0)*Sin(v0)*coords.eye()), + pt2(f(u0 + N1*du)*coords.sea() + + g(u0 + N1*du)*Cos(v0)*coords.sky() + + g(u0 + N1*du)*Sin(v0)*coords.eye()), + pt3(f(u0 + N1*du)*coords.sea() + + g(u0 + N1*du)*Cos(v0 + N2*dv)*coords.sky() + + g(u0 + N1*du)*Sin(v0 + N2*dv)*coords.eye()), + pt4(f(u0)*coords.sea() + + g(u0)*Cos(v0 + N2*dv)*coords.sky() + + g(u0)*Sin(v0 + N2*dv)*coords.eye()), + center(0.25*(pt1 + pt2 + pt3 + pt4)), + direction(center-cam().viewpt()), distance(norm(direction)) + { + perp = ((pt2 - center)*(pt1 - center)); + + if (norm(perp) < EPIX_EPSILON) + perp = (pt4 - center)*(pt3 - center); + + perp *= recip(norm(perp)); + + // bottom edge + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + i*du)*coords.sea() + + g(u0 + i*du)*Cos(v0)*coords.sky() + + g(u0 + i*du)*Sin(v0)*coords.eye()); + + // right edge + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0 + N1*du)*coords.sea() + + g(u0 + N1*du)*Cos(v0 + j*dv)*coords.sky() + + g(u0 + N1*du)*Sin(v0 + j*dv)*coords.eye()); + + // top edge (backward) + for (unsigned int i=0; i<N1; ++i) + bd.pt(f(u0 + (N1-i)*du)*coords.sea() + + g(u0 + (N1-i)*du)*Cos(v0 + N2*dv)*coords.sky() + + g(u0 + (N1-i)*du)*Sin(v0 + N2*dv)*coords.eye()); + + // left edge (downward) + for (unsigned int j=0; j<N2; ++j) + bd.pt(f(u0)*coords.sea() + + g(u0)*Cos(v0 + (N2-j)*dv)*coords.sky() + + g(u0)*Sin(v0 + (N2-j)*dv)*coords.eye()); + + bd.close().fill(!m_tint.is_unset()); + } + + + facet* facet::clone() const + { + return new facet(*this); + } + + double facet::how_far() const { return distance; } + + bool facet::front_facing() const + { + return (-direction|perp) > -EPIX_EPSILON; + } + + // N.B. We assume the fill state is stored by our caller + void facet::draw(int cull) const + { + if (( cull == 1 && front_facing() ) || ( cull == -1 && !front_facing() )) + return; + + // else + Color paint(m_tint); + if (paint.is_unset()) + paint = White(); + + Color ink(m_line.color()); + if (ink.is_unset()) + ink = paint; + + if (m_fill) + { + // calculate cosine^2 of normal angle + // Magic formula (simulated ambient lighting) + const double dens(0.5*(1+pow(perp|(recip(distance)*direction), 2))); + + paint *= dens; + ink *= dens; + } + + bd.draw(paint, pen_data(ink, m_line.width())); + } // end of facet::draw(bool, int) + + + bool by_distance::operator() (const facet& arg1, const facet& arg2) + { + return arg1.how_far() > arg2.how_far(); + } + + bool by_distance::operator() (const facet* arg1, const facet* arg2) + { + return arg1->how_far() > arg2->how_far(); + } +} // end of namespace |