]> gerrit.simantics Code Review - simantics/3d.git/blob - org.jcae.opencascade/src-java/org/jcae/opencascade/Shape.java
Avoid extra write transactions when opening Plant3D editor
[simantics/3d.git] / org.jcae.opencascade / src-java / org / jcae / opencascade / Shape.java
1 /*
2  * Project Info:  http://jcae.sourceforge.net
3  * 
4  * This program is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU Lesser General Public License as published by the Free
6  * Software Foundation; either version 2.1 of the License, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12  * details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
17  *
18  * (C) Copyright 2008,2009, by EADS France
19  */
20 package org.jcae.opencascade;
21
22 import java.io.PrintWriter;
23 import java.util.AbstractList;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.Map;
31 import java.util.NoSuchElementException;
32 import java.util.Set;
33 import java.util.logging.Level;
34 import java.util.logging.Logger;
35 import org.jcae.opencascade.jni.BRepBndLib;
36 import org.jcae.opencascade.jni.BRepBuilderAPI_MakeVertex;
37 import org.jcae.opencascade.jni.BRepBuilderAPI_Sewing;
38 import org.jcae.opencascade.jni.BRepTools;
39 import org.jcae.opencascade.jni.BRep_Builder;
40 import org.jcae.opencascade.jni.BRep_Tool;
41 import org.jcae.opencascade.jni.Bnd_Box;
42 import org.jcae.opencascade.jni.GeomAPI_ProjectPointOnSurf;
43 import org.jcae.opencascade.jni.Geom_Surface;
44 import org.jcae.opencascade.jni.TopAbs_ShapeEnum;
45 import org.jcae.opencascade.jni.TopExp_Explorer;
46 import org.jcae.opencascade.jni.TopoDS_Compound;
47 import org.jcae.opencascade.jni.TopoDS_Face;
48 import org.jcae.opencascade.jni.TopoDS_Iterator;
49 import org.jcae.opencascade.jni.TopoDS_Shape;
50 import org.jcae.opencascade.jni.TopoDS_Vertex;
51 import org.w3c.dom.Element;
52 import org.w3c.dom.Node;
53 import org.w3c.dom.NodeList;
54
55 /**
56  * An abstraction level over TopoDS_Shape to easily decorate and serialize the
57  * Opencascade shape graph.
58  *
59  * This class use the <a href="http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern">curiously
60  * recurring template pattern</a> to enforce type safety; static polymorphism is
61  * checked when compiling, there is no cast at run time.  In short, this recursive
62  * definition <code>class Shape&lt;T extends Shape&lt;T>></code> means that derived
63  * classes must be declared as <code>class Foo extends Shape&lt;Foo></code>,
64  * one cannot declare <code>class Foo extends Shape&lt;Bar></code>.
65  *
66  * <p>
67  * When a class is declared like <code>class Foo extends Shape&lt;Foo></code>,
68  * this means that all nodes of this graph are of class <code>Foo</code>.
69  * Thus {@link #children} and {@link #parents} members are declared as
70  * <code>T</code> arrays and not <code>Shape</code> arrays.  Likewise, the map
71  * used in Shape constructor must be of type <code>Map&lt;TopoDS_Shape, T></code>.
72  * In order to build a node with the right type, it is obvious that a factory
73  * is needed.  This factory is parameterized, and the parameter is the derived
74  * class of the node being created.  Under some circumstances, we sometimes
75  * need to downcast the current instance.  This could be achieved by a method like
76  * </p>
77  * <pre>
78  *   public T downcast()
79  *   {
80  *       return (T) this;
81  *   }
82  * </pre>
83  *
84  * But there is a better alternative, declare
85  * <pre>
86  *   protected abstract T getDerived();
87  * </pre>
88  * in Shape, and let all derived classes declare
89  * <pre>
90  *   protected T getDerived()
91  *   {
92  *       return this;
93  *   }
94  * </pre>
95  * @author Jerome Robert
96  */
97 public abstract class Shape<T extends Shape<T>> implements Comparable<T>
98 {
99         private static final Logger LOGGER = Logger.getLogger(Shape.class.getCanonicalName());
100
101         private static enum ListOfShapes {
102                 COMPOUND (TopAbs_ShapeEnum.COMPOUND,  "Compound",  "co"),
103                 COMPSOLID(TopAbs_ShapeEnum.COMPSOLID, "CompSolid", "cs"),
104                 SOLID    (TopAbs_ShapeEnum.SOLID,     "Solid",     "so"),
105                 SHELL    (TopAbs_ShapeEnum.SHELL,     "Shell",     "sh"),
106                 FACE     (TopAbs_ShapeEnum.FACE,      "Face",      "f"),
107                 WIRE     (TopAbs_ShapeEnum.WIRE,      "Wire",      "w"),
108                 EDGE     (TopAbs_ShapeEnum.EDGE,      "Edge",      "e"),
109                 VERTEX   (TopAbs_ShapeEnum.VERTEX,    "Vertex",    "v"),
110                 SHAPE    (TopAbs_ShapeEnum.SHAPE,     "Shape",     null);
111
112                 TopAbs_ShapeEnum type;
113                 String label;
114                 String xmlName;
115                 private ListOfShapes(TopAbs_ShapeEnum type, String label, String xmlName)
116                 {
117                         this.type = type;
118                         this.label = label;
119                         this.xmlName = xmlName;
120                 }
121         };
122         protected static GeomAPI_ProjectPointOnSurf projectPointOnSurf;
123         /** map TopoDS_Compound.class to "co" */
124         private final static Map<TopAbs_ShapeEnum, String> TYPE_MAP_XML;
125         /** map "co" to TopoDS_Compound.class */
126         private final static Map<String, TopAbs_ShapeEnum> TYPE_MAP_XML_INV;
127         /** map TopoDS_Compound.class to "Compound" */
128         private final static Map<TopAbs_ShapeEnum, String> TYPE_MAP_NAME;
129         private final static TopAbs_ShapeEnum[] TYPE;
130         private final static String[] TYPE_LABEL;
131         
132         static
133         {
134                 HashMap<TopAbs_ShapeEnum, String> m = new HashMap<TopAbs_ShapeEnum, String>();
135                 HashMap<TopAbs_ShapeEnum, String> mm = new HashMap<TopAbs_ShapeEnum, String>();
136                 HashMap<String, TopAbs_ShapeEnum> mi = new HashMap<String, TopAbs_ShapeEnum>();
137                 ListOfShapes[] shapes = ListOfShapes.values();
138                 TYPE = new TopAbs_ShapeEnum[shapes.length];
139                 TYPE_LABEL = new String[shapes.length];
140                 int i = 0;
141                 for(ListOfShapes s : shapes)
142                 {
143                         if (s != ListOfShapes.SHAPE)
144                         {
145                                 m.put(s.type, s.xmlName);
146                                 mi.put(s.xmlName, s.type);
147                         }
148                         mm.put(s.type, s.label);
149                         TYPE[i] = s.type;
150                         TYPE_LABEL[i] = s.label;
151                         i++;
152                 }
153                 TYPE_MAP_XML=Collections.unmodifiableMap(m);
154                 TYPE_MAP_NAME=Collections.unmodifiableMap(mm);
155                 TYPE_MAP_XML_INV=Collections.unmodifiableMap(mi);
156         }
157         
158         public interface Attributes
159         {
160                 String toXML();
161                 void fromXML(Element node);
162         }
163         
164         protected interface Factory<T>
165         {
166                 T create(TopoDS_Shape shape, Map<TopoDS_Shape, T> map, T[] parents);
167                 T[] createArray(int length);
168         }
169         
170         protected TopoDS_Shape impl;
171         private T[] children;
172         private T[] parents;
173
174         protected Shape()
175         {
176                 this((TopoDS_Shape)null);
177         }
178
179         protected Shape(TopoDS_Shape shape)
180         {
181                 this(shape, new HashMap<TopoDS_Shape, T>(), null);
182         }
183
184         protected Shape(String fileName)
185         {
186                 this(Utilities.readFile(fileName));
187         }
188
189         protected Shape(TopoDS_Shape shape, Map<TopoDS_Shape, T> map, T[] parents)
190         {
191                 if(shape == null)
192                 {
193                         TopoDS_Compound c =new TopoDS_Compound();
194                         new BRep_Builder().makeCompound(c);
195                         this.impl = c;
196                 }
197                 else
198                         this.impl = shape;
199                 if(parents == null)
200                         parents = getFactory().createArray(0);
201                 
202                 this.parents = parents;
203                 int cntChildren = 0;
204                 for (TopoDS_Iterator it = new TopoDS_Iterator(impl); it.more(); it.next())
205                         cntChildren++;
206                 this.children = getFactory().createArray(cntChildren);
207                 cntChildren = 0;
208                 for (TopoDS_Iterator it = new TopoDS_Iterator(impl); it.more(); it.next())
209                 {
210                         TopoDS_Shape tds = it.value();
211                         T css = map.get(tds);
212                         if (css == null)
213                         {
214                                 T[] pArray = getFactory().createArray(1);
215                                 pArray[0] = getDerived();
216                                 css = getFactory().create(tds, map, pArray);
217                         }
218
219                         children[cntChildren] = css;
220                         cntChildren++;
221                 }
222                 map.put(shape, getDerived());
223         }
224
225         public static String[] getLabels(TopAbs_ShapeEnum from)
226         {
227                 int startIndex = from.ordinal();
228                 String[] toReturn = new String[TopAbs_ShapeEnum.values().length - 1 - startIndex];
229                 System.arraycopy(TYPE_LABEL, startIndex, toReturn, 0, toReturn.length);
230                 return toReturn;
231         }
232
233         protected abstract Factory<T> getFactory();
234         protected abstract T getDerived();
235         
236         public void add(T newShape)
237         {
238                 impl.free(true);
239                 new BRep_Builder().add(impl, newShape.impl);
240                 T[] nc = getFactory().createArray(children.length + 1);
241                 System.arraycopy(children, 0, nc, 0, children.length);
242                 nc[nc.length - 1] = newShape;
243                 children = nc;
244
245                 T[] np = newShape.getFactory().createArray(newShape.parents.length+1);
246                 System.arraycopy(newShape.parents, 0, np, 0, np.length - 1);
247                 np[np.length - 1]=getDerived();
248                 newShape.parents = np;
249         }
250         
251         /**
252          * Add a Vertex to this shape
253          * @return the created vertex
254          */
255         public T addVertex(double[] coords)
256         {
257                 TopoDS_Vertex v = (TopoDS_Vertex) new BRepBuilderAPI_MakeVertex(
258                         coords).shape();
259                 T vs = getFactory().create(v, new HashMap<TopoDS_Shape, T>(), getFactory().createArray(0));
260                 add(vs);
261                 if(impl instanceof TopoDS_Face)
262                 {
263                         TopoDS_Face face = (TopoDS_Face) impl;
264                         //Project p5 on surface
265                         double [] uvTol = new double[3];
266                         projectPoint(coords, uvTol);
267                         new BRep_Builder().updateVertex(v, uvTol[0], uvTol[1], face, uvTol[2]);
268                 }               
269                 return vs;
270         }
271
272         /**
273          * Project a point on surface.
274          * result[2] will contains Double.POSITIVE_INFINITY if no projection are
275          * found.
276          * @param result {u, v, distance, x, y, z}
277          * @throws ClassCastException if this shape is not a surface
278          */
279         public void projectPoint(double[] coords, double[] result)
280         {
281                 TopoDS_Face face = (TopoDS_Face) impl;
282                 Geom_Surface surface = BRep_Tool.surface(face);
283                 if(projectPointOnSurf == null)
284                         projectPointOnSurf = new GeomAPI_ProjectPointOnSurf(coords, surface);
285                 else
286                         projectPointOnSurf.init(coords, surface);
287                 if(projectPointOnSurf.nbPoints()>0)
288                 {
289                         projectPointOnSurf.lowerDistanceParameters(result);
290                         double[] p = projectPointOnSurf.nearestPoint();
291                         result[2] = projectPointOnSurf.lowerDistance();
292                         System.arraycopy(p, 0, result, 3, 3);
293                 }
294                 else
295                         result[2] = Double.POSITIVE_INFINITY;
296         }
297         
298         /** Remove this shape from its parents */
299         public void remove()
300         {
301                 BRep_Builder bb = new BRep_Builder();
302                 T shape = getDerived();
303                 for(T parent : parents)
304                 {
305                         ArrayList<T> set = new ArrayList<T>(Arrays.asList(parent.children));
306                         if(set.contains(shape))
307                         {                                               
308                                 parent.impl.free(true);
309                                 bb.remove(parent.impl, impl);
310                                 set.remove(shape);
311                                 parent.children = set.toArray(getFactory().createArray(set.size()));
312                         }
313                 }
314                 parents = getFactory().createArray(0);
315         }
316         
317         public void reverse()
318         {
319                 T[] parentSav = parents.clone();
320                 remove();
321                 impl.reverse();
322                 for(T s : parentSav)
323                         s.add(getDerived());
324         }
325                 
326         //TODO remplace this by a "sew" method which keep track of attributes. See
327         // aseris-hf GUI for an example of that.
328         public T sewed(double tolerance, boolean option, boolean cutting, boolean manifold)
329         {
330                 BRepBuilderAPI_Sewing sewer=new BRepBuilderAPI_Sewing();
331                 sewer.init(tolerance, option, cutting, manifold);
332                 sewer.add(impl);
333                 sewer.perform();
334                 return getFactory().create(sewer.sewedShape(), new HashMap<TopoDS_Shape, T>(), getFactory().createArray(0));
335         }
336         
337         public void dump(PrintWriter writer)
338         {
339                 int[] ids = new int[TopAbs_ShapeEnum.values().length - 1];
340                 Arrays.fill(ids, 1);
341                 writer.println("<geometry>");
342                 dump(writer, new HashSet<T>(), ids);
343                 writer.println("</geometry>");
344         }
345
346         private void dump(PrintWriter writer, Set<T> shapeSet, int[] id)
347         {
348                 T shape = getDerived();
349                 if (!shapeSet.contains(shape))
350                 {
351                         int type = getType().ordinal();
352                         shapeSet.add(shape);
353                         if(getAttributes()!=null)
354                         {
355                                 String e = TYPE_MAP_XML.get(impl.shapeType());
356                                 writer.println("<" + e + " id=\"" + id[type] + "\">");
357                                 writer.println(getAttributes().toXML());
358                                 writer.println("</"+e+">");
359                         }
360                         id[type]++;
361                         for (T s : children)
362                                 s.dump(writer, shapeSet, id);
363                 }
364         }
365
366         public void load(Node node)
367         {
368                 NodeList nodes = node.getChildNodes();
369                 for(int i = 0, imax = nodes.getLength(); i < imax; i++)
370                 {
371                         Node n = nodes.item(i);
372                         if(n.getNodeType() == Node.ELEMENT_NODE)
373                         {
374                                 TopAbs_ShapeEnum type = TYPE_MAP_XML_INV.get(n.getNodeName());
375                                 Element e = (Element)n;
376                                 int id = Integer.parseInt(e.getAttribute("id"));
377                                 Shape s = getShapeFromID(id, type);
378                                 if(s.getAttributes()==null)
379                                         s.createAttributes();
380                                 s.getAttributes().fromXML(e);
381                         }                       
382                 }
383         }
384         
385         /**
386          * Return the ID of this shape, considering it's in a given root shape
387          * @return the ID of this shape or -1 if this shape is not a child of
388          * rootShape
389          */
390         public int getID(T rootShape)
391         {
392                 int[] ids = new int[]{0};
393                 if (getID(rootShape, new HashSet<T>(), ids, impl.shapeType()))
394                         return ids[0];
395                 else
396                         return -1;
397         }
398         
399         public int getID()
400         {
401                 T r = getRootShape();
402                 int id = getID(r);
403                 if(id<0)
404                         throw new NoSuchElementException("Cannot find " + impl + " in " + r);
405                 return id;
406         }       
407         
408         private boolean getID(T rootShape, Set<T> shapeSet, int[] number,
409                 TopAbs_ShapeEnum wantedType)
410         {       
411                 if (shapeSet.contains(rootShape))
412                         return false;
413                 
414                 shapeSet.add(rootShape);
415                 //check if the root shape have the right type
416                 int compare = rootShape.impl.shapeType().compareTo(wantedType);
417                 if (compare == 0)
418                 {
419                         number[0]++;    
420                         if(this.equals(rootShape))
421                                 return true;
422                         //A compound can include another compound
423                         else if(rootShape.impl instanceof TopoDS_Compound)
424                         {
425                                 //So we don't give up but iterate on children
426                                 for (T s : rootShape.children)
427                                         //only on TopoDS_Compound children
428                                         if (s.impl instanceof TopoDS_Compound &&
429                                             getID(s, shapeSet, number, wantedType))
430                                                 return true;                                    
431                         }
432                 }
433                 else if (compare < 0)
434                 {
435                         //look for this shape in children
436                         for (T s : rootShape.children)
437                                 if (getID(s, shapeSet, number, wantedType))
438                                         return true;
439                 }
440                 return false;
441         }       
442         
443         /**
444          * @param result will contains the found shapes. Use a HashSet to get unique
445          * shapes (getFromID) and ArrayList to get doublon (explore)
446          * @param wantedType the type of shape to return
447          * @param maxsize the maximum number of returned shapes
448          * @param shape exploration will end when this shape will be found
449          */
450         private T explore(Collection<T> result, TopAbs_ShapeEnum wantedType, int maxsize,
451                 TopoDS_Shape shape)
452         {
453                 if(impl.shapeType().equals(wantedType))
454                 {
455                         result.add(getDerived());
456                         if(result.size()>=maxsize)
457                                 return getDerived();
458                         if(impl.equals(shape))
459                                 return getDerived();
460                 }
461                 
462                 for(T s : children)
463                 {
464                         T toReturn = s.explore(result, wantedType, maxsize, shape);
465                         if(toReturn != null)
466                                 return toReturn;
467                 }
468                 
469                 return null;
470         }
471         
472         /**
473          * Return the children of this shape whose type is type
474          */
475         public Collection<T> explore(TopAbs_ShapeEnum type)
476         {
477                 ArrayList<T> toReturn = new ArrayList<T>();
478                 explore(toReturn, type, Integer.MAX_VALUE, null);
479                 return toReturn;
480         }
481         
482         public T getRootShape()
483         {
484                 T aparent = getDerived();
485                 while(aparent.parents.length!=0)
486                         aparent = aparent.parents[0];
487                 return aparent;
488         }
489         
490         /**
491          * @param id from 1 to n
492          * @param type shape type
493          * @return the shape of the given type with this id
494          */
495         public T getShapeFromID(int id, TopAbs_ShapeEnum type)
496         {
497                 if(id<1)
498                         throw new IllegalArgumentException("Shape ID must be greater than 1");
499
500                 Collection<T> result = new HashSet<T>();
501                 T toReturn = explore(result, type, id, null);
502                 if(toReturn == null)
503                 {
504                         throw new ArrayIndexOutOfBoundsException("This shape contains only "
505                                 +result.size()+" elements of type "+type);
506                 }
507                 return toReturn;
508         }
509         
510         public T getShapeFromImpl(TopoDS_Shape shape)
511         {
512                 Collection<T> dummy = new AbstractList<T>()
513                 {
514                         @Override
515                         public void add(int index, T element) {}
516
517                         @Override
518                         public T get(int index)
519                         {
520                                 throw new UnsupportedOperationException();
521                         }
522
523                         @Override
524                         public int size()
525                         {
526                                 return 0;
527                         }
528                 };
529                 return explore(dummy, shape.shapeType(), Integer.MAX_VALUE, shape);
530         }
531         
532         /**
533          * Return the closest parent shape which is a Compound
534          * @return the closest parent shape which is a Compound
535          */
536         public T getCompound()
537         {
538                 if(impl instanceof TopoDS_Compound)
539                         return getDerived();
540                 else if(parents.length>0)
541                         return parents[0].getCompound();
542                 else
543                         return null;
544         }
545         
546         public double getTolerance()
547         {
548                 return Utilities.tolerance(impl);
549         }
550
551         public TopAbs_ShapeEnum getType()
552         {
553                 return impl.shapeType();
554         }
555
556         /**return {xmin, ymin, zmin, xmax, ymax, zmax} */ 
557         public double[] getBounds()
558         {
559                 Bnd_Box box = new Bnd_Box();                    
560                 BRepBndLib.add(impl,box);                       
561                 return box.get();
562         }
563         
564         /**
565          * return the attributes of this nodes.
566          * Can be null if it as no attributes (default values)
567          */
568         protected Attributes getAttributes()
569         {
570                 return null;
571         }
572
573         /**
574          * Initialise the attributes. Ones called getAttributes will not return
575          * null.
576          */
577         protected void createAttributes()
578         {
579         }
580
581         public String getName()
582         {
583                 return TYPE_MAP_NAME.get(impl.shapeType());
584         }
585
586         public void saveImpl(String fileName)
587         {
588                 BRepTools.write(impl, fileName);
589         }
590         
591         public int compareTo(T o)
592         {
593                 int r = getType().compareTo(o.getType());
594                 if( r == 0 )
595                         r = getID() - o.getID();
596
597                 return r;
598         }       
599         
600         /** For debugging */
601         private static void dumpTopExp(TopoDS_Shape shape)
602         {
603                 for (TopAbs_ShapeEnum type : TopAbs_ShapeEnum.values())
604                 {
605                         if (type.equals(TopAbs_ShapeEnum.SHAPE))
606                                 continue;
607                         TopExp_Explorer ex = new TopExp_Explorer(shape, type);
608                         while (ex.more())
609                         {
610                                 System.out.println(ex.current());
611                                 ex.next();
612                         }
613                 }
614         }
615
616         /** For debugging */
617         public static void main(final String[] args)
618         {
619                 try
620                 {
621                         long t1 = System.nanoTime();
622                         TopoDS_Shape rootShape = Utilities.readFile("/home/jerome/Models/F1.brep");
623                         long t2 = System.nanoTime();
624                         LOGGER.info("Time to load brep: " + (t2 - t1) / 1E9);
625                         System.gc();
626                         LOGGER.info("Used memory :" +
627                                 (Runtime.getRuntime().totalMemory() -
628                                 Runtime.getRuntime().freeMemory()) / 1E6 + " Mb");                      
629                         t1 = System.nanoTime();
630                         ShapeImpl rootShapeJ = new ShapeImpl(rootShape, new HashMap<TopoDS_Shape, ShapeImpl>(), new ShapeImpl[0]);
631                         t2 = System.nanoTime();
632                         LOGGER.info("Time to create dual graph: " + (t2 - t1) / 1E9);
633                         System.gc();
634                         LOGGER.info("Used memory :" +
635                                 (Runtime.getRuntime().totalMemory() -
636                                 Runtime.getRuntime().freeMemory()) / 1E6 + " Mb");
637                         LOGGER.info(rootShapeJ.toString());
638                         t1 = System.nanoTime();
639                         ShapeImpl s = rootShapeJ.getShapeFromID(330, TopAbs_ShapeEnum.EDGE);
640                         t2 = System.nanoTime();
641                         ShapeImpl ss = rootShapeJ.getShapeFromImpl(s.impl);
642                         long t3 = System.nanoTime();
643                         int id = ss.getID();
644                         long t4 = System.nanoTime();
645                         System.out.println("time for getShapeFromID: "+(t2-t1)/1E9);
646                         System.out.println("time for getShapeFromImpl: "+(t3-t2)/1E9);
647                         System.out.println("time for getID: "+(t4-t3)/1E9);
648                 }
649                 catch (Exception ex)
650                 {
651                         LOGGER.log(Level.SEVERE, null, ex);
652                 }       
653         }
654
655         private static final Factory<ShapeImpl> DEFAULT_FACTORY=new Factory<ShapeImpl>()
656         {
657                 public ShapeImpl create(TopoDS_Shape shape, Map<TopoDS_Shape, ShapeImpl> map, ShapeImpl[] parents)
658                 {
659                         return new ShapeImpl(shape, map, parents);
660                 }
661
662                 public ShapeImpl[] createArray(int length)
663                 {
664                         return new ShapeImpl[length];
665                 }
666         };
667
668         private static class ShapeImpl extends Shape<ShapeImpl>
669         {
670                 public ShapeImpl(TopoDS_Shape shape, Map<TopoDS_Shape, ShapeImpl> map, ShapeImpl[] parents)
671                 {
672                         super(shape, map, parents);
673                 }
674
675                 protected Factory<ShapeImpl> getFactory()
676                 {
677                         return DEFAULT_FACTORY;
678                 }
679
680                 protected ShapeImpl getDerived()
681                 {
682                         return this;
683                 }
684         }
685 }