IsWallCheck.java 5.63 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*-
 *  Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
 * 
 *  This file is part of CityDoctor2.
 *
 *  CityDoctor2 is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  CityDoctor2 is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with CityDoctor2.  If not, see <https://www.gnu.org/licenses/>.
 */
package de.hft.stuttgart.citydoctor2.checks.semantics;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
25
import java.util.Set;
26
27
28
29

import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult;
30
import de.hft.stuttgart.citydoctor2.check.RequirementType;
31
import de.hft.stuttgart.citydoctor2.check.DefaultParameter;
32
import de.hft.stuttgart.citydoctor2.check.Requirement;
33
34
35
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.Unit;
import de.hft.stuttgart.citydoctor2.check.error.NotWallError;
36
import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurfaceType;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;

/**
 * checks if the normal direction of a polygon labeled as WallSurface are
 * horizontal or not.
 * 
 * @author dwagner
 * @author Matthias Betz - 12bema1bif@hft-stuttgart.de
 *
 */
public class IsWallCheck extends Check {
	
	private static final String LOWER_ANGLE_NAME = "lowerAngle";
	private static final String UPPER_ANGLE_NAME = "upperAngle";

	private static final List<CheckId> dependencies;
	private static final List<DefaultParameter> defaultParameters;

	static {
		ArrayList<CheckId> deps = new ArrayList<>();
		deps.add(CheckId.C_GE_R_TOO_FEW_POINTS);
		deps.add(CheckId.C_GE_R_NOT_CLOSED);
		deps.add(CheckId.C_GE_R_DUPLICATE_POINT);
		deps.add(CheckId.C_GE_R_SELF_INTERSECTION);
		deps.add(CheckId.C_GE_P_NON_PLANAR);
		dependencies = Collections.unmodifiableList(deps);
		
		ArrayList<DefaultParameter> defParameters = new ArrayList<>(3);
		defParameters.add(new DefaultParameter(LOWER_ANGLE_NAME, "45", Unit.DEGREE));
		defParameters.add(new DefaultParameter(UPPER_ANGLE_NAME, "135", Unit.DEGREE));
		defaultParameters = Collections.unmodifiableList(defParameters);
	}

	private static final Vector3d Z_AXIS = new Vector3d(0, 0, 1);
	
	// The SIG3d handbook proposes a +-45 degree to the horizontal plane. To
	// minimize computation the upper and lower values are calculated only once
	// and in advance. The algorithm is based on the angle calculation between
	// the normal of the polygon and the positive z direction vector.
	private double lowerAngleCos = Math.cos(45 * Math.PI / 180);
	private double upperAngleCos = Math.cos(135 * Math.PI / 180);
	
	@Override
	public void init(Map<String, String> params, ParserConfiguration config) {
		String lowerAngleString = params.get(LOWER_ANGLE_NAME);
		if (lowerAngleString != null) {
			lowerAngleCos = Double.parseDouble(lowerAngleString);
			lowerAngleCos = Math.cos(lowerAngleCos * Math.PI / 180);
		}
		String upperAngleString = params.get(UPPER_ANGLE_NAME);
		if (upperAngleString != null) {
			upperAngleCos = Double.parseDouble(upperAngleString);
			upperAngleCos = Math.cos(upperAngleCos * Math.PI / 180);
		}
	}
	

	@Override
	public void check(BoundarySurface bs) {
		// works only on wall surfaces
		if (bs.getType() != BoundarySurfaceType.WALL) {
			return;
		}
		
		for (Geometry geom : bs.getGeometries()) {
			for (Polygon p : geom.getPolygons()) {
				Vector3d normal = p.calculateNormal();
				double dot = normal.dot(Z_AXIS);

				// The angle should be between 45 and 135 degree, measured
				// against the z-direction, hence the optimal angle would be 90 degree
				// CAUTION: This might seems odd, but keep in mind, that the acos won't
				// be calculated and we won't receive measures in radian or degree.
				// The values for cosine are:
				// cos [0°, 90°) > 0
				// cos ( 90° ) = 0
				// cos ( 90°, 180°] < 0
				// Hence we need to check if the calculated angle is above the lower
				// angle cosine or below the upper angle cosine
				if (dot > lowerAngleCos || dot < upperAngleCos) {
					NotWallError err = new NotWallError(bs, p, normal);
					CheckResult cr = new CheckResult(this, ResultStatus.ERROR, err);
					bs.addCheckResult(cr);
					return;
				}
			}
		}
		CheckResult cr = new CheckResult(this, ResultStatus.OK, null);
		bs.addCheckResult(cr);
	}

	@Override
	public List<CheckId> getDependencies() {
		return dependencies;
	}
	
138
139
140
141
142
	@Override
	public Set<Requirement> appliesToRequirements() {
		return CollectionUtils.singletonSet(Requirement.R_SE_BS_IS_WALL);
	}
	
143
144
145
146
147
148
	@Override
	public List<DefaultParameter> getDefaultParameter() {
		return defaultParameters;
	}

	@Override
149
150
	public RequirementType getType() {
		return RequirementType.SEMANTIC;
151
152
153
154
155
156
157
	}

	@Override
	public Check createNewInstance() {
		return new IsWallCheck();
	}

Matthias Betz's avatar
Matthias Betz committed
158
159
	@Override
	public CheckId getCheckId() {
160
		return CheckId.C_SE_BS_IS_WALL;
Matthias Betz's avatar
Matthias Betz committed
161
162
	}

163
}