~ubuntu-branches/debian/sid/geogebra/sid

« back to all changes in this revision

Viewing changes to geogebra/kernel/AlgoMacro.java

  • Committer: Package Import Robot
  • Author(s): Giovanni Mascellani
  • Date: 2012-01-10 11:37:41 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20120110113741-satwohsd4de4ite1
Tags: 4.0.19.0+dfsg1-1
* New upstream version (closes: #649893).
* Update dependency: icedtea-plugin -> icedtea-netx-common (LP: #893007).
* New thumbnailer configuration compatible with Gnome 3.
* Package building is now managed by javahelper instead of upstream
  build.xml.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* 
2
 
GeoGebra - Dynamic Mathematics for Everyone
3
 
http://www.geogebra.org
4
 
 
5
 
This file is part of GeoGebra.
6
 
 
7
 
This program is free software; you can redistribute it and/or modify it 
8
 
under the terms of the GNU General Public License as published by 
9
 
the Free Software Foundation.
10
 
 
11
 
*/
12
 
 
13
 
package geogebra.kernel;
14
 
 
15
 
import geogebra.kernel.arithmetic.ExpressionNode;
16
 
import geogebra.kernel.arithmetic.ExpressionValue;
17
 
import geogebra.kernel.arithmetic.Function;
18
 
import geogebra.main.Application;
19
 
 
20
 
import java.util.ArrayList;
21
 
import java.util.HashMap;
22
 
 
23
 
 
24
 
/**
25
 
 * Algorithm to invoke a specific macro. 
26
 
 * 
27
 
 * @author  Markus
28
 
 * @version 
29
 
 */
30
 
public class AlgoMacro extends AlgoElement 
31
 
implements EuclidianViewAlgo {
32
 
 
33
 
        private static final long serialVersionUID = 1L;        
34
 
        
35
 
        private Macro macro; 
36
 
        
37
 
        // macro construction, its input and output used by this algo   
38
 
        private GeoElement [] macroInput, macroOutput;
39
 
        
40
 
        // maps macro geos to algo geos
41
 
        private HashMap macroToAlgoMap;
42
 
        
43
 
        // all keys of macroToAlgoMap that are not part of macroInput
44
 
        private ArrayList macroOutputAndReferencedGeos;
45
 
        private ArrayList algoOutputAndReferencedGeos; // for efficiency, see getMacroConstructionState()       
46
 
        
47
 
    /**
48
 
     * Creates a new algorithm that applies a macro to the
49
 
     * given input objects.        
50
 
     */
51
 
    public AlgoMacro(Construction cons, String [] labels, Macro macro, GeoElement [] input) {
52
 
        super(cons);
53
 
          
54
 
        this.input = input;
55
 
        this.macro = macro;
56
 
        
57
 
        this.macroInput = macro.getMacroInput();
58
 
        this.macroOutput = macro.getMacroOutput();
59
 
                           
60
 
        // register algorithm with macro
61
 
        macro.registerAlgorithm(this);
62
 
        
63
 
        // create copies for the output objects
64
 
        createOutputObjects();
65
 
                
66
 
        // initialize the mapping between macro geos and algo geos
67
 
        initMap();              
68
 
        
69
 
        setInputOutput();               
70
 
        compute(); 
71
 
        
72
 
        // check if macro construction has euclidianAlgos
73
 
        if (macro.getMacroConstruction().hasEuclidianViewAlgos()) {
74
 
                cons.registerEuclidianViewAlgo(this);
75
 
        }
76
 
        
77
 
        GeoElement.setLabels(labels, output);           
78
 
    }         
79
 
    
80
 
    public void remove() {
81
 
        macro.unregisterAlgorithm(this);
82
 
        super.remove();         
83
 
    }           
84
 
    
85
 
    protected String getClassName() {
86
 
                return "AlgoMacro";
87
 
        }
88
 
        
89
 
        String getCommandName() {
90
 
                return macro.getCommandName();
91
 
        }
92
 
    
93
 
        protected void setInputOutput() {                    
94
 
        setDependencies();
95
 
    }       
96
 
                
97
 
    final protected void compute() {
98
 
        try {                   
99
 
                // set macro geos to algo geos state
100
 
                setMacroConstructionState();
101
 
 
102
 
                        // update all algorithms of macro-construction
103
 
                        macro.getMacroConstruction().updateAllAlgorithms();             
104
 
       
105
 
                // set algo geos to macro geos state   
106
 
                getMacroConstructionState();
107
 
                
108
 
        } catch (Exception e) {
109
 
                Application.debug("AlgoMacro compute():\n");
110
 
                e.printStackTrace();
111
 
                for (int i=0; i < output.length; i++) {
112
 
                        output[i].setUndefined();
113
 
                }
114
 
        }
115
 
    }   
116
 
    
117
 
    final public String toString() {            
118
 
        return getCommandDescription();
119
 
    }            
120
 
    
121
 
    /**
122
 
     * Returns true when macroGeo is part of macroInput.
123
 
     */
124
 
        private boolean isMacroInputObject(GeoElement macroGeo) {
125
 
                for (int i=0; i < macroInput.length; i++) {
126
 
                        if (macroGeo == macroInput[i])
127
 
                                return true;
128
 
                }               
129
 
                return false;
130
 
        }               
131
 
 
132
 
        
133
 
        /** 
134
 
         * Sets macro geos to the current state of algo geos.    
135
 
         */
136
 
        final void setMacroConstructionState() {                                                                        
137
 
                // set input objects of macro construction              
138
 
                for (int i=0; i < macroInput.length; i++) {   
139
 
                        macroInput[i].set(input[i]);                            
140
 
                        macroInput[i].setRealLabel(input[i].getLabel());
141
 
                        //Application.debug("SET INPUT object: " + input[i] + " => " + macroInput[i]);
142
 
        }               
143
 
        }
144
 
 
145
 
        
146
 
        /** 
147
 
         * Sets algo geos to the current state of macro geos.    
148
 
         */
149
 
        final void getMacroConstructionState() {        
150
 
                // for efficiency: instead of lookups in macroToAlgoMap 
151
 
                // we use an array list algoOutputAndReferencedGeos with corresponding macro and algo geos
152
 
                int size = macroOutputAndReferencedGeos.size();
153
 
                for (int i=0; i < size; i++) {  
154
 
                        GeoElement macroGeo = (GeoElement) macroOutputAndReferencedGeos.get(i);
155
 
                        GeoElement algoGeo = (GeoElement) algoOutputAndReferencedGeos.get(i);
156
 
                        if (macroGeo.isDefined()) {
157
 
                                algoGeo.set(macroGeo); 
158
 
                        }
159
 
                        else algoGeo.setUndefined();
160
 
//                      System.out.println("RESULT from macro: " + macroGeo + "\n => " + algoGeo);                      
161
 
//                      System.out.println("  macroGeo kernel: " + macroGeo.kernel + ", printFigures: " + macroGeo.kernel.getPrintFigures());
162
 
//                      System.out.println("  algoGeo  kernel: " + algoGeo.kernel + ", printFigures: " + algoGeo.kernel.getPrintFigures());
163
 
                                
164
 
                }
165
 
                
166
 
// old code:            
167
 
//              int size = macroOutputAndReferencedGeos.size();
168
 
//              for (int i=0; i < size; i++) {                  
169
 
//                      GeoElement macroGeo = (GeoElement) macroOutputAndReferencedGeos.get(i);
170
 
//                      GeoElement algoGeo = (GeoElement) macroToAlgoMap.get(macroGeo);                                                 
171
 
//                      algoGeo.set(macroGeo);  
172
 
//                      
173
 
//                      Application.debug("RESULT from macro: " + macroGeo + " => " + algoGeo);
174
 
//      
175
 
//              }
176
 
        }
177
 
        
178
 
        
179
 
        /**
180
 
         * Creates the output objects of this macro algorithm
181
 
         */
182
 
        private void createOutputObjects() {            
183
 
                output = new GeoElement[macroOutput.length];                                                                                                            
184
 
                
185
 
                for (int i=0; i < macroOutput.length; i++) {  
186
 
                        // copy output object of macro and make the copy part of this construction
187
 
                        output[i] = macroOutput[i].copyInternal(cons);                  
188
 
                        output[i].setUseVisualDefaults(false);
189
 
                        output[i].setVisualStyle(macroOutput[i]);       
190
 
                        output[i].setAlgoMacroOutput(true);
191
 
        }
192
 
        }
193
 
        
194
 
        /**
195
 
         * Inits the mapping of macro geos to algo geos construction.
196
 
         * The map is used to set and get the state of the macro construction in compute()
197
 
         * and to make sure that all output geos of the algorithm and all
198
 
         * their references (e.g. the start point of a ray) are part of the algorithm's 
199
 
         * construction.
200
 
         */
201
 
        private void initMap() {        
202
 
                macroToAlgoMap = new HashMap();
203
 
                macroOutputAndReferencedGeos = new ArrayList();
204
 
                algoOutputAndReferencedGeos = new ArrayList();
205
 
                        
206
 
                // INPUT initing        
207
 
                // map macro input to algo input
208
 
                for (int i=0; i < macroInput.length; i++) {
209
 
                        map(macroInput[i], input[i]);
210
 
                }                                       
211
 
                                                
212
 
                // OUTPUT initing       
213
 
                // map macro output to algo output
214
 
                for (int i=0; i < macroOutput.length; i++) {
215
 
                        map(macroOutput[i], output[i]);                                 
216
 
        }                               
217
 
                // SPECIAL REFERENCES of output
218
 
                // make sure all algo-output objects reference objects in their own construction                
219
 
                // note: we do this in an extra loop to make sure we don't create output objects twice  
220
 
                for (int i=0; i < macroOutput.length; i++) { 
221
 
                        initSpecialReferences(macroOutput[i], output[i]);                                       
222
 
        }                                                                                                                                               
223
 
        }
224
 
        
225
 
        /**
226
 
         * Adds a (macroGeo, algoGeo) pair to the map.                  
227
 
         */             
228
 
        private void map(GeoElement macroGeo, GeoElement algoGeo) {                                     
229
 
                if (macroToAlgoMap.get(macroGeo) == null) {
230
 
                        // map macroGeo to algoGeo
231
 
                        macroToAlgoMap.put(macroGeo, algoGeo);  
232
 
                        
233
 
                        if (!isMacroInputObject(macroGeo)) {                                            
234
 
                                macroOutputAndReferencedGeos.add(macroGeo);
235
 
                                // for efficiency: to avoid lookups in macroToAlgoMap
236
 
                                algoOutputAndReferencedGeos.add(algoGeo); 
237
 
                        }                                       
238
 
                }
239
 
        }
240
 
        
241
 
        /**
242
 
         * Returns a GeoElement in this algo's construction
243
 
         * that corresponds to the given macroGeo from the macro construction.
244
 
         * If a macro-geo is not yet
245
 
         * mapped to an algo-geo, a new algo-geo is created and added to 
246
 
         * the map automatically.
247
 
         */
248
 
        private GeoElement getAlgoGeo(GeoElement macroGeo) {
249
 
                if (macroGeo == null) return null;
250
 
                GeoElement algoGeo = (GeoElement) macroToAlgoMap.get(macroGeo);
251
 
                
252
 
                // if we don't have a corresponding GeoElement in our map yet, 
253
 
                // create a new geo and update the map
254
 
                if (algoGeo == null) {          
255
 
                        algoGeo = createAlgoCopy(macroGeo);
256
 
                        map(macroGeo, algoGeo); 
257
 
                }                       
258
 
                
259
 
                return algoGeo;         
260
 
        }
261
 
        
262
 
        /**
263
 
         * Creates a new algo-geo in this construction that is copy of macroGeo from
264
 
         * the macro construction.
265
 
         */
266
 
        private GeoElement createAlgoCopy(GeoElement macroGeo) {
267
 
                GeoElement algoGeo = macroGeo.copyInternal(cons);       
268
 
                return algoGeo;
269
 
        }
270
 
        
271
 
                
272
 
        /**
273
 
         * Some GeoElement types need special settings as they reference other
274
 
         * GeoElement objects. We need to make sure that algoGeo
275
 
         * only reference objects in its own construction.
276
 
         */     
277
 
        private void initSpecialReferences(GeoElement macroGeo, GeoElement algoGeo) {
278
 
                
279
 
                switch (macroGeo.getGeoClassType()) {                           
280
 
                        case GeoElement.GEO_CLASS_FUNCTION:
281
 
                                initFunction(((GeoFunction) algoGeo).getFunction());
282
 
                                break;
283
 
                                
284
 
                        case GeoElement.GEO_CLASS_FUNCTIONCONDITIONAL:
285
 
                                // done by set() in GeoFunctionConditional 
286
 
                                // actually a GeoFunctionConditional consists of three GeoFunction objects,
287
 
                                // so initFunction() is eventually used for them
288
 
                                break;
289
 
                                                                                        
290
 
                        case GeoElement.GEO_CLASS_LIST:
291
 
                                initList((GeoList) macroGeo, (GeoList) algoGeo);
292
 
                                break;                                                                  
293
 
                                                                                
294
 
                        case GeoElement.GEO_CLASS_LINE:                                         
295
 
                                initLine((GeoLine) macroGeo, (GeoLine) algoGeo);
296
 
                                break;  
297
 
                                
298
 
                        case GeoElement.GEO_CLASS_POLYGON:
299
 
                                initPolygon((GeoPolygon) macroGeo, (GeoPolygon) algoGeo);
300
 
                                break;                                  
301
 
                                
302
 
                        case GeoElement.GEO_CLASS_CONIC:
303
 
                                initConic((GeoConic) macroGeo, (GeoConic) algoGeo);
304
 
                                break;
305
 
 
306
 
                        case GeoElement.GEO_CLASS_TEXT:                         
307
 
                        case GeoElement.GEO_CLASS_VECTOR:
308
 
                        case GeoElement.GEO_CLASS_IMAGE:
309
 
                                initLocateable((Locateable) macroGeo, (Locateable) algoGeo);
310
 
                                break;
311
 
 
312
 
                        default:
313
 
                        // no special treatment necessary at the moment
314
 
                                // case GeoElement.GEO_CLASS_ANGLE:                                                             
315
 
                                // case GeoElement.GEO_CLASS_BOOLEAN:                           
316
 
                                // case GeoElement.GEO_CLASS_CONICPART:
317
 
                                // case GeoElement.GEO_CLASS_LOCUS:
318
 
                                // case GeoElement.GEO_CLASS_NUMERIC:
319
 
                                // case GeoElement.GEO_CLASS_POINT:     
320
 
                                // case GeoElement.GEO_CLASS_AXIS:
321
 
                                // case GeoElement.GEO_CLASS_RAY:
322
 
                                // case GeoElement.GEO_CLASS_SEGMENT:
323
 
                                // case GeoElement.GEO_CLASS_POLYGON:
324
 
                }                                               
325
 
        }               
326
 
        
327
 
        /**
328
 
         * Makes sure that the start and end point of a line are
329
 
         * in its construction (if the line has this kind of information).
330
 
         */                     
331
 
        private void initLine(GeoLine macroLine, GeoLine line) {                                
332
 
                GeoPoint startPoint = (GeoPoint) getAlgoGeo(macroLine.getStartPoint());
333
 
                GeoPoint endPoint   = (GeoPoint) getAlgoGeo(macroLine.getEndPoint());                                           
334
 
                line.setStartPoint(startPoint);
335
 
                line.setEndPoint(endPoint);                                     
336
 
        }
337
 
        
338
 
        /**
339
 
         * Makes sure that all points on conic are
340
 
         * in its construction.
341
 
         */                     
342
 
        private void initConic(GeoConic macroConic, GeoConic conic) {
343
 
                ArrayList macroPoints = macroConic.getPointsOnConic();
344
 
                if (macroPoints == null) return;
345
 
                
346
 
                int size = macroPoints.size();
347
 
                ArrayList points = new ArrayList(size);         
348
 
                for (int i=0; i < size; i++) {
349
 
                        points.add(getAlgoGeo((GeoElement) macroPoints.get(i)));
350
 
                }
351
 
                conic.setPointsOnConic(points);                                 
352
 
        }
353
 
 
354
 
        /**
355
 
         * Makes sure that the start points of locateable are
356
 
         * in its construction.
357
 
         */     
358
 
        private void initLocateable(Locateable macroLocateable, Locateable locateable) {
359
 
                GeoPoint [] macroStartPoints = macroLocateable.getStartPoints();
360
 
                if (macroStartPoints == null) return;
361
 
                
362
 
                try {                                   
363
 
                        for (int i=0; i < macroStartPoints.length; i++) {
364
 
                                GeoPoint point = (GeoPoint) getAlgoGeo(macroStartPoints[i]);
365
 
                                locateable.initStartPoint(point, i);
366
 
                                
367
 
                                //Application.debug("set start point: " + locateable + " => " + point + "(" + point.cons +")");
368
 
                                
369
 
                        }       
370
 
                } catch (Exception e) {
371
 
                        Application.debug("AlgoMacro.initLocateable:\n" + e.getStackTrace());
372
 
                }
373
 
        }               
374
 
        
375
 
        /**
376
 
         * Makes sure that the points and segments of poly are
377
 
         * in its construction.
378
 
         */
379
 
        private void initPolygon(GeoPolygon macroPoly, GeoPolygon poly) {                                                               
380
 
                // points
381
 
                GeoPoint [] macroPolyPoints = macroPoly.getPoints();
382
 
                GeoPoint [] polyPoints = new GeoPoint[macroPolyPoints.length];                                                                          
383
 
                for (int i=0; i < macroPolyPoints.length; i++) {
384
 
                        polyPoints[i] = (GeoPoint) getAlgoGeo( macroPolyPoints[i] );    
385
 
                }
386
 
                poly.setPoints(polyPoints);
387
 
                
388
 
 
389
 
//              // segments
390
 
//              GeoSegment [] macroPolySegments = macroPoly.getSegments();
391
 
//              GeoSegment [] polySegments = new GeoSegment[macroPolySegments.length];                                                                          
392
 
//              for (int i=0; i < macroPolySegments.length; i++) {
393
 
//                      polySegments[i] = (GeoSegment) getAlgoGeo( macroPolySegments[i] );      
394
 
//                      initLine(macroPolySegments[i], polySegments[i]);
395
 
//              }
396
 
//              poly.setSegments(polySegments);
397
 
                                                                                
398
 
        } 
399
 
        
400
 
        
401
 
        /**
402
 
         * Makes sure that all referenced GeoElements of geoList are
403
 
         * in its construction.
404
 
         */                     
405
 
        final public void initList(GeoList macroList, GeoList geoList) {                        
406
 
                // make sure all referenced GeoElements are from the algo-construction
407
 
                
408
 
                int size = macroList.size();
409
 
                geoList.clear();
410
 
                geoList.ensureCapacity(size);
411
 
                for (int i=0; i < size; i++) {  
412
 
                        geoList.add( getAlgoGeo(macroList.get(i)) );                            
413
 
                }                       
414
 
        } 
415
 
        
416
 
        /**
417
 
         * Makes sure that all referenced GeoElements of fun are
418
 
         * in this algorithm's construction.
419
 
         */                     
420
 
        final public void initFunction(Function fun) {                                                          
421
 
                // geoFun was created as a copy of macroFun, 
422
 
                // make sure all referenced GeoElements are from the algo-construction
423
 
                replaceReferencedMacroObjects(fun.getExpression());
424
 
        } 
425
 
                
426
 
        /**
427
 
         * Replaces all references to macroGeos in expression exp by references to the corresponding
428
 
         * algoGeos
429
 
         */
430
 
        private void replaceReferencedMacroObjects(ExpressionNode exp) {
431
 
                ExpressionValue left = exp.getLeft();
432
 
                ExpressionValue right = exp.getRight();
433
 
                
434
 
                // left tree
435
 
                if (left.isGeoElement()) {                                                              
436
 
                        GeoElement referencedGeo = (GeoElement) left;                   
437
 
                        if (macro.isInMacroConstruction(referencedGeo)) {
438
 
                                exp.setLeft(getAlgoGeo(referencedGeo));                 
439
 
                        }       
440
 
                }               
441
 
                else if (left.isExpressionNode()) {
442
 
                        replaceReferencedMacroObjects((ExpressionNode) left);
443
 
                } 
444
 
                
445
 
                // right tree
446
 
                if (right == null) 
447
 
                        return;
448
 
                else if (right.isGeoElement()) {
449
 
                        GeoElement referencedGeo = (GeoElement) right;
450
 
                        if (macro.isInMacroConstruction(referencedGeo)) {       
451
 
                                exp.setRight(getAlgoGeo(referencedGeo));
452
 
                        }       
453
 
                }
454
 
                else if (right.isExpressionNode()) {
455
 
                        replaceReferencedMacroObjects((ExpressionNode) right);
456
 
                }               
457
 
        }
458
 
 
459
 
    
460
 
}
 
1
/* 
 
2
GeoGebra - Dynamic Mathematics for Everyone
 
3
http://www.geogebra.org
 
4
 
 
5
This file is part of GeoGebra.
 
6
 
 
7
This program is free software; you can redistribute it and/or modify it 
 
8
under the terms of the GNU General Public License as published by 
 
9
the Free Software Foundation.
 
10
 
 
11
*/
 
12
 
 
13
package geogebra.kernel;
 
14
 
 
15
import geogebra.euclidian.EuclidianView;
 
16
import geogebra.kernel.arithmetic.ExpressionNode;
 
17
import geogebra.kernel.arithmetic.ExpressionValue;
 
18
import geogebra.kernel.arithmetic.FunctionNVar;
 
19
import geogebra.kernel.kernelND.GeoPointND;
 
20
import geogebra.main.Application;
 
21
 
 
22
import java.util.ArrayList;
 
23
import java.util.HashMap;
 
24
 
 
25
 
 
26
/**
 
27
 * Algorithm to invoke a specific macro. 
 
28
 * 
 
29
 * @author  Markus
 
30
 * @version 
 
31
 */
 
32
public class AlgoMacro extends AlgoElement 
 
33
implements EuclidianViewCE {
 
34
 
 
35
        private static final long serialVersionUID = 1L;        
 
36
        
 
37
        private Macro macro; 
 
38
        
 
39
        // macro construction, its input and output used by this algo   
 
40
        private GeoElement [] macroInput, macroOutput;
 
41
        
 
42
        // maps macro geos to algo geos
 
43
        private HashMap<GeoElement,GeoElement> macroToAlgoMap;
 
44
        
 
45
        // all keys of macroToAlgoMap that are not part of macroInput
 
46
        private ArrayList<GeoElement> macroOutputAndReferencedGeos;
 
47
        private ArrayList<GeoElement> algoOutputAndReferencedGeos; // for efficiency, see getMacroConstructionState()   
 
48
        
 
49
    /**
 
50
     * Creates a new algorithm that applies a macro to the
 
51
     * given input objects.        
 
52
     * @param cons
 
53
     * @param labels
 
54
     * @param macro
 
55
     * @param input
 
56
     */
 
57
    public AlgoMacro(Construction cons, String [] labels, Macro macro, GeoElement [] input) {
 
58
        super(cons);
 
59
          
 
60
        this.input = input;
 
61
        this.macro = macro;
 
62
        
 
63
        this.macroInput = macro.getMacroInput();
 
64
        this.macroOutput = macro.getMacroOutput();
 
65
                           
 
66
        // register algorithm with macro
 
67
        macro.registerAlgorithm(this);
 
68
        
 
69
        // create copies for the output objects
 
70
        createOutputObjects();
 
71
                
 
72
        // initialize the mapping between macro geos and algo geos
 
73
        initMap();              
 
74
        
 
75
        setInputOutput();               
 
76
        compute(); 
 
77
        
 
78
        // check if macro construction has euclidianAlgos
 
79
        if (macro.getMacroConstruction().hasEuclidianViewCE()) {
 
80
                cons.registerEuclidianViewCE(this);
 
81
        }
 
82
        
 
83
        GeoElement.setLabels(labels, getOutput());     
 
84
        
 
85
        //we hide objects that are hidden in macro construction, but
 
86
        //we want to do this only with 4.0 macros
 
87
        if(macro.isCopyCaptionsAndVisibility()){
 
88
                        for(int i=0;i<macroOutput.length;i++)
 
89
                                if(!macroOutput[i].isEuclidianVisible()){
 
90
                                        getOutput(i).setEuclidianVisible(false);
 
91
                                        getOutput(i).update();
 
92
                                }
 
93
                }
 
94
    }         
 
95
    
 
96
    public void remove() {
 
97
        macro.unregisterAlgorithm(this);
 
98
        super.remove();         
 
99
    }           
 
100
    
 
101
    public String getClassName() {
 
102
                return "AlgoMacro";
 
103
        }
 
104
        
 
105
        public String getCommandName() {
 
106
                return macro.getCommandName();
 
107
        }
 
108
    
 
109
        protected void setInputOutput() {                    
 
110
        setDependencies();
 
111
    }       
 
112
                
 
113
    final protected void compute() {
 
114
        try {                   
 
115
                // set macro geos to algo geos state
 
116
                setMacroConstructionState();
 
117
 
 
118
                        // update all algorithms of macro-construction
 
119
                        macro.getMacroConstruction().updateAllAlgorithms();             
 
120
       
 
121
                // set algo geos to macro geos state   
 
122
                getMacroConstructionState();
 
123
                
 
124
        } catch (Exception e) {
 
125
                Application.debug("AlgoMacro compute():\n");
 
126
                e.printStackTrace();
 
127
                for (int i=0; i < getOutputLength(); i++) {
 
128
                        getOutput(i).setUndefined();
 
129
                }
 
130
        }
 
131
    }   
 
132
    
 
133
    final public String toString() {            
 
134
        return getCommandDescription();
 
135
    }            
 
136
    
 
137
    /**
 
138
     * Returns true when macroGeo is part of macroInput.
 
139
     */
 
140
        private boolean isMacroInputObject(GeoElement macroGeo) {
 
141
                for (int i=0; i < macroInput.length; i++) {
 
142
                        if (macroGeo == macroInput[i])
 
143
                                return true;
 
144
                }               
 
145
                return false;
 
146
        }               
 
147
 
 
148
        
 
149
        /** 
 
150
         * Sets macro geos to the current state of algo geos.   
 
151
         * Start points of vectors should not be copied. 
 
152
         */
 
153
        final void setMacroConstructionState() {                                                                        
 
154
                // set input objects of macro construction              
 
155
                for (int i=0; i < macroInput.length; i++) {                             
 
156
                        macroInput[i].set(input[i]);
 
157
                        try{
 
158
                                if(macroInput[i]instanceof GeoVector)((GeoVector)macroInput[i]).setStartPoint(null);
 
159
                        }catch(Exception e){
 
160
                                Application.debug("Exception while handling vector input: "+e);
 
161
                        }
 
162
                        macroInput[i].setRealLabel(input[i].label);             
 
163
                        //Application.debug("SET INPUT object: " + input[i] + " => " + macroInput[i]);
 
164
        }               
 
165
        }
 
166
 
 
167
        
 
168
        /** 
 
169
         * Sets algo geos to the current state of macro geos.    
 
170
         */
 
171
        final void getMacroConstructionState() {        
 
172
                // for efficiency: instead of lookups in macroToAlgoMap 
 
173
                // we use an array list algoOutputAndReferencedGeos with corresponding macro and algo geos
 
174
                int size = macroOutputAndReferencedGeos.size();
 
175
                for (int i=0; i < size; i++) {  
 
176
                        GeoElement macroGeo = (GeoElement) macroOutputAndReferencedGeos.get(i);
 
177
                        GeoElement algoGeo = (GeoElement) algoOutputAndReferencedGeos.get(i);
 
178
                        if(macroGeo.isDefined()){
 
179
                                algoGeo.set(macroGeo);  
 
180
                                AlgoElement drawAlgo = macroGeo.getParentAlgorithm();
 
181
                                if(drawAlgo instanceof AlgoDrawInformation){
 
182
                                        ((GeoNumeric) algoGeo).setDrawable(true);
 
183
                                        algoGeo.setDrawAlgorithm(((AlgoDrawInformation)drawAlgo).copy());
 
184
                                }
 
185
 
 
186
                        }
 
187
                        else algoGeo.setUndefined();            
 
188
                }               
 
189
        }
 
190
        
 
191
        
 
192
        /**
 
193
         * Creates the output objects of this macro algorithm
 
194
         */
 
195
        private void createOutputObjects() {            
 
196
                setOutputLength(macroOutput.length);                                                                                                            
 
197
                EuclidianView ev = app.getEuclidianView();
 
198
                int layer = ev == null ? 0 :ev.getMaxLayerUsed();
 
199
                for (int i=0; i < macroOutput.length; i++) {  
 
200
                        // copy output object of macro and make the copy part of this construction
 
201
                        setOutput(i,macroOutput[i].copyInternal(cons));
 
202
                        GeoElement out = getOutput(i); 
 
203
                        out.setUseVisualDefaults(false);
 
204
                        out.setAdvancedVisualStyle(macroOutput[i]);     
 
205
                        if(macro.isCopyCaptionsAndVisibility()){
 
206
                                out.setCaption(macroOutput[i].getCaptionNoReplace());                                                           
 
207
                        }
 
208
                        out.setLayer(layer);
 
209
                        AlgoElement drawAlgo = macroOutput[i].getParentAlgorithm();
 
210
                        if(drawAlgo instanceof AlgoDrawInformation){
 
211
                                ((GeoNumeric) out).setDrawable(true);
 
212
                                out.setDrawAlgorithm(((AlgoDrawInformation)drawAlgo).copy());
 
213
                        }
 
214
                        
 
215
                        out.setAlgoMacroOutput(true);
 
216
        }
 
217
        }
 
218
        
 
219
        /**
 
220
         * Inits the mapping of macro geos to algo geos construction.
 
221
         * The map is used to set and get the state of the macro construction in compute()
 
222
         * and to make sure that all output geos of the algorithm and all
 
223
         * their references (e.g. the start point of a ray) are part of the algorithm's 
 
224
         * construction.
 
225
         */
 
226
        private void initMap() {        
 
227
                macroToAlgoMap = new HashMap<GeoElement,GeoElement>();
 
228
                macroOutputAndReferencedGeos = new ArrayList<GeoElement>();
 
229
                algoOutputAndReferencedGeos = new ArrayList<GeoElement>();
 
230
                        
 
231
                // INPUT initing        
 
232
                // map macro input to algo input
 
233
                for (int i=0; i < macroInput.length; i++) {
 
234
                        map(macroInput[i], input[i]);
 
235
                }                                       
 
236
                                                
 
237
                // OUTPUT initing       
 
238
                // map macro output to algo output
 
239
                for (int i=0; i < macroOutput.length; i++) {
 
240
                        map(macroOutput[i], getOutput(i));                                      
 
241
        }                               
 
242
                // SPECIAL REFERENCES of output
 
243
                // make sure all algo-output objects reference objects in their own construction                
 
244
                // note: we do this in an extra loop to make sure we don't create output objects twice  
 
245
                for (int i=0; i < macroOutput.length; i++) { 
 
246
                        initSpecialReferences(macroOutput[i], getOutput(i));                                    
 
247
        }                                                                                                                                               
 
248
        }
 
249
        
 
250
        /**
 
251
         * Adds a (macroGeo, algoGeo) pair to the map.                  
 
252
         */             
 
253
        private void map(GeoElement macroGeo, GeoElement algoGeo) {                                     
 
254
                if (macroToAlgoMap.get(macroGeo) == null) {
 
255
                        // map macroGeo to algoGeo
 
256
                        macroToAlgoMap.put(macroGeo, algoGeo);  
 
257
                        
 
258
                        if (!isMacroInputObject(macroGeo)) {                                            
 
259
                                macroOutputAndReferencedGeos.add(macroGeo);
 
260
                                // for efficiency: to avoid lookups in macroToAlgoMap
 
261
                                algoOutputAndReferencedGeos.add(algoGeo); 
 
262
                        }                                       
 
263
                }
 
264
        }
 
265
        
 
266
        /**
 
267
         * Returns a GeoElement in this algo's construction
 
268
         * that corresponds to the given macroGeo from the macro construction.
 
269
         * If a macro-geo is not yet
 
270
         * mapped to an algo-geo, a new algo-geo is created and added to 
 
271
         * the map automatically.
 
272
         */
 
273
        private GeoElement getAlgoGeo(GeoElement macroGeo) {
 
274
                if (macroGeo == null) return null;
 
275
                GeoElement algoGeo = (GeoElement) macroToAlgoMap.get(macroGeo);
 
276
                
 
277
                // if we don't have a corresponding GeoElement in our map yet, 
 
278
                // create a new geo and update the map
 
279
                if (algoGeo == null) {          
 
280
                        algoGeo = createAlgoCopy(macroGeo);
 
281
                        map(macroGeo, algoGeo); 
 
282
                }                       
 
283
                
 
284
                return algoGeo;         
 
285
        }
 
286
        
 
287
        /**
 
288
         * Creates a new algo-geo in this construction that is copy of macroGeo from
 
289
         * the macro construction.
 
290
         */
 
291
        private GeoElement createAlgoCopy(GeoElement macroGeo) {
 
292
                GeoElement algoGeo = macroGeo.copyInternal(cons);       
 
293
                return algoGeo;
 
294
        }
 
295
        
 
296
                
 
297
        /**
 
298
         * Some GeoElement types need special settings as they reference other
 
299
         * GeoElement objects. We need to make sure that algoGeo
 
300
         * only reference objects in its own construction.
 
301
         */     
 
302
        private void initSpecialReferences(GeoElement macroGeo, GeoElement algoGeo) {
 
303
                
 
304
                switch (macroGeo.getGeoClassType()) {                           
 
305
                case GeoElement.GEO_CLASS_INTERVAL:
 
306
                case GeoElement.GEO_CLASS_FUNCTION:
 
307
                                initFunction(((GeoFunction) algoGeo).getFunction());
 
308
                                break;
 
309
                                
 
310
                        case GeoElement.GEO_CLASS_FUNCTIONCONDITIONAL:
 
311
                                // done by set() in GeoFunctionConditional 
 
312
                                // actually a GeoFunctionConditional consists of three GeoFunction objects,
 
313
                                // so initFunction() is eventually used for them
 
314
                                break;
 
315
                                                                                        
 
316
                        case GeoElement.GEO_CLASS_LIST:
 
317
                                initList((GeoList) macroGeo, (GeoList) algoGeo);
 
318
                                break;                                                                  
 
319
                                                                                
 
320
                        case GeoElement.GEO_CLASS_LINE:                                         
 
321
                        case GeoElement.GEO_CLASS_LINEAR_INEQUALITY:                                            
 
322
                                initLine((GeoLine) macroGeo, (GeoLine) algoGeo);
 
323
                                break;  
 
324
                                
 
325
                        case GeoElement.GEO_CLASS_POLYGON:
 
326
                                initPolygon((GeoPolygon) macroGeo, (GeoPolygon) algoGeo);
 
327
                                break;                                  
 
328
                                
 
329
                        case GeoElement.GEO_CLASS_CONIC:
 
330
                                initConic((GeoConic) macroGeo, (GeoConic) algoGeo);
 
331
                                break;
 
332
 
 
333
                        case GeoElement.GEO_CLASS_TEXT:                         
 
334
                        case GeoElement.GEO_CLASS_VECTOR:
 
335
                        case GeoElement.GEO_CLASS_IMAGE:
 
336
                                initLocateable((Locateable) macroGeo, (Locateable) algoGeo);
 
337
                                break;
 
338
 
 
339
                        default:
 
340
                        // no special treatment necessary at the moment
 
341
                                // case GeoElement.GEO_CLASS_ANGLE:                                                             
 
342
                                // case GeoElement.GEO_CLASS_BOOLEAN:                           
 
343
                                // case GeoElement.GEO_CLASS_CONICPART:
 
344
                                // case GeoElement.GEO_CLASS_LOCUS:
 
345
                                // case GeoElement.GEO_CLASS_NUMERIC:
 
346
                                // case GeoElement.GEO_CLASS_POINT:     
 
347
                                // case GeoElement.GEO_CLASS_AXIS:
 
348
                                // case GeoElement.GEO_CLASS_RAY:
 
349
                                // case GeoElement.GEO_CLASS_SEGMENT:
 
350
                                // case GeoElement.GEO_CLASS_POLYGON:
 
351
                }                                               
 
352
        }               
 
353
        
 
354
        /**
 
355
         * Makes sure that the start and end point of a line are
 
356
         * in its construction (if the line has this kind of information).
 
357
         */                     
 
358
        private void initLine(GeoLine macroLine, GeoLine line) {                                
 
359
                GeoPoint startPoint = (GeoPoint) getAlgoGeo(macroLine.getStartPoint());
 
360
                GeoPoint endPoint   = (GeoPoint) getAlgoGeo(macroLine.getEndPoint());                                           
 
361
                line.setStartPoint(startPoint);
 
362
                line.setEndPoint(endPoint);                                     
 
363
        }
 
364
        
 
365
        /**
 
366
         * Makes sure that all points on conic are
 
367
         * in its construction.
 
368
         */                     
 
369
        private void initConic(GeoConic macroConic, GeoConic conic) {
 
370
                ArrayList<GeoPoint> macroPoints = macroConic.getPointsOnConic();
 
371
                if (macroPoints == null) return;
 
372
                
 
373
                int size = macroPoints.size();
 
374
                ArrayList<GeoPoint> points = new ArrayList<GeoPoint>(size);             
 
375
                for (int i=0; i < size; i++) {
 
376
                        points.add((GeoPoint)getAlgoGeo(macroPoints.get(i)));
 
377
                }
 
378
                conic.setPointsOnConic(points);                                 
 
379
        }
 
380
 
 
381
        /**
 
382
         * Makes sure that the start points of locateable are
 
383
         * in its construction.
 
384
         */     
 
385
        private void initLocateable(Locateable macroLocateable, Locateable locateable) {
 
386
                GeoPoint [] macroStartPoints = (GeoPoint[]) macroLocateable.getStartPoints();
 
387
                if (macroStartPoints == null) return;
 
388
                
 
389
                try {                                   
 
390
                        for (int i=0; i < macroStartPoints.length; i++) {
 
391
                                GeoPoint point = (GeoPoint) getAlgoGeo(macroStartPoints[i]);
 
392
                                locateable.initStartPoint(point, i);
 
393
                                
 
394
                                //Application.debug("set start point: " + locateable + " => " + point + "(" + point.cons +")");
 
395
                                
 
396
                        }       
 
397
                } catch (Exception e) {
 
398
                        Application.debug("AlgoMacro.initLocateable:\n" + e.getStackTrace());
 
399
                }
 
400
        }               
 
401
        
 
402
        /**
 
403
         * Makes sure that the points and segments of poly are
 
404
         * in its construction.
 
405
         */
 
406
        private void initPolygon(GeoPolygon macroPoly, GeoPolygon poly) {                                                               
 
407
                // points
 
408
                GeoPointND [] macroPolyPoints = macroPoly.getPoints();
 
409
                GeoPoint [] polyPoints = new GeoPoint[macroPolyPoints.length];                                                                          
 
410
                for (int i=0; i < macroPolyPoints.length; i++) {
 
411
                        polyPoints[i] = (GeoPoint) getAlgoGeo( (GeoElement) macroPolyPoints[i] );       
 
412
                }
 
413
                poly.setPoints(polyPoints);
 
414
                
 
415
 
 
416
//              // segments
 
417
//              GeoSegment [] macroPolySegments = macroPoly.getSegments();
 
418
//              GeoSegment [] polySegments = new GeoSegment[macroPolySegments.length];                                                                          
 
419
//              for (int i=0; i < macroPolySegments.length; i++) {
 
420
//                      polySegments[i] = (GeoSegment) getAlgoGeo( macroPolySegments[i] );      
 
421
//                      initLine(macroPolySegments[i], polySegments[i]);
 
422
//              }
 
423
//              poly.setSegments(polySegments);
 
424
                                                                                
 
425
        } 
 
426
        
 
427
        
 
428
        /**
 
429
         * Makes sure that all referenced GeoElements of geoList are
 
430
         * in its construction.
 
431
         * @param macroList GeoList of macro geos 
 
432
         * @param geoList GeoList of construction geos
 
433
         */                     
 
434
        final public void initList(GeoList macroList, GeoList geoList) {                        
 
435
                // make sure all referenced GeoElements are from the algo-construction
 
436
                
 
437
                int size = macroList.size();
 
438
                geoList.clear();
 
439
                geoList.ensureCapacity(size);
 
440
                for (int i=0; i < size; i++) {  
 
441
                        geoList.add( getAlgoGeo(macroList.get(i)) );                            
 
442
                }                       
 
443
        } 
 
444
        
 
445
                
 
446
        /**
 
447
         * Makes sure that all referenced GeoElements of fun are
 
448
         * in this algorithm's construction.
 
449
         * @param fun
 
450
         */                     
 
451
        final public void initFunction(FunctionNVar fun) {                                                              
 
452
                // geoFun was created as a copy of macroFun, 
 
453
                // make sure all referenced GeoElements are from the algo-construction
 
454
                replaceReferencedMacroObjects(fun.getExpression());
 
455
        } 
 
456
                
 
457
        /**
 
458
         * Replaces all references to macroGeos in expression exp by references to the corresponding
 
459
         * algoGeos
 
460
         */
 
461
        private void replaceReferencedMacroObjects(ExpressionNode exp) {
 
462
                ExpressionValue left = exp.getLeft();
 
463
                ExpressionValue right = exp.getRight();
 
464
                
 
465
                // left tree
 
466
                if (left.isGeoElement()) {                                                              
 
467
                        GeoElement referencedGeo = (GeoElement) left;                   
 
468
                        if (macro.isInMacroConstruction(referencedGeo)) {
 
469
                                exp.setLeft(getAlgoGeo(referencedGeo));                 
 
470
                        }       
 
471
                }               
 
472
                else if (left.isExpressionNode()) {
 
473
                        replaceReferencedMacroObjects((ExpressionNode) left);
 
474
                } 
 
475
                
 
476
                // right tree
 
477
                if (right == null) 
 
478
                        return;
 
479
                else if (right.isGeoElement()) {
 
480
                        GeoElement referencedGeo = (GeoElement) right;
 
481
                        if (macro.isInMacroConstruction(referencedGeo)) {       
 
482
                                exp.setRight(getAlgoGeo(referencedGeo));
 
483
                        }       
 
484
                }
 
485
                else if (right.isExpressionNode()) {
 
486
                        replaceReferencedMacroObjects((ExpressionNode) right);
 
487
                }               
 
488
        }
 
489
 
 
490
    
 
491
}