예제 #1
0
int NumAssociatedFaces(Grid& grid, Vertex* v)
{
    Grid::face_traits::secure_container faces;
    grid.associated_elements(faces, v);
    return (int)faces.size();
}
예제 #2
0
bool CollapseEdge(Grid& grid, Edge* e, Vertex* newVrt)
{
//	prepare the grid, so that we may perform Grid::replace_vertex.
//	create collapse geometries first and delete old geometries.
	Grid::face_traits::secure_container assFaces;
	if(grid.num_faces() > 0){
	//	collect adjacent faces
		grid.associated_elements(assFaces, e);

	//	a vector thats is used to store the collapse-geometries.
		vector<Face*> vNewFaces;

		for(uint i = 0; i < assFaces.size(); ++i)
		{

			Face* f = assFaces[i];
			int eInd = GetEdgeIndex(f, e);

		//	create the collapse-geometry
			f->collapse_edge(vNewFaces, eInd, newVrt);

		//	register the new faces
			for(uint j = 0; j < vNewFaces.size(); ++j)
				grid.register_element(vNewFaces[j], f);

		//	before we erase the face, we first have to notify whether
		//	edges were merged
			if(f->num_edges() == 3){
			//	two edges will be merged. we have to inform the grid.
				Vertex* conVrt = GetConnectedVertex(e, f);
			//	now get the edge between conVrt and newVrt
				Edge* target = grid.get_edge(conVrt, newVrt);
			//	now get the two old edges
				Edge* e1 = grid.get_edge(f, (eInd + 1) % 3);
				Edge* e2 = grid.get_edge(f, (eInd + 2) % 3);
				grid.objects_will_be_merged(target, e1, e2);
			}
		}
	}

	Grid::volume_traits::secure_container assVols;
	if(grid.num_volumes() > 0){
	//	used to identify merge-faces
		Grid::edge_traits::secure_container assEdges;

	//	collect adjacent volumes
		grid.associated_elements(assVols, e);

	//	a vector thats used to store the collapse-geometries.
		vector<Volume*> vNewVolumes;

		for(uint i = 0; i < assVols.size(); ++i)
		{
			Volume* v = assVols[i];
		//	create the collapse-geometry
			int eInd = GetEdgeIndex(v, e);
			v->collapse_edge(vNewVolumes, eInd, newVrt);

		//	register the new volumes
			for(uint j = 0; j < vNewVolumes.size(); ++j)
				grid.register_element(vNewVolumes[j], v);

		//	if v is a tetrahedron, two faces will be merged
			if(v->num_vertices() == 4){
			//	find the opposing edge of e
				Edge* oppEdge = NULL;
				grid.associated_elements(assEdges, v);
				for_each_in_vec(Edge* te, assEdges){
					if(!GetSharedVertex(e, te)){
						oppEdge = te;
						break;
					}
				}end_for;

				if(oppEdge){
					Face* f0 = grid.get_face(FaceDescriptor(
										e->vertex(0),
										oppEdge->vertex(0),
										oppEdge->vertex(1)));
					Face* f1 = grid.get_face(FaceDescriptor(
										e->vertex(1),
										oppEdge->vertex(0),
										oppEdge->vertex(1)));
					Face* fNew = grid.get_face(FaceDescriptor(
										newVrt,
										oppEdge->vertex(0),
										oppEdge->vertex(1)));
					if(f0 && f1 && fNew)
						grid.objects_will_be_merged(fNew, f0, f1);
				}
			}
		}
void AdaptiveRegularRefiner_MultiGrid::
create_closure_elements_2d()
{
//todo:	This method currently only works for one type of elements. No manifolds
//		are currently supported.

//	for each surface element (faces in 2d, volumes in 3d) adjacent to a constraining
//	element, we generate closure elements in the level above.

	if(!multi_grid()){
		UG_THROW("AdaptiveRegularRefiner_MultiGrid has to be associated with a grid!");
	}

//	remove all closure elements. This is currently required, since the selector
//	m_closureElems is currently also used to store non-closer elements, which are
//	to be refined.
	remove_closure_elements();

	MultiGrid& mg = *multi_grid();

//	iterate over all constraining edges and collect associated surface faces
//	Those then have to be refined to generate a closure.

	Grid::face_traits::secure_container	assElems;
	Grid::edge_traits::secure_container assEdges;
	Face::ConstVertexArray vrts;
	std::vector<Vertex*> newVrtVrts;
	std::vector<Vertex*> newEdgeVrts;
	std::vector<Face*>	newFaces;
	EdgeDescriptor ed;

//	we'll select all new elements on the fly
	m_closureElems.enable_autoselection(true);

	for(Grid::traits<ConstrainingEdge>::iterator i_edge = mg.begin<ConstrainingEdge>();
		i_edge != mg.end<ConstrainingEdge>(); ++i_edge)
	{
	//	check all associated elements of i_edge, whether one is a surface element.
	//	If so, create the closure.
		mg.associated_elements(assElems, *i_edge);

		for(size_t i_elem = 0; i_elem < assElems.size(); ++i_elem){
			Face* elem = assElems[i_elem];
			if(mg.has_children(elem))
				continue;

			newVrtVrts.clear();
			newEdgeVrts.clear();

		//	copy associated vertices and edges to the next level
			vrts = elem->vertices();
			size_t numVrts = elem->num_vertices();
			for(size_t i_vrt = 0; i_vrt < numVrts; ++i_vrt){
				Vertex* vrt = vrts[i_vrt];
				if(!mg.has_children(vrt)){
					newVrtVrts.push_back(*mg.create<RegularVertex>(vrt));
					if(m_refCallback)
						m_refCallback->new_vertex(newVrtVrts.back(), vrt);
				}
				else
					newVrtVrts.push_back(mg.get_child_vertex(vrt));
			}

			mg.associated_elements_sorted(assEdges, elem);
			for(size_t i = 0; i < assEdges.size(); ++i){
				Edge* e = assEdges[i];
				if(!mg.has_children(e)){
					ed.set_vertices(mg.get_child_vertex(e->vertex(0)),
									mg.get_child_vertex(e->vertex(1)));
					mg.create<RegularEdge>(ed, e);
					newEdgeVrts.push_back(NULL);
				}
				else
					newEdgeVrts.push_back(mg.get_child_vertex(e));
			}

		//	refine the element
			Vertex* newFaceVrt;
			if(elem->refine(newFaces, &newFaceVrt, &newEdgeVrts.front(),
							NULL, &newVrtVrts.front()))
			{
				if(newFaceVrt){
					mg.register_element(newFaceVrt, elem);
					if(m_refCallback)
						m_refCallback->new_vertex(newFaceVrt, elem);
				}
				for(size_t i = 0; i < newFaces.size(); ++i)
					mg.register_element(newFaces[i], elem);
			}
		}
	}

//	stop selecting new elements
	m_closureElems.enable_autoselection(false);
}
void AdaptiveRegularRefiner_MultiGrid::
create_closure_elements_3d()
{
//todo:	This method currently only works for one type of elements. No manifolds
//		are currently supported.

//	for each surface element (faces in 2d, volumes in 3d) adjacent to a constraining
//	element, we generate closure elements in the level above.

	if(!multi_grid()){
		UG_THROW("AdaptiveRegularRefiner_MultiGrid has to be associated with a grid!");
	}

//	remove all closure elements. This is currently required, since the selector
//	m_closureElems is currently also used to store non-closer elements, which are
//	to be refined.
	remove_closure_elements();

	MultiGrid& mg = *multi_grid();

//	iterate over all constraining edges and collect associated surface faces / volumes.
//	Those then have to be refined to generate a closure.

	Grid::volume_traits::secure_container	assElems;
	Grid::edge_traits::secure_container assEdges;
	Grid::face_traits::secure_container assFaces;
	Volume::ConstVertexArray vrts;
	std::vector<Vertex*> newVolVrtVrts;
	std::vector<Vertex*> newVolEdgeVrts;
	std::vector<Vertex*> newVolFaceVrts;
	std::vector<Volume*> newVols;
	EdgeDescriptor ed;
	FaceDescriptor fd;
	
//	when refining the associated faces, we need some structs, too
	Grid::edge_traits::secure_container assFaceEdges;
	std::vector<Vertex*> newFaceVrtVrts;
	std::vector<Vertex*> newFaceEdgeVrts;
	std::vector<Face*> newFaces;

//	we'll select all new elements on the fly
	m_closureElems.enable_autoselection(true);

	for(Grid::traits<ConstrainingEdge>::iterator i_edge = mg.begin<ConstrainingEdge>();
		i_edge != mg.end<ConstrainingEdge>(); ++i_edge)
	{
	//	check all associated elements of i_edge, whether one is a surface element.
	//	If so, select it into m_closureElems. This is only temporary, since it
	//	isn't a real closure element.
		mg.associated_elements(assElems, *i_edge);

		for(size_t i_elem = 0; i_elem < assElems.size(); ++i_elem){
			Volume* elem = assElems[i_elem];
			if(mg.has_children(elem))
				continue;

			newVolVrtVrts.clear();
			newVolEdgeVrts.clear();
			newVolFaceVrts.clear();

		//	copy associated vertices and edges to the next level
			vrts = elem->vertices();
			size_t numVrts = elem->num_vertices();
			for(size_t i_vrt = 0; i_vrt < numVrts; ++i_vrt){
				Vertex* vrt = vrts[i_vrt];
				if(!mg.has_children(vrt)){
					newVolVrtVrts.push_back(*mg.create<RegularVertex>(vrt));
					if(m_refCallback)
						m_refCallback->new_vertex(newVolVrtVrts.back(), vrt);
				}
				else
					newVolVrtVrts.push_back(mg.get_child_vertex(vrt));
			}

			mg.associated_elements_sorted(assEdges, elem);
			for(size_t i = 0; i < assEdges.size(); ++i){
				Edge* e = assEdges[i];
				if(!mg.has_children(e)){
					ed.set_vertices(mg.get_child_vertex(e->vertex(0)),
									mg.get_child_vertex(e->vertex(1)));
					mg.create<RegularEdge>(ed, e);
					newVolEdgeVrts.push_back(NULL);
				}
				else
					newVolEdgeVrts.push_back(mg.get_child_vertex(e));
			}

		//	we have to either refine or copy associated faces
			mg.associated_elements_sorted(assFaces, elem);
			for(size_t i_face = 0; i_face < assFaces.size(); ++i_face){
				
				Face* f = assFaces[i_face];
				if(mg.has_children(f)){
					newVolFaceVrts.push_back(mg.get_child_vertex(f));
					continue;
				}
				
			//	collect child vertices of associated edges
				mg.associated_elements_sorted(assFaceEdges, f);
				newFaceEdgeVrts.clear();
				
				bool faceRefinement = false;
				for(size_t i = 0; i < assFaceEdges.size(); ++i){
					Vertex* child = mg.get_child_vertex(assFaceEdges[i]);
					newFaceEdgeVrts.push_back(child);
					faceRefinement |= (child != NULL);
				}				
				
				if(faceRefinement){
					newFaceVrtVrts.clear();
					for(size_t i = 0; i < f->num_vertices(); ++i)
						newFaceVrtVrts.push_back(mg.get_child_vertex(f->vertex(i)));
					
					Vertex* newFaceVrt = NULL;
					if(f->refine(newFaces, &newFaceVrt, &newFaceEdgeVrts.front(),
								 NULL, &newFaceVrtVrts.front()))
					{
						if(newFaceVrt){
							mg.register_element(newFaceVrt, f);
							if(m_refCallback)
								m_refCallback->new_vertex(newFaceVrt, f);
						}
						for(size_t i = 0; i < newFaces.size(); ++i)
							mg.register_element(newFaces[i], f);
					}
					newVolFaceVrts.push_back(newFaceVrt);
				}	
				else{
					Face::ConstVertexArray fvrts = f->vertices();
					if(f->num_vertices() == 3)
						mg.create<Triangle>(TriangleDescriptor(
												mg.get_child_vertex(fvrts[0]),
												mg.get_child_vertex(fvrts[1]),
												mg.get_child_vertex(fvrts[2])),
											f);
					else if(f->num_vertices() == 4)
						mg.create<Quadrilateral>(QuadrilateralDescriptor(
													mg.get_child_vertex(fvrts[0]),
													mg.get_child_vertex(fvrts[1]),
													mg.get_child_vertex(fvrts[2]),
													mg.get_child_vertex(fvrts[3])),
												f);
					newVolFaceVrts.push_back(NULL);
				}
			}

		//	refine the element
		//	if we're performing tetrahedral refinement, we have to collect
		//	the corner coordinates, so that the refinement algorithm may choose
		//	the best interior diagonal.
			vector3 corners[4];
			vector3* pCorners = NULL;
			if((elem->num_vertices() == 4) && m_refCallback){
				for(size_t i = 0; i < 4; ++i){
					m_refCallback->current_pos(&corners[i].x(), vrts[i], 3);
				}
				pCorners = corners;
			}

			Vertex* newVolVrt;
			if(elem->refine(newVols, &newVolVrt, &newVolEdgeVrts.front(),
							&newVolFaceVrts.front(), NULL, RegularVertex(),
							&newVolVrtVrts.front(), pCorners))
			{
				if(newVolVrt){
					mg.register_element(newVolVrt, elem);
					if(m_refCallback)
						m_refCallback->new_vertex(newVolVrt, elem);
				}

				for(size_t i = 0; i < newVols.size(); ++i)
					mg.register_element(newVols[i], elem);
			}
		}
	}

//	stop selecting new elements
	m_closureElems.enable_autoselection(false);
}
예제 #5
0
bool AdaptSurfaceGridToCylinder(Selector& selOut, Grid& grid,
                                Vertex* vrtCenter, const vector3& normal,
                                number radius, number rimSnapThreshold,  AInt& aInt,
                                APosition& aPos)
{
    if(!grid.has_vertex_attachment(aPos)) {
        UG_THROW("Position attachment required!");
    }

    Grid::VertexAttachmentAccessor<APosition> aaPos(grid, aPos);

    if(rimSnapThreshold < 0)
        rimSnapThreshold = 0;

    if(rimSnapThreshold > (radius - SMALL))
        rimSnapThreshold = radius - SMALL;

    const number smallRadius = radius - rimSnapThreshold;
    const number smallRadiusSq = smallRadius * smallRadius;
    const number largeRadius = radius + rimSnapThreshold;
    const number largeRadiusSq = largeRadius * largeRadius;

//	the cylinder geometry
    vector3 axis;
    VecNormalize(axis, normal);
    vector3 center = aaPos[vrtCenter];

//	recursively select all vertices in the cylinder which can be reached from a
//	selected vertex by following an edge. Start with the given one.
//	We'll also select edges which connect inner with outer vertices. Note that
//	some vertices are considered rim-vertices (those with a distance between
//	smallRadius and largeRadius). Those are neither considered inner nor outer.
    Selector& sel = selOut;
    sel.clear();
    sel.select(vrtCenter);

    stack<Vertex*> vrtStack;
    vrtStack.push(vrtCenter);

    Grid::edge_traits::secure_container edges;
    Grid::face_traits::secure_container faces;
    vector<Quadrilateral*> quads;

    while(!vrtStack.empty()) {
        Vertex* curVrt = vrtStack.top();
        vrtStack.pop();

        //	we have to convert associated quadrilaterals to triangles.
        //	Be careful not to alter the array of associated elements while we iterate
        //	over it...
        quads.clear();
        grid.associated_elements(faces, curVrt);
        for(size_t i = 0; i < faces.size(); ++i) {
            if(faces[i]->num_vertices() == 4) {
                Quadrilateral* q = dynamic_cast<Quadrilateral*>(faces[i]);
                if(q)
                    quads.push_back(q);
            }
        }

        for(size_t i = 0; i < quads.size(); ++i) {
            Triangulate(grid, quads[i], &aaPos);
        }

        //	now check whether edges leave the cylinder and mark them accordingly.
        //	Perform projection of vertices to the cylinder rim for vertices which
        //	lie in the threshold area.
        grid.associated_elements(edges, curVrt);

        for(size_t i_edge = 0; i_edge < edges.size(); ++i_edge) {
            Edge* e = edges[i_edge];
            Vertex* vrt = GetConnectedVertex(e, curVrt);

            if(sel.is_selected(vrt))
                continue;

            vector3 p = aaPos[vrt];
            vector3 proj;
            ProjectPointToRay(proj, p, center, axis);
            number distSq = VecDistanceSq(p, proj);

            if(distSq < smallRadiusSq) {
                sel.select(vrt);
                vrtStack.push(vrt);
            }
            else if(distSq < largeRadiusSq) {
                sel.select(vrt);
                //	cut the ray from center through p with the cylinder hull to calculate
                //	the new position of vrt.
                vector3 dir;
                VecSubtract(dir, p, center);
                number t0, t1;
                if(RayCylinderIntersection(t0, t1, center, dir, center, axis, radius))
                    VecScaleAdd(aaPos[vrt], 1., center, t1, dir);
            }
            else {
                //	the edge will be refined later on
                sel.select(e);
            }
        }
    }

//	refine selected edges and use a special refinement callback, which places
//	new vertices on edges which intersect a cylinder on the cylinders hull.
    CylinderCutProjector refCallback(MakeGeometry3d(grid, aPos),
                                     center, axis, radius);
    Refine(grid, sel, aInt, &refCallback);

//	finally select all triangles which lie in the cylinder
    sel.clear();
    vrtStack.push(vrtCenter);
    sel.select(vrtCenter);

    while(!vrtStack.empty()) {
        Vertex* curVrt = vrtStack.top();
        vrtStack.pop();
        grid.associated_elements(faces, curVrt);

        for(size_t i_face = 0; i_face < faces.size(); ++i_face) {
            Face* f = faces[i_face];
            if(sel.is_selected(f))
                continue;

            sel.select(f);

            for(size_t i = 0; i < f->num_vertices(); ++i) {
                Vertex* vrt = f->vertex(i);
                if(!sel.is_selected(vrt)) {
                    number dist = DistancePointToRay(aaPos[vrt], center, axis);
                    if(dist < (radius - SMALL)) {
                        sel.select(vrt);
                        vrtStack.push(vrt);
                    }
                }
            }
        }
    }

    sel.clear<Vertex>();

    return true;
}