View Javadoc

1   /*
2   
3       dsh-venn  Lightweight components for venn diagrams.
4       Copyright (c) 2009-2013 held jointly by the individual authors.
5   
6       This library is free software; you can redistribute it and/or modify it
7       under the terms of the GNU Lesser General Public License as published
8       by the Free Software Foundation; either version 3 of the License, or (at
9       your option) any later version.
10  
11      This library is distributed in the hope that it will be useful, but WITHOUT
12      ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
13      FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14      License for more details.
15  
16      You should have received a copy of the GNU Lesser General Public License
17      along with this library;  if not, write to the Free Software Foundation,
18      Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
19  
20      > http://www.fsf.org/licensing/licenses/lgpl.html
21      > http://www.opensource.org/licenses/lgpl-license.php
22  
23  */
24  package org.dishevelled.venn.layouter;
25  
26  import java.awt.geom.Area;
27  import java.awt.geom.Ellipse2D;
28  import java.awt.geom.Point2D;
29  import java.awt.geom.Rectangle2D;
30  
31  import org.dishevelled.venn.VennModel;
32  import org.dishevelled.venn.BinaryVennLayout;
33  import org.dishevelled.venn.BinaryVennModel;
34  import org.dishevelled.venn.TernaryVennLayout;
35  import org.dishevelled.venn.TernaryVennModel;
36  import org.dishevelled.venn.QuaternaryVennLayout;
37  import org.dishevelled.venn.QuaternaryVennModel;
38  import org.dishevelled.venn.VennLayout;
39  import org.dishevelled.venn.VennLayouter;
40  
41  import org.dishevelled.venn.layout.BinaryVennLayoutImpl;
42  import org.dishevelled.venn.layout.TernaryVennLayoutImpl;
43  import org.dishevelled.venn.layout.QuaternaryVennLayoutImpl;
44  
45  /**
46   * Venn layout algorithm.
47   *
48   * @param <E> value type
49   * @author  Michael Heuer
50   */
51  public final class VennLayouterImpl<E> implements VennLayouter<E>
52  {
53  
54      /** {@inheritDoc} */
55      public VennLayout layout(final VennModel<E> model,
56                               final Rectangle2D boundingRectangle,
57                               final PerformanceHint performanceHint)
58      {
59          if (model == null)
60          {
61              throw new IllegalArgumentException("model must not be null");
62          }
63          if (boundingRectangle == null)
64          {
65              throw new IllegalArgumentException("boundingRectangle must not be null");
66          }
67          if (performanceHint == null)
68          {
69              throw new IllegalArgumentException("performanceHint must not be null");
70          }
71  
72          if (model instanceof BinaryVennModel)
73          {
74              return layout((BinaryVennModel<E>) model, boundingRectangle);
75          }
76          else if (model instanceof TernaryVennModel)
77          {
78              return layout((TernaryVennModel<E>) model, boundingRectangle);
79          }
80          else if (model instanceof QuaternaryVennModel)
81          {
82              return layout((QuaternaryVennModel<E>) model, boundingRectangle);
83          }
84  
85          // todo: apply venn/euler algorithm
86  
87          return null;
88      }
89  
90      /**
91       * Layout the specified binary venn diagram within the specified bounding rectangle.
92       *
93       * @param model binary venn model, must not be null
94       * @param boundingRectangle bounding rectangle, must not be null
95       * @return the result of the layout operation
96       */
97      BinaryVennLayout layout(final BinaryVennModel<E> model,
98                              final Rectangle2D boundingRectangle)
99      {
100         double w = boundingRectangle.getWidth();
101         double h = boundingRectangle.getHeight();
102         double cx = w / 2.0d;
103         double cy = h / 2.0d;
104         double d = Math.min(h, 3.0d * w / 5.0d);
105         double r = d / 2.0d;
106         double x = cx - 5.0d * d / 6.0d;
107         double y = cy - d / 2.0d;
108 
109         Ellipse2D firstShape = new Ellipse2D.Double(x, y, d, d);
110         Ellipse2D secondShape = new Ellipse2D.Double(x + 2.0d * d / 3.0d, y, d, d);
111         Point2D firstOnlyCenter = new Point2D.Double(cx - r, cy);
112         Point2D secondOnlyCenter = new Point2D.Double(cx + r, cy);
113         Point2D intersectionCenter = new Point2D.Double(cx, cy);
114 
115         return new BinaryVennLayoutImpl(firstShape, secondShape,
116                                         firstOnlyCenter, secondOnlyCenter, intersectionCenter, boundingRectangle);
117     }
118 
119     /**
120      * Layout the specified ternary venn diagram within the specified bounding rectangle.
121      *
122      * @param model ternary venn model, must not be null
123      * @param boundingRectangle bounding rectangle, must not be null
124      * @return the result of the layout operation
125      */
126     TernaryVennLayout layout(final TernaryVennModel<E> model,
127                              final Rectangle2D boundingRectangle)
128     {
129         double w = boundingRectangle.getWidth();
130         double h = boundingRectangle.getHeight();
131         double d = 5.0d / (3.0d * Math.min(w, h));
132 
133         Ellipse2D firstShape = new Ellipse2D.Double(0.0d, 0.0d, d, d);
134         Ellipse2D secondShape = new Ellipse2D.Double(((2.0d * d) / 3.0d), 0.0d, d, d);
135         Ellipse2D thirdShape = new Ellipse2D.Double(d / 3.0d, (2.0d * d) / 3.0d, d, d);
136 
137         Area f = new Area(firstShape);
138         Area s = new Area(secondShape);
139         Area t = new Area(thirdShape);
140 
141         Area firstOnly = new Area();
142         firstOnly.add(f);
143         firstOnly.subtract(s);
144         firstOnly.subtract(t);
145         Point2D firstOnlyCenter = centerOf(firstOnly);
146 
147         Area secondOnly = new Area();
148         secondOnly.add(s);
149         secondOnly.subtract(f);
150         secondOnly.subtract(t);
151         Point2D secondOnlyCenter = centerOf(secondOnly);
152 
153         Area thirdOnly = new Area();
154         thirdOnly.add(t);
155         thirdOnly.subtract(f);
156         thirdOnly.subtract(s);
157         Point2D thirdOnlyCenter = centerOf(thirdOnly);
158 
159         Area firstSecond = new Area();
160         firstSecond.add(f);
161         firstSecond.intersect(s);
162         firstSecond.subtract(t);
163         Point2D firstSecondCenter = centerOf(firstSecond);
164 
165         Area firstThird = new Area();
166         firstThird.add(f);
167         firstThird.intersect(t);
168         firstThird.subtract(s);
169         Point2D firstThirdCenter = centerOf(firstThird);
170 
171         Area secondThird = new Area();
172         secondThird.add(s);
173         secondThird.intersect(t);
174         secondThird.subtract(f);
175         Point2D secondThirdCenter = centerOf(secondThird);
176 
177         Area intersection = new Area();
178         intersection.add(f);
179         intersection.intersect(s);
180         intersection.intersect(t);
181         Point2D intersectionCenter = centerOf(intersection);
182 
183         return new TernaryVennLayoutImpl(firstShape, secondShape, thirdShape, firstOnlyCenter, secondOnlyCenter,
184                                          thirdOnlyCenter, firstSecondCenter, firstThirdCenter, secondThirdCenter,
185                                          intersectionCenter, boundingRectangle);
186     }
187 
188     /**
189      * Layout the specified quaternary venn diagram within the specified bounding rectangle.
190      *
191      * @param model quaternary venn model, must not be null
192      * @param boundingRectangle bounding rectangle, must not be null
193      * @return the result of the layout operation
194      */
195     QuaternaryVennLayout layout(final QuaternaryVennModel<E> model,
196                                 final Rectangle2D boundingRectangle)
197     {
198         return null;
199     }
200 
201     /**
202      * Find and return the center of the specified area using its bounds rectangle.
203      *
204      * @param area area, must not be null
205      * @return the center of the specified area using its bounds rectangle
206      */
207     static Point2D centerOf(final Area area)
208     {
209         if (area == null)
210         {
211             throw new IllegalArgumentException("area must not be null");
212         }
213         Rectangle2D rectangle = area.getBounds2D();
214         return new Point2D.Double(rectangle.getCenterX(), rectangle.getCenterY());
215     }
216 }