Beispiel #1
0
FPoint3 CreateUnitLinkVector(FPoint3 p1, FPoint3 p2)
{
	FPoint3 v = p2 - p1;
	v.y = 0;
	v.Normalize();
	return v;
}
Beispiel #2
0
void vtLevel::GetEdgePlane(uint i, FPlane &plane)
{
	vtEdge *edge = m_Edges[i];
	int islope = edge->m_iSlope;
	float slope = (islope / 180.0f * PIf);

	int index = i;
	int ring = m_LocalFootprint.WhichRing(index);
	FLine3 &loop = m_LocalFootprint[ring];
	uint ring_edges = loop.GetSize();
	int next = (index+1 == ring_edges) ? 0 : index+1;

	// get edge vector
	FPoint3 vec = loop[next] - loop[index];
	vec.Normalize();

	// get perpendicular (upward pointing) vector
	FPoint3 perp;
	perp.Set(0, 1, 0);

	// create rotation matrix to rotate it upward
	FMatrix4 mat;
	mat.Identity();
	mat.AxisAngle(vec, slope);

	// create normal
	FPoint3 norm;
	mat.TransformVector(perp, norm);

	plane.Set(loop[index], norm);
}
Beispiel #3
0
FPoint3 LinkGeom::FindPointAlongRoad(float fDistance)
{
	FPoint3 v;

	float length = 0.0f;

	if (fDistance <= 0) {
		static int c = 0;
		c++;
		return m_centerline[0];
	}
	// compute 2D length of this link, by adding up the 2d link segment lengths
	for (uint j = 0; j < GetSize()-1; j++)
	{
		// consider length of next segment
		v.x = m_centerline[j+1].x - m_centerline[j].x;
		v.y = 0;
		v.z = m_centerline[j+1].z - m_centerline[j].z;
		length = v.Length();
		if (fDistance <= length)
		{
			float fraction = fDistance / length;
			FPoint3 p0, p1, diff;
			p0 = m_centerline[j];
			v *= fraction;
			return p0 + v;
		}
		fDistance -= length;
	}
	// if we pass the end of line, just return the last point
	return m_centerline[GetSize()-1];
}
Beispiel #4
0
FPoint3 vtTin::GetTriangleNormal(int iTriangle) const
{
	FPoint3 wp0, wp1, wp2;
	_GetLocalTrianglePoints(iTriangle, wp0, wp1, wp2);
	FPoint3 norm = (wp1 - wp0).Cross(wp2 - wp0);
	norm.Normalize();
	return norm;
}
Beispiel #5
0
FPoint3 SidewaysVector(const FPoint3 &p0, const FPoint3 &p1)
{
	FPoint3 diff = p1 - p0;
	FPoint3 up(0,1,0);
	FPoint3 cross = diff.Cross(up);
	cross.Normalize();
	return cross;
}
Beispiel #6
0
//
// helper: given two points along a link, produce a vector
// along to that link, parallel to the ground plane,
// with length corresponding to the supplied width
//
FPoint3 CreateRoadVector(const FPoint3 &p1, const FPoint3 &p2, const float w)
{
	FPoint3 v = p2 - p1;
	v.y = 0;
	v.Normalize();
	v.x *= (w / 2.0f);
	v.z *= (w / 2.0f);
	return v;
}
Beispiel #7
0
void AdaptiveLayerHeights::calculateMeshTriangleSlopes()
{
    // loop over all mesh faces (triangles) and find their slopes
    for (const Mesh& mesh : Application::getInstance().current_slice->scene.current_mesh_group->meshes)
    {
        // Skip meshes that are not printable
        if (mesh.settings.get<bool>("infill_mesh") || mesh.settings.get<bool>("cutting_mesh") || mesh.settings.get<bool>("anti_overhang_mesh"))
        {
            continue;
        }

        for (const MeshFace& face : mesh.faces)
        {
            const MeshVertex& v0 = mesh.vertices[face.vertex_index[0]];
            const MeshVertex& v1 = mesh.vertices[face.vertex_index[1]];
            const MeshVertex& v2 = mesh.vertices[face.vertex_index[2]];

            const FPoint3 p0 = v0.p;
            const FPoint3 p1 = v1.p;
            const FPoint3 p2 = v2.p;

            float min_z = p0.z;
            min_z = std::min(min_z, p1.z);
            min_z = std::min(min_z, p2.z);
            float max_z = p0.z;
            max_z = std::max(max_z, p1.z);
            max_z = std::max(max_z, p2.z);

            // calculate the angle of this triangle in the z direction
            const FPoint3 n = FPoint3(p1 - p0).cross(p2 - p0);
            const FPoint3 normal = n.normalized();
            AngleRadians z_angle = std::acos(std::abs(normal.z));

            // prevent flat surfaces from influencing the algorithm
            if (z_angle == 0)
            {
                z_angle = M_PI;
            }

            face_min_z_values.push_back(min_z * 1000);
            face_max_z_values.push_back(max_z * 1000);
            face_slopes.push_back(z_angle);
        }
    }
}
Beispiel #8
0
//
// Return the 2D length of this link segment in world units
//
float LinkGeom::Length()
{
	FPoint3 v;
	v.y = 0;
	float length = 0.0f;

	// compute 2D length of this link, by adding up the 2d link segment lengths
	for (uint j = 0; j < GetSize(); j++)
	{
		if (j > 0)
		{
			// increment length
			v.x = m_centerline[j].x - m_centerline[j-1].x;
			v.z = m_centerline[j].z - m_centerline[j-1].z;
			float l = v.Length();
			if (l < 0) {
				assert(false);
			}
			length += l;
		}
	}
	return length;
}
Beispiel #9
0
//
// Test code
//
void EnviroFrame::DoTestCode()
{
	SetMode(MM_SLOPE);

#if 0
	// Shadow tests
	const int ReceivesShadowTraversalMask = 0x1;
	const int CastsShadowTraversalMask = 0x2;

	osg::ref_ptr<osgShadow::ShadowedScene> shadowedScene = new osgShadow::ShadowedScene;

	shadowedScene->setReceivesShadowTraversalMask(ReceivesShadowTraversalMask);
	shadowedScene->setCastsShadowTraversalMask(CastsShadowTraversalMask);

#if 0
	osg::ref_ptr<osgShadow::ShadowMap> sm = new osgShadow::ShadowMap;
	shadowedScene->setShadowTechnique(sm.get());
	int mapres = 1024;
	sm->setTextureSize(osg::Vec2s(mapres,mapres));
#else
	osg::ref_ptr<osgShadow::ShadowTexture> sm = new osgShadow::ShadowTexture;
	shadowedScene->setShadowTechnique(sm.get());
#endif

	osg::Group* cessna1 = (osg::Group*) osgDB::readNodeFile("cessna.osg");
	if (!cessna1)
		return;
	cessna1->setNodeMask(CastsShadowTraversalMask);
	cessna1->getChild(0)->setNodeMask(CastsShadowTraversalMask);

	osg::Group* cessna2 = (osg::Group*) osgDB::readNodeFile("cessna.osg");
	if (!cessna2)
		return;
	int flags_off = ~(CastsShadowTraversalMask | ReceivesShadowTraversalMask);
	cessna2->setNodeMask(flags_off);
	cessna2->getChild(0)->setNodeMask(flags_off);

	osg::MatrixTransform* positioned = new osg::MatrixTransform;
	positioned->setDataVariance(osg::Object::STATIC);
	positioned->setMatrix(osg::Matrix::rotate(osg::inDegrees(-90.0f),0.0f,1.0f,0.0f)
		*osg::Matrix::translate(40,40,0));
	positioned->addChild(cessna1);

//osg::ref_ptr<osg::Group> shadowedScene = new osg::Group;
	shadowedScene->addChild(positioned);
	shadowedScene->addChild(cessna2);

	//	osg::ref_ptr<osg::Group> container = new osg::Group;
	//	container->addChild(positioned);
	//    container->addChild(cessna2);

	vtGroup *vtg = GetCurrentTerrain()->GetTerrainGroup();
	vtg->GetOsgGroup()->addChild(shadowedScene.get());
	//	vtg->GetOsgGroup()->addChild(container.get());

	vtLogGraph(shadowedScene.get());
#endif
#if 0
	if (pTerr && g_App.m_bSelectedStruct)
	{
		vtStructureArray3d *sa = pTerr->GetStructureLayer();
		int i = 0;
		while (!sa->GetAt(i)->IsSelected())
			i++;
		vtBuilding3d *bld = sa->GetBuilding(i);
		// (Do something to the building as a test)
		sa->ConstructStructure(bld);
	}
#endif
#if 0
	{
		// Read points from a text file, create OBJ file with geometry at that locations
		FILE *fp = fopen("test.txt", "r");
		if (!fp) return;

		char buf[80];
		float depth, x, y;

		// Add the geometry and materials to the shape
		vtGeode *pGeode = new vtGeode;
		vtMaterialArray *pMats = new vtMaterialArray;
		pMats->AddRGBMaterial(RGBf(1.0f, 1.0f, 1.0f), false, false, false);
		pGeode->SetMaterials(pMats);

		vtMesh *mesh = new vtMesh(osg::PrimitiveSet::TRIANGLES, VT_Normals | VT_Colors, 4000);

		int line = 0;
		fgets(buf, 80, fp);	// skip first
		while (fgets(buf, 80, fp) != NULL)
		{
			sscanf(buf, "%f\t%f\t%f", &depth, &x, &y);
			int idx = mesh->NumVertices();
			for (int i = 0; i < 20; i++)
			{
				double angle = (double)i / 20.0 * PI2d;
				FPoint3 vec;
				vec.x = x/2 * cos(angle);
				vec.y = 0.0f;
				vec.z = y/2 * sin(angle);

				// normal
				FPoint3 norm = vec;
				norm.Normalize();

				// color
				RGBAf col(1.0f, 1.0f, 1.0f, 1.0f);
				if (x > y)
				{
					float frac = (x-y)/1.5f;	// typical: 0 - 1.2
					col.g -= frac;
					col.b -= frac;
				}
				else if (y > x)
				{
					float frac = (y-x)/1.5f;	// typical: 0 - 1.2
					col.r -= frac;
					col.g -= frac;
				}

				int add = mesh->AddVertexN(vec.x, /*650*/-depth, vec.z,
					norm.x, norm.y, norm.z);
				mesh->SetVtxColor(add, col);
			}
			if (line != 0)
			{
				for (int i = 0; i < 20; i++)
				{
					int next = (i+1)%20;
					mesh->AddTri(idx-20 + i, idx + i,    idx-20 + next);
					mesh->AddTri(idx    + i, idx + next, idx-20 + next);
				}
			}
			line++;
		}
		pGeode->AddMesh(mesh, 0);
		WriteGeomToOBJ(pGeode, "bore.obj");

		vtTransform *model = new vtTransform;
		model->addChild(pGeode);
		DPoint3 pos;
		g_App.m_pTerrainPicker->GetCurrentEarthPos(pos);
		GetCurrentTerrain()->AddNode(model);
		GetCurrentTerrain()->PlantModelAtPoint(model, DPoint2(pos.x, pos.y));
	}
#endif
}
Beispiel #10
0
/* Core code contributed by Kevin Behilo, 2/20/04.
 *
 * Possible TODO: add code to soften and blend shadow edges
 *  (see aliasing comments in source).
 *
 * Definite TODO: the whole thing can be sped up by precalculating the
 *  surface normals once.  In fact that should be placed in a separate Shading
 *  Context, so that it could be re-used for quickly re-shading multiple times.
 */
void vtHeightFieldGrid3d::ShadowCastDib(vtBitmapBase *pBM, const FPoint3 &light_dir,
	float fLightFactor, float fAmbient, bool progress_callback(int)) const
{
	const IPoint2 bitmap_size = pBM->GetSize();

	// Compute area that we will sample for shading, bounded by the texel
	//  centers, which are 1/2 texel in from the grid extents.
	const DPoint2 texel_size(m_EarthExtents.Width() / bitmap_size.x,
							 m_EarthExtents.Height() / bitmap_size.y);
	DRECT texel_area = m_EarthExtents;
	texel_area.Grow(-texel_size.x/2, -texel_size.y/2);
	const DPoint2 texel_base(texel_area.left, texel_area.bottom);

	const bool b8bit = (pBM->GetDepth() == 8);

	// These values are hardcoded here but could be exposed in the GUI
	const float sun =  0.7f;

	// If we have light that's pointing UP, rather than down at the terrain,
	//  then it's only going to take a really long time to produce a
	//  completely dark terrain.  We can catch this case up front.
	if (light_dir.y > 0)
	{
		for (int i = 0; i < bitmap_size.x; i++)
		{
			for (int j = 0; j < bitmap_size.y; j++)
			{
				if (b8bit)
					pBM->ScalePixel8(i, j, fAmbient);
				else
					pBM->ScalePixel24(i, j, fAmbient);
			}
		}
		return;
	}

	// Create array to hold flags
	LightMap lightmap(bitmap_size.x, bitmap_size.y);

	// This factor is used when applying shading to non-shadowed areas to
	// try and keep the "contrast" down to a min. (still get "patches" of
	// dark/light spots though).
	// It is initialized to 1.0, because in case there are no shadows at all
	//  (such as at noon) we still need a reasonable value.
	float darkest_shadow = 1.0;

	// For the vector used to cast shadows, we need it in grid coordinates,
	//  which are (Column,Row) where Row is north.  But the direction passed
	//  in uses OpenGL coordinates where Z is south.  So flip Z.
	FPoint3 grid_light_dir = light_dir;
	grid_light_dir.z = -grid_light_dir.z;

	// Scale the light vector such that the X or Z component (whichever is
	//  larger) is 1.  This is will serve as our direction vector in grid
	//  coordinates, when drawing a line across the grid to cast the shadow.
	//
	// Code adapted from aaron_torpy:
	// http://www.geocities.com/aaron_torpy/algorithms.htm
	//
	float f, HScale;
	if ( fabs(grid_light_dir.x) > fabs(grid_light_dir.z) )
	{
		HScale = m_fStep.x;
		f = fabs(light_dir.x);
	}
	else
	{
		HScale = m_fStep.y;
		f = fabs(light_dir.z);
	}
	grid_light_dir /= f;

	int i_init, i_final, i_incr;
	int j_init, j_final, j_incr;
	if (grid_light_dir.x > 0)
	{
		i_init=0;
		i_final=bitmap_size.x;
		i_incr=1;
	}
	else
	{
		i_init=bitmap_size.x-1;
		i_final=-1;
		i_incr=-1;
	}
	if (grid_light_dir.z > 0)
	{
		j_init=0;
		j_final=bitmap_size.y;
		j_incr=1;
	}
	else
	{
		j_init=bitmap_size.y-1;
		j_final=-1;
		j_incr=-1;
	}

	// First pass: find each point that it is in shadow.
	DPoint2 pos;
	float shadowheight, elevation;
	FPoint3 normal;
	FPoint3 p3;
	int x, z;
	float shade;

	for (int j = j_init; j != j_final; j += j_incr)
	{
		if (progress_callback != NULL && (j%20) == 0)
			progress_callback(abs(j-j_init) * 100 / bitmap_size.y);

		for (int i = i_init; i != i_final; i += i_incr)
		{
			pos = GridPos(texel_base, texel_size, i, j);
			FindAltitudeOnEarth(pos, shadowheight, true);

			if (shadowheight == INVALID_ELEVATION)
			{
				// set a flag so we won't visit this one again
				lightmap.Set(i, j, 1);
				continue;
			}

			bool Under_Out = false;
			for (int k = 1; Under_Out == false; k++)
			{
				x = (int) (i + grid_light_dir.x*k + 0.5f);
				z = (int) (j + grid_light_dir.z*k + 0.5f);
				shadowheight += grid_light_dir.y * HScale;

				if ((x<0) || (x>bitmap_size.x-1) || (z<0) || (z>bitmap_size.y-1))
				{
					Under_Out = true; // Out of the grid
					break;
				}

				pos = GridPos(texel_base, texel_size, x, z);
				FindAltitudeOnEarth(pos, elevation, true);

				// skip holes in the grid
				if (elevation == INVALID_ELEVATION)
					continue;

				if (elevation > shadowheight)
				{
					if (k>1)
						Under_Out = true; // Under the terrain
					break;
				}

				// Combine color and shading.
				// Only do shadow if we have not shaded this i,j before.
				if (lightmap.Get(x,z) < 1)
				{
					// 3D elevation query to get slope
					m_LocalCS.EarthToLocal(pos, p3.x, p3.z);
					FindAltitudeAtPoint(p3, p3.y, true, 0, &normal);

					//*****************************************
					// Here the Sun(r, g, b) = 0 because we are in the shade
					// therefore I(r, g, b) = Amb(r, g, b) * (0.5*N[z] + 0.5)

				//	shade =  sun*normal.Dot(-light_direction) + fAmbient * (0.5f*normal.y + 0.5f);
					shade =  fAmbient * (0.5f*normal.y + 0.5f);
					//*****************************************
					//*****************************************
					if (darkest_shadow > shade)
						darkest_shadow = shade;

					// Rather than doing the shading at this point we may want to
					// simply save the value into the LightMap array. Then apply
					// some anti-aliasing or edge softening algorithm to the LightMap.
					// Once that's done, apply the whole LightMap to the DIB.
					if (b8bit)
						pBM->ScalePixel8(x, bitmap_size.y-1-z, shade);
					else
						pBM->ScalePixel24(x, bitmap_size.y-1-z, shade);

					// set a flag to show that this texel has been shaded.
					// (or set to value of the shading - see comment above)
					lightmap.Set(x, z, lightmap.Get(x, z)+1);
				}
			}
		} //for i
	} //for j

	// For dot-product lighting, we use the normal 3D vector, only inverted
	//  so that we can compare it to the upward-pointing ground normals.
	const FPoint3 inv_light_dir = -light_dir;

	// Second pass.  Now we are going to loop through the LightMap and apply
	//  the full lighting formula to each texel that has not been shaded yet.
	for (int j = 0; j < bitmap_size.y; j++)
	{
		if (progress_callback != NULL && (j%20) == 0)
			progress_callback(j * 100 / bitmap_size.y);

		for (int i = 0; i < bitmap_size.x; i++)
		{
			if (lightmap.Get(i, j) > 0)
				continue;

			pos = GridPos(texel_base, texel_size, i, j);

			// 2D elevation query to check for holes in the grid
			FindAltitudeOnEarth(pos, elevation, true);
			if (elevation == INVALID_ELEVATION)
				continue;

			// 3D elevation query to get slope
			m_LocalCS.EarthToLocal(pos, p3.x, p3.z);
			FindAltitudeAtPoint(p3, p3.y, true, 0, &normal);

			//*****************************************
			//*****************************************
			//shade formula based on:
			//http://www.geocities.com/aaron_torpy/algorithms.htm#calc_intensity

			// The Amb value was arbitrarily chosen
			// Need to experiment more to determine the best value
			// Perhaps calculating Sun(r, g, b) and Amb(r, g, b) for a
			//  given time of day (e.g. warmer colors close to sunset)
			// or give control to user since textures will differ

			// I(r, g, b) = Sun(r, g, b) * scalarprod(N, v) + Amb(r, g, b) * (0.5*N[z] + 0.5)
			shade = sun * normal.Dot(inv_light_dir);

			// It's a reasonable assuption that an angle of 45 degrees is
			//  sufficient to fully illuminate the ground.
			shade /= .7071f;

			// Now add ambient component
			shade += fAmbient * (0.5f*normal.y + 0.5f);

			// Maybe clipping values can be exposed to the user as well.
			// Clip - don't shade down below lowest ambient level
			if (shade < darkest_shadow)
				shade = darkest_shadow;
			else if (shade > 1.2f)
				shade = 1.2f;

			// Push the value of 'shade' toward 1.0 by the fLightFactor factor.
			// This means that fLightFactor=0 means no lighting, 1 means full lighting.
			float diff = 1 - shade;
			diff = diff * (1 - fLightFactor);
			shade += diff;

			// Rather than doing the shading at this point we may want to
			// simply save the value into the LightMap array. Then apply
			// some anti-aliasing or edge softening algorithm to the LightMap.
			// Once that's done, apply the whole LightMap to the DIB.
			// LightMap[I][J]= shade; // set to value of the shading - see comment above)
			if (b8bit)
				pBM->ScalePixel8(i, bitmap_size.y-1-j, shade);
			else
				pBM->ScalePixel24(i, bitmap_size.y-1-j, shade);
		}
	}

	// Possible TODO: Apply edge softening algorithm (?)
}
Beispiel #11
0
/**
 * Create a set of points on the heightfield for a 2D polyline by draping the point onto
 * the surface.
 *
 * \param line	The 2D line to drape, in Earth coordinates.
 * \param fSpacing	The approximate spacing of the surface tessellation, used to
 *		decide how finely to tessellate the line.
 * \param fOffset	An offset to elevate each point in the resulting geometry,
 *		useful for keeping it visibly above the ground.
 * \param bInterp	True to interpolate between the vertices of the input
 *		line. This is generally desirable when the ground is much more finely
 *		spaced than the input line.
 * \param bCurve	True to interpret the vertices of the input line as
 *		control points of a curve.  The created geometry will consist of
 *		a draped line which passes through the control points.
 * \param bTrue		True to use the true elevation of the terrain, ignoring
 *		whatever scale factor is being used to exaggerate elevation for
 *		display.
 * \param output	Received the points.
 * \return The approximate length of the resulting 3D polyline.
 */
float vtHeightField3d::LineOnSurface(const DLine2 &line, float fSpacing, float fOffset,
	bool bInterp, bool bCurve, bool bTrue, FLine3 &output)
{
	uint i, j;
	FPoint3 v1, v2, v;

	float fTotalLength = 0.0f;
	int iVerts = 0;
	uint points = line.GetSize();
	if (bCurve)
	{
		DPoint2 p2, last(1E9,1E9);
		DPoint3 p3;

		int spline_points = 0;
		CubicSpline spline;
		for (i = 0; i < points; i++)
		{
			p2 = line[i];
			if (i > 1 && p2 == last)
				continue;
			p3.Set(p2.x, p2.y, 0);
			spline.AddPoint(p3);
			spline_points++;
			last = p2;
		}
		spline.Generate();

		// Estimate how many steps to subdivide this line into
		const double dLinearLength = line.Length();
		float fLinearLength, dummy;
		m_LocalCS.VectorEarthToLocal(DPoint2(dLinearLength, 0.0), fLinearLength, dummy);
		double full = (double) (spline_points-1);
		int iSteps = (uint) (fLinearLength / fSpacing);
		if (iSteps < 3)
			iSteps = 3;
		double dStep = full / iSteps;

		FPoint3 last_v;
		for (double f = 0; f <= full; f += dStep)
		{
			spline.Interpolate(f, &p3);

			m_LocalCS.EarthToLocal(p3.x, p3.y, v.x, v.z);
			FindAltitudeAtPoint(v, v.y, bTrue);
			v.y += fOffset;
			output.Append(v);
			iVerts++;

			// keep a running total of approximate ground length
			if (f > 0)
				fTotalLength += (v - last_v).Length();
			last_v = v;
		}
	}
	else
	{
		// not curved: straight line in earth coordinates
		FPoint3 last_v;
		for (i = 0; i < points; i++)
		{
			if (bInterp)
			{
				v1 = v2;
				m_LocalCS.EarthToLocal(line[i].x, line[i].y, v2.x, v2.z);
				if (i == 0)
					continue;

				// estimate how many steps to subdivide this segment into
				FPoint3 diff = v2 - v1;
				float fLen = diff.Length();
				uint iSteps = (uint) (fLen / fSpacing);
				if (iSteps < 1) iSteps = 1;

				for (j = (i == 1 ? 0:1); j <= iSteps; j++)
				{
					// simple linear interpolation of the ground coordinate
					v.Set(v1.x + diff.x / iSteps * j, 0.0f, v1.z + diff.z / iSteps * j);
					FindAltitudeAtPoint(v, v.y, bTrue);
					v.y += fOffset;
					output.Append(v);
					iVerts++;

					// keep a running total of approximate ground length
					if (j > 0)
						fTotalLength += (v - last_v).Length();
					last_v = v;
				}
			}
			else
			{
				m_LocalCS.EarthToLocal(line[i], v.x, v.z);
				FindAltitudeAtPoint(v, v.y, bTrue);
				v.y += fOffset;
				output.Append(v);
			}
		}
	}
	return fTotalLength;
}
Beispiel #12
0
void vtIcoGlobe::BuildSphericalPoints(GlobeLayer *glay, float fSize)
{
    vtFeatureSet *feat = glay->m_pSet;
    int i, j, size;
    vtArray<FSphere> spheres;

    size = feat->GetNumEntities();
    spheres.SetSize(size);

    vtFeatureSetPoint2D *pSetP2 = dynamic_cast<vtFeatureSetPoint2D*>(feat);
    if (!pSetP2)
        return;

    DPoint2 p;
    for (i = 0; i < size; i++)
    {
        pSetP2->GetPoint(i, p);

        if (p.x == 0.0 && p.y == 0.0)	// ignore some
            continue;

        FPoint3 loc;
        geo_to_xyz(1.0, p, loc);

        spheres[i].center = loc;
        spheres[i].radius = fSize;
    }

    FPoint3 diff;

    // volume of sphere, 4/3 PI r^3
    // surface area of sphere, 4 PI r^2
    // area of circle of sphere as seen from distance, PI r^2
    int merges;
    do {
        merges = 0;
        // Try merging overlapping points together, so that information
        // is not lost in the overlap.
        // To consider: do we combine the blobs based on their 2d radius,
        // their 2d area, their 3d radius, or their 3d volume?  See
        // Tufte, http://www.edwardtufte.com/
        // Implemented here: preserve 2d area
        for (i = 0; i < size-1; i++)
        {
            for (j = i+1; j < size; j++)
            {
                if (spheres[i].radius == 0.0f || spheres[j].radius == 0.0f)
                    continue;

                diff = spheres[i].center - spheres[j].center;

                // if one sphere contains the center of the other
                if (diff.Length() < spheres[i].radius ||
                        diff.Length() < spheres[j].radius)
                {
                    // combine
                    float area1 = PIf * spheres[i].radius * spheres[i].radius;
                    float area2 = PIf * spheres[j].radius * spheres[j].radius;
                    float combined = (area1 + area2);
                    float newrad = sqrtf( combined / PIf );
                    // larger eats the smaller
                    if (area1 > area2)
                    {
                        spheres[i].radius = newrad;
                        spheres[j].radius = 0.0f;
                    }
                    else
                    {
                        spheres[j].radius = newrad;
                        spheres[i].radius = 0.0f;
                    }
                    merges++;
                    break;
                }
            }
        }
    }
    while (merges != 0);

    // Now create and place the little geometry objects to represent the
    // point data.

#if 0
    // create simple hemisphere mesh
    int res = 6;
    vtMesh *mesh = new vtMesh(osg::PrimitiveSet::TRIANGLE_STRIP, 0, res*res*2);
    FPoint3 scale(1.0f, 1.0f, 1.0f);
    mesh->CreateEllipsoid(scale, res, true);
#else
    // create cylinder mesh instead
    int res = 14;
    int verts = res * 2;
    vtMesh *mesh = new vtMesh(osg::PrimitiveSet::TRIANGLE_STRIP, 0, verts);
    mesh->CreateCylinder(1.0f, 1.0f, res, true, false, false);
#endif

    // use Area to show amount, otherwise height
    bool bArea = true;

    // create and place the geometries
    size = spheres.GetSize();
    for (i = 0; i < size; i++)
    {
        if (spheres[i].radius == 0.0f)
            continue;

        vtGeode *geode = new vtGeode;
        geode->SetMaterials(m_coremats);
        geode->AddMesh(mesh, m_yellow);

        vtMovGeode *mgeom = new vtMovGeode(geode);
        mgeom->setName("GlobeShape");

        mgeom->PointTowards(spheres[i].center);
        mgeom->RotateLocal(FPoint3(1,0,0), -PID2f);
        mgeom->SetTrans(spheres[i].center);
        if (bArea)
        {
            // scale just the radius of the cylinder
            mgeom->Scale3(spheres[i].radius, 0.001f, spheres[i].radius);
        }
        else
        {
            // scale just the height of the cylinder
            double area = PIf * spheres[i].radius * spheres[i].radius;
            mgeom->Scale3(0.002f, (float)area*1000, 0.002f);
        }
        m_SurfaceGroup->addChild(mgeom);
        glay->addChild(mgeom);
    }
}
Beispiel #13
0
/*!
Returns the index of the 'other' face connected to the edge between vertices with indices idx0 and idx1.
In case more than two faces are connected via the same edge, the next face in a counter-clockwise ordering (looking from idx1 to idx0) is returned.

\cond DOXYGEN_EXCLUDE
    [NON-RENDERED COMENTS]
    For two faces abc and abd with normals n and m, we have that:
    \f{eqnarray*}{
    n &=& \frac{ab \times ac}{\|ab \times ac\|}     \\
    m &=& \frac{ab \times ad}{\|ab \times ad\|}     \\
    n \times m &=& \|n\| \cdot \|m\| \mathbf{p} \sin \alpha  \\
    && (\mathbf{p} \perp n \wedge \mathbf{p} \perp m) \\
    \sin \alpha &=& \|n \times m \|
    &=& \left\| \frac{(ab \times ac) \times (ab \times ad)}{\|ab \times ac\| \cdot \|ab \times ad\|}  \right\|    \\
    &=& \left\| \frac{ (ab \cdot (ac \times ad)) ab  }{\|ab \times ac\| \cdot \|ab \times ad\|}  \right\|    \\
    &=&  \frac{ (ab \cdot (ac \times ad)) \left\| ab   \right\| }{\|ab\| \|ac\| \sin bac \cdot \|ab\| \|ad\| \sin bad}    \\
    &=&  \frac{  ab \cdot (ac \times ad)  }{\|ab\| \|ac\| \|ad\|  \sin bac \sin bad}    \\
    \f}}
\endcond

See <a href="http://stackoverflow.com/questions/14066933/direct-way-of-computing-clockwise-angle-between-2-vectors">Direct way of computing clockwise angle between 2 vectors</a>


*/
int Mesh::getFaceIdxWithPoints(int idx0, int idx1, int notFaceIdx) const
{
    std::vector<int> candidateFaces; // in case more than two faces meet at an edge, multiple candidates are generated
    int notFaceVertexIdx = -1; // index of the third vertex of the face corresponding to notFaceIdx
    for(int f : vertices[idx0].connected_faces) // search through all faces connected to the first vertex and find those that are also connected to the second
    {
        if (f == notFaceIdx)
        {
            for (int i = 0; i<3; i++) // find the vertex which is not idx0 or idx1
                if (faces[f].vertex_index[i] != idx0 && faces[f].vertex_index[i] != idx1)
                    notFaceVertexIdx = faces[f].vertex_index[i];
            continue;
        }
        if ( faces[f].vertex_index[0] == idx1 // && faces[f].vertex_index[1] == idx0 // next face should have the right direction!
          || faces[f].vertex_index[1] == idx1 // && faces[f].vertex_index[2] == idx0
          || faces[f].vertex_index[2] == idx1 // && faces[f].vertex_index[0] == idx0
            )  candidateFaces.push_back(f);

    }

    if (candidateFaces.size() == 0) { cura::logError("Couldn't find face connected to face %i.\n", notFaceIdx); return -1; }
    if (candidateFaces.size() == 1) { return candidateFaces[0]; }


    if (notFaceVertexIdx < 0) { cura::logError("Couldn't find third point on face %i.\n", notFaceIdx); return -1; }

    if (candidateFaces.size() % 2 == 0) cura::log("Warning! Edge with uneven number of faces connecting it!(%i)\n", candidateFaces.size()+1);

    FPoint3 vn = vertices[idx1].p - vertices[idx0].p;
    FPoint3 n = vn / vn.vSize(); // the normal of the plane in which all normals of faces connected to the edge lie => the normalized normal
    FPoint3 v0 = vertices[idx1].p - vertices[idx0].p;

// the normals below are abnormally directed! : these normals all point counterclockwise (viewed from idx1 to idx0) from the face, irrespective of the direction of the face.
    FPoint3 n0 = FPoint3(vertices[notFaceVertexIdx].p - vertices[idx0].p).cross(v0);

    if (n0.vSize() <= 0) cura::log("Warning! Face %i has zero area!", notFaceIdx);

    double smallestAngle = 1000; // more then 2 PI (impossible angle)
    int bestIdx = -1;

    for (int candidateFace : candidateFaces)
    {
        int candidateVertex;
        {// find third vertex belonging to the face (besides idx0 and idx1)
            for (candidateVertex = 0; candidateVertex<3; candidateVertex++)
                if (faces[candidateFace].vertex_index[candidateVertex] != idx0 && faces[candidateFace].vertex_index[candidateVertex] != idx1)
                    break;
        }

        FPoint3 v1 = vertices[candidateVertex].p -vertices[idx0].p;
        FPoint3 n1 = v1.cross(v0);

        double dot = n0 * n1;
        double det = n * n0.cross(n1);
        double angle = std::atan2(det, dot);
        if (angle < 0) angle += 2*M_PI; // 0 <= angle < 2* M_PI

        if (angle == 0)
        {
            cura::log("Warning! Overlapping faces: face %i and face %i.\n", notFaceIdx, candidateFace);
            std::cerr<< n.vSize() <<"; "<<n1.vSize()<<";"<<n0.vSize() <<std::endl;
        }
        if (angle < smallestAngle)
        {
            smallestAngle = angle;
            bestIdx = candidateFace;
        }
    }
    if (bestIdx < 0) cura::logError("Couldn't find face connected to face %i.\n", notFaceIdx);
    return bestIdx;
}
Beispiel #14
0
void vtFence3d::AddProfileConnectionMesh(const FLine3 &p3)
{
	uint i, j, npoints = p3.GetSize(), prof_points = m_Profile.GetSize();

	// Must have at least 2 points in the profile
	if (prof_points < 2)
		return;

	// Each segment of the profile becomes a long triangle strip.
	// If there are no shared vertices between segments, the number of
	//  vertices is, for a profile of N points and a line of P points:
	//   P * (N-1) * 2, for the sides
	//   N*2, for the end caps (or more if we have to tessellate)
	//
	int iEstimateVerts = npoints * (prof_points-1) * 2 + (prof_points * 2);
	vtMesh *pMesh = new vtMesh(osg::PrimitiveSet::TRIANGLE_STRIP,
		VT_TexCoords | VT_Normals, iEstimateVerts);

	vtMaterialDescriptor *desc = GetMatDescriptor(m_Params.m_ConnectMaterial);
	if (!desc)
	{
		VTLOG1("Warning: could not find material: ");
		VTLOG1(m_Params.m_ConnectMaterial);
		VTLOG1("\n");
		return;
	}
	FPoint2 uvscale = desc->GetUVScale();

	// determine side-pointing vector
	vtArray<float> ExtraElevation(npoints);
	FLine3 sideways(npoints);
	for (j = 0; j < npoints; j++)
	{
		// determine side-pointing vector
		if (j == 0)
			sideways[j] = SidewaysVector(p3[j], p3[j+1]);
		else if (j > 0 && j < npoints-1)
		{
			AngleSideVector(p3[j-1], p3[j], p3[j+1], sideways[j]);
			sideways[j] = -sideways[j];	// We want a vector pointing left, not right
		}
		else if (j == npoints-1)
			sideways[j] = SidewaysVector(p3[j-1], p3[j]);

		ExtraElevation[j] = 0.0f;
		if (m_Params.m_bConstantTop)
			ExtraElevation[j] = m_fMaxGroundY - p3[j].y;
	}

	float u;
	float v1, v2;
	for (i = 0; i < prof_points-1; i++)
	{
		float y1, y2;
		float z1, z2;
		FPoint3 pos, normal;

		// determine v texture coordinate
		float seg_length = m_Profile.SegmentLength(i);
		if (uvscale.y == -1)
		{
			v1 = 0.0f;
			v2 = 1.0f;
		}
		else
		{
			if (i == 0)
			{
				v1 = 0.0f;
				v2 = seg_length / uvscale.y;
			}
			else
			{
				v1 = v2;
				v2 += seg_length / uvscale.y;
			}
		}

		// determine Y and Z values
		y1 = m_Profile[i].y;
		y2 = m_Profile[i+1].y;
		z1 = m_Profile[i].x;
		z2 = m_Profile[i+1].x;

		u = 0.0f;
		int start = pMesh->NumVertices();
		for (j = 0; j < npoints; j++)
		{
			// determine vertex normal (for shading)
			float diffy = y2-y1;
			float diffz = z2-z1;
			float dy = -diffz;
			float dz = diffy;

			FPoint3 n1, n2;
			n1.Set(0, y1, 0);
			n1 += (sideways[j] * z1);
			n2.Set(0, y1 + dy, 0);
			n2 += (sideways[j] * (z1 + dz));

			normal = n2 - n1;
			normal.Normalize();

			// determine the two points of this segment edge, and add them
			pos = p3[j];
			pos.y += y2;
			pos.y += ExtraElevation[j];
			pos += (sideways[j] * z2);
			pMesh->AddVertexNUV(pos, normal, FPoint2(u, v2));

			pos = p3[j];
			pos.y += y1;
			pos.y += ExtraElevation[j];
			pos += (sideways[j] * z1);
			pMesh->AddVertexNUV(pos, normal, FPoint2(u, v1));

			if (j < npoints-1)
			{
				// increment u based on the length of each fence segment
				float length_meters = (p3[j+1] - p3[j]).Length();
				u += (length_meters / uvscale.x);
			}
		}
		pMesh->AddStrip2(npoints * 2, start);
	}

	// We must assume the profile is interpreted as a closed polygon, which
	//  may not be convex.  Hence it must be triangulated.
	FLine2 result;
	Triangulate_f::Process(m_Profile, result);
	uint tcount = result.GetSize()/3;

	int ind[3];
	int line_point;
	FPoint3 normal;

	// add cap at beginning
	line_point = 0;
	normal = p3[0] - p3[1];
	normal.Normalize();
	for (i=0; i<tcount; i++)
	{
		for (j = 0; j < 3; j++)
		{
			FPoint2 p2 = result[i*3+j];

			FPoint3 pos = p3[line_point];
			pos.y += p2.y;
			pos.y += ExtraElevation[line_point];
			pos += (sideways[line_point] * p2.x);

			FPoint2 uv = p2;
			if (uvscale.y != -1)
				uv.Div(uvscale);	// divide meters by [meters/uv] to get uv

			ind[j] = pMesh->AddVertexNUV(pos, normal, uv);
		}
		pMesh->AddTri(ind[0], ind[1], ind[2]);
	}

	// add cap at end
	line_point = npoints-1;
	normal = p3[npoints-1] - p3[npoints-2];
	normal.Normalize();
	for (i=0; i<tcount; i++)
	{
		for (j = 0; j < 3; j++)
		{
			FPoint2 p2 = result[i*3+j];

			FPoint3 pos = p3[line_point];
			pos.y += p2.y;
			pos.y += ExtraElevation[line_point];
			pos += (sideways[line_point] * p2.x);

			FPoint2 uv = p2;
			if (uvscale.y != -1)
				uv.Div(uvscale);	// divide meters by [meters/uv] to get uv

			ind[j] = pMesh->AddVertexNUV(pos, normal, uv);
		}
		pMesh->AddTri(ind[0], ind[2], ind[1]);
	}

	m_pFenceGeom->AddMesh(pMesh, GetMatIndex(desc));
}