1 /*
2  *
3  * Copyright (C) 2007,2008  Markko Merzin (markko.merzin@ut.ee)
4  *
5  * This file is part of ImageJ plugin Volumest.
6  * 
7  * Volumest plugin is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 *****************************************************************************
21 */
22package ee.ut.mrz.volumest;
23
24import ij.measure.Calibration;
25import java.awt.Point;
26import java.util.ArrayList;
27import java.util.Iterator;
28
29/**
30 * Model for one grid.
31 * @author Markko Merzin
32 */
33public class Grid {
34    // private ArrayList gridPoints;
35    private GridPointsSet gridPointsSet = new GridPointsSet();
36    private Reper reper;
37    private int activePointsCount = 0;
38    private int intersectionsCount = 0;
39    private int pixelsPerGridWitdh;
40    private boolean recalculateActive = true;
41    private boolean recalculateIntersections = true;
42
43    Grid(Point imageEdge, double gridWitdh, Calibration calibration) {
44
45        this.reper = new Reper(gridWitdh, calibration);
46
47        double pixelsPerUnit = 1 / calibration.pixelWidth;
48        // FIXME: see peaks olema double!
49        pixelsPerGridWitdh = (int) Math.round(pixelsPerUnit * gridWitdh);
50
51        ArrayList<GridPoint> gridPoints = new ArrayList<GridPoint>();
52        for (double x = -Math.sqrt(2) * imageEdge.getX(); x < Math.sqrt(2) * imageEdge.getX(); x = x + pixelsPerGridWitdh) {
53            for (double y = -Math.sqrt(2) * imageEdge.getY(); y < Math.sqrt(2) * imageEdge.getY(); y = y + pixelsPerGridWitdh) {
54                GridPoint point = new GridPoint(x, y, reper);
55                if (point.getXInAfineReper() > 0.0 - pixelsPerGridWitdh * Math.sqrt(2) &&
56                        point.getXInAfineReper() < imageEdge.getX() + pixelsPerGridWitdh * Math.sqrt(2) &&
57                        point.getYInAfineReper() > 0.0 - pixelsPerGridWitdh * Math.sqrt(2) &&
58                        point.getYInAfineReper() < imageEdge.getY() + pixelsPerGridWitdh * Math.sqrt(2)) {
59
60                    gridPoints.add(point);
61
62                }
63
64
65            }
66        }
67
68        gridPointsSet.add(gridPoints);
69
70    }
71
72    /**
73     * Returns ArrayList with currently active points set.
74     * @return ArrayList with currently active points set.
75     */
76    public ArrayList<GridPoint> getGridPoints() {
77        // return this.gridPoints;
78        recalculateActive = recalculateIntersections = true;
79        return gridPointsSet.getCurrentObj();
80    }
81
82    /**
83     * Activates or deactivates gridpoint witch is within selection margins.
84     * @param point Point in affine reper (one on display).
85     * @param activate Activate or deactivate.
86     */
87    public void activateGridPoint(java.awt.Point point, boolean activate) {
88        recalculateActive = true;
89
90        double xInCross = reper.xFromAfineToCross(point.getX(), point.getY());
91        double yInCross = reper.yFromAfineToCross(point.getX(), point.getY());
92
93        // Iterator iter = this.gridPoints.iterator();
94        Iterator iter = gridPointsSet.getCurrentObj().iterator();
95        while (iter.hasNext()) {
96            GridPoint gridPoint = (GridPoint) iter.next();
97            double xLeftMark = gridPoint.getXInCrossReper() - pixelsPerGridWitdh / 2.0;
98            double xRightMark = gridPoint.getXInCrossReper() + pixelsPerGridWitdh / 2.0;
99            double yDownMark = gridPoint.getYInCrossReper() - pixelsPerGridWitdh / 2.0;
00            double yUpMark = gridPoint.getYInCrossReper() + pixelsPerGridWitdh / 2.0;
01
02            if (xInCross > xLeftMark &&
03                    xInCross < xRightMark &&
04                    yInCross > yDownMark &&
05                    yInCross < yUpMark) {
06
07                if (!gridPoint.isIntersection()) {
08                    if (activate) {
09                        if (!gridPoint.isActive()) {
10                            gridPoint.setActive(true);
11                        // this.activePointsCount++;
12                        }
13                    } else {
14                        if (gridPoint.isActive()) {
15                            gridPoint.setActive(false);
16                        // this.activePointsCount--;
17                        }
18                    }
19                }
20            }
21        }
22    }
23
24    /**
25     * Count activated points in grid.
26     * @return Count of active points in grid.
27     */
28    public int getActivePointsCount() {
29        if (recalculateActive) {
30            int activePoints = 0;
31            // Iterator iter = this.gridPoints.iterator();
32            Iterator iter = gridPointsSet.getCurrentObj().iterator();
33            while (iter.hasNext()) {
34                GridPoint gp = (GridPoint) iter.next();
35                if (gp.isActive()) {
36                    activePoints++;
37                }
38            }
39            activePointsCount = activePoints;
40            recalculateActive = false;
41            return activePoints;
42        } else {
43            return activePointsCount;
44        }
45    }
46
47    /**
48     * Count intersectionpoints.
49     * @return Count of intersections.
50     */
51    public int getIntersectionPointsCount() {
52        if (recalculateIntersections) {
53            int intersectionPoints = 0;
54            Iterator iter = gridPointsSet.getCurrentObj().iterator();
55            while (iter.hasNext()) {
56                GridPoint gp = (GridPoint) iter.next();
57                if (gp.isIntersection()) {
58                    intersectionPoints++;
59                }
60            }
61            intersectionsCount = intersectionPoints;
62            recalculateIntersections = false;
63            return intersectionPoints;
64        } else {
65            return intersectionsCount;
66        }
67    }
68
69    /**
70     * Returns reper.
71     * @return Reper witch is associated with this grid.
72     */
73    public Reper getReper() {
74        return reper;
75    }
76
77    /**
78     * Reserved for future use. For processing in multiple threads.
79     */
80    public void beginTransaction() {
81        // see if we have change after undo
82        // throw away anything after current point
83        /*
84        if ( this.gridPointsSet.size() > this.currentPointSet + 1 ) {
85        this.gridPointsSet.subList( this.currentPointSet + 1 , this.gridPointsSet.size() - 1 ).clear();
86        }
87        addCurrentPointSetToUndoBuffer();
88        this.currentPointSet++;
89         */
90
91        recalculateActive = recalculateIntersections = true;
92        gridPointsSet.copyLastSet();
93    }
94
95    /**
96     * Reserverd for future use. For processing in multiple threads.
97     */
98    public void endTransaction() {
99
00    }
01
02    /**
03     * Step back in undo chain.
04     */
05    public void undoStep() {
06        recalculateActive = recalculateIntersections = true;
07        gridPointsSet.undoStep();
08    }
09
10    /**
11     * Step forward in undo chain.
12     */
13    public void redoStep() {
14        recalculateActive = recalculateIntersections = true;
15        gridPointsSet.redoStep();
16    }
17
18    /**
19     * Counts undosteps.
20     * @return Count of undosteps.
21     */
22    public int getUndoStepsCount() {
23        return gridPointsSet.getPossibleUndoStepsCount();
24    }
25
26    /**
27     * Counts possible redo steps.
28     * @return Count of possible redo steps.
29     */
30    public int getRedoStepsCount() {
31        return gridPointsSet.getPossibleRedoStepsCount();
32    }
33
34    /**
35     * Creates new intersectionpoint.
36     * @param point Intersectionpoint in affine reper (one in display).
37     * @param activate Wether activate or deactivate point.
38     */
39    public void activateIntersectionPoint(java.awt.Point point, boolean activate) {
40        recalculateIntersections = true;
41
42        if (activate) {
43            GridPoint gp = new GridPoint(point, reper, GridPoint.POINT_IN_AFINE_REPER);
44            gp.setIntersection(true);
45            gridPointsSet.getCurrentObj().add(gp);
46        } else {
47            lastInter:
48            for (int c = gridPointsSet.getCurrentObj().size() - 1; c > 0; c--) {
49                GridPoint gridPoint = (GridPoint) gridPointsSet.getCurrentObj().get(c);
50                if (gridPoint.isIntersection()) {
51
52                    double xLeftMark = gridPoint.getXInAfineReper() - pixelsPerGridWitdh / 4.0;
53                    double xRightMark = gridPoint.getXInAfineReper() + pixelsPerGridWitdh / 4.0;
54                    double yDownMark = gridPoint.getYInAfineReper() - pixelsPerGridWitdh / 4.0;
55                    double yUpMark = gridPoint.getYInAfineReper() + pixelsPerGridWitdh / 4.0;
56
57                    double x = point.getX();
58                    double y = point.getY();
59
60                    if (x > xLeftMark &&
61                            x < xRightMark &&
62                            y > yDownMark &&
63                            y < yUpMark) {
64                        gridPointsSet.getCurrentObj().remove(c);
65                        break lastInter;
66                    }
67
68                }
69            }
70        }
71
72    }
73
74    /**
75     * Returns pixels per gridwidth.
76     * @return How many pixels is per grid width.
77     */
78    public int getPixelsPerGridWitdh() {
79        return pixelsPerGridWitdh;
80    }
81}
82