TubeEditorWindow.java :  » Graphic-3D » Art-of-Illusion » ArtOfIllusion » Java Open Source

Java Open Source » Graphic 3D » Art of Illusion 
Art of Illusion » ArtOfIllusion » TubeEditorWindow.java
/* Copyright (C) 2002-2008 by Peter Eastman

   This program 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.

   This program 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. */

package artofillusion;

import artofillusion.object.*;
import artofillusion.texture.*;
import artofillusion.ui.*;
import buoy.event.*;
import buoy.widget.*;

import java.awt.*;

/** The TubeEditorWindow class represents the window for editing Tube objects. */

public class TubeEditorWindow extends CurveEditorWindow
{
  private BCheckBoxMenuItem endsItem[];
  private boolean topology;

  public TubeEditorWindow(EditingWindow parent, String title, ObjectInfo obj, Runnable onClose, boolean allowTopology)
  {
    super(parent, title, obj);
    this.onClose = onClose;
    topology = allowTopology;
    FormContainer content = new FormContainer(new double [] {0, 1}, new double [] {1, 0, 0});
    setContent(content);
    content.setDefaultLayout(new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH, null, null));
    content.add(helpText = new BLabel(), 0, 1, 2, 1);
    content.add(viewsContainer, 1, 0);
    RowContainer buttons = new RowContainer();
    buttons.add(Translate.button("ok", this, "doOk"));
    buttons.add(Translate.button("cancel", this, "doCancel"));
    content.add(buttons, 0, 2, 2, 1, new LayoutInfo());
    content.add(tools = new ToolPalette(1, 7), 0, 0, new LayoutInfo(LayoutInfo.NORTH, LayoutInfo.NONE, null, null));
    EditingTool metaTool, altTool, compoundTool;
    tools.addTool(defaultTool = new ReshapeMeshTool(this, this));
    tools.addTool(new ScaleMeshTool(this, this));
    tools.addTool(new RotateMeshTool(this, this, false));
    tools.addTool(new SkewMeshTool(this, this));
    tools.addTool(new TaperMeshTool(this, this));
    tools.addTool(compoundTool = new MoveScaleRotateMeshTool(this, this));
    if (ArtOfIllusion.getPreferences().getUseCompoundMeshTool())
      defaultTool = compoundTool;
    tools.addTool(metaTool = new MoveViewTool(this));
    tools.addTool(altTool = new RotateViewTool(this));
    tools.setDefaultTool(defaultTool);
    tools.selectTool(defaultTool);
    for (int i = 0; i < theView.length; i++)
    {
      MeshViewer view = (MeshViewer) theView[i];
      view.setMetaTool(metaTool);
      view.setAltTool(altTool);
      view.setScene(parent.getScene(), obj);
    }
    createEditMenu();
    createMeshMenu((Tube) obj.getObject());
    createViewMenu();
    recursivelyAddListeners(this);
    UIUtilities.applyDefaultFont(content);
    UIUtilities.applyDefaultBackground(content);
    Rectangle screenBounds = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
    Dimension windowDim = new Dimension((screenBounds.width*3)/4, (screenBounds.height*3)/4);
    setBounds(new Rectangle((screenBounds.width-windowDim.width)/2, (screenBounds.height-windowDim.height)/2, windowDim.width, windowDim.height));
    tools.requestFocus();
    selected = new boolean [((Tube) obj.getObject()).getVertices().length];
    findSelectionDistance();
    updateMenus();
  }

  void createMeshMenu(Tube obj)
  {
    meshMenu = Translate.menu("tube");
    menubar.add(meshMenu);
    meshMenuItem = new BMenuItem [8];
    meshMenuItem[0] = Translate.menuItem("deletePoints", this, "deleteCommand");
    if (topology)
      meshMenu.add(meshMenuItem[0]);
    meshMenuItem[1] = Translate.menuItem("subdivide", this, "subdivideCommand");
    if (topology)
      meshMenu.add(meshMenuItem[1]);
    meshMenu.add(meshMenuItem[2] = Translate.menuItem("editPoints", this, "setPointsCommand"));
    meshMenu.add(meshMenuItem[3] = Translate.menuItem("transformPoints", this, "transformPointsCommand"));
    meshMenu.add(meshMenuItem[4] = Translate.menuItem("randomize", this, "randomizeCommand"));
    meshMenu.add(meshMenuItem[5] = Translate.menuItem("parameters", this, "setParametersCommand"));
    meshMenu.add(meshMenuItem[6] = Translate.menuItem("thickness", this, "setThicknessCommand"));
    meshMenu.add(Translate.menuItem("centerTube", this, "centerCommand"));
    meshMenu.addSeparator();
    meshMenu.add(meshMenuItem[7] = Translate.menuItem("smoothness", this, "setSmoothnessCommand"));
    meshMenu.add(smoothMenu = Translate.menu("smoothingMethod"));
    smoothItem = new BCheckBoxMenuItem [3];
    smoothMenu.add(smoothItem[0] = Translate.checkboxMenuItem("none", this, "smoothingChanged", obj.getSmoothingMethod() == Curve.NO_SMOOTHING));
    smoothMenu.add(smoothItem[1] = Translate.checkboxMenuItem("interpolating", this, "smoothingChanged", obj.getSmoothingMethod() == Curve.INTERPOLATING));
    smoothMenu.add(smoothItem[2] = Translate.checkboxMenuItem("approximating", this, "smoothingChanged", obj.getSmoothingMethod() == Curve.APPROXIMATING));
    endsItem = new BCheckBoxMenuItem [3];
    BMenu endsMenu = Translate.menu("endsStyle");
    meshMenu.add(endsMenu);
    endsMenu.add(endsItem[0] = Translate.checkboxMenuItem("openEnds", this, "endsStyleChanged", obj.getEndsStyle() == Tube.OPEN_ENDS));
    endsMenu.add(endsItem[1] = Translate.checkboxMenuItem("closedEnds", this, "endsStyleChanged", obj.getEndsStyle() == Tube.CLOSED_ENDS));
    endsMenu.add(endsItem[2] = Translate.checkboxMenuItem("flatEnds", this, "endsStyleChanged", obj.getEndsStyle() == Tube.FLAT_ENDS));
  }
  
  protected BMenu createShowMenu()
  {
    BMenu menu = Translate.menu("show");
    MeshViewer view = (MeshViewer) theView[currentView];
    showItem = new BCheckBoxMenuItem [4];
    menu.add(showItem[0] = Translate.checkboxMenuItem("curve", this, "shownItemChanged", view.getMeshVisible()));
    menu.add(showItem[1] = Translate.checkboxMenuItem("surface", this, "shownItemChanged", view.getSurfaceVisible()));
    menu.add(showItem[3] = Translate.checkboxMenuItem("entireScene", this, "shownItemChanged", view.getSceneVisible()));
    return menu;
  }

  public void updateMenus()
  {
    super.updateMenus();
    int i;
    for (i = 0; i < selected.length && !selected[i]; i++);
    if (i < selected.length)
    {
      editMenuItem[0].setEnabled(true);
      for (i = 0; i < meshMenuItem.length; i++)
        meshMenuItem[i].setEnabled(true);
    }
    else
    {
      editMenuItem[0].setEnabled(false);
      for (i = 0; i < meshMenuItem.length; i++)
        meshMenuItem[i].setEnabled(false);
    }
  }
  
  private void endsStyleChanged(WidgetEvent ev)
  {
    Widget source = ev.getWidget();
    for (int i = 0; i < endsItem.length; i++)
      if (source == endsItem[i])
      {
        for (int j = 0; j < endsItem.length; j++)
          endsItem[j].setState(false);
        endsItem[i].setState(true);
        ((Tube) objInfo.getObject()).setEndsStyle(i);
        objectChanged();
        updateImage();
      }
  }

  protected void doOk()
  {
    Tube theMesh = (Tube) objInfo.getObject();
    if (((Tube) oldMesh).getMaterial() != null)
    {
      if (!theMesh.isClosed())
      {
        String options[] = new String [] {Translate.text("button.ok"), Translate.text("button.cancel")};
        BStandardDialog dlg = new BStandardDialog("", UIUtilities.breakString(Translate.text("surfaceNoLongerClosed")), BStandardDialog.WARNING);
        int choice = dlg.showOptionDialog(this, options, options[0]);
        if (choice == 1)
          return;
        theMesh.setMaterial(null, null);
      }
      else
        theMesh.setMaterial(((Tube) oldMesh).getMaterial(), ((Tube) oldMesh).getMaterialMapping());
    }
    oldMesh.copyObject(theMesh);
    oldMesh = null;
    dispose();
    onClose.run();
  }
  
  protected void doCancel()
  {
    oldMesh = null;
    dispose();
  }

  /** Delete the selected vertices. */

  public void deleteCommand()
  {
    if (!topology)
      return;
    int i, j, num = 0;
    Tube theTube = (Tube) objInfo.getObject();
    boolean newsel[];
    MeshVertex vt[] = theTube.getVertices(), newv[];
    double t[] = theTube.getThickness(), newt[];
    float s[] = theTube.getSmoothness(), news[];

    for (i = 0; i < selected.length; i++)
      if (selected[i])
  num++;
    if (num == 0)
      return;
    if (theTube.getEndsStyle() != Tube.CLOSED_ENDS && selected.length-num < 2)
    {
      new BStandardDialog("", Translate.text("tubeNeeds2Points"), BStandardDialog.INFORMATION).showMessageDialog(this);
      return;
    }
    if (theTube.getEndsStyle() == Tube.CLOSED_ENDS && selected.length-num < 3)
    {
      new BStandardDialog("", Translate.text("tubeNeeds3Points"), BStandardDialog.INFORMATION).showMessageDialog(this);
      return;
    }
    setUndoRecord(new UndoRecord(this, false, UndoRecord.COPY_OBJECT, new Object [] {theTube, theTube.duplicate()}));
    newv = new MeshVertex [vt.length-num];
    newt = new double [vt.length-num];
    news = new float [vt.length-num];
    newsel = new boolean [vt.length-num];
    for (i = 0, j = 0; i < vt.length; i++)
    {
      if (!selected[i])
      {
        newsel[j] = selected[i];
        newt[j] = t[i];
        news[j] = s[i];
        newv[j++] = vt[i];
      }
    }
    theTube.setShape(newv, news, newt);
    setSelection(newsel);
    objectChanged();
    updateImage();
  }

  /** Subdivide the tube between the selected vertices. */

  public void subdivideCommand()
  {
    Tube theTube = (Tube) objInfo.getObject();
    MeshVertex vt[] = theTube.getVertices(), newpos[];
    float s[] = theTube.getSmoothness(), news[];
    double t[] = theTube.getThickness(), newt[];
    int numParam = (theTube.getParameters() == null ? 0 : theTube.getParameters().length);
    double param[][], newparam[][], paramTemp[] = new double [numParam];
    boolean newsel[], split[];
    int i, j, p1, p3, p4, splitcount = 0, method = theTube.getSmoothingMethod();
    
    // Record parameter values.
    
    param = new double [vt.length][numParam];
    ParameterValue paramValue[] = theTube.getParameterValues();
    for (i = 0; i < numParam; i++)
    {
      if (paramValue[i] instanceof VertexParameterValue)
      {
        double val[] = ((VertexParameterValue) paramValue[i]).getValue();
        for (j = 0; j < val.length; j++)
          param[j][i] = val[j];
      }
    }
    
    // Determine which parts need to be subdivided.
    
    if (theTube.getEndsStyle() == Tube.CLOSED_ENDS)
      split = new boolean [vt.length];
    else
      split = new boolean [vt.length-1];
    for (i = 0; i < split.length; i++)
      if (selected[i] && selected[(i+1)%selected.length])
      {
        split[i] = true;
        splitcount++;
      }
    newpos = new MeshVertex [vt.length+splitcount];
    news = new float [vt.length+splitcount];
    newt = new double [vt.length+splitcount];
    newparam = new double [vt.length+splitcount][numParam];
    newsel = new boolean [vt.length+splitcount];
    
    // Do the subdivision.

    for (i = 0, j = 0; i < split.length; i++)
    {
      newsel[j] = selected[i];
      p1 = i-1;
      if (p1 < 0)
      {
        if (theTube.getEndsStyle() == Tube.CLOSED_ENDS)
          p1 = vt.length-1;
        else
          p1 = 0;
      }
      if (i < vt.length-1)
        p3 = i+1;
      else
      {
        if (theTube.getEndsStyle() == Tube.CLOSED_ENDS)
          p3 = 0;
        else
          p3 = vt.length-1;
      }
      if (selected[i] && method == Mesh.APPROXIMATING)
      {
        newpos[j] = SplineMesh.calcApproxPoint(vt, s, param, paramTemp, p1, i, p3);
        newt[j] = Tube.calcApproxThickness(t, s, p1, i, p3);
        for (int k = 0; k < numParam; k++)
          newparam[j][k] = paramTemp[k];
      }
      else
      {
        newpos[j] = vt[i];
        newt[j] = t[i];
        newparam[j] = param[i];
      }
      if (selected[i])
        news[j] = Math.min(s[i]*2.0f, 1.0f);
      else
        news[j] = s[i];
      if (!split[i])
      {
        j++;
        continue;
      }
      if (method == Mesh.NO_SMOOTHING)
      {
        newpos[j+1] = MeshVertex.blend(vt[i], vt[p3], 0.5, 0.5);
        for (int k = 0; k < numParam; k++)
          newparam[j+1][k] = 0.5*(param[i][k]+param[p3][k]);
      }
      else if (method == Mesh.INTERPOLATING)
      {
        if (i < vt.length-2)
          p4 = i+2;
        else
        {
          if (theTube.getEndsStyle() == Tube.CLOSED_ENDS)
            p4 = (i+2)%vt.length;
          else
            p4 = vt.length-1;
        }
        newpos[j+1] = SplineMesh.calcInterpPoint(vt, s, param, paramTemp, p1, i, p3, p4);
        newt[j+1] = Tube.calcInterpThickness(t, s, p1, i, p3, p4);
        for (int k = 0; k < numParam; k++)
          newparam[j+1][k] = paramTemp[k];
      }
      else
      {
        newpos[j+1] = MeshVertex.blend(vt[i], vt[p3], 0.5, 0.5);
        newt[j+1] = 0.5*(t[i]+t[p3]);
        for (int k = 0; k < numParam; k++)
          newparam[j+1][k] = 0.5*(param[i][k]+param[p3][k]);
      }
      news[j+1] = 1.0f;
      newsel[j+1] = true;
      j += 2;
    }
    if (theTube.getEndsStyle() != Tube.CLOSED_ENDS)
    {
      newpos[0] = vt[0];
      newpos[j] = vt[i];
      newt[0] = t[0];
      newt[j] = t[i];
      news[j] = s[i];
      newparam[0] = param[0];
      newparam[j] = param[i];
      newsel[j] = selected[i];
    }
    setUndoRecord(new UndoRecord(this, false, UndoRecord.COPY_OBJECT, new Object [] {theTube, theTube.duplicate()}));
    theTube.setShape(newpos, news, newt);
    for (i = 0; i < numParam; i++)
    {
      if (paramValue[i] instanceof VertexParameterValue)
      {
        double val[] = new double [newpos.length];
        for (j = 0; j < val.length; j++)
          val[j] = newparam[j][i];
        paramValue[i] = new VertexParameterValue(val);
      }
    }
    theTube.setParameterValues(paramValue);
    setSelection(newsel);
    objectChanged();
    updateImage();
  }
  
  /** Allow the user to set the thickness for selected vertices. */
  
  public void setThicknessCommand()
  {
    Tube theTube = (Tube) objInfo.getObject();
    double thickness[] = theTube.getThickness(), initial = -1;
    int selectDist[] = getSelectionDistance();

    for (int i = 0; i < selectDist.length; i++)
      if (selectDist[i] == 0)
      {
        if (initial == -1)
          initial = thickness[i];
        else if (initial != thickness[i])
          initial = Double.NaN;
      }
    if (initial == -1)
      return;  // No selected vertices.
    ValueField thicknessField = new ValueField(initial, ValueField.NONNEGATIVE, 5);
    ComponentsDialog dlg = new ComponentsDialog(this, Translate.text("setThicknessTitle"),
      new Widget [] {thicknessField}, new String [] {Translate.text("Thickness")});
    if (!dlg.clickedOk() || Double.isNaN(thicknessField.getValue()))
      return;
    setUndoRecord(new UndoRecord(this, false, UndoRecord.COPY_OBJECT, new Object [] {theTube, theTube.duplicate()}));
    for (int i = 0; i < selectDist.length; i++)
      if (selectDist[i] == 0)
        thickness[i] = thicknessField.getValue();
    theTube.setThickness(thickness);
    objectChanged();
    updateImage();
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.