vtkDataArray *
avtPolarCoordinatesExpression::DeriveVariable(vtkDataSet *in_ds, int currentDomainsIndex)
{
    vtkIdType npts = in_ds->GetNumberOfPoints();
    vtkDataArray *rv = CreateArrayFromMesh(in_ds);
    rv->SetNumberOfComponents(3);
    rv->SetNumberOfTuples(npts);
    bool in3D = 
            (GetInput()->GetInfo().GetAttributes().GetSpatialDimension() == 3);
    for (vtkIdType i = 0 ; i < npts ; i++)
    {
        double pt[3];
        in_ds->GetPoint(i, pt);
        
        double r = sqrt(pt[0]*pt[0] + pt[1]*pt[1] + pt[2]*pt[2]);
        rv->SetComponent(i, 0, r);

        double theta = atan2(pt[1], pt[0]);
        rv->SetComponent(i, 1, theta);

        double phi = 0.;
        if (in3D && r != 0)
            phi = acos(pt[2] / r);
        else
            phi = 0;
        rv->SetComponent(i, 2, phi);
    }
    
    return rv;
}
vtkDataArray *
avtFacePlanarity::DeriveVariable(vtkDataSet *in_ds, int currentDomainsIndex)
{
    vtkDataArray *arr = CreateArrayFromMesh(in_ds);
    vtkIdType ncells = in_ds->GetNumberOfCells();
    arr->SetNumberOfTuples(ncells);

    for (vtkIdType i = 0 ; i < ncells ; i++)
    {
        vtkCell *cell = in_ds->GetCell(i);
        double vol = GetFacePlanarityForCell(cell, takeRel);
        arr->SetTuple1(i, vol);
    }

    return arr;
}
vtkDataArray *
avtRevolvedVolume::DeriveVariable(vtkDataSet *in_ds)
{
    vtkDataArray *arr = CreateArrayFromMesh(in_ds);
    vtkIdType ncells = in_ds->GetNumberOfCells();
    arr->SetNumberOfTuples(ncells);

    for (vtkIdType i = 0 ; i < ncells ; i++)
    {
        vtkCell *cell = in_ds->GetCell(i);
        double vol = GetZoneVolume(cell);
        arr->SetTuple1(i, vol);
    }

    return arr;
}
vtkDataArray *
avtMinCornerArea::DeriveVariable(vtkDataSet *in_ds, int currentDomainsIndex)
{
    vtkDataArray *arr = CreateArrayFromMesh(in_ds);
    vtkIdType ncells = in_ds->GetNumberOfCells();
    arr->SetNumberOfTuples(ncells);

    for (vtkIdType i = 0 ; i < ncells ; i++)
    {
        vtkCell *cell = in_ds->GetCell(i);
        double mcar = GetMinCornerArea(cell);
        arr->SetTuple1(i, mcar);
    }

    return arr;
}
vtkDataArray *
avtSurfaceNormalExpression::RectilinearDeriveVariable(vtkRectilinearGrid *rgrid)
{
    int dims[3];
    rgrid->GetDimensions(dims);
    int nMatch = 0;
    bool doX = (dims[0] == 1);
    if (doX)
        nMatch++;
    bool doY = (dims[1] == 1);
    if (doY)
        nMatch++;
    bool doZ = (dims[2] == 1);
    if (doZ)
        nMatch++;
    if (nMatch == 0)
    {
        EXCEPTION2(ExpressionException, outputVariableName, "Can not determine "
                   "surface normals for a 3D data set.");
    }
    if (nMatch > 1)
    {
        EXCEPTION2(ExpressionException, outputVariableName, "Can not determine "
                   "surface normals for lines and vertices.");
    }
    vtkDataArray *n = CreateArrayFromMesh(rgrid);
    n->SetNumberOfComponents(3);
    vtkIdType ntuples = (isPoint ? rgrid->GetNumberOfPoints() 
                           : rgrid->GetNumberOfCells());
    n->SetNumberOfTuples(ntuples);
    double norm[3] = { 0, 0, 0 };
    if (doX)  
        norm[0] = 1.0;
    if (doY)  
        norm[1] = 1.0;
    if (doZ)  
        norm[2] = 1.0;
    for (vtkIdType i = 0 ; i < ntuples ; i++)
    {
        n->SetTuple(i, norm);
    }

    return n;
}
vtkDataArray *
avtCylindricalCoordinatesExpression::DeriveVariable(vtkDataSet *in_ds)
{
    vtkIdType npts = in_ds->GetNumberOfPoints();
    vtkDataArray *rv = CreateArrayFromMesh(in_ds);
    rv->SetNumberOfComponents(3);
    rv->SetNumberOfTuples(npts);
    for (vtkIdType i = 0 ; i < npts ; i++)
    {
        double pt[3];
        in_ds->GetPoint(i, pt);
        
        double r = sqrt(pt[0]*pt[0] + pt[1]*pt[1]);
        rv->SetComponent(i, 0, r);

        double theta = atan2(pt[1], pt[0]);
        rv->SetComponent(i, 1, theta);

        rv->SetComponent(i, 2, pt[2]);
    }
    
    return rv;
}
vtkDataArray *
avtCylindricalRadiusExpression::DeriveVariable(vtkDataSet *in_ds, int currentDomainsIndex)
{
    vtkIdType npts = in_ds->GetNumberOfPoints();
    vtkDataArray *rv = CreateArrayFromMesh(in_ds);
    rv->SetNumberOfComponents(1);
    rv->SetNumberOfTuples(npts);
    
    // The cylindrical radius is:
    // norm(pt) * sin(acos(dot(pt,axis)/(norm(pt)*norm(axis))))
    // 
    
    avtVector ax_vec(axisVector);
    ax_vec.normalize();
    
    for (vtkIdType i = 0 ; i < npts ; i++)
    {
        double pt[3];
        in_ds->GetPoint(i, pt);
        avtVector pt_vec(pt);
        
        double pt_vec_mag = pt_vec.norm();
     
        // dot prod of normalized vecs to get angle
        double dp = pt_vec * ax_vec;
        dp = dp / pt_vec_mag ;
        double ang = acos(dp);
        
        // find the orthogonal component
        avtVector proj = pt_vec * sin(ang);
        double r = proj.norm();
        rv->SetComponent(i, 0, r);
    }

    return rv;
}
vtkDataArray *
avtUnaryMathExpression::DeriveVariable(vtkDataSet *in_ds, int currentDomainsIndex)
{
    int  i;

    vtkDataArray *cell_data = NULL;
    vtkDataArray *point_data = NULL;
    vtkDataArray *data = NULL;

    if (activeVariable == NULL)
    {
        //
        // This hack is getting more and more refined.  This situation comes up
        // when we don't know what the active variable is (mostly for the
        // constant creation filter).  We probably need more infrastructure
        // to handle this.
        // Iteration 1 of this hack said take any array.
        // Iteration 2 said take any array that isn't vtkGhostLevels, etc.
        // Iteration 3 says take the first scalar array if one is available,
        //             provided that array is not vtkGhostLevels, etc.
        //             This is because most constants we create are scalar.
        //
        // Note: this hack used to be quite important because we would use
        // the resulting array to determine the centering of the variable.
        // Now we use the IsPointVariable() method.  So this data array is
        // only used to get the type.
        //
        int ncellArray = in_ds->GetCellData()->GetNumberOfArrays();
        for (i = 0 ; i < ncellArray ; i++)
        {
            vtkDataArray *candidate = in_ds->GetCellData()->GetArray(i);
            if (strstr(candidate->GetName(), "vtk") != NULL)
                continue;
            if (strstr(candidate->GetName(), "avt") != NULL)
                continue;
            if (candidate->GetNumberOfComponents() == 1)
            {
                // Definite winner
                cell_data = candidate;
                break;
            }
            else
                // Potential winner -- keep looking
                cell_data = candidate;
        }
        int npointArray = in_ds->GetPointData()->GetNumberOfArrays();
        for (i = 0 ; i < npointArray ; i++)
        {
            vtkDataArray *candidate = in_ds->GetPointData()->GetArray(i);
            if (strstr(candidate->GetName(), "vtk") != NULL)
                continue;
            if (strstr(candidate->GetName(), "avt") != NULL)
                continue;
            if (candidate->GetNumberOfComponents() == 1)
            {
                // Definite winner
                point_data = candidate;
                break;
            }
            else
                // Potential winner -- keep looking
                point_data = candidate;
        }

        if (cell_data != NULL && cell_data->GetNumberOfComponents() == 1)
        {
            data = cell_data;
            centering = AVT_ZONECENT;
        }
        else if (point_data != NULL && point_data->GetNumberOfComponents()== 1)
        {
            data = point_data;
            centering = AVT_NODECENT;
        }
        else if (cell_data != NULL)
        {
            data = cell_data;
            centering = AVT_ZONECENT;
        }
        else
        {
            data = point_data;
            centering = AVT_NODECENT;
        }
    } 
    else
    {
        cell_data = in_ds->GetCellData()->GetArray(activeVariable);
        point_data = in_ds->GetPointData()->GetArray(activeVariable);

        if (cell_data != NULL)
        {
            data = cell_data;
            centering = AVT_ZONECENT;
        }
        else
        {
            data = point_data;
            centering = AVT_NODECENT;
        }
    }

    //
    // Set up a VTK variable reflecting the calculated variable
    //
    int ncomps = 0;
    int nvals = 0;
    if (FilterCreatesSingleton())
        nvals = 1;
    else if (activeVariable == NULL || data == NULL)
        nvals = (IsPointVariable() ? in_ds->GetNumberOfPoints() 
                                   : in_ds->GetNumberOfCells());
    else
        nvals = data->GetNumberOfTuples();

    vtkDataArray *dv = NULL;
    if (data == NULL)
    {
        //
        // We could not find a single array.  We must be doing something with
        // the mesh.
        //
        ncomps = 1;
        dv = CreateArrayFromMesh(in_ds);
    }
    else
    {
        ncomps = data->GetNumberOfComponents();
        dv = CreateArray(data);
    }

    if (data == NULL)
    {
        if (! NullInputIsExpected())
        {
            // One way to get here is to have vtkPolyData Curve plots.
            EXCEPTION2(ExpressionException, outputVariableName,
                 "An internal error occurred when "
                 "trying to calculate your expression.  Please contact a "
                 "VisIt developer.");
        }
    }

    int noutcomps = GetNumberOfComponentsInOutput(ncomps);
    dv->SetNumberOfComponents(noutcomps);
    dv->SetNumberOfTuples(nvals);

    //
    // Should we send in ncomps or noutcomps?  They are the same number 
    // unless the derived type re-defined GetNumberOfComponentsInOutput.
    // If it did, it probably doesn't matter.  If not, then it is the same
    // number.  So send in the input.  Really doesn't matter.
    //
    cur_mesh = in_ds;
    DoOperation(data, dv, ncomps, nvals);
    cur_mesh = NULL;

    return dv;
}
avtDataRepresentation *
avtNeighborExpression::ExecuteData(avtDataRepresentation *in_dr)
{
    //
    // Get the VTK data set.
    //
    vtkDataSet *in_ds = in_dr->GetDataVTK();

    // Let's get the points from the input dataset.
    vtkPoints *pts = NULL;
    switch (in_ds->GetDataObjectType())
    {
      // Easily done, just grab them.
      case VTK_UNSTRUCTURED_GRID:
      case VTK_POLY_DATA:
      case VTK_STRUCTURED_GRID:
        pts = ((vtkPointSet *) in_ds)->GetPoints();
        break;
 
      // If they're any other type of grid, this filter shouldn't be used
      default:
        EXCEPTION0(ImproperUseException);
    }
 
    vtkIdType nPoints = pts->GetNumberOfPoints();

    // A neighbor filter would require the existance of neighbors
    if (nPoints < 2)
        EXCEPTION0(ImproperUseException);

    // Now that we've done all of our checks for improper use,
    // let's allocate for our needs
    vtkPolyData *results = vtkPolyData::New();
    vtkCellArray *verts = vtkCellArray::New();
    vtkDataArray *data = CreateArrayFromMesh(in_ds);

    results->SetPoints(pts);

    data->SetNumberOfComponents(1);
    data->SetNumberOfTuples(nPoints);

    double bounds[6];
    in_ds->GetBounds(bounds);

    // Create the point locator
    vtkPointLocator *ptLoc = vtkPointLocator::New();
    ptLoc->SetDataSet(in_ds);
    ptLoc->BuildLocator();

    for (vtkIdType id = 0; id < nPoints; id++)
    {
        // Build the vertex list
        vtkVertex *v = vtkVertex::New();
        v->Initialize( 1, &id, pts);
        verts->InsertNextCell(v);
        v->Delete();

        // And at the same time, set the distance data
        double coords[3];
        pts->GetPoint(id, coords);

        // Find the closest 2 points, since the closest is itself of course.
        vtkIdList *closeId = vtkIdList::New();
        ptLoc->FindClosestNPoints(2, coords, closeId);

        double nearCoords[3];
        pts->GetPoint(closeId->GetId(1), nearCoords);

        double distance = (coords[0]-nearCoords[0])*(coords[0]-nearCoords[0]) +
                         (coords[1]-nearCoords[1])*(coords[1]-nearCoords[1]) +  
                         (coords[2]-nearCoords[2])*(coords[2]-nearCoords[2]);
        distance=sqrt(distance);

        data->SetTuple1(id, distance);
        closeId->Delete();
    }
 
    data->SetName("neighbor");
    results->GetPointData()->AddArray(data);
    results->GetPointData()->SetActiveScalars("neighbor");

    results->SetVerts(verts);


    //
    // Make our best attempt at maintaining our extents.
    //
    double exts[2];
    double range[2];
    data->GetRange(range, 0);
    exts[0] = range[0];
    exts[1] = range[1];

    GetOutput()->GetInfo().GetAttributes().GetOriginalDataExtents()->Merge(exts);

    data->Delete();
    verts->Delete();
    pts->Delete();

    avtDataRepresentation *out_dr = new avtDataRepresentation(results,
        in_dr->GetDomain(), in_dr->GetLabel());

    results->Delete();

    return out_dr;    
}
vtkDataArray *
avtRevolvedSurfaceArea::DeriveVariable(vtkDataSet *in_ds, int currentDomainsIndex)
{
    //
    // Create a copy of the input with each zone's id number.  This will be 
    // used to match up the line segments with the zones they came from later.
    //
    vtkDataSet *tmp_ds = in_ds->NewInstance();
    tmp_ds->ShallowCopy(in_ds);
    vtkIdType n_orig_cells = tmp_ds->GetNumberOfCells();
    vtkIntArray *iarray = vtkIntArray::New();
    iarray->SetName("_rsa_ncells");
    iarray->SetNumberOfTuples(n_orig_cells);
    for (vtkIdType i = 0 ; i < n_orig_cells ; i++)
        iarray->SetValue(i, i);
    tmp_ds->GetCellData()->AddArray(iarray);
    iarray->Delete();

    //
    // Create the boundary edges.
    //
    vtkGeometryFilter *geomFilter = vtkGeometryFilter::New();
    vtkVisItFeatureEdges *boundaryFilter = vtkVisItFeatureEdges::New();
    vtkPolyData *allLines = NULL;

    avtDataAttributes &atts = GetInput()->GetInfo().GetAttributes();
    if (atts.GetTopologicalDimension() == 2)
    {
        geomFilter->SetInputData(tmp_ds);
        boundaryFilter->BoundaryEdgesOn();
        boundaryFilter->FeatureEdgesOff();
        boundaryFilter->NonManifoldEdgesOff();
        boundaryFilter->ManifoldEdgesOff();
        boundaryFilter->ColoringOff();
    
        boundaryFilter->SetInputConnection(geomFilter->GetOutputPort());
        vtkStreamingDemandDrivenPipeline::SetUpdateGhostLevel(boundaryFilter->GetInformation(), 2);
        boundaryFilter->Update();

        allLines = boundaryFilter->GetOutput();
    }
    else if (tmp_ds->GetDataObjectType() == VTK_POLY_DATA)
    {
        allLines = (vtkPolyData *) tmp_ds;
    }
    else
    {
        geomFilter->SetInputData(tmp_ds);
        allLines = geomFilter->GetOutput();
    }

    //
    // Remove ghost zones.
    //
    vtkDataSetRemoveGhostCells *gzFilter = vtkDataSetRemoveGhostCells::New();
    gzFilter->SetInputData(allLines);
    gzFilter->Update();
    vtkDataSet *ds_1d_nogz = gzFilter->GetOutput();

    // We need line segment polydata, and should have it by now.
    if (ds_1d_nogz->GetDataObjectType() != VTK_POLY_DATA)
    {
        tmp_ds->Delete();
        geomFilter->Delete();
        gzFilter->Delete();
        boundaryFilter->Delete();
        debug1 << "ERROR:Did not get polydata from ghost zone filter output\n";
        return NULL;
    }
    vtkPolyData *pd_1d_nogz = (vtkPolyData*)ds_1d_nogz;

    //
    // Only some of the zones are actually external to the domain and
    // contribute to the resolved surface area.  These zones are exactly
    // the zones in pd_1d_nogz.  But we need to create an output that is
    // sized for the input mesh.  So construct an array with all 0's (the
    // zones that aren't on the exterior contribute 0 surface area) and then
    // add in the contributions from the zones on the exterior.
    //
    vtkDataArray *arr = CreateArrayFromMesh(in_ds);
    arr->SetNumberOfTuples(n_orig_cells);
    for (vtkIdType i = 0 ; i < n_orig_cells ; i++)
        arr->SetTuple1(i, 0.);

    vtkIdType ncells = pd_1d_nogz->GetNumberOfCells();
    vtkIntArray *orig_cells = (vtkIntArray *)
                            pd_1d_nogz->GetCellData()->GetArray("_rsa_ncells");
    for (vtkIdType i = 0 ; i < ncells ; i++)
    {
        vtkCell *cell = pd_1d_nogz->GetCell(i);
        double area = GetCellArea(cell);
        int orig_cell = orig_cells->GetValue(i);
        double orig_area = arr->GetTuple1(orig_cell);
        double new_area = area + orig_area;
        arr->SetTuple1(orig_cell, new_area);
    }

    //
    // Clean up.
    //
    tmp_ds->Delete();
    geomFilter->Delete();
    gzFilter->Delete();
    boundaryFilter->Delete();

    return arr;
}