1 /* 2 Copyright 2008,2009 3 Matthias Ehmann, 4 Michael Gerhaeuser, 5 Carsten Miller, 6 Bianca Valentin, 7 Alfred Wassermann, 8 Peter Wilfahrt 9 10 This file is part of JSXGraph. 11 12 JSXGraph is free software: you can redistribute it and/or modify 13 it under the terms of the GNU Lesser General Public License as published by 14 the Free Software Foundation, either version 3 of the License, or 15 (at your option) any later version. 16 17 JSXGraph is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 GNU Lesser General Public License for more details. 21 22 You should have received a copy of the GNU Lesser General Public License 23 along with JSXGraph. If not, see <http://www.gnu.org/licenses/>. 24 */ 25 26 /** 27 * Creates a new instance of Polygon. 28 * @class Polygon stores all style and functional properties that are required 29 * to draw a polygon on a board. 30 * @param {JXG.Board} board Reference to the board the polygon is drawn on. 31 * @param {Array} vertices Unique identifiers for the points defining the polygon. 32 * Last point must be first point. 33 * @param {Array} borders Unique identifiers for the derived borderlines of the polygon 34 * @param {String} id Unique identifier for this object. If null or an empty string is given, 35 * an unique id will be generated by Board 36 * @param {String} name Not necessarily unique name, displayed on the board. If null or an 37 * empty string is given, an unique name will be generated. 38 * @see JXG.Board#addPolygon 39 * @constructor 40 * @extends JXG.GeometryElement 41 */ 42 43 JXG.Polygon = function (board, vertices, borders, id, name, withLines, withLabel, lineLabels, layer) { 44 var i, vertex, l; 45 46 /* Call the constructor of GeometryElement */ 47 this.constructor(); 48 /** 49 * Sets type of GeometryElement, value is OBJECT_TYPE_POLYGON. 50 * @final 51 * @type Number 52 */ 53 this.type = JXG.OBJECT_TYPE_POLYGON; 54 this.elementClass = JXG.OBJECT_CLASS_AREA; 55 56 this.init(board, id, name); 57 /** 58 * Set the display layer. 59 */ 60 if (layer == null) layer = board.options.layer['polygon']; 61 this.layer = layer; 62 63 if( (typeof withLines == 'undefined') || (withLines == null) ) { 64 withLines = true; 65 } 66 if( (typeof lineLabels == 'undefined') || (lineLabels == null) ) { 67 lineLabels = false; 68 } 69 70 /** 71 * Is the polygon bordered by lines? 72 * @type Boolean 73 */ 74 this.withLines = withLines; 75 76 /** 77 * References to the points defining the polygon. 78 * Last vertex is the same as first vertex. 79 * 80 * @type Array 81 */ 82 this.vertices = []; 83 for(i=0; i<vertices.length; i++) { 84 vertex = JXG.getReference(this.board, vertices[i]); 85 this.vertices[i] = vertex; 86 } 87 88 if((typeof borders == 'undefined') || (borders == null)) { 89 borders = []; 90 for(i=0; i<vertices.length-1; i++) { 91 borders[i] = {}; 92 } 93 } 94 95 if(this.vertices[this.vertices.length-1] != this.vertices[0]) { 96 this.vertices.push(this.vertices[0]); 97 borders.push({}); 98 } 99 100 this.visProp['fillColor'] = this.board.options.polygon.fillColor; 101 this.visProp['highlightFillColor'] = this.board.options.polygon.highlightFillColor; 102 this.visProp['fillOpacity'] = this.board.options.polygon.fillOpacity; 103 this.visProp['highlightFillOpacity'] = this.board.options.polygon.highlightFillOpacity; 104 105 /** 106 * References to the borderlines of the polygon. 107 * 108 * @type Array 109 */ 110 this.borders = []; 111 if(withLines) { 112 for(i=0; i<this.vertices.length-1; i++) { 113 /* create the borderlines */ 114 l = new JXG.Line(board, this.vertices[i], this.vertices[i+1], borders[i].id, borders[i].name, lineLabels, this.layer+1); // keine Labels? 115 // Layer +1, da sonst die Linien teils 116 // hinter dem Polygon verschwinden 117 l.setStraight(false,false); // Strecke 118 this.borders[i] = l; 119 l.parentPolygon = this; 120 } 121 } 122 123 /* Add polygon as child to defining points */ 124 for(i=0; i<this.vertices.length-1; i++) { // last vertex is first vertex 125 vertex = JXG.getReference(this.board, this.vertices[i]); 126 vertex.addChild(this); 127 } 128 129 // create label 130 this.createLabel(withLabel,[0,0]); 131 132 /* Register polygon at board */ 133 this.id = this.board.setId(this,'Py'); 134 this.board.renderer.drawPolygon(this); 135 this.board.finalizeAdding(this); 136 }; 137 JXG.Polygon.prototype = new JXG.GeometryElement; 138 139 /** 140 * Checks whether (x,y) is near the polygon. 141 * @param {int} x Coordinate in x direction, screen coordinates. 142 * @param {int} y Coordinate in y direction, screen coordinates. 143 * @return {bool} Always false, because the polygons interior shall not be highlighted 144 */ 145 JXG.Polygon.prototype.hasPoint = function (x,y) { 146 return false; 147 }; 148 149 /** 150 * Uses the boards renderer to update the polygon. 151 */ 152 JXG.Polygon.prototype.updateRenderer = function () { 153 if (this.needsUpdate) { 154 this.board.renderer.updatePolygon(this); 155 this.needsUpdate = false; 156 } 157 if(this.hasLabel && this.label.content.visProp['visible']) { 158 //this.label.setCoordinates(this.coords); 159 this.label.content.update(); 160 //this.board.renderer.updateLabel(this.label); 161 this.board.renderer.updateText(this.label.content); 162 } 163 }; 164 165 /** 166 * return TextAnchor 167 */ 168 JXG.Polygon.prototype.getTextAnchor = function() { 169 var a = 0; 170 var b = 0; 171 var x = 0; 172 var y = 0; 173 a = x = this.vertices[0].X(); 174 b = y = this.vertices[0].Y(); 175 for (var i = 0; i < this.vertices.length; i++) { 176 if (this.vertices[i].X() < a) 177 a = this.vertices[i].X(); 178 if (this.vertices[i].X() > x) 179 x = this.vertices[i].X(); 180 if (this.vertices[i].Y() > b) 181 b = this.vertices[i].Y(); 182 if (this.vertices[i].Y() < y) 183 y = this.vertices[i].Y(); 184 } 185 return new JXG.Coords(JXG.COORDS_BY_USER, [(a + x)*0.5, (b + y)*0.5], this.board); 186 }; 187 188 JXG.Polygon.prototype.getLabelAnchor = function() { 189 var a = 0; 190 var b = 0; 191 var x = 0; 192 var y = 0; 193 a = x = this.vertices[0].X(); 194 b = y = this.vertices[0].Y(); 195 for (var i = 0; i < this.vertices.length; i++) { 196 if (this.vertices[i].X() < a) 197 a = this.vertices[i].X(); 198 if (this.vertices[i].X() > x) 199 x = this.vertices[i].X(); 200 if (this.vertices[i].Y() > b) 201 b = this.vertices[i].Y(); 202 if (this.vertices[i].Y() < y) 203 y = this.vertices[i].Y(); 204 } 205 return new JXG.Coords(JXG.COORDS_BY_USER, [(a + x)*0.5, (b + y)*0.5], this.board); 206 }; 207 208 /** 209 * Copy the element to the background. 210 */ 211 JXG.Polygon.prototype.cloneToBackground = function(addToTrace) { 212 var copy = {}, er; 213 copy.id = this.id + 'T' + this.numTraces; 214 this.numTraces++; 215 copy.vertices = this.vertices; 216 copy.visProp = this.visProp; 217 JXG.clearVisPropOld(copy); 218 219 er = this.board.renderer.enhancedRendering; 220 this.board.renderer.enhancedRendering = true; 221 this.board.renderer.drawPolygon(copy); 222 this.board.renderer.enhancedRendering = er; 223 this.traces[copy.id] = copy.rendNode; //$(copy.id); 224 225 delete copy; 226 }; 227 228 JXG.createPolygon = function(board, parents, atts) { 229 var el, i; 230 231 atts = JXG.checkAttributes(atts,{withLabel:JXG.readOption(board.options,'polygon','withLabel'), layer:null}); 232 // Sind alles Punkte? 233 for(i=0; i<parents.length; i++) { 234 parents[i] = JXG.getReference(board, parents[i]); 235 if(!JXG.isPoint(parents[i])) 236 throw new Error("JSXGraph: Can't create polygon with parent types other than 'point'."); 237 } 238 239 el = new JXG.Polygon(board, parents, atts["borders"], atts["id"],atts["name"],atts["withLines"], 240 atts['withLabel'],atts['lineLabels'],atts['layer']); 241 242 /*if(atts["withLines"] || true) { 243 for(i=0; i<el.borders.length; i++) { 244 el.borders[i].setProperty(atts); 245 } 246 }*/ 247 248 return el; 249 }; 250 251 JXG.JSXGraph.registerElement('polygon', JXG.createPolygon); 252 253 JXG.Polygon.prototype.hideElement = function() { 254 this.visProp['visible'] = false; 255 this.board.renderer.hide(this); 256 257 if(this.withLines) { 258 for(var i=0; i<this.borders.length; i++) { 259 this.borders[i].hideElement(); 260 } 261 } 262 263 if (this.hasLabel && this.label!=null) { 264 this.label.hiddenByParent = true; 265 if(this.label.content.visProp['visible']) { 266 this.board.renderer.hide(this.label.content); 267 } 268 } 269 }; 270 271 JXG.Polygon.prototype.showElement = function() { 272 this.visProp['visible'] = true; 273 this.board.renderer.show(this); 274 275 if(this.withLines) { 276 for(var i=0; i<this.borders.length; i++) { 277 this.borders[i].showElement(); 278 } 279 } 280 }; 281 282 JXG.Polygon.prototype.Area = function() { 283 //Surveyor's Formula 284 var area=0, i; 285 for(i=0; i<this.vertices.length-1; i++) { 286 area += (this.vertices[i].X()*this.vertices[i+1].Y()-this.vertices[i+1].X()*this.vertices[i].Y()); // last vertex is first vertex 287 } 288 area /= 2.0; 289 return Math.abs(area); 290 }; 291 292 /** 293 * @class Constructs a regular polygon. It needs two points which define the base line and the number of vertices. 294 * @pseudo 295 * @description Constructs a regular polygon. It needs two points which define the base line and the number of vertices, or a set of points. 296 * @constructor 297 * @name RegularPolygon 298 * @type JXG.Polygon 299 * @augments JXG.Polygon 300 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 301 * @param {JXG.Point_JXG.Point_Number} p1,p2,n The constructed regular polygon has n vertices and the base line defined by p1 and p2. 302 * @example 303 * var p1 = board.create('point', [0.0, 2.0]); 304 * var p2 = board.create('point', [2.0, 1.0]); 305 * 306 * var pol = board.create('regularpolygon', [p1, p2, 5]); 307 * </pre><div id="682069e9-9e2c-4f63-9b73-e26f8a2b2bb1" style="width: 400px; height: 400px;"></div> 308 * <script type="text/javascript"> 309 * var ccmex1_board = JXG.JSXGraph.initBoard('682069e9-9e2c-4f63-9b73-e26f8a2b2bb1', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}); 310 * var regpol_p1 = ccmex1_board.create('point', [0.0, 2.0]); 311 * var regpol_p2 = ccmex1_board.create('point', [2.0, 1.0]); 312 * var regpol_cc1 = ccmex1_board.create('regularpolygon', [ccmex1_p1, ccmex1_p2, 5]); 313 * </script><pre> 314 * @example 315 * var p1 = board.create('point', [0.0, 2.0]); 316 * var p2 = board.create('point', [0.0,-2.0]); 317 * var p3 = board.create('point', [-2.0,0.0]); 318 * 319 * var pol = board.create('regularpolygon', [p1, p2, p3]); 320 * </pre><div id="096a78b3-bd50-4bac-b958-3be5e7df17ed" style="width: 400px; height: 400px;"></div> 321 * <script type="text/javascript"> 322 * var ccmex2_board = JXG.JSXGraph.initBoard('096a78b3-bd50-4bac-b958-3be5e7df17ed', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}); 323 * var ccmex2_p1 = ccmex2_board.create('point', [0.0, 2.0]); 324 * var ccmex2_p2 = ccmex2_board.create('point', [0.0, -2.0]); 325 * var ccmex2_p3 = ccmex2_board.create('point', [-2.0,0.0]); 326 * var ccmex2_cc1 = ccmex2_board.create('regularpolygon', [ccmex2_p1, ccmex2_p2, ccmex2_p3]); 327 * </script><pre> 328 */ 329 JXG.createRegularPolygon = function(board, parents, atts) { 330 var el, i, n, p = [], rot, c, len, pointsExist; 331 332 atts = JXG.checkAttributes(atts,{withLabel:JXG.readOption(board.options,'polygon','withLabel'), layer:null}); 333 if (JXG.isNumber(parents[parents.length-1]) && parents.length!=3) { 334 throw new Error("JSXGraph: A regular polygon needs two point and a number as input."); 335 } 336 337 len = parents.length; 338 n = parents[len-1]; 339 if ((!JXG.isNumber(n) && !JXG.isPoint(JXG.getReference(board, n))) || n<3) { 340 throw new Error("JSXGraph: The third parameter has to be number greater than 2 or a point."); 341 } 342 343 if (JXG.isPoint(JXG.getReference(board, n))) { // Regular polygon given by n points 344 n = len; 345 pointsExist = true; 346 } else { 347 len--; 348 pointsExist = false; 349 } 350 // Sind alles Punkte? 351 for(i=0; i<len; i++) { 352 parents[i] = JXG.getReference(board, parents[i]); 353 if(!JXG.isPoint(parents[i])) 354 throw new Error("JSXGraph: Can't create regular polygon if the first two parameters aren't points."); 355 } 356 357 p[0] = parents[0]; 358 p[1] = parents[1]; 359 for (i=2;i<n;i++) { 360 rot = board.create('transform', [Math.PI*(2.0-(n-2)/n),p[i-1]], {type:'rotate'}); 361 if (pointsExist) { 362 p[i] = parents[i]; 363 p[i].addTransform(parents[i-2],rot); 364 } else { 365 p[i] = board.create('point',[p[i-2],rot],{name:'', withLabel:false,fixed:true,face:'o',size:1}); 366 } 367 } 368 el = board.create('polygon',p,atts); 369 370 return el; 371 }; 372 373 JXG.JSXGraph.registerElement('regularpolygon', JXG.createRegularPolygon); 374