/*
* citygml4j - The Open Source Java API for CityGML
* https://github.com/citygml4j
*
* Copyright 2013-2017 Claus Nagel <claus.nagel@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.citygml4j.util.walker;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import org.citygml4j.model.citygml.core.LodRepresentation;
import org.citygml4j.model.citygml.texturedsurface._TexturedSurface;
import org.citygml4j.model.common.visitor.GeometryFunctor;
import org.citygml4j.model.gml.geometry.AbstractGeometry;
import org.citygml4j.model.gml.geometry.GeometryArrayProperty;
import org.citygml4j.model.gml.geometry.GeometryProperty;
import org.citygml4j.model.gml.geometry.InlineGeometryProperty;
import org.citygml4j.model.gml.geometry.aggregates.AbstractGeometricAggregate;
import org.citygml4j.model.gml.geometry.aggregates.MultiCurve;
import org.citygml4j.model.gml.geometry.aggregates.MultiGeometry;
import org.citygml4j.model.gml.geometry.aggregates.MultiLineString;
import org.citygml4j.model.gml.geometry.aggregates.MultiPoint;
import org.citygml4j.model.gml.geometry.aggregates.MultiPolygon;
import org.citygml4j.model.gml.geometry.aggregates.MultiSolid;
import org.citygml4j.model.gml.geometry.aggregates.MultiSurface;
import org.citygml4j.model.gml.geometry.complexes.CompositeCurve;
import org.citygml4j.model.gml.geometry.complexes.CompositeSolid;
import org.citygml4j.model.gml.geometry.complexes.CompositeSurface;
import org.citygml4j.model.gml.geometry.complexes.GeometricComplex;
import org.citygml4j.model.gml.geometry.primitives.AbstractCurve;
import org.citygml4j.model.gml.geometry.primitives.AbstractGeometricPrimitive;
import org.citygml4j.model.gml.geometry.primitives.AbstractRing;
import org.citygml4j.model.gml.geometry.primitives.AbstractRingProperty;
import org.citygml4j.model.gml.geometry.primitives.AbstractSolid;
import org.citygml4j.model.gml.geometry.primitives.AbstractSurface;
import org.citygml4j.model.gml.geometry.primitives.AbstractSurfacePatch;
import org.citygml4j.model.gml.geometry.primitives.Curve;
import org.citygml4j.model.gml.geometry.primitives.CurveProperty;
import org.citygml4j.model.gml.geometry.primitives.GeometricPrimitiveProperty;
import org.citygml4j.model.gml.geometry.primitives.LineString;
import org.citygml4j.model.gml.geometry.primitives.LineStringProperty;
import org.citygml4j.model.gml.geometry.primitives.LinearRing;
import org.citygml4j.model.gml.geometry.primitives.OrientableCurve;
import org.citygml4j.model.gml.geometry.primitives.OrientableSurface;
import org.citygml4j.model.gml.geometry.primitives.Point;
import org.citygml4j.model.gml.geometry.primitives.PointProperty;
import org.citygml4j.model.gml.geometry.primitives.Polygon;
import org.citygml4j.model.gml.geometry.primitives.PolygonProperty;
import org.citygml4j.model.gml.geometry.primitives.Rectangle;
import org.citygml4j.model.gml.geometry.primitives.Ring;
import org.citygml4j.model.gml.geometry.primitives.Solid;
import org.citygml4j.model.gml.geometry.primitives.SolidProperty;
import org.citygml4j.model.gml.geometry.primitives.Surface;
import org.citygml4j.model.gml.geometry.primitives.SurfacePatchArrayProperty;
import org.citygml4j.model.gml.geometry.primitives.SurfaceProperty;
import org.citygml4j.model.gml.geometry.primitives.Tin;
import org.citygml4j.model.gml.geometry.primitives.Triangle;
import org.citygml4j.model.gml.geometry.primitives.TriangulatedSurface;
import org.citygml4j.model.gml.grids.Grid;
import org.citygml4j.model.gml.grids.RectifiedGrid;
public abstract class GeometryFunctionWalker<T> implements GeometryFunctor<T>, Walker {
private Set<Object> visited = new HashSet<Object>();
private boolean shouldWalk = true;
public GeometryFunctionWalker() {
}
public void reset() {
visited.clear();
shouldWalk = true;
}
public boolean shouldWalk() {
return shouldWalk;
}
public void setShouldWalk(boolean shouldWalk) {
this.shouldWalk = shouldWalk;
}
public boolean addToVisited(Object object) {
return visited.add(object);
}
public boolean hasVisited(Object object) {
return visited.contains(object);
}
public T apply(LodRepresentation lodRepresentation) {
if (lodRepresentation != null) {
for (int lod = 0; lod < 5; lod++) {
if (lodRepresentation.isSetLodGeometry(lod)) {
for (GeometryProperty<?> geometryProperty : lodRepresentation.getLodGeometry(lod)) {
T object = apply(geometryProperty);
if (object != null)
return object;
}
}
}
}
return null;
}
public T apply(AbstractGeometry abstractGeometry) {
return null;
}
public T apply(AbstractGeometricPrimitive abstractGeometricPrimitive) {
return apply((AbstractGeometry)abstractGeometricPrimitive);
}
public T apply(AbstractGeometricAggregate abstractGeometricAggregate) {
return apply((AbstractGeometry)abstractGeometricAggregate);
}
public T apply(AbstractCurve abstractCurve) {
return apply((AbstractGeometricPrimitive)abstractCurve);
}
public T apply(AbstractSolid abstractSolid) {
return apply((AbstractGeometricPrimitive)abstractSolid);
}
public T apply(AbstractSurface abstractSurface) {
return apply((AbstractGeometricPrimitive)abstractSurface);
}
public T apply(AbstractRing abstractRing) {
return apply((AbstractGeometry)abstractRing);
}
public T apply(Triangle triangle) {
if (triangle.isSetExterior()) {
T object = apply(triangle.getExterior());
if (object != null)
return object;
}
return null;
}
public T apply(Rectangle rectangle) {
if (rectangle.isSetExterior()) {
T object = apply(rectangle.getExterior());
if (object != null)
return object;
}
return null;
}
public T apply(CompositeCurve compositeCurve) {
T object = apply((AbstractCurve)compositeCurve);
if (object != null)
return object;
if (compositeCurve.isSetCurveMember()) {
for (CurveProperty curveProperty : new ArrayList<CurveProperty>(compositeCurve.getCurveMember())) {
object = apply(curveProperty);
if (object != null)
return object;
}
}
return null;
}
public T apply(CompositeSolid compositeSolid) {
T object = apply((AbstractSolid)compositeSolid);
if (object != null)
return object;
if (compositeSolid.isSetSolidMember()) {
for (SolidProperty solidProperty : new ArrayList<SolidProperty>(compositeSolid.getSolidMember())) {
object = apply(solidProperty);
if (object != null)
return object;
}
}
return null;
}
public T apply(CompositeSurface compositeSurface) {
T object = apply((AbstractSurface)compositeSurface);
if (object != null)
return object;
if (compositeSurface.isSetSurfaceMember()) {
for (SurfaceProperty surfaceProperty : new ArrayList<SurfaceProperty>(compositeSurface.getSurfaceMember())) {
object = apply(surfaceProperty);
if (object != null)
return object;
}
}
return null;
}
public T apply(Curve curve) {
return apply((AbstractCurve)curve);
}
public T apply(GeometricComplex geometricComplex) {
T object = apply((AbstractGeometry)geometricComplex);
if (object != null)
return object;
if (geometricComplex.isSetElement()) {
for (GeometricPrimitiveProperty geometricPrimitiveProperty : new ArrayList<GeometricPrimitiveProperty>(geometricComplex.getElement())) {
object = apply(geometricPrimitiveProperty);
if (object != null)
return object;
}
}
return null;
}
public T apply(Grid grid) {
return apply((AbstractGeometry)grid);
}
public T apply(LinearRing linearRing) {
return apply((AbstractRing)linearRing);
}
public T apply(LineString lineString) {
return apply((AbstractCurve)lineString);
}
public T apply(MultiCurve multiCurve) {
T object = apply((AbstractGeometricAggregate)multiCurve);
if (object != null)
return object;
if (multiCurve.isSetCurveMember()) {
for (CurveProperty curveProperty : new ArrayList<CurveProperty>(multiCurve.getCurveMember())) {
object = apply(curveProperty);
if (object != null)
return object;
}
}
if (multiCurve.isSetCurveMembers()) {
object = apply(multiCurve.getCurveMembers());
if (object != null)
return object;
}
return null;
}
public T apply(MultiGeometry multiGeometry) {
T object = apply((AbstractGeometricAggregate)multiGeometry);
if (object != null)
return object;
if (multiGeometry.isSetGeometryMember()) {
for (GeometryProperty<? extends AbstractGeometry> geometryProperty : new ArrayList<GeometryProperty<? extends AbstractGeometry>>(multiGeometry.getGeometryMember())) {
object = apply(geometryProperty);
if (object != null)
return object;
}
}
if (multiGeometry.isSetGeometryMembers()) {
object = apply(multiGeometry.getGeometryMembers());
if (object != null)
return object;
}
return null;
}
public T apply(MultiLineString multiLineString) {
T object = apply((AbstractGeometricAggregate)multiLineString);
if (object != null)
return object;
if (multiLineString.isSetLineStringMember()) {
for (LineStringProperty lineStringProperty : new ArrayList<LineStringProperty>(multiLineString.getLineStringMember())) {
object = apply(lineStringProperty);
if (object != null)
return object;
}
}
return null;
}
public T apply(MultiPoint multiPoint) {
T object = apply((AbstractGeometricAggregate)multiPoint);
if (object != null)
return object;
if (multiPoint.isSetPointMember()) {
for (PointProperty pointProperty : new ArrayList<PointProperty>(multiPoint.getPointMember())) {
object = apply(pointProperty);
if (object != null)
return object;
}
}
if (multiPoint.isSetPointMembers()) {
object = apply(multiPoint.getPointMembers());
if (object != null)
return object;
}
return null;
}
public T apply(MultiPolygon multiPolygon) {
T object = apply((AbstractGeometricAggregate)multiPolygon);
if (object != null)
return object;
if (multiPolygon.isSetPolygonMember()) {
for (PolygonProperty polygonProperty : new ArrayList<PolygonProperty>(multiPolygon.getPolygonMember())) {
object = apply(polygonProperty);
if (object != null)
return object;
}
}
return null;
}
public T apply(MultiSolid multiSolid) {
T object = apply((AbstractGeometricAggregate)multiSolid);
if (object != null)
return object;
if (multiSolid.isSetSolidMember()) {
for (SolidProperty solidProperty : new ArrayList<SolidProperty>(multiSolid.getSolidMember())) {
object = apply(solidProperty);
if (object != null)
return object;
}
}
if (multiSolid.isSetSolidMembers()) {
object = apply(multiSolid.getSolidMembers());
if (object != null)
return object;
}
return null;
}
public T apply(MultiSurface multiSurface) {
T object = apply((AbstractGeometricAggregate)multiSurface);
if (object != null)
return object;
if (multiSurface.isSetSurfaceMember()) {
for (SurfaceProperty surfaceProperty : new ArrayList<SurfaceProperty>(multiSurface.getSurfaceMember())) {
object = apply(surfaceProperty);
if (object != null)
return object;
}
}
if (multiSurface.isSetSurfaceMembers()) {
object = apply(multiSurface.getSurfaceMembers());
if (object != null)
return object;
}
return null;
}
public T apply(OrientableCurve orientableCurve) {
T object = apply((AbstractCurve)orientableCurve);
if (object != null)
return object;
if (orientableCurve.isSetBaseCurve()) {
object = apply(orientableCurve.getBaseCurve());
if (object != null)
return object;
}
return null;
}
public T apply(OrientableSurface orientableSurface) {
T object = apply((AbstractSurface)orientableSurface);
if (object != null)
return object;
if (orientableSurface.isSetBaseSurface()) {
object = apply(orientableSurface.getBaseSurface());
if (object != null)
return object;
}
return null;
}
public T apply(_TexturedSurface texturedSurface) {
T object = apply((OrientableSurface)texturedSurface);
if (object != null)
return object;
return null;
}
public T apply(Point point) {
return apply((AbstractGeometricPrimitive)point);
}
public T apply(Polygon polygon) {
T object = apply((AbstractSurface)polygon);
if (object != null)
return object;
if (polygon.isSetExterior()) {
object = apply(polygon.getExterior());
if (object != null)
return object;
}
if (polygon.isSetInterior()) {
for (AbstractRingProperty abstractRingProperty : new ArrayList<AbstractRingProperty>(polygon.getInterior())) {
object = apply(abstractRingProperty);
if (object != null)
return object;
}
}
return null;
}
public T apply(RectifiedGrid rectifiedGrid) {
T object = apply((Grid)rectifiedGrid);
if (object != null)
return object;
if (rectifiedGrid.isSetOrigin()) {
object = apply(rectifiedGrid.getOrigin());
if (object != null)
return object;
}
return null;
}
public T apply(Ring ring) {
T object = apply((AbstractRing)ring);
if (object != null)
return object;
if (ring.isSetCurveMember()) {
for (CurveProperty curveProperty : new ArrayList<CurveProperty>(ring.getCurveMember())) {
object = apply(curveProperty);
if (object != null)
return object;
}
}
return null;
}
public T apply(Solid solid) {
T object = apply((AbstractSolid)solid);
if (object != null)
return object;
if (solid.isSetExterior()) {
object = apply(solid.getExterior());
if (object != null)
return object;
}
if (solid.isSetInterior()) {
for (SurfaceProperty surfaceProperty : new ArrayList<SurfaceProperty>(solid.getInterior())) {
object = apply(surfaceProperty);
if (object != null)
return object;
}
}
return null;
}
public T apply(Surface surface) {
T object = apply((AbstractSurface)surface);
if (object != null)
return object;
if (surface.isSetPatches()) {
object = apply(surface.getPatches());
if (object != null)
return object;
}
return null;
}
public T apply(Tin tin) {
return apply((TriangulatedSurface)tin);
}
public T apply(TriangulatedSurface triangulatedSurface) {
return apply((Surface)triangulatedSurface);
}
public <E extends AbstractGeometry> T apply(GeometryProperty<E> geometryProperty) {
if (geometryProperty.isSetGeometry() && shouldWalk && visited.add(geometryProperty.getGeometry())) {
T object = geometryProperty.getGeometry().accept(this);
if (object != null)
return object;
}
return null;
}
public <E extends AbstractGeometry> T apply(InlineGeometryProperty<E> geometryProperty) {
if (geometryProperty.isSetGeometry() && shouldWalk && visited.add(geometryProperty.getGeometry())) {
T object = geometryProperty.getGeometry().accept(this);
if (object != null)
return object;
}
return null;
}
public <E extends AbstractGeometry> T apply(GeometryArrayProperty<E> geometryArrayProperty) {
if (geometryArrayProperty.isSetGeometry()) {
for (AbstractGeometry abstractGeometry : new ArrayList<AbstractGeometry>(geometryArrayProperty.getGeometry())) {
if (shouldWalk && visited.add(abstractGeometry)) {
T object = abstractGeometry.accept(this);
if (object != null)
return object;
}
}
}
return null;
}
public T apply(SurfacePatchArrayProperty surfacePatchArrayProperty) {
T object = null;
if (surfacePatchArrayProperty.isSetSurfacePatch()) {
for (AbstractSurfacePatch abstractSurfacePatch : new ArrayList<AbstractSurfacePatch>(surfacePatchArrayProperty.getSurfacePatch())) {
if (shouldWalk && visited.add(abstractSurfacePatch)) {
if (abstractSurfacePatch instanceof Triangle) {
object = apply((Triangle)abstractSurfacePatch);
if (object != null)
return object;
} else if (abstractSurfacePatch instanceof Rectangle) {
object = apply((Rectangle)abstractSurfacePatch);
if (object != null)
return object;
}
}
}
}
return null;
}
}