Package org.openscience.jchempaint.controller

Source Code of org.openscience.jchempaint.controller.RotateModule

/*
* Copyright (C) 2008  Gilleain Torrance <gilleain.torrance@gmail.com>
*               2009  Mark Rijnbeek <mark_rynbeek@users.sourceforge.net>
*
* Contact: cdk-devel@lists.sourceforge.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
* All I ask is that proper credit is given for my work, which includes
* - but is not limited to - adding the above copyright notice to the beginning
* of your source code files, and to any copyright notice that you may distribute
* with programs based on this work.
*
* 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.openscience.jchempaint.controller;

import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.Map;

import javax.vecmath.Point2d;

import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.tools.ILoggingTool;
import org.openscience.cdk.tools.LoggingToolFactory;
import org.openscience.jchempaint.controller.undoredo.IUndoRedoFactory;
import org.openscience.jchempaint.controller.undoredo.IUndoRedoable;
import org.openscience.jchempaint.controller.undoredo.UndoRedoHandler;
import org.openscience.jchempaint.renderer.BoundsCalculator;
import org.openscience.cdk.renderer.selection.IChemObjectSelection;

/**
* Module to rotate a selection of atoms (and their bonds).
*
* @cdk.module controlbasic
*/
public class RotateModule extends ControllerModuleAdapter {

    protected static ILoggingTool logger =
        LoggingToolFactory.createLoggingTool(RotateModule.class);

    private double rotationAngle;
    protected boolean selectionMade = false;
    protected IChemObjectSelection selection;
    protected Point2d rotationCenter;
    protected Point2d[] startCoordsRelativeToRotationCenter;
    protected Map<IAtom, Point2d[]> atomCoordsMap;
    protected boolean rotationPerformed;
    protected String ID;

    /**
     * Constructor
     * @param chemModelRelay
     */
    public RotateModule(IChemModelRelay chemModelRelay) {
        super(chemModelRelay);
        logger.debug("constructor");
    }

    /**
     * Initializes possible rotation. Determines rotation center and stores
     * coordinates of atoms to be rotated. These stored coordinates are relative
     * to the rotation center.
     */
    public void mouseClickedDown(Point2d worldCoord) {
        logger.debug("rotate mouseClickedDown, initializing rotation");
        rotationCenter = null;
        selection = super.chemModelRelay.getRenderer().getRenderer2DModel()
                .getSelection();

        if (   selection == null
            ||!selection.isFilled()
            || selection.getConnectedAtomContainer() == null
            || selection.getConnectedAtomContainer().getAtomCount()==0) {

            /*
             * Nothing selected- return. Dragging the mouse will not result in
             * any rotation logic.
             */
            logger.debug("Nothing selected for rotation");
            selectionMade = false;
            return;
       
        } else {
            rotationPerformed = false;
            //if we are outside bounding box, we deselect, else
            //we actually start a rotation.
            Rectangle2D bounds = BoundsCalculator.calculateBounds(this.chemModelRelay.getRenderer().getRenderer2DModel().getSelection().getConnectedAtomContainer());
               
            rotationAngle = 0.0;
            selectionMade = true;

            /* Keep original coordinates for possible undo/redo */
            atomCoordsMap = new HashMap<IAtom, Point2d[]>();
            for (IAtom atom : selection.getConnectedAtomContainer().atoms()) {
                Point2d[] coordsforatom = new Point2d[2];
                coordsforatom[1] = atom.getPoint2d();
                atomCoordsMap.put(atom, coordsforatom);
            }

            /*
             * Determine rotationCenter as the middle of a region defined by
             * min(x,y) and max(x,y) of coordinates of the selected atoms.
             */
            IAtomContainer selectedAtoms =
                selection.getConnectedAtomContainer();


            Double upperX = null, lowerX = null, upperY = null, lowerY = null;
            for (int i = 0; i < selectedAtoms.getAtomCount(); i++) {
                if (upperX == null) {
                    upperX = selectedAtoms.getAtom(i).getPoint2d().x;
                    lowerX = upperX;
                    upperY = selectedAtoms.getAtom(i).getPoint2d().y;
                    lowerY = selectedAtoms.getAtom(i).getPoint2d().y;
                } else {
                    double currX = selectedAtoms.getAtom(i).getPoint2d().x;
                    if (currX > upperX)
                        upperX = currX;
                    if (currX < lowerX)
                        lowerX = currX;

                    double currY = selectedAtoms.getAtom(i).getPoint2d().y;
                    if (currY > upperY)
                        upperY = currY;
                    if (currY < lowerY)
                        lowerY = currY;
                }
            }
            rotationCenter = new Point2d();
            rotationCenter.x = (upperX + lowerX) / 2;
            rotationCenter.y = (upperY + lowerY) / 2;
            logger.debug("rotationCenter "
                    + rotationCenter.x + " "
                    + rotationCenter.y);

            /* Store the original coordinates relative to the rotation center.
             * These are necessary to rotate around the center of the
             * selection rather than the draw center. */
            startCoordsRelativeToRotationCenter = new Point2d[selectedAtoms
                                                              .getAtomCount()];
            for (int i = 0; i < selectedAtoms.getAtomCount(); i++) {
                Point2d relativeAtomPosition = new Point2d();
                relativeAtomPosition.x = selectedAtoms.getAtom(i).getPoint2d().x
                - rotationCenter.x;
                relativeAtomPosition.y = selectedAtoms.getAtom(i).getPoint2d().y
                - rotationCenter.y;
                startCoordsRelativeToRotationCenter[i] = relativeAtomPosition;
            }
        }
    }

    /**
     * On mouse drag, actual rotation around the center is done
     */
    public void mouseDrag(Point2d worldCoordFrom, Point2d worldCoordTo) {
        if (selectionMade) {
            rotationPerformed=true;
            /*
             * Determine the quadrant the user is currently in, relative to the
             * rotation center.
             */
            int quadrant = 0;
            if ((worldCoordFrom.x >= rotationCenter.x))
                if ((worldCoordFrom.y <= rotationCenter.y))
                    quadrant = 1; // 12 to 3 o'clock
                else
                    quadrant = 2; // 3 to 6 o'clock
            else if ((worldCoordFrom.y <= rotationCenter.y))
                quadrant = 4; // 9 to 12 o'clock
            else
                quadrant = 3; // 6 to 9 o'clock

            /*
             * The quadrant and the drag combined determine in which direction
             * the rotation will be done. For example, dragging in direction
             * left/down in quadrant 4 means rotating counter clockwise.
             */
            final int SLOW_DOWN_FACTOR=4;
            switch (quadrant) {
            case 1:
                rotationAngle += (worldCoordTo.x - worldCoordFrom.x)/SLOW_DOWN_FACTOR
                        + (worldCoordTo.y - worldCoordFrom.y)/SLOW_DOWN_FACTOR;
                break;
            case 2:
                rotationAngle += (worldCoordFrom.x - worldCoordTo.x)/SLOW_DOWN_FACTOR
                        + (worldCoordTo.y - worldCoordFrom.y)/SLOW_DOWN_FACTOR;
                break;
            case 3:
                rotationAngle += (worldCoordFrom.x - worldCoordTo.x)/SLOW_DOWN_FACTOR
                        + (worldCoordFrom.y - worldCoordTo.y)/SLOW_DOWN_FACTOR;
                break;
            case 4:
                rotationAngle += (worldCoordTo.x - worldCoordFrom.x)/SLOW_DOWN_FACTOR
                        + (worldCoordFrom.y - worldCoordTo.y)/SLOW_DOWN_FACTOR;
                break;
            }

            /* For more info on the mathematics, see Wiki at
             * http://en.wikipedia.org/wiki/Coordinate_rotation
             */
            double cosine = java.lang.Math.cos(rotationAngle);
            double sine = java.lang.Math.sin(rotationAngle);
            IAtomContainer atc = selection.getConnectedAtomContainer();
            for (int i = 0; i < startCoordsRelativeToRotationCenter.length; i++) {
                double newX = (startCoordsRelativeToRotationCenter[i].x * cosine)
                        - (startCoordsRelativeToRotationCenter[i].y * sine);
                double newY = (startCoordsRelativeToRotationCenter[i].x * sine)
                        + (startCoordsRelativeToRotationCenter[i].y * cosine);

                Point2d newCoords = new Point2d(newX + rotationCenter.x, newY
                        + rotationCenter.y);

                atc.getAtom(i).setPoint2d(newCoords);
            }
        }
        chemModelRelay.updateView();
    }
   
    /**
     * After the rotation (=mouse up after drag), post the undo/redo information
     * with the old and the new coordinates
     */
    public void mouseClickedUp(Point2d worldCoord) {
        if(rotationPerformed && atomCoordsMap!=null && selection.getConnectedAtomContainer()!=null) {
            logger.debug("posting undo/redo for rotation");

            /* Keep new coordinates for the sake of possible undo/redo */
            for (IAtom atom : selection.getConnectedAtomContainer().atoms()) {
                Point2d[] coords = atomCoordsMap.get(atom);
                coords[0] = atom.getPoint2d();
            }

            /* Post the rotation */
            IUndoRedoFactory factory = chemModelRelay.getUndoRedoFactory();
            UndoRedoHandler handler = chemModelRelay.getUndoRedoHandler();
            if (factory != null && handler != null) {
                IUndoRedoable undoredo = factory.getChangeCoordsEdit(
                        atomCoordsMap, "Rotation");
                handler.postEdit(undoredo);
            }
        }
    }

   
    public void setChemModelRelay(IChemModelRelay relay) {
        this.chemModelRelay = relay;
    }

    public String getDrawModeString() {
        return "Rotate";
    }

    public String getID() {
        return ID;
    }

    public void setID(String ID) {
        this.ID=ID;
    }

}
TOP

Related Classes of org.openscience.jchempaint.controller.RotateModule

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.