/// \brief Keep the value of \p infinity as small as possible to improve precision in Winding_Clip. void Winding_createInfinite(FixedWinding& winding, const Plane3& plane, double infinity) { double max = -infinity; int x = -1; for (int i=0 ; i<3; i++) { double d = fabs(plane.normal()[i]); if (d > max) { x = i; max = d; } } if(x == -1) { globalErrorStream() << "invalid plane\n"; return; } DoubleVector3 vup = g_vector3_identity; switch (x) { case 0: case 1: vup[2] = 1; break; case 2: vup[0] = 1; break; } vector3_add(vup, vector3_scaled(plane.normal(), -vector3_dot(vup, plane.normal()))); vector3_normalise(vup); DoubleVector3 org = vector3_scaled(plane.normal(), plane.dist()); DoubleVector3 vright = vector3_cross(vup, plane.normal()); vector3_scale(vup, infinity); vector3_scale(vright, infinity); // project a really big axis aligned box onto the plane DoubleLine r1, r2, r3, r4; r1.origin = vector3_added(vector3_subtracted(org, vright), vup); r1.direction = vector3_normalised(vright); winding.push_back(FixedWindingVertex(r1.origin, r1, c_brush_maxFaces)); r2.origin = vector3_added(vector3_added(org, vright), vup); r2.direction = vector3_normalised(vector3_negated(vup)); winding.push_back(FixedWindingVertex(r2.origin, r2, c_brush_maxFaces)); r3.origin = vector3_subtracted(vector3_added(org, vright), vup); r3.direction = vector3_normalised(vector3_negated(vright)); winding.push_back(FixedWindingVertex(r3.origin, r3, c_brush_maxFaces)); r4.origin = vector3_subtracted(vector3_subtracted(org, vright), vup); r4.direction = vector3_normalised(vup); winding.push_back(FixedWindingVertex(r4.origin, r4, c_brush_maxFaces)); }
void TextureProjection::transformLocked (std::size_t width, std::size_t height, const Plane3& plane, const Matrix4& identity2transformed) { Vector3 normalTransformed(matrix4_transformed_direction(identity2transformed, plane.normal())); // identity: identity space // transformed: transformation // stIdentity: base st projection space before transformation // stTransformed: base st projection space after transformation // stOriginal: original texdef space // stTransformed2stOriginal = stTransformed -> transformed -> identity -> stIdentity -> stOriginal Matrix4 identity2stIdentity; basisForNormal(plane.normal(), identity2stIdentity); Matrix4 transformed2stTransformed; basisForNormal(normalTransformed, transformed2stTransformed); Matrix4 stTransformed2identity(matrix4_affine_inverse(matrix4_multiplied_by_matrix4(transformed2stTransformed, identity2transformed))); Vector3 originalProjectionAxis(matrix4_affine_inverse(identity2stIdentity).z().getVector3()); Vector3 transformedProjectionAxis(stTransformed2identity.z().getVector3()); Matrix4 stIdentity2stOriginal = m_texdef.getTransform((float) width, (float) height); Matrix4 identity2stOriginal(matrix4_multiplied_by_matrix4(stIdentity2stOriginal, identity2stIdentity)); double dot = originalProjectionAxis.dot(transformedProjectionAxis); if (dot == 0) { // The projection axis chosen for the transformed normal is at 90 degrees // to the transformed projection axis chosen for the original normal. // This happens when the projection axis is ambiguous - e.g. for the plane // 'X == Y' the projection axis could be either X or Y. Matrix4 identityCorrected = matrix4_reflection_for_plane45(plane, originalProjectionAxis, transformedProjectionAxis); identity2stOriginal = matrix4_multiplied_by_matrix4(identity2stOriginal, identityCorrected); } Matrix4 stTransformed2stOriginal = matrix4_multiplied_by_matrix4(identity2stOriginal, stTransformed2identity); setTransform((float) width, (float) height, stTransformed2stOriginal); m_texdef.normalise((float) width, (float) height); }
Vector3 Winding::centroid(const Plane3& plane) const { Vector3 centroid(0,0,0); float area2 = 0, x_sum = 0, y_sum = 0; const ProjectionAxis axis = projectionaxis_for_normal(plane.normal()); const indexremap_t remap = indexremap_for_projectionaxis(axis); for (std::size_t i = size() - 1, j = 0; j < size(); i = j, ++j) { const float ai = (*this)[i].vertex[remap.x] * (*this)[j].vertex[remap.y] - (*this)[j].vertex[remap.x] * (*this)[i].vertex[remap.y]; area2 += ai; x_sum += ((*this)[j].vertex[remap.x] + (*this)[i].vertex[remap.x]) * ai; y_sum += ((*this)[j].vertex[remap.y] + (*this)[i].vertex[remap.y]) * ai; } centroid[remap.x] = x_sum / (3 * area2); centroid[remap.y] = y_sum / (3 * area2); { Ray ray(Vector3(0, 0, 0), Vector3(0, 0, 0)); ray.origin[remap.x] = centroid[remap.x]; ray.origin[remap.y] = centroid[remap.y]; ray.direction[remap.z] = 1; centroid[remap.z] = ray.getDistance(plane); } return centroid; }
/// \brief Returns the point at which \p line intersects \p plane, or an undefined value if there is no intersection. inline DoubleVector3 line_intersect_plane(const DoubleLine& line, const Plane3& plane) { return line.origin + vector3_scaled( line.direction, -plane3_distance_to_point(plane, line.origin) / vector3_dot(line.direction, plane.normal()) ); }
/// \brief Calculate the \p centroid of the polygon defined by \p winding which lies on plane \p plane. void Winding_Centroid(const Winding& winding, const Plane3& plane, Vector3& centroid) { double area2 = 0, x_sum = 0, y_sum = 0; const ProjectionAxis axis = projectionaxis_for_normal(plane.normal()); const indexremap_t remap = indexremap_for_projectionaxis(axis); for(std::size_t i = winding.numpoints-1, j = 0; j < winding.numpoints; i = j, ++j) { const double ai = winding[i].vertex[remap.x] * winding[j].vertex[remap.y] - winding[j].vertex[remap.x] * winding[i].vertex[remap.y]; area2 += ai; x_sum += (winding[j].vertex[remap.x] + winding[i].vertex[remap.x]) * ai; y_sum += (winding[j].vertex[remap.y] + winding[i].vertex[remap.y]) * ai; } centroid[remap.x] = static_cast<float>(x_sum / (3 * area2)); centroid[remap.y] = static_cast<float>(y_sum / (3 * area2)); { Ray ray(Vector3(0, 0, 0), Vector3(0, 0, 0)); ray.origin[remap.x] = centroid[remap.x]; ray.origin[remap.y] = centroid[remap.y]; ray.direction[remap.z] = 1; centroid[remap.z] = static_cast<float>(ray_distance_to_plane(ray, plane)); } }
scene::INodePtr BrushDef3Parser::parse(parser::DefTokeniser& tok) const { // Create a new brush scene::INodePtr node = GlobalBrushCreator().createBrush(); // Cast the node, this must succeed IBrushNodePtr brushNode = boost::dynamic_pointer_cast<IBrushNode>(node); assert(brushNode != NULL); IBrush& brush = brushNode->getIBrush(); tok.assertNextToken("{"); // Parse face tokens until a closing brace is encountered while (1) { std::string token = tok.nextToken(); // Token should be either a "(" (start of face) or "}" (end of brush) if (token == "}") { break; // end of brush } else if (token == "(") // FACE { // Construct a plane and parse its values Plane3 plane; plane.normal().x() = string::to_float(tok.nextToken()); plane.normal().y() = string::to_float(tok.nextToken()); plane.normal().z() = string::to_float(tok.nextToken()); plane.dist() = -string::to_float(tok.nextToken()); // negate d tok.assertNextToken(")"); // Parse TexDef Matrix4 texdef; tok.assertNextToken("("); tok.assertNextToken("("); texdef.xx() = string::to_float(tok.nextToken()); texdef.yx() = string::to_float(tok.nextToken()); texdef.tx() = string::to_float(tok.nextToken()); tok.assertNextToken(")"); tok.assertNextToken("("); texdef.xy() = string::to_float(tok.nextToken()); texdef.yy() = string::to_float(tok.nextToken()); texdef.ty() = string::to_float(tok.nextToken()); tok.assertNextToken(")"); tok.assertNextToken(")"); // Parse Shader std::string shader = tok.nextToken(); // Parse Flags (usually each brush has all faces detail or all faces structural) IBrush::DetailFlag flag = static_cast<IBrush::DetailFlag>( string::convert<std::size_t>(tok.nextToken(), IBrush::Structural)); brush.setDetailFlag(flag); // Ignore the other two flags tok.skipTokens(2); // Finally, add the new face to the brush /*IFace& face = */brush.addFace(plane, texdef, shader); } else { std::string text = (boost::format(_("BrushDef3Parser: invalid token '%s'")) % token).str(); throw parser::ParseException(text); } } // Final outer "}" tok.assertNextToken("}"); return node; }
/// \brief Returns the infinite line that is the intersection of \p plane and \p other. inline DoubleLine plane3_intersect_plane3(const Plane3& plane, const Plane3& other) { DoubleLine line; line.direction = vector3_cross(plane.normal(), other.normal()); switch(vector3_largest_absolute_component_index(line.direction)) { case 0: line.origin.x() = 0; line.origin.y() = (-other.dist() * plane.normal().z() - -plane.dist() * other.normal().z()) / line.direction.x(); line.origin.z() = (-plane.dist() * other.normal().y() - -other.dist() * plane.normal().y()) / line.direction.x(); break; case 1: line.origin.x() = (-plane.dist() * other.normal().z() - -other.dist() * plane.normal().z()) / line.direction.y(); line.origin.y() = 0; line.origin.z() = (-other.dist() * plane.normal().x() - -plane.dist() * other.normal().x()) / line.direction.y(); break; case 2: line.origin.x() = (-other.dist() * plane.normal().y() - -plane.dist() * other.normal().y()) / line.direction.z(); line.origin.y() = (-plane.dist() * other.normal().x() - -other.dist() * plane.normal().x()) / line.direction.z(); line.origin.z() = 0; break; default: break; } return line; }
inline double plane3_distance_to_point(const Plane3& plane, const Vector3& point) { return vector3_dot(point, plane.normal()) - plane.dist(); }