// -*- C++ -*-
// $RCSfile: amtriangleiterator.C,v $
// $Revision: 1.8 $
// $Author: langer $
// $Date: 2000/11/01 17:07:44 $
/* This software was produced by NIST, an agency of the U.S. government,
* and by statute is not subject to copyright in the United States.
* Recipients of this software assume all responsibilities associated
* with its operation, modification and maintenance. However, to
* facilitate maintenance we ask that before distributing modifed
* versions of this software, you first contact the authors at
* oof_manager@ctcms.nist.gov.
*/
// Iterate over pixels underlying a triangle
// Usage:
// Triangle tri = ...;
// for(AMTriangleIterator i(tri); !i.end(); ++i) {
// Cell_coordinate pixel = tri[i];
// ...
// }
#include "adaptmesh.h"
#include "amtriangle.h"
#include "amtriangleiterator.h"
#include "goof.h"
// Divide the triangle into two triangles with a horizontal division
// through one vertex. Loop over the bottom half first.
AMTriangleIterator::AMTriangleIterator(const AMTriangle &triangle)
: btm_done(0), // has the bottom half been done?
top_done(0), // has the top half been done?
maxx(triangle.mesh->goof->query_width()-1),
maxy(triangle.mesh->goof->query_height()-1)
{
// find botttom node
btmnode = triangle.node[0];
double btmy = btmnode->coord().y;
int btmi = 0;
for(int i=1; i<3; i++) {
double y = triangle.node[i]->coord().y;
if(y < btmy) {
btmy = y;
btmnode = triangle.node[i];
btmi = i;
}
}
// find middle node and top nodes
int n1 = (btmi+1)%3;
int n2 = (btmi+2)%3;
if(triangle.node[n1]->coord().y < triangle.node[n2]->coord().y) {
midnode = triangle.node[n1];
topnode = triangle.node[n2];
}
else {
midnode = triangle.node[n2];
topnode = triangle.node[n1];
}
// is the middle node to the right or left of the line joining top and btm?
midright = ((midnode->coord() - btmnode->coord()) %
(topnode->coord() - btmnode->coord()) > 0);
// find equations for sides
if(btmnode->coord().y == midnode->coord().y)
btm_done = 1; // there is no bottom triangle
else {
// compute slopes of edges, assuming that the midpoint is on the left side
lslope_btm = (midnode->coord().x - btmnode->coord().x)
/ (midnode->coord().y - btmnode->coord().y);
rslope_btm = (topnode->coord().x - btmnode->coord().x)
/ (topnode->coord().y - btmnode->coord().y);
if(midright) { // wrong assumption!
double temp = lslope_btm;
lslope_btm = rslope_btm;
rslope_btm = temp;
}
if(rslope_btm == lslope_btm)
btm_done = 1;
}
if(midnode->coord().y == topnode->coord().y)
top_done = 1; // there is no top triangle
else {
// compute slopes of edges, assuming that the midpoint is on the left side
lslope_top = (topnode->coord().x - midnode->coord().x)
/ (topnode->coord().y - midnode->coord().y);
rslope_top = (topnode->coord().x - btmnode->coord().x)
/ (topnode->coord().y - btmnode->coord().y);
if(midright) { // wrong assumption
double temp = rslope_top;
rslope_top = lslope_top;
lslope_top = temp;
}
if(rslope_top == lslope_top)
top_done = 1;
}
if(!btm_done) {
current.y = (short) btmnode->coord().y;
current.x = (short) xmin_btm(current.y);
current_xmax = (int) xmax_btm(current.y);
}
else {
current.y = (short) midnode->coord().y;
current.x = (short) xmin_top(current.y);
current_xmax = (int) xmax_top(current.y);
}
}
double AMTriangleIterator::xmin_btm(double y) const {
// Find the minimum x value for a pixel within the bottom triangle
// at this y. Use the equation for the left edge of the triangle,
// but be careful if the edge has an end within this row of pixels
// (ie between y and y+1).
double min;
double yint; // y at minimum value of x
if(lslope_btm > 0) {
// edge
// y+1 ---------/------------------------------------/-------
// / yint is the lowest y /
// / for the edge in this row B
// y ------/-------------------------------------+---------
// xmin xmin when btm node
// is within the row
yint = y;
if(y < btmnode->coord().y) // bottom node is in this row of pixels
yint = btmnode->coord().y;
}
else { // lslope_btm < 0
yint = y + 1;
if(!midright && midnode->coord().y < yint) // left edge ends within this row
yint = midnode->coord().y;
}
min = floor(btmnode->coord().x + lslope_btm*(yint - btmnode->coord().y));
if(min < 0) min = 0;
if(min > maxx) min = maxx;
return min;
}
double AMTriangleIterator::xmax_btm(double y) const {
double max;
double yint;
if(rslope_btm > 0) {
yint = y + 1;
if(midright && midnode->coord().y < yint) // midnode is within this row
yint = midnode->coord().y;
}
else { // rslope_btm < 0
yint = y;
if(y < btmnode->coord().y) // bottom node is in this row of pixels
yint = btmnode->coord().y;
}
max = floor(btmnode->coord().x + rslope_btm*(yint - btmnode->coord().y));
if(max > maxx) max = maxx;
if(max < 0) max = 0;
return max;
}
double AMTriangleIterator::xmin_top(double y) const {
double min;
double yint;
if(lslope_top > 0) {
yint = y;
if(!midright && midnode->coord().y > yint) // middle node is within this row
yint = midnode->coord().y;
}
else { // lslope_top < 0
yint = y + 1;
if(topnode->coord().y < y + 1)
yint = topnode->coord().y;
}
min = floor(topnode->coord().x + lslope_top*(yint - topnode->coord().y));
if(min < 0) min = 0;
if(min > maxx) min = maxx;
return min;
}
double AMTriangleIterator::xmax_top(double y) const {
double max;
double yint;
if(rslope_top > 0) {
yint = y + 1;
if(topnode->coord().y < y + 1)
yint = topnode->coord().y;
}
else { // rslope_top < 0
yint = y;
if(midright && midnode->coord().y > y)
yint = midnode->coord().y;
}
max = floor(topnode->coord().x + rslope_top*(yint - topnode->coord().y));
if(max > maxx) max = maxx;
if(max < 0) max = 0;
return max;
}
void AMTriangleIterator::operator++() {
if(!btm_done) {
current.x++; // next pixel in this row
if(current.x > current_xmax) { // done with this row?
current.y++; // go up to next row
if(current.y > maxy || current.y > topnode->coord().y) {
top_done = btm_done = 1;
}
else if(current.y > midnode->coord().y) { // done with btm triangle?
btm_done = 1;
// initial settings for top triangle
current.x = (short) xmin_top(current.y);
current_xmax = (int) xmax_top(current.y);
}
else { // new row in bottom triangle
current.x = (short) xmin_btm(current.y);
current_xmax = (int) xmax_btm(current.y);
}
}
}
else if(!top_done) {
current.x++;
if(current.x > current_xmax) { // done with this row?
current.y++;
if(current.y > maxy || current.y > topnode->coord().y)
top_done = 1;
else {
current.x = (short) xmin_top(current.y);
current_xmax = (int) xmax_top(current.y);
}
}
}
}
Cell_coordinate AMTriangle::operator[](AMTriangleIterator &iter) const {
return iter.current;
}
syntax highlighted by Code2HTML, v. 0.9.1