package org.geogebra.common.geogebra3D.euclidian3D.draw; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import org.geogebra.common.geogebra3D.euclidian3D.Hits3D; import org.geogebra.common.geogebra3D.euclidian3D.Hitting; import org.geogebra.common.geogebra3D.euclidian3D.openGL.Renderer; import org.geogebra.common.geogebra3D.euclidian3D.printer3D.ExportToPrinter3D; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.Matrix.Coords; import org.geogebra.common.kernel.geos.GeoElement; /** * Class to list the 3D drawables for EuclidianView3D * * @author ggb3D * * */ public class Drawable3DLists { protected static class Drawable3DList extends ArrayList<Drawable3D> { /** * */ private static final long serialVersionUID = 1L; @Override public String toString() { StringBuilder sb = new StringBuilder(); for (Drawable3D d : this) { sb.append(d); sb.append(" -- "); sb.append(d.getGeoElement() .getLabel(StringTemplate.defaultTemplate)); sb.append("\n"); } return sb.toString(); } } /** lists of Drawable3D */ protected Drawable3DList[] lists; /** * default constructor * * @param view3D */ public Drawable3DLists() { lists = new Drawable3DList[Drawable3D.DRAW_TYPE_MAX]; for (int i = 0; i < Drawable3D.DRAW_TYPE_MAX; i++) { lists[i] = new Drawable3DList(); } } /** * add the drawable to the correct list * * @param drawable * drawable to add */ public void add(Drawable3D drawable) { drawable.addToDrawable3DLists(this); } /** * add a list of drawables * * @param list */ public void add(LinkedList<Drawable3D> list) { for (Drawable3D d : list) { add(d); } } /** * remove the drawable from the correct list * * @param drawable * drawable to remove */ protected void remove(Drawable3D drawable) { // TODO fix it if (drawable != null) { // Log.debug(drawable.getGeoElement()+""); drawable.removeFromDrawable3DLists(this); } } /** * remove all drawables contained in the list * * @param list */ public void remove(LinkedList<Drawable3D> list) { for (Drawable3D d : list) { remove(d); } } /** * * @param type * list type * @return list */ public Drawable3DList getList(int type) { return lists[type]; } /** * * @return true if contains clipped surfaces */ public boolean containsClippedSurfacesInclLists() { return !lists[Drawable3D.DRAW_TYPE_CLIPPED_SURFACES].isEmpty() || !lists[Drawable3D.DRAW_TYPE_LISTS].isEmpty(); } /** * * @return true if contains clipped curves */ private boolean containsClippedCurves() { return !lists[Drawable3D.DRAW_TYPE_CLIPPED_CURVES].isEmpty(); } @Override public String toString() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < Drawable3D.DRAW_TYPE_MAX; i++) { sb.append("list #"); sb.append(i); sb.append(":\n"); sb.append(lists[i].toString()); } return sb.toString(); } /** * clear all the lists */ public void clear() { for (int i = 0; i < Drawable3D.DRAW_TYPE_MAX; i++) { lists[i].clear(); } } // private boolean isUpdatingAll = false; /** update all 3D objects */ public void updateAll() { /* * if (isUpdatingAll){ Application.printStacktrace("is already updating" * ); return; } * * isUpdatingAll = true; */ for (int i = 0; i < Drawable3D.DRAW_TYPE_MAX; i++) { for (Iterator<Drawable3D> d = lists[i].iterator(); d.hasNext();) { Drawable3D d3d = d.next(); // Application.debug("updating :"+d3d.getGeoElement()); d3d.update(); } } // isUpdatingAll = false; } /** says all have to be reset */ public void resetAllDrawables() { for (int i = 0; i < Drawable3D.DRAW_TYPE_MAX; i++) { for (Iterator<Drawable3D> d = lists[i].iterator(); d.hasNext();) { d.next().setWaitForReset(); } } } /** says all have to be reset */ public void resetAllLabels() { for (int i = 0; i < Drawable3D.DRAW_TYPE_MAX; i++) { for (Iterator<Drawable3D> d = lists[i].iterator(); d.hasNext();) { d.next().setLabelWaitForReset(); } } } /** says all visual styles to be updated */ public void resetAllVisualStyles() { for (int i = 0; i < Drawable3D.DRAW_TYPE_MAX; i++) { for (Iterator<Drawable3D> d = lists[i].iterator(); d.hasNext();) { d.next().setWaitForUpdateVisualStyle(null); } } } /** * draw hidden parts not dashed * * @param renderer */ final public void drawHiddenNotTextured(Renderer renderer) { // points TODO hidden aspect ? for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_POINTS] .iterator(); d.hasNext();) { d.next().drawHidden(renderer); } for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_LISTS] .iterator(); d.hasNext();) { ((DrawList3D) d.next()).getDrawable3DLists() .drawHiddenNotTextured(renderer); } renderer.resetCenter(); } /** * export to 3D printer format * * @param exportToPrinter3D * exporter * */ public void exportToPrinter3D(ExportToPrinter3D exportToPrinter3D) { for (Drawable3DList list : lists) { for (Drawable3D d : list) { d.exportToPrinter3D(exportToPrinter3D); } } } /** * draw surfaces that are not transparent * * @param renderer */ public void drawNotTransparentSurfaces(Renderer renderer) { for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_SURFACES] .iterator(); d.hasNext();) { d.next().drawNotTransparentSurface(renderer); } // lists for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_LISTS] .iterator(); d.hasNext();) { ((DrawList3D) d.next()).getDrawable3DLists() .drawNotTransparentSurfaces(renderer); } } /** * draw closed surfaces that are not transparent * * @param renderer */ public void drawNotTransparentSurfacesClosed(Renderer renderer) { for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_CLOSED_SURFACES_NOT_CURVED] .iterator(); d.hasNext();) { d.next().drawNotTransparentSurface(renderer); } for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_CLOSED_SURFACES_CURVED] .iterator(); d.hasNext();) { d.next().drawNotTransparentSurface(renderer); } // lists for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_LISTS] .iterator(); d.hasNext();) { ((DrawList3D) d.next()).getDrawable3DLists() .drawNotTransparentSurfacesClosed(renderer); } } /** * draw clipped surfaces that are not transparent * * @param renderer */ public void drawNotTransparentSurfacesClipped(Renderer renderer) { for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_CLIPPED_SURFACES] .iterator(); d.hasNext();) { d.next().drawNotTransparentSurface(renderer); } // lists for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_LISTS] .iterator(); d.hasNext();) { ((DrawList3D) d.next()).getDrawable3DLists() .drawNotTransparentSurfacesClipped(renderer); } } /** * draw the hidden (dashed) parts of curves and points * * @param renderer * opengl context */ public void drawHiddenTextured(Renderer renderer) { // curves // TODO if there's no surfaces, no hidden part has to be drawn // if(!lists[Drawable3D.DRAW_TYPE_SURFACES].isEmpty()) for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_CURVES] .iterator(); d.hasNext();) { d.next().drawHidden(renderer); } if (containsClippedCurves()) { renderer.enableClipPlanesIfNeeded(); for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_CLIPPED_CURVES] .iterator(); d.hasNext();) { d.next().drawHidden(renderer); } renderer.disableClipPlanesIfNeeded(); } // lists for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_LISTS] .iterator(); d.hasNext();) { ((DrawList3D) d.next()).getDrawable3DLists() .drawHiddenTextured(renderer); } } /** * draw surfaces as transparent parts * * @param renderer * opengl context */ public void drawTransp(Renderer renderer) { for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_SURFACES] .iterator(); d.hasNext();) { d.next().drawTransp(renderer); } // lists for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_LISTS] .iterator(); d.hasNext();) { ((DrawList3D) d.next()).getDrawable3DLists().drawTransp(renderer); } } /** * draw transparent closed surfaces * * @param renderer */ public void drawTranspClosedNotCurved(Renderer renderer) { for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_CLOSED_SURFACES_NOT_CURVED] .iterator(); d.hasNext();) { d.next().drawTransp(renderer); } // lists for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_LISTS] .iterator(); d.hasNext();) { ((DrawList3D) d.next()).getDrawable3DLists() .drawTranspClosedNotCurved(renderer); } } /** * draw transparent closed surfaces * * @param renderer */ public void drawTranspClosedCurved(Renderer renderer) { for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_CLOSED_SURFACES_CURVED] .iterator(); d.hasNext();) { d.next().drawTransp(renderer); } // lists for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_LISTS] .iterator(); d.hasNext();) { ((DrawList3D) d.next()).getDrawable3DLists() .drawTranspClosedCurved(renderer); } } /** * draw transparent clipped surfaces * * @param renderer */ public void drawTranspClipped(Renderer renderer) { for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_CLIPPED_SURFACES] .iterator(); d.hasNext();) { d.next().drawTransp(renderer); } // lists for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_LISTS] .iterator(); d.hasNext();) { ((DrawList3D) d.next()).getDrawable3DLists() .drawTranspClipped(renderer); } } /** * draw the not hidden (solid) parts of curves and points * * @param renderer * opengl context */ public void draw(Renderer renderer) { // curves for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_CURVES] .iterator(); d.hasNext();) { d.next().drawOutline(renderer); } if (containsClippedCurves()) { renderer.enableClipPlanesIfNeeded(); for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_CLIPPED_CURVES] .iterator(); d.hasNext();) { d.next().drawOutline(renderer); } renderer.disableClipPlanesIfNeeded(); } // lists for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_LISTS] .iterator(); d.hasNext();) { ((DrawList3D) d.next()).getDrawable3DLists().draw(renderer); } } /** * draw the labels of objects * * @param renderer * opengl context */ public void drawLabel(Renderer renderer) { for (int i = 0; i < Drawable3D.DRAW_TYPE_TEXTS; i++) { for (Iterator<Drawable3D> d = lists[i].iterator(); d.hasNext();) { d.next().drawLabel(renderer); } } } /** * draw texts (not in absolute position) * * @param renderer * opengl context */ public void drawNotAbsoluteText(Renderer renderer) { // texts for (Drawable3D d : lists[Drawable3D.DRAW_TYPE_TEXTS]) { ((DrawText3D) d).drawNotAbsolutePosition(renderer); } // lists for (Drawable3D d : lists[Drawable3D.DRAW_TYPE_LISTS]) { ((DrawList3D) d).getDrawable3DLists().drawNotAbsoluteText(renderer); } } /** * draw texts (in absolute position) * * @param renderer * opengl context */ public void drawAbsoluteText(Renderer renderer) { // texts for (Drawable3D d : lists[Drawable3D.DRAW_TYPE_TEXTS]) { ((DrawText3D) d).drawAbsolutePosition(renderer); } // lists for (Drawable3D d : lists[Drawable3D.DRAW_TYPE_LISTS]) { ((DrawList3D) d).getDrawable3DLists().drawAbsoluteText(renderer); } } /** * draw the hiding (surfaces) parts * * @param renderer * opengl context */ public void drawSurfacesForHiding(Renderer renderer) { for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_SURFACES] .iterator(); d.hasNext();) { d.next().drawHiding(renderer); } // lists for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_LISTS] .iterator(); d.hasNext();) { ((DrawList3D) d.next()).getDrawable3DLists() .drawSurfacesForHiding(renderer); } } /** * draw the hiding (closed surfaces) parts * * @param renderer * opengl context */ public void drawClosedSurfacesForHiding(Renderer renderer) { for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_CLOSED_SURFACES_NOT_CURVED] .iterator(); d.hasNext();) { d.next().drawHiding(renderer); } for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_CLOSED_SURFACES_CURVED] .iterator(); d.hasNext();) { d.next().drawHiding(renderer); } // lists for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_LISTS] .iterator(); d.hasNext();) { ((DrawList3D) d.next()).getDrawable3DLists() .drawClosedSurfacesForHiding(renderer); } } /** * draw the hiding (clipped surfaces) parts * * @param renderer * opengl context */ public void drawClippedSurfacesForHiding(Renderer renderer) { for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_CLIPPED_SURFACES] .iterator(); d.hasNext();) { d.next().drawHiding(renderer); } // lists for (Iterator<Drawable3D> d = lists[Drawable3D.DRAW_TYPE_LISTS] .iterator(); d.hasNext();) { ((DrawList3D) d.next()).getDrawable3DLists() .drawClippedSurfacesForHiding(renderer); } } /** * process the hit * * @param hitting * e.g. ray * @param hits * hits where drawables are stored */ public void hit(Hitting hitting, Hits3D hits) { for (Drawable3DList list : lists) { for (Drawable3D d : list) { d.hitIfVisibleAndPickable(hitting, hits); } } } /** * * @param x * mouse x location * @param y * mouse y location * @return first hitted label geo */ final public GeoElement getLabelHit(double x, double y) { for (Drawable3DList list : lists) { for (Drawable3D d : list) { if (d.isVisible()) { GeoElement geo = d.getGeoElement(); if (!geo.isGeoText() && geo.isPickable() && d.label.hit(x, y)) { return geo; } } } } return null; } /** * * @param origin * mouse origin * @param direction * mouse direction * @return first hitted label geo */ public GeoElement getLabelHit(Coords origin, Coords direction) { for (Drawable3DList list : lists) { for (Drawable3D d : list) { if (d.isVisible()) { GeoElement geo = d.getGeoElement(); if (!geo.isGeoText() && geo.isPickable() && d.label.hit(origin, direction)) { return geo; } } } } return null; } }