/******************************************************************************
* Aligns the modifier's slicing plane to the three selected particles.
******************************************************************************/
void PickParticlePlaneInputMode::alignPlane(SliceModifier* mod)
{
	OVITO_ASSERT(_pickedParticles.size() == 3);

	try {
		Plane3 worldPlane(_pickedParticles[0].worldPos, _pickedParticles[1].worldPos, _pickedParticles[2].worldPos, true);
		if(worldPlane.normal.equals(Vector3::Zero(), FLOATTYPE_EPSILON))
			throw Exception(tr("Cannot set the new slicing plane. The three selected particle are colinear."));

		// Get the object to world transformation for the currently selected node.
		ObjectNode* node = _pickedParticles[0].objNode;
		TimeInterval interval;
		const AffineTransformation& nodeTM = node->getWorldTransform(mod->dataset()->animationSettings()->time(), interval);

		// Transform new plane from world to object space.
		Plane3 localPlane = nodeTM.inverse() * worldPlane;

		// Flip new plane orientation if necessary to align it with old orientation.
		if(localPlane.normal.dot(mod->normal()) < 0)
			localPlane = -localPlane;

		localPlane.normalizePlane();
		UndoableTransaction::handleExceptions(mod->dataset()->undoStack(), tr("Align plane to particles"), [mod, &localPlane]() {
			mod->setNormal(localPlane.normal);
			mod->setDistance(localPlane.dist);
		});
	}
	catch(const Exception& ex) {
		ex.showError();
	}
}
bool ConvexPolyhedron3<Real>::ComputeSilhouette (V3Array& rkTerminator,
    const Vector3<Real>& rkEye, const Plane3<Real>& rkPlane,
    const Vector3<Real>& rkU, const Vector3<Real>& rkV,
    V2Array& rkSilhouette)
{
    Real fEDist = rkPlane.DistanceTo(rkEye);  // assert:  fEDist > 0

    // closest planar point to E is K = E-dist*N
    Vector3<Real> kClosest = rkEye - fEDist*rkPlane.GetNormal();

    // project polyhedron points onto plane
    for (int i = 0; i < (int)rkTerminator.size(); i++)
    {
        Vector3<Real>& rkPoint = rkTerminator[i];

        Real fVDist = rkPlane.DistanceTo(rkPoint);
        if ( fVDist >= fEDist )
        {
            // cannot project vertex onto plane
            return false;
        }

        // compute projected point Q
        Real fRatio = fEDist/(fEDist-fVDist);
        Vector3<Real> kProjected = rkEye + fRatio*(rkPoint - rkEye);

        // compute (x,y) so that Q = K+x*U+y*V+z*N
        Vector3<Real> kDiff = kProjected - kClosest;
        rkSilhouette.push_back(Vector2<Real>(rkU.Dot(kDiff),rkV.Dot(kDiff)));
    }

    return true;
}
Beispiel #3
0
	// TODO: 最优分割面选择需要考虑到二叉树的平衡性
	// weight = fabs(左数目-右数目)+分割数目
	// 越小越优先考虑
	int BspTree::BspNode::BestIndex( std::vector< BspTriangle >& polyList )
	{
		/**
		* The current hueristic is blind least-split
		*/
		// run through the list, searching for the best one.
		// the highest BspTriangle we'll bother testing (10% of total)
		int maxCheck;
		maxCheck = (int)(polyList.size() * percentageToCheck);
		if( !maxCheck ) maxCheck = 1;

		int bestSplits = 100000;
		int bestIndex = -1;
		int currSplits;				// 这个平面总共分割了多少平面
		int frontCount, backCount;
		Plane3 currPlane;
		for(int i=0; i<maxCheck; i++ )
		{
			currSplits = 0;
			frontCount = backCount = 0;
			currPlane = Plane3( polyList[i] );
			PointListLoc res;

			for(unsigned int i2=0; i2< polyList.size(); i2++ )
			{
				if( i == i2 ) continue;

				res = currPlane.TestPoly( polyList[i2] );
				switch(res)
				{
				case plistSplit:
					currSplits++;
					break;
				case plistFront:
					frontCount++;
					break;
				case plistBack:
					backCount++;
					break;
				}
			}

			int weight = abs(frontCount - backCount) + currSplits;
			//int weight = currSplits;

			if( weight < bestSplits )
			{
				bestSplits = weight;
				bestIndex = i;
			}
		}
		assert( bestIndex >= 0 );
		return bestIndex;
	}
void FaceInstance::addLight(const Matrix4& localToWorld, const RendererLight& light)
{
	const Plane3& facePlane = getFace().plane3();

	Plane3 tmp = Plane3(facePlane.normal(), -facePlane.dist())
                 .transformed(localToWorld);

	if (!tmp.testPoint(light.worldOrigin()) || !tmp.testPoint(light.getLightOrigin()))
    {
		m_lights.addLight(light);
	}
}
Beispiel #5
0
bool Wml::Culled (const Plane3<Real>& rkPlane, const Box3<Real>& rkBox)
{
    Real fTmp[3] =
    {
        rkBox.Extent(0)*(rkPlane.GetNormal().Dot(rkBox.Axis(0))),
        rkBox.Extent(1)*(rkPlane.GetNormal().Dot(rkBox.Axis(1))),
        rkBox.Extent(2)*(rkPlane.GetNormal().Dot(rkBox.Axis(2)))
    };

    Real fRadius = Math<Real>::FAbs(fTmp[0]) + Math<Real>::FAbs(fTmp[1]) +
        Math<Real>::FAbs(fTmp[2]);

    Real fPseudoDistance = rkPlane.DistanceTo(rkBox.Center());
    return fPseudoDistance <= -fRadius;
}
Beispiel #6
0
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);
}
Beispiel #7
0
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;
}
bool Wml::Culled (const Plane3<Real>& rkPlane,
    const Ellipsoid3<Real>& rkEllipsoid, bool bUnitNormal)
{
    Vector3<Real> kNormal = rkPlane.GetNormal();
    Real fConstant = rkPlane.GetConstant();
    if ( !bUnitNormal )
    {
        Real fLength = kNormal.Normalize();
        fConstant /= fLength;
    }

    Real fDiscr = kNormal.Dot(rkEllipsoid.InverseA()*kNormal);
    Real fRoot = Math<Real>::Sqrt(Math<Real>::FAbs(fDiscr));
    Real fSDist = kNormal.Dot(rkEllipsoid.Center()) - fConstant;
    return fSDist <= -fRoot;
}
Beispiel #9
0
	bool PlaneCullTest(const Plane3& plane, const AABB3& box){
		Vector3 testVertex;
		// find the vertex with the greatest distance value
		if(plane.n.x >= 0.f){
			if(plane.n.y >= 0.f){
				if(plane.n.z >= 0.f){
					testVertex = box.max;
				}else{
					testVertex = MakeVector3(box.max.x, box.max.y, box.min.z);
				}
			}else{
				if(plane.n.z >= 0.f){
					testVertex = MakeVector3(box.max.x, box.min.y, box.max.z);
				}else{
					testVertex = MakeVector3(box.max.x, box.min.y, box.min.z);
				}
			}
		}else{
			if(plane.n.y >= 0.f){
				if(plane.n.z >= 0.f){
					testVertex = MakeVector3(box.min.x, box.max.y, box.max.z);
				}else{
					testVertex = MakeVector3(box.min.x, box.max.y, box.min.z);
				}
			}else{
				if(plane.n.z >= 0.f){
					testVertex = MakeVector3(box.min.x, box.min.y, box.max.z);
				}else{
					testVertex = box.min;
				}
			}
		}
		return plane.GetDistanceTo(testVertex) >= 0.f;
	}
Beispiel #10
0
/// \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())
  );
}
Beispiel #11
0
/* ------------------------------------------------------- */
int SphereVolume::whichSide(const Plane3& plane) const
{
	float d = plane.distanceTo(m_center);
	if (d > m_radius)
		return 1;
	else if (d < -m_radius)
		return -1;
	else
		return 0;
}
Beispiel #12
0
/* see https://github.com/kduske/TrenchBroom/issues/1033
 commented out because it breaks the release build process
 */
TEST(PlaneTest, planePointFinder) {
    Plane3 plane;
    const Vec3 points[3] = {Vec3(48, 16, 28), Vec3(16.0, 16.0, 27.9980487823486328125), Vec3(48, 18, 22)};
    ASSERT_FALSE(points[1].isInteger());
    ASSERT_TRUE(setPlanePoints(plane, points[0], points[1], points[2]));


    // Some verts that should lie (very close to) on the plane
    std::vector<Vec3> verts;
    verts.push_back(Vec3(48, 18, 22));
    verts.push_back(Vec3(48, 16, 28));
    verts.push_back(Vec3(16, 16, 28));
    verts.push_back(Vec3(16, 18, 22));

    for (size_t i=0; i<verts.size(); i++) {
        FloatType dist = Math::abs(plane.pointDistance(verts[i]));
        ASSERT_LT(dist, 0.01);
    }

    // Now find a similar plane with integer points

    Vec3 intpoints[3];
    for (size_t i=0; i<3; i++)
        intpoints[i] = points[i];

    TrenchBroom::Model::PlanePointFinder::findPoints(plane, intpoints, 3);

    ASSERT_TRUE(intpoints[0].isInteger());
    ASSERT_TRUE(intpoints[1].isInteger());
    ASSERT_TRUE(intpoints[2].isInteger());

    Plane3 intplane;
    ASSERT_TRUE(setPlanePoints(intplane, intpoints[0], intpoints[1], intpoints[2]));
    //	ASSERT_FALSE(intplane.equals(plane)); no longer fails

    // Check that the verts are still close to the new integer plane

    for (size_t i=0; i<verts.size(); i++) {
        FloatType dist = Math::abs(intplane.pointDistance(verts[i]));
        ASSERT_LT(dist, 0.01);
    }
}
Beispiel #13
0
BrushSplitType Winding::classifyPlane(const Plane3& plane) const
{
	BrushSplitType split;

	for (const_iterator i = begin(); i != end(); ++i)
	{
		++split.counts[classifyDistance(plane.distanceToPoint(i->vertex), ON_EPSILON)];
	}

	return split;
}
 void updatePolyhedron(const Vec3& current) {
     const Grid& grid = m_tool->grid();
     
     const Math::Axis::Type axis = m_plane.normal.firstComponent();
     const Plane3 swizzledPlane(swizzle(m_plane.anchor(), axis), swizzle(m_plane.normal, axis));
     const Vec3 theMin = swizzle(grid.snapDown(min(m_initialPoint, current)), axis);
     const Vec3 theMax = swizzle(grid.snapUp  (max(m_initialPoint, current)), axis);
     
     const Vec2     topLeft2(theMin.x(), theMin.y());
     const Vec2    topRight2(theMax.x(), theMin.y());
     const Vec2  bottomLeft2(theMin.x(), theMax.y());
     const Vec2 bottomRight2(theMax.x(), theMax.y());
     
     const Vec3     topLeft3 = unswizzle(Vec3(topLeft2,     swizzledPlane.zAt(topLeft2)),     axis);
     const Vec3    topRight3 = unswizzle(Vec3(topRight2,    swizzledPlane.zAt(topRight2)),    axis);
     const Vec3  bottomLeft3 = unswizzle(Vec3(bottomLeft2,  swizzledPlane.zAt(bottomLeft2)),  axis);
     const Vec3 bottomRight3 = unswizzle(Vec3(bottomRight2, swizzledPlane.zAt(bottomRight2)), axis);
     
     Polyhedron3 polyhedron = m_oldPolyhedron;
     polyhedron.addPoint(topLeft3);
     polyhedron.addPoint(bottomLeft3);
     polyhedron.addPoint(bottomRight3);
     polyhedron.addPoint(topRight3);
     m_tool->update(polyhedron);
 }
/******************************************************************************
* Aligns the current viewing direction to the slicing plane.
******************************************************************************/
void SliceModifierEditor::onAlignViewToPlane()
{
	TimeInterval interval;

	Viewport* vp = dataset()->viewportConfig()->activeViewport();
	if(!vp) return;

	// Get the object to world transformation for the currently selected object.
	ObjectNode* node = dynamic_object_cast<ObjectNode>(dataset()->selection()->front());
	if(!node) return;
	const AffineTransformation& nodeTM = node->getWorldTransform(dataset()->animationSettings()->time(), interval);

	// Transform the current slicing plane to the world coordinate system.
	SliceModifier* mod = static_object_cast<SliceModifier>(editObject());
	if(!mod) return;
	Plane3 planeLocal = mod->slicingPlane(dataset()->animationSettings()->time(), interval);
	Plane3 planeWorld = nodeTM * planeLocal;

	// Calculate the intersection point of the current viewing direction with the current slicing plane.
	Ray3 viewportRay(vp->cameraPosition(), vp->cameraDirection());
	FloatType t = planeWorld.intersectionT(viewportRay);
	Point3 intersectionPoint;
	if(t != FLOATTYPE_MAX)
		intersectionPoint = viewportRay.point(t);
	else
		intersectionPoint = Point3::Origin() + nodeTM.translation();

	if(vp->isPerspectiveProjection()) {
		FloatType distance = (vp->cameraPosition() - intersectionPoint).length();
		vp->setViewType(Viewport::VIEW_PERSPECTIVE);
		vp->setCameraDirection(-planeWorld.normal);
		vp->setCameraPosition(intersectionPoint + planeWorld.normal * distance);
	}
	else {
		vp->setViewType(Viewport::VIEW_ORTHO);
		vp->setCameraDirection(-planeWorld.normal);
	}

	vp->zoomToSelectionExtents();
}
Beispiel #16
0
/// \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));
}
Beispiel #17
0
bool Winding::testPlane(const Plane3& plane, bool flipped) const
{
	const int test = (flipped) ? ePlaneBack : ePlaneFront;

	for (const_iterator i = begin(); i != end(); ++i)
	{
		if (test == classifyDistance(plane.distanceToPoint(i->vertex), ON_EPSILON))
		{
			return false;
		}
	}

	return true;
}
        void CreateEntityTool::updateEntityPosition2D(const Ray3& pickRay) {
            assert(m_entity != NULL);
            
            MapDocumentSPtr document = lock(m_document);

            const Vec3 toMin = m_referenceBounds.min - pickRay.origin;
            const Vec3 toMax = m_referenceBounds.max - pickRay.origin;
            const Vec3 anchor = toMin.dot(pickRay.direction) > toMax.dot(pickRay.direction) ? m_referenceBounds.min : m_referenceBounds.max;
            const Plane3 dragPlane(anchor, -pickRay.direction);
            
            const FloatType distance = dragPlane.intersectWithRay(pickRay);
            if (Math::isnan(distance))
                return;
            
            const Vec3 hitPoint = pickRay.pointAtDistance(distance);
            
            const Grid& grid = document->grid();
            const Vec3 delta = grid.moveDeltaForBounds(dragPlane, m_entity->bounds(), document->worldBounds(), pickRay, hitPoint);
            
            if (delta.null())
                return;
            
            document->translateObjects(delta);
        }
int BVaabb::WhichSide(const Plane3& plane) const
{
	if (mAlwaysPass)
		return 1;
	Real fDistance = plane.DistanceTo(mCenter);
	if (fDistance <= -mRadius)
	{
		return -1;
	}

	if (fDistance >= mRadius)
	{
		return +1;
	}

	return 0;
}
/******************************************************************************
* Renders the plane in the viewports.
******************************************************************************/
Box3 SliceModifier::renderPlane(SceneRenderer* renderer, const Plane3& plane, const Box3& bb, const ColorA& color) const
{
	// Compute intersection lines of slicing plane and bounding box.
	QVector<Point3> vertices;
	Point3 corners[8];
	for(int i = 0; i < 8; i++)
		corners[i] = bb[i];

	planeQuadIntersection(corners, {{0, 1, 5, 4}}, plane, vertices);
	planeQuadIntersection(corners, {{1, 3, 7, 5}}, plane, vertices);
	planeQuadIntersection(corners, {{3, 2, 6, 7}}, plane, vertices);
	planeQuadIntersection(corners, {{2, 0, 4, 6}}, plane, vertices);
	planeQuadIntersection(corners, {{4, 5, 7, 6}}, plane, vertices);
	planeQuadIntersection(corners, {{0, 2, 3, 1}}, plane, vertices);

	// If there is not intersection with the simulation box then
	// project the simulation box onto the plane.
	if(vertices.empty()) {
		const static int edges[12][2] = {
				{0,1},{1,3},{3,2},{2,0},
				{4,5},{5,7},{7,6},{6,4},
				{0,4},{1,5},{3,7},{2,6}
		};
		for(int edge = 0; edge < 12; edge++) {
			vertices.push_back(plane.projectPoint(corners[edges[edge][0]]));
			vertices.push_back(plane.projectPoint(corners[edges[edge][1]]));
		}
	}

	if(renderer) {
		// Render plane-box intersection lines.
		std::shared_ptr<LinePrimitive> buffer = renderer->createLinePrimitive();
		buffer->setVertexCount(vertices.size());
		buffer->setVertexPositions(vertices.constData());
		buffer->setLineColor(color);
		buffer->render(renderer);
	}

	// Compute bounding box.
	Box3 vertexBoundingBox;
	vertexBoundingBox.addPoints(vertices.constData(), vertices.size());
	return vertexBoundingBox;
}
/******************************************************************************
* Computes the intersection lines of a plane and a quad.
******************************************************************************/
void SliceModifier::planeQuadIntersection(const Point3 corners[8], const std::array<int,4>& quadVerts, const Plane3& plane, QVector<Point3>& vertices) const
{
	Point3 p1;
	bool hasP1 = false;
	for(int i = 0; i < 4; i++) {
		Ray3 edge(corners[quadVerts[i]], corners[quadVerts[(i+1)%4]]);
		FloatType t = plane.intersectionT(edge, FLOATTYPE_EPSILON);
		if(t < 0 || t > 1) continue;
		if(!hasP1) {
			p1 = edge.point(t);
			hasP1 = true;
		}
		else {
			Point3 p2 = edge.point(t);
			if(!p2.equals(p1)) {
				vertices.push_back(p1);
				vertices.push_back(p2);
				return;
			}
		}
	}
}
Beispiel #22
0
// Convert a plane equation to a rigid transform.
static void
planeToCFrame(Plane3 const & plane, Vector3 const & centroid, CoordinateFrame3 & cframe)
{
  Vector3 n;
  Real d;
  plane.getEquation(n.x(), n.y(), n.z(), d);

  Matrix3 rot;
  if (n.y() < -0.999)
  {
    rot = Matrix3(1,  0,  0,
                  0, -1,  0,
                  0,  0, -1);
  }
  else
  {
    Quat quat = rotationArc(Vector3::unitY(), n);
    rot = quat.toRotationMatrix();
  }

  cframe = CoordinateFrame3::_fromAffine(AffineTransform3(rot, centroid));
}
void PerspectiveProjectEllipsoid (const Ellipsoid3<Real>& ellipsoid,
    const Vector3<Real>& eye, const Plane3<Real>& plane,
    const Vector3<Real>& U, const Vector3<Real>& V, Vector3<Real>& P,
    Ellipse2<Real>& ellipse)
{
    // Get coefficients for ellipsoid as X^T*A*X + B^T*X + C = 0.
    Matrix3<Real> A;
    Vector3<Real> B;
    Real C;
    ellipsoid.ToCoefficients(A, B, C);

    // Compute matrix M (see PerspectiveProjectionEllipsoid.pdf).
    Vector3<Real> AE = A*eye;
    Real EAE = eye.Dot(AE);
    Real BE = B.Dot(eye);
    Real QuadE = ((Real)4)*(EAE + BE + C);
    Vector3<Real> Bp2AE = B + ((Real)2)*AE;
    Matrix3<Real> mat = Matrix3<Real>(Bp2AE, Bp2AE) - QuadE*A;

    // Compute coefficients for projected ellipse.
    Vector3<Real> MU = mat*U;
    Vector3<Real> MV = mat*V;
    Vector3<Real> MN = mat*plane.Normal;
    Real DmNdE = -plane.DistanceTo(eye);
    P = eye + DmNdE*plane.Normal;

    Matrix2<Real> AOut;
    Vector2<Real> BOut;
    Real COut;
    AOut[0][0] = U.Dot(MU);
    AOut[0][1] = U.Dot(MV);
    AOut[1][1] = V.Dot(MV);
    AOut[1][0] = AOut[0][1];
    BOut[0] = ((Real)2)*DmNdE*(U.Dot(MN));
    BOut[1] = ((Real)2)*DmNdE*(V.Dot(MN));
    COut = DmNdE*DmNdE*(plane.Normal.Dot(MN));
    ellipse.FromCoefficients(AOut, BOut, COut);
}
Beispiel #24
0
/// \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;
}
Beispiel #26
0
int ConvexClipper<Real>::Clip (const Plane3<Real>& plane)
{
    // Sompute signed distances from vertices to plane.
    int numPositive = 0, numNegative = 0;
    const int numVertices = (int)mVertices.size();
    for (int v = 0; v < numVertices; ++v)
    {
        Vertex& vertex = mVertices[v];
        if (vertex.Visible)
        {
            vertex.Distance = plane.DistanceTo(vertex.Point);
            if (vertex.Distance >= mEpsilon)
            {
                ++numPositive;
            }
            else if (vertex.Distance <= -mEpsilon)
            {
                ++numNegative;
                vertex.Visible = false;
            }
            else
            {
                // The point is on the plane (within floating point
                // tolerance).
                vertex.Distance = (Real)0;
            }
        }
    }

    if (numPositive == 0)
    {
        // Mesh is in negative half-space, fully clipped.
        return -1;
    }

    if (numNegative == 0)
    {
        // Mesh is in positive half-space, fully visible.
        return +1;
    }

    // Clip the visible edges.
    const int numEdges = (int)mEdges.size();
    for (int e = 0; e < numEdges; ++e)
    {
        Edge& edge = mEdges[e];
        if (edge.Visible)
        {
            int v0 = edge.Vertex[0];
            int v1 = edge.Vertex[1];
            int f0 = edge.Face[0];
            int f1 = edge.Face[1];
            Face& face0 = mFaces[f0];
            Face& face1 = mFaces[f1];
            Real d0 = mVertices[v0].Distance;
            Real d1 = mVertices[v1].Distance;

            if (d0 <= (Real)0 && d1 <= (Real)0)
            {
                // The edge is culled.  If the edge is exactly on the clip
                // plane, it is possible that a visible triangle shares it.
                // The edge will be re-added during the face loop.
                face0.Edges.erase(e);
                if (face0.Edges.empty())
                {
                    face0.Visible = false;
                }

                face1.Edges.erase(e);
                if (face1.Edges.empty())
                {
                    face1.Visible = false;
                }

                edge.Visible = false;
                continue;
            }

            if (d0 >= (Real)0 && d1 >= (Real)0)
            {
                // Face retains the edge.
                continue;
            }

            // The edge is split by the plane.  Compute the point of
            // intersection.  If the old edge is <V0,V1> and I is the
            // intersection point, the new edge is <V0,I> when d0 > 0 or
            // <I,V1> when d1 > 0.
            int vNew = (int)mVertices.size();
            mVertices.push_back(Vertex());
            Vertex& vertexNew = mVertices[vNew];

            Vector3<Real>& point0 = mVertices[v0].Point;
            Vector3<Real>& point1 = mVertices[v1].Point;
            vertexNew.Point = point0 + (d0/(d0 - d1))*(point1 - point0);

            if (d0 > (Real)0)
            {
                edge.Vertex[1] = vNew;
            }
            else
            {
                edge.Vertex[0] = vNew;
            }
        }
    }

    // The mesh straddles the plane.  A new convex polygonal face will be
    // generated.  Add it now and insert edges when they are visited.
    int fNew = (int)mFaces.size();
    mFaces.push_back(Face());
    Face& faceNew = mFaces[fNew];
    faceNew.Plane = plane;

    // Process the faces.
    for (int f = 0; f < fNew; ++f)
    {
        Face& face = mFaces[f];
        if (face.Visible)
        {
            // Determine if the face is on the negative side, the positive
            // side, or split by the clipping plane.  The Occurs members
            // are set to zero to help find the end points of the polyline
            // that results from clipping a face.
            assertion(face.Edges.size() >= 2, "Unexpected condition.\n");
            std::set<int>::iterator iter = face.Edges.begin();
            std::set<int>::iterator end = face.Edges.end();
            while (iter != end)
            {
                int e = *iter++;
                Edge& edge = mEdges[e];
                assertion(edge.Visible, "Unexpected condition.\n");
                mVertices[edge.Vertex[0]].Occurs = 0;
                mVertices[edge.Vertex[1]].Occurs = 0;
            }

            int vStart, vFinal;
            if (GetOpenPolyline(face, vStart, vFinal))
            {
                // Polyline is open, close it up.
                int eNew = (int)mEdges.size();
                mEdges.push_back(Edge());
                Edge& edgeNew = mEdges[eNew];

                edgeNew.Vertex[0] = vStart;
                edgeNew.Vertex[1] = vFinal;
                edgeNew.Face[0] = f;
                edgeNew.Face[1] = fNew;

                // Add new edge to polygons.
                face.Edges.insert(eNew);
                faceNew.Edges.insert(eNew);
            }
        }
    }

    // Process 'faceNew' to make sure it is a simple polygon (theoretically
    // convex, but numerically may be slightly not convex).  Floating-point
    // round-off errors can cause the new face from the last loop to be
    // needle-like with a collapse of two edges into a single edge.  This
    // block guarantees the invariant "face always a simple polygon".
    Postprocess(fNew, faceNew);
    if (faceNew.Edges.size() < 3)
    {
        // Face is completely degenerate, remove it from mesh.
        mFaces.pop_back();
    }

    return 0;
}
void IntrTetrahedron3Tetrahedron3<Real>::SplitAndDecompose (
    Tetrahedron3<Real> tetra, const Plane3<Real>& plane,
    std::vector<Tetrahedron3<Real> >& inside)
{
    // Determine on which side of the plane the points of the tetrahedron lie.
    Real C[4];
    int i, pos[4], neg[4], zer[4];
    int positive = 0, negative = 0, zero = 0;

    for (i = 0; i < 4; ++i)
    {
        C[i] = plane.DistanceTo(tetra.V[i]);
        if (C[i] > (Real)0)
        {
            pos[positive++] = i;
        }
        else if (C[i] < (Real)0)
        {
            neg[negative++] = i;
        }
        else
        {
            zer[zero++] = i;
        }
    }

    // For a split to occur, one of the c_i must be positive and one must
    // be negative.

    if (negative == 0)
    {
        // Tetrahedron is completely on the positive side of plane, full clip.
        return;
    }

    if (positive == 0)
    {
        // Tetrahedron is completely on the negative side of plane.
        inside.push_back(tetra);
        return;
    }

    // Tetrahedron is split by plane.  Determine how it is split and how to
    // decompose the negative-side portion into tetrahedra (6 cases).
    Real w0, w1, invCDiff;
    Vector3<Real> intp[4];

    if (positive == 3)
    {
        // +++-
        for (i = 0; i < positive; ++i)
        {
            invCDiff = ((Real)1)/(C[pos[i]] - C[neg[0]]);
            w0 = -C[neg[0]]*invCDiff;
            w1 = +C[pos[i]]*invCDiff;
            tetra.V[pos[i]] = w0*tetra.V[pos[i]] +
                w1*tetra.V[neg[0]];
        }
        inside.push_back(tetra);
    }
    else if (positive == 2)
    {
        if (negative == 2)
        {
            // ++--
            for (i = 0; i < positive; ++i)
            {
                invCDiff = ((Real)1)/(C[pos[i]] - C[neg[0]]);
                w0 = -C[neg[0]]*invCDiff;
                w1 = +C[pos[i]]*invCDiff;
                intp[i] = w0*tetra.V[pos[i]] + w1*tetra.V[neg[0]];
            }
            for (i = 0; i < negative; ++i)
            {
                invCDiff = ((Real)1)/(C[pos[i]] - C[neg[1]]);
                w0 = -C[neg[1]]*invCDiff;
                w1 = +C[pos[i]]*invCDiff;
                intp[i+2] = w0*tetra.V[pos[i]] +
                    w1*tetra.V[neg[1]];
            }

            tetra.V[pos[0]] = intp[2];
            tetra.V[pos[1]] = intp[1];
            inside.push_back(tetra);

            inside.push_back(Tetrahedron3<Real>(tetra.V[neg[1]],
                intp[3], intp[2], intp[1]));

            inside.push_back(Tetrahedron3<Real>(tetra.V[neg[0]],
                intp[0], intp[1], intp[2]));
        }
        else
        {
            // ++-0
            for (i = 0; i < positive; ++i)
            {
                invCDiff = ((Real)1)/(C[pos[i]] - C[neg[0]]);
                w0 = -C[neg[0]]*invCDiff;
                w1 = +C[pos[i]]*invCDiff;
                tetra.V[pos[i]] = w0*tetra.V[pos[i]] +
                    w1*tetra.V[neg[0]];
            }
            inside.push_back(tetra);
        }
    }
    else if (positive == 1)
    {
        if (negative == 3)
        {
            // +---
            for (i = 0; i < negative; ++i)
            {
                invCDiff = ((Real)1)/(C[pos[0]] - C[neg[i]]);
                w0 = -C[neg[i]]*invCDiff;
                w1 = +C[pos[0]]*invCDiff;
                intp[i] = w0*tetra.V[pos[0]] + w1*tetra.V[neg[i]];
            }

            tetra.V[pos[0]] = intp[0];
            inside.push_back(tetra);

            inside.push_back(Tetrahedron3<Real>(intp[0],
                tetra.V[neg[1]], tetra.V[neg[2]], intp[1]));

            inside.push_back(Tetrahedron3<Real>(tetra.V[neg[2]],
                intp[1], intp[2], intp[0]));
        }
        else if (negative == 2)
        {
            // +--0
            for (i = 0; i < negative; ++i)
            {
                invCDiff = ((Real)1)/(C[pos[0]] - C[neg[i]]);
                w0 = -C[neg[i]]*invCDiff;
                w1 = +C[pos[0]]*invCDiff;
                intp[i] = w0*tetra.V[pos[0]] + w1*tetra.V[neg[i]];
            }

            tetra.V[pos[0]] = intp[0];
            inside.push_back(tetra);

            inside.push_back(Tetrahedron3<Real>(intp[1],
                tetra.V[zer[0]], tetra.V[neg[1]], intp[0]));
        }
        else
        {
            // +-00
            invCDiff = ((Real)1)/(C[pos[0]] - C[neg[0]]);
            w0 = -C[neg[0]]*invCDiff;
            w1 = +C[pos[0]]*invCDiff;
            tetra.V[pos[0]] = w0*tetra.V[pos[0]] +
                w1*tetra.V[neg[0]];
            inside.push_back(tetra);
        }
    }
}
Beispiel #28
0
Vector3
reflectVector(Vector3 const & v, Plane3 const & mirror_plane)
{
  // Assume Plane3::normal() is unit
  return v - 2 * v.dot(mirror_plane.getNormal()) * mirror_plane.getNormal();
}
Beispiel #29
0
Vector3
reflectPoint(Vector3 const & p, Plane3 const & mirror_plane)
{
  // Assume Plane3::normal() is unit
  return p - 2 * (p - mirror_plane.getPoint()).dot(mirror_plane.getNormal()) * mirror_plane.getNormal();
}
        void ParaxialTexCoordSystem::doTransform(const Plane3& oldBoundary, const Mat4x4& transformation, BrushFaceAttributes& attribs, bool lockTexture, const Vec3& oldInvariant) {
            const Vec3 offset     = transformation * Vec3::Null;
            const Vec3& oldNormal = oldBoundary.normal;
                  Vec3 newNormal  = transformation * oldNormal - offset;
            assert(Math::eq(newNormal.length(), 1.0));
            
            // fix some rounding errors - if the old and new texture axes are almost the same, use the old axis
            if (newNormal.equals(oldNormal, 0.01))
                newNormal = oldNormal;
            
            if (!lockTexture || attribs.xScale() == 0.0f || attribs.yScale() == 0.0f) {
                setRotation(newNormal, attribs.rotation(), attribs.rotation());
                return;
            }
            
            // calculate the current texture coordinates of the origin
            const Vec2f oldInvariantTexCoords = computeTexCoords(oldInvariant, attribs.scale()) + attribs.offset();

            // project the texture axes onto the boundary plane along the texture Z axis
            const Vec3 boundaryOffset     = oldBoundary.project(Vec3::Null, getZAxis());
            const Vec3 oldXAxisOnBoundary = oldBoundary.project(m_xAxis * attribs.xScale(), getZAxis()) - boundaryOffset;
            const Vec3 oldYAxisOnBoundary = oldBoundary.project(m_yAxis * attribs.yScale(), getZAxis()) - boundaryOffset;

            // transform the projected texture axes and compensate the translational component
            const Vec3 transformedXAxis = transformation * oldXAxisOnBoundary - offset;
            const Vec3 transformedYAxis = transformation * oldYAxisOnBoundary - offset;
            
            const Vec2f textureSize = attribs.textureSize();
            const bool preferX = textureSize.x() >= textureSize.y();

            /*
            const FloatType dotX = transformedXAxis.normalized().dot(oldXAxisOnBoundary.normalized());
            const FloatType dotY = transformedYAxis.normalized().dot(oldYAxisOnBoundary.normalized());
            const bool preferX = Math::abs(dotX) < Math::abs(dotY);
            */
            
            // obtain the new texture plane norm and the new base texture axes
            Vec3 newBaseXAxis, newBaseYAxis, newProjectionAxis;
            const size_t newIndex = planeNormalIndex(newNormal);
            axes(newIndex, newBaseXAxis, newBaseYAxis, newProjectionAxis);

            const Plane3 newTexturePlane(0.0, newProjectionAxis);
            
            // project the transformed texture axes onto the new texture projection plane
            const Vec3 projectedTransformedXAxis = newTexturePlane.project(transformedXAxis);
            const Vec3 projectedTransformedYAxis = newTexturePlane.project(transformedYAxis);
            assert(!projectedTransformedXAxis.nan() &&
                   !projectedTransformedYAxis.nan());

            const Vec3 normalizedXAxis = projectedTransformedXAxis.normalized();
            const Vec3 normalizedYAxis = projectedTransformedYAxis.normalized();
            
            // determine the rotation angle from the dot product of the new base axes and the transformed, projected and normalized texture axes
            float cosX = static_cast<float>(newBaseXAxis.dot(normalizedXAxis.normalized()));
            float cosY = static_cast<float>(newBaseYAxis.dot(normalizedYAxis.normalized()));
            assert(!Math::isnan(cosX));
            assert(!Math::isnan(cosY));

            float radX = std::acos(cosX);
            if (crossed(newBaseXAxis, normalizedXAxis).dot(newProjectionAxis) < 0.0)
                radX *= -1.0f;
            
            float radY = std::acos(cosY);
            if (crossed(newBaseYAxis, normalizedYAxis).dot(newProjectionAxis) < 0.0)
                radY *= -1.0f;
            
            // TODO: be smarter about choosing between the X and Y axis rotations - sometimes either
            // one can be better
            float rad = preferX ? radX : radY;
            
            // for some reason, when the texture plane normal is the Y axis, we must rotation clockwise
            if (newIndex == 4)
                rad *= -1.0f;
            
            const float newRotation = Math::correct(Math::normalizeDegrees(Math::degrees(rad)), 4);
            doSetRotation(newNormal, newRotation, newRotation);
            
            // finally compute the scaling factors
            Vec2f newScale = Vec2f(projectedTransformedXAxis.length(),
                                   projectedTransformedYAxis.length()).corrected(4);

            // the sign of the scaling factors depends on the angle between the new texture axis and the projected transformed axis
            if (m_xAxis.dot(normalizedXAxis) < 0.0)
                newScale[0] *= -1.0f;
            if (m_yAxis.dot(normalizedYAxis) < 0.0)
                newScale[1] *= -1.0f;
            
            // compute the parameters of the transformed texture coordinate system
            const Vec3 newInvariant = transformation * oldInvariant;

            // determine the new texture coordinates of the transformed center of the face, sans offsets
            const Vec2f newInvariantTexCoords = computeTexCoords(newInvariant, newScale);
            
            // since the center should be invariant, the offsets are determined by the difference of the current and
            // the original texture coordiknates of the center
            const Vec2f newOffset = attribs.modOffset(oldInvariantTexCoords - newInvariantTexCoords).corrected(4);
            
            assert(!newOffset.nan());
            assert(!newScale.nan());
            assert(!Math::isnan(newRotation));
            assert(!Math::zero(newScale.x()));
            assert(!Math::zero(newScale.y()));
            
            attribs.setOffset(newOffset);
            attribs.setScale(newScale);
            attribs.setRotation(newRotation);
        }