commit
						f14838a475
					
				 19 changed files with 4399 additions and 0 deletions
			
			
		@ -0,0 +1,42 @@ | 
				
			|||
cmake_minimum_required (VERSION 3.2.0) | 
				
			|||
 | 
				
			|||
# Project name | 
				
			|||
project (OCCTMeshless CXX) | 
				
			|||
 | 
				
			|||
list(APPEND CMAKE_PREFIX_PATH "F:/OCC/demo/opencascade-install" ) | 
				
			|||
 | 
				
			|||
# Enable C++17 | 
				
			|||
set(CMAKE_CXX_STANDARD 17) | 
				
			|||
set(CMAKE_CXX_STANDARD_REQUIRED ON) | 
				
			|||
set(CMAKE_CXX_EXTENSIONS OFF) | 
				
			|||
 | 
				
			|||
# OpenCascade | 
				
			|||
find_package(OpenCASCADE REQUIRED) | 
				
			|||
 | 
				
			|||
# Eigen3 | 
				
			|||
set(EIGEN3_INCLUDE_DIR "F:/eigen-3.4.0") | 
				
			|||
 | 
				
			|||
# Configure C++ compiler's includes dir | 
				
			|||
include_directories (SYSTEM ${OpenCASCADE_INCLUDE_DIR} ) | 
				
			|||
include_directories(${EIGEN3_INCLUDE_DIR}) | 
				
			|||
include_directories(${PROJECT_SOURCE_DIR}/include) | 
				
			|||
 | 
				
			|||
 | 
				
			|||
file(GLOB HEADER_FILES "include/*.h*") | 
				
			|||
file(GLOB SRC_FILES "src/*.cpp") | 
				
			|||
source_group("include" FILES HEADER_FILES) | 
				
			|||
 | 
				
			|||
# Add executable | 
				
			|||
add_executable (${PROJECT_NAME} | 
				
			|||
   ${SRC_FILES} | 
				
			|||
  ${HEADER_FILES} | 
				
			|||
) | 
				
			|||
 | 
				
			|||
# Add linker options | 
				
			|||
foreach (LIB ${OpenCASCADE_LIBRARIES}) | 
				
			|||
  target_link_libraries(${PROJECT_NAME} PUBLIC ${OpenCASCADE_LIBRARY_DIR}/${LIB}.lib) | 
				
			|||
  target_link_libraries(${PROJECT_NAME} PUBLIC ${OpenCASCADE_LIBRARY_DIR}d/${LIB}.lib) | 
				
			|||
endforeach() | 
				
			|||
 | 
				
			|||
# Adjust runtime environment | 
				
			|||
set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DEBUGGER_ENVIRONMENT "PATH=$<$<CONFIG:DEBUG>:${OpenCASCADE_BINARY_DIR}d>$<$<NOT:$<CONFIG:DEBUG>>:${OpenCASCADE_BINARY_DIR}>;%PATH%") | 
				
			|||
@ -0,0 +1,96 @@ | 
				
			|||
#pragma once | 
				
			|||
#include "assert.hpp" | 
				
			|||
#include "DomainDiscretization_fwd.hpp" | 
				
			|||
 | 
				
			|||
namespace meshless { | 
				
			|||
	template<typename vec> | 
				
			|||
	const vec& DomainDiscretization<vec>::normal(int i) const { | 
				
			|||
		assert_msg(0 <= i && i <= size(), "Index %d out of range [0, %d)", i, size()); | 
				
			|||
		assert_msg(types_[i] < 0, "Node %d must be a boundary node, got type %d.", i, types_[i]); | 
				
			|||
		assert_msg(boundaryMap_[i] != -1, "Node %d does not have a normal. Maybe you manually set" | 
				
			|||
			" supports and positions instead of using addInternalNode* methods?", | 
				
			|||
			i); | 
				
			|||
		return normals_[boundaryMap_[i]]; | 
				
			|||
 | 
				
			|||
	} | 
				
			|||
	template<typename vec> | 
				
			|||
	vec& DomainDiscretization<vec>::normal(int i) { | 
				
			|||
		assert_msg(0 <= i && i <= size(), "Index %d out of range [0, %d)", i, size()); | 
				
			|||
		assert_msg(types_[i] < 0, "Node %d must be a boundary node, got type %d.", i, types_[i]); | 
				
			|||
		assert_msg(boundaryMap_[i] != -1, "Node %d does not have a normal. Maybe you manually set" | 
				
			|||
			" supports and positions instead of using addInternalNode* methods?", | 
				
			|||
			i); | 
				
			|||
		return normals_[boundaryMap_[i]]; | 
				
			|||
 | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	template<typename vec> | 
				
			|||
	int DomainDiscretization<vec>::addInternalNode(const vec& point, int type) { | 
				
			|||
 | 
				
			|||
		assert_msg(type > 0, "This function is for adding internal points, but got type %d, which is " | 
				
			|||
			"not positive. Use addBoundaryNode to add boundary nodes.", | 
				
			|||
			type); | 
				
			|||
		return addNode(point, type); | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	template<typename vec> | 
				
			|||
	int DomainDiscretization<vec>::addInternalNodeWithT(const vec& point, double t, int type) { | 
				
			|||
 | 
				
			|||
		assert_msg(type > 0, "This function is for adding internal points, but got type %d, which is " | 
				
			|||
			"not positive. Use addBoundaryNode to add boundary nodes.", | 
				
			|||
			type); | 
				
			|||
		return addNodeWithT(point, t, type); | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	/**
 | 
				
			|||
	 * Adds a boundary node with given type and normal to the domain. | 
				
			|||
	 * @param point Coordinates of the node to add. | 
				
			|||
	 * @param type Type of the point, must be negative. | 
				
			|||
	 * @param normal Outside unit normal to the boundary at point `point`. | 
				
			|||
	 * @return The index of the new node. | 
				
			|||
	 * @sa addInternalNode | 
				
			|||
	 */ | 
				
			|||
	template<typename vec> | 
				
			|||
	int DomainDiscretization<vec>::addBoundaryNode(const vec& point, int type, const vec& normal) { | 
				
			|||
		assert_msg(type < 0, "Type of boundary points must be negative, got %d.", type); | 
				
			|||
		int idx = addNode(point, type); | 
				
			|||
		boundaryMap_[idx] = normals_.size(); | 
				
			|||
		normals_.push_back(normal); | 
				
			|||
		return idx; | 
				
			|||
 | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	template<typename vec> | 
				
			|||
	int DomainDiscretization<vec>::addBoundaryNodeWithT(const vec& point, double t, int type, const vec& normal) { | 
				
			|||
		assert_msg(type < 0, "Type of boundary points must be negative, got %d.", type); | 
				
			|||
		int idx = addNodeWithT(point, t, type); | 
				
			|||
		boundaryMap_[idx] = normals_.size(); | 
				
			|||
		normals_.push_back(normal); | 
				
			|||
		return idx; | 
				
			|||
 | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	template<typename vec> | 
				
			|||
	int DomainDiscretization<vec>::addNode(const vec& point, int type) { | 
				
			|||
		positions_.push_back(point); | 
				
			|||
		types_.push_back(type); | 
				
			|||
		support_.emplace_back(); | 
				
			|||
		boundaryMap_.push_back(-1); | 
				
			|||
		return positions_.size() - 1; | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	template<typename vec> | 
				
			|||
	int DomainDiscretization<vec>::addNodeWithT(const vec& point, double t, int type) { | 
				
			|||
		positions_.push_back(point); | 
				
			|||
		inCurve_.push_back(t); | 
				
			|||
		types_.push_back(type); | 
				
			|||
		support_.emplace_back(); | 
				
			|||
		boundaryMap_.push_back(-1); | 
				
			|||
		return positions_.size() - 1; | 
				
			|||
	} | 
				
			|||
	//bool DomainDiscretization::contains(const vec& point)const;
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
}; | 
				
			|||
@ -0,0 +1,197 @@ | 
				
			|||
#pragma once | 
				
			|||
#include <vector> | 
				
			|||
#include <Eigen/Core> | 
				
			|||
#include "OccShape.hpp" | 
				
			|||
 | 
				
			|||
namespace  meshless { | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
	template<typename vec> | 
				
			|||
	class DomainDiscretization { | 
				
			|||
	protected: | 
				
			|||
		std::vector<vec> positions_; | 
				
			|||
		std::vector<int> types_; | 
				
			|||
		std::vector<std::vector<int>> support_; | 
				
			|||
		std::vector<int> boundaryMap_; | 
				
			|||
		std::vector<vec> normals_; | 
				
			|||
		OccShape shape_; | 
				
			|||
		std::vector<double> inCurve_; | 
				
			|||
 | 
				
			|||
	public: | 
				
			|||
		DomainDiscretization() {} | 
				
			|||
		DomainDiscretization(const OccShape& shape) { | 
				
			|||
			shape_.max_points = shape.max_points; | 
				
			|||
			shape_.seed_ = shape.seed_; | 
				
			|||
			shape_.n_samples = shape.n_samples; | 
				
			|||
			shape_.zeta = shape.zeta; | 
				
			|||
			shape_.myShape = shape.myShape; | 
				
			|||
 | 
				
			|||
		} | 
				
			|||
		const double getT(int i)const { | 
				
			|||
			return inCurve_[i]; | 
				
			|||
		} | 
				
			|||
		const std::vector<vec>& positions()const { | 
				
			|||
			return positions_; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		const vec& pos(int i)const { | 
				
			|||
			return positions_[i]; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		vec& pos(int i) { | 
				
			|||
			return positions_[i]; | 
				
			|||
		} | 
				
			|||
		double pos(int i, int j) const { | 
				
			|||
			return positions_[i][j]; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		const std::vector<std::vector<int> >& supports()const { | 
				
			|||
			return support_; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		const std::vector<int>& support(int i)const { | 
				
			|||
			return support_[i]; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		std::vector<int>& support(int i) { | 
				
			|||
			return support_[i]; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		int support(int i, int j) const { | 
				
			|||
			return support_[i][j]; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		std::vector<vec> supportNodes(int i) const { | 
				
			|||
			auto sp = support_[i]; | 
				
			|||
			std::vector<vec> retsP; | 
				
			|||
			for(auto it : sp) { | 
				
			|||
				retsP.push_back(positions_[it]); | 
				
			|||
 | 
				
			|||
			} | 
				
			|||
			return retsP; | 
				
			|||
		} | 
				
			|||
		/// Returns position of `j`-th support node of `i`-th node.
 | 
				
			|||
		vec supportNode(int i, int j) const { | 
				
			|||
			return positions_[support_[i][j]]; | 
				
			|||
		} | 
				
			|||
		/// Returns Euclidean distance to the second support node.
 | 
				
			|||
		double dr(int i) const { | 
				
			|||
			return (positions_[i] - positions_[support_[i][1]]).norm(); | 
				
			|||
		} | 
				
			|||
		/// Returns size of `i`-th node support.
 | 
				
			|||
		int supportSize(int i) const { | 
				
			|||
			return support_[i].size(); | 
				
			|||
		} | 
				
			|||
		/// Returns a vector of support sizes for each node.
 | 
				
			|||
		//std::vector<int> supportSizes() const;
 | 
				
			|||
 | 
				
			|||
		/// Returns types of all nodes.
 | 
				
			|||
		const std::vector<int>& types() const { | 
				
			|||
			return types_; | 
				
			|||
		} | 
				
			|||
		/// Returns mutable types of all nodes.
 | 
				
			|||
		std::vector<int>& types() { | 
				
			|||
			return types_; | 
				
			|||
		} | 
				
			|||
		/// Returns type of `i`-th node.
 | 
				
			|||
		int type(int i) const { | 
				
			|||
			return types_[i]; | 
				
			|||
		} | 
				
			|||
		/// Returns writeable type of `i`-th node.
 | 
				
			|||
		int& type(int i) { | 
				
			|||
			return types_[i]; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
		/// Returns boundary map. @sa boundary_map_
 | 
				
			|||
		const std::vector<int>& bmap() const { | 
				
			|||
			return boundaryMap_; | 
				
			|||
		} | 
				
			|||
		/**
 | 
				
			|||
		 * Returns index of node `node` among only boundary nodes. The returned index is | 
				
			|||
		 * in range `[0, boundary().size())` if `node` is a boundary node, and `-1` otherwise. | 
				
			|||
		 */ | 
				
			|||
		int bmap(int node) const { | 
				
			|||
			return boundaryMap_[node]; | 
				
			|||
		} | 
				
			|||
		/// Returns normals of all boundary nodes.
 | 
				
			|||
		const std::vector<vec>& normals() const { | 
				
			|||
			return normals_; | 
				
			|||
		} | 
				
			|||
		/**
 | 
				
			|||
		 * Returns outside unit normal of `i`-th node. The node must be a boundary node. | 
				
			|||
		 * @throw Assertion fails if the noe is not a boundary node, i.e.\ `type(i) < 0` must hold. | 
				
			|||
		 */ | 
				
			|||
		const vec& normal(int i) const; | 
				
			|||
		/// Returns writable outside unit normal of `i`-th node. @sa normal
 | 
				
			|||
		vec& normal(int i); | 
				
			|||
 | 
				
			|||
		/// Returns indexes of all boundary nodes.
 | 
				
			|||
		std::vector<int> boundary() const { | 
				
			|||
			std::vector<int> ret; | 
				
			|||
			for(int i = 0; i < types_.size(); i++) { | 
				
			|||
				if(types_[i] < 0) { | 
				
			|||
					ret.push_back(i); | 
				
			|||
				} | 
				
			|||
			} | 
				
			|||
			return ret; | 
				
			|||
		} | 
				
			|||
		/// Returns indexes of all internal nodes.
 | 
				
			|||
		std::vector<int> interior() const { | 
				
			|||
			std::vector<int> ret; | 
				
			|||
			for(int i = 0; i < types_.size(); i++) { | 
				
			|||
				if(types_[i] > 0) { | 
				
			|||
					ret.push_back(i); | 
				
			|||
				} | 
				
			|||
			} | 
				
			|||
			return ret; | 
				
			|||
		} | 
				
			|||
		/// Returns indexes of all nodes, i.e.\ `{0, 1, ..., N-1}`.
 | 
				
			|||
		std::vector<int> all() const { | 
				
			|||
			std::vector<int> ret; | 
				
			|||
			for(int i = 0; i < types_.size(); i++) { | 
				
			|||
				if(types_[i] != 0) { | 
				
			|||
					ret.push_back(i); | 
				
			|||
				} | 
				
			|||
			} | 
				
			|||
			return ret; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		/// Returns `N`, the number of nodes in this discretization.
 | 
				
			|||
		int size() const { | 
				
			|||
			return positions_.size(); | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		/**
 | 
				
			|||
		 * Adds a single interior node with specified type to this discretization. | 
				
			|||
		 * @param point Coordinates of the node to add. | 
				
			|||
		 * @param type Type of the node to add. Must be positive. | 
				
			|||
		 * @return The index of the new node. | 
				
			|||
		 * @sa addBoundaryNode | 
				
			|||
		 */ | 
				
			|||
		int addInternalNode(const vec& point, int type); | 
				
			|||
 | 
				
			|||
		/**
 | 
				
			|||
		 * Adds a boundary node with given type and normal to the domain. | 
				
			|||
		 * @param point Coordinates of the node to add. | 
				
			|||
		 * @param type Type of the point, must be negative. | 
				
			|||
		 * @param normal Outside unit normal to the boundary at point `point`. | 
				
			|||
		 * @return The index of the new node. | 
				
			|||
		 * @sa addInternalNode | 
				
			|||
		 */ | 
				
			|||
		int addBoundaryNode(const vec& point, int type, const vec& normal); | 
				
			|||
 | 
				
			|||
		int addBoundaryNodeWithT(const vec& point, double t, int type, const vec& normal); | 
				
			|||
		int addInternalNodeWithT(const vec& point, double t, int type); | 
				
			|||
	private: | 
				
			|||
		int addNode(const vec& point, int type); | 
				
			|||
		int addNodeWithT(const vec& point, double t, int type); | 
				
			|||
 | 
				
			|||
	public: | 
				
			|||
		//bool discreteContains(const vec& point, )const;
 | 
				
			|||
	}; | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
}; | 
				
			|||
@ -0,0 +1,193 @@ | 
				
			|||
#pragma once | 
				
			|||
#include "FillBoundary_fwd.hpp" | 
				
			|||
#include "KDTree.hpp" | 
				
			|||
#include "KDTreeMutable.hpp" | 
				
			|||
#include <iomanip> | 
				
			|||
#include <random> | 
				
			|||
#include <map> | 
				
			|||
 | 
				
			|||
namespace meshless { | 
				
			|||
 | 
				
			|||
	DomainDiscretization<Eigen::Vector3d> discretizeBoundaryWithDensity(const OccShape& shape, const std::function<double(Eigen::Vector3d)>& h, int type) { | 
				
			|||
		if(type == 0)type = -1; | 
				
			|||
		std::mt19937 gen(shape.seed_); | 
				
			|||
		DomainDiscretization<Eigen::Vector3d> domainGlobal(shape); | 
				
			|||
		KDTreeMutable treeGlobal; | 
				
			|||
		TopExp_Explorer expFace(shape.myShape, TopAbs_FACE); | 
				
			|||
		int numFace = 0; | 
				
			|||
 | 
				
			|||
		std::cout.precision(10); | 
				
			|||
 | 
				
			|||
		for(; expFace.More(); expFace.Next()) { | 
				
			|||
			std::cout << "正在离散化第" << ++numFace << "张曲面" << std::endl; | 
				
			|||
			//if(numFace != 5)continue;
 | 
				
			|||
			bool reverseNormal = false; | 
				
			|||
			const TopoDS_Face& face = TopoDS::Face(expFace.Current()); | 
				
			|||
			Handle(Geom_Surface) geomSurface = BRep_Tool::Surface(face); | 
				
			|||
			if(face.Orientable() == TopAbs_REVERSED) { | 
				
			|||
				std::cout << "该面法线需反向\n"; | 
				
			|||
				reverseNormal = true; | 
				
			|||
			} | 
				
			|||
 | 
				
			|||
			//开始离散化每个wire
 | 
				
			|||
			auto outerWire = BRepTools::OuterWire(face); | 
				
			|||
			int numWire = 0; | 
				
			|||
			TopExp_Explorer expWire(face, TopAbs_WIRE); | 
				
			|||
			for(; expWire.More(); expWire.Next()) { | 
				
			|||
				std::cout << "正在离散化第" << ++numWire << "个Wire" << std::endl; | 
				
			|||
				const TopoDS_Wire& wire = TopoDS::Wire(expWire.Current()); | 
				
			|||
				if(wire == outerWire) { | 
				
			|||
					std::cout << "此wire为外环\n"; | 
				
			|||
				} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
				DomainDiscretization<Eigen::Vector2d> domainParamLocalPatch(shape); | 
				
			|||
 | 
				
			|||
				TopExp_Explorer expEdge(wire, TopAbs_EDGE); | 
				
			|||
				int numEdge = 0; | 
				
			|||
				int genPoints = 0; | 
				
			|||
				for(; expEdge.More(); expEdge.Next()) { | 
				
			|||
 | 
				
			|||
					std::cout << "正在离散化第" << ++numEdge << "条Edge" << std::endl; | 
				
			|||
					//if(numEdge != 5)continue;
 | 
				
			|||
					const TopoDS_Edge& edge = TopoDS::Edge(expEdge.Current()); | 
				
			|||
 | 
				
			|||
					KDTreeMutable treeLocal; | 
				
			|||
					Standard_Real firstParam, lastParam; | 
				
			|||
					Handle(Geom_Curve) geomCurve = BRep_Tool::Curve(edge, firstParam, lastParam); | 
				
			|||
					//std::cout << "param: " << firstParam << " -> " << lastParam << '\n';
 | 
				
			|||
 | 
				
			|||
					//曲线参数点在曲面参数域上的坐标
 | 
				
			|||
					Standard_Real pCurveFirstParam, pCurveLastParam; | 
				
			|||
					Handle(Geom2d_Curve) geomPCurve = BRep_Tool::CurveOnSurface(edge, face, pCurveFirstParam, pCurveLastParam); | 
				
			|||
					Handle(Geom2d_TrimmedCurve) geomTrimmedCurve = new Geom2d_TrimmedCurve(geomPCurve, pCurveFirstParam, pCurveLastParam); | 
				
			|||
 | 
				
			|||
					//GeomTools::Dump(geomCurve, std::cout);
 | 
				
			|||
					//std::cout << "In param Pcurve:\n";
 | 
				
			|||
					//GeomTools::Dump(geomPCurve, std::cout);
 | 
				
			|||
					std::cout << "GeomPcurve P:" << pCurveFirstParam << ',' << pCurveLastParam << '\n'; | 
				
			|||
 | 
				
			|||
					std::uniform_real_distribution<> dis(pCurveFirstParam, pCurveLastParam); | 
				
			|||
					//曲线参数点
 | 
				
			|||
					double tSeedInParam = dis(gen); | 
				
			|||
					gp_Pnt2d tSeedInPCurve; | 
				
			|||
					geomPCurve->D0(tSeedInParam, tSeedInPCurve); | 
				
			|||
 | 
				
			|||
 | 
				
			|||
					//std::cout << "t in param: " << tSeedInParam << "\n";
 | 
				
			|||
					//std::cout << "t in PCurve: " << tSeedInPCurve.Coord().X() << "," << tSeedInPCurve.Coord().Y() << "\n";
 | 
				
			|||
 | 
				
			|||
					//!这里两种计算方法得到的结果不一致,第一种更准确
 | 
				
			|||
					gp_Pnt tSeedInCurve; | 
				
			|||
					geomCurve->D0(tSeedInParam, tSeedInCurve); | 
				
			|||
					gp_Pnt tSeedInSurf; | 
				
			|||
					geomSurface->D0(tSeedInPCurve.X(), tSeedInPCurve.Y(), tSeedInSurf); | 
				
			|||
					//! Tip: use GeomLib::NormEstim() to calculate surface normal at specified (U, V) point.
 | 
				
			|||
 | 
				
			|||
					std::cout << "t in Surface:#1 " << tSeedInCurve.Coord().X() << "," << tSeedInCurve.Coord().Y() << "," << tSeedInCurve.Coord().Z() << "\n"; | 
				
			|||
					std::cout << "t in Surface:#2 " << tSeedInSurf.Coord().X() << "," << tSeedInSurf.Coord().Y() << "," << tSeedInSurf.Coord().Z() << "\n"; | 
				
			|||
 | 
				
			|||
					Eigen::Vector3d eigenSeedPnt(tSeedInCurve.X(), tSeedInCurve.Y(), tSeedInCurve.Z()); | 
				
			|||
					Eigen::Vector2d eigenSeedPntParam(tSeedInPCurve.X(), tSeedInPCurve.Y()); | 
				
			|||
					domainParamLocalPatch.addInternalNodeWithT(transPnt2d(tSeedInPCurve), tSeedInParam, 1); | 
				
			|||
					treeLocal.insert(transPnt(tSeedInCurve)); | 
				
			|||
 | 
				
			|||
 | 
				
			|||
					//Insert into global structures.
 | 
				
			|||
					double checkRadiusSeed = h(eigenSeedPnt); | 
				
			|||
 | 
				
			|||
					double d_sq = treeGlobal.size() == 0 ? 10 * checkRadiusSeed * checkRadiusSeed : treeGlobal.query(eigenSeedPnt).second[0]; | 
				
			|||
					if(d_sq >= (shape.zeta * checkRadiusSeed) * (shape.zeta * checkRadiusSeed)) { | 
				
			|||
						//domainGlobal.addBoundaryNode(eigenSeedPnt, -1);
 | 
				
			|||
						gp_Dir tSeedNormal; | 
				
			|||
						auto retStatus = GeomLib::NormEstim(geomSurface, tSeedInPCurve, 1e-6, tSeedNormal); | 
				
			|||
						if(retStatus >= 2) { | 
				
			|||
							std::cout << "calculate wrong!\n"; | 
				
			|||
							exit(-1); | 
				
			|||
						} | 
				
			|||
						if(reverseNormal) tSeedNormal = -tSeedNormal; | 
				
			|||
						Eigen::Vector3d eigenNormal(tSeedNormal.X(), tSeedNormal.Y(), tSeedNormal.Z()); | 
				
			|||
						domainGlobal.addBoundaryNode(eigenSeedPnt, type, eigenNormal); | 
				
			|||
						treeGlobal.insert(eigenSeedPnt); | 
				
			|||
					} | 
				
			|||
 | 
				
			|||
					int curNode = domainParamLocalPatch.size() - 1; | 
				
			|||
					int endNode = domainParamLocalPatch.size(); | 
				
			|||
					while(curNode < endNode && endNode < shape.max_points) { | 
				
			|||
						genPoints++; | 
				
			|||
						//std::cout << "curNode / endNode : " << curNode << '/' << endNode << '\n';
 | 
				
			|||
						auto param = domainParamLocalPatch.pos(curNode); | 
				
			|||
						double t = domainParamLocalPatch.getT(curNode); | 
				
			|||
						std::vector<double> candidates{ 1.0, -1.0 }; | 
				
			|||
 | 
				
			|||
						gp_Pnt pt; | 
				
			|||
						gp_Vec der; | 
				
			|||
						geomCurve->D1(t, pt, der); | 
				
			|||
						std::cout << "pt: " << pt.X() << "," << pt.Y() << "," << pt.Z() << '\n'; | 
				
			|||
						std::cout << "der: " << der.X() << "," << der.Y() << "," << der.Z() << '\n'; | 
				
			|||
 | 
				
			|||
 | 
				
			|||
						std::cout << "der.Mag:" << der.Magnitude() << '\n'; | 
				
			|||
						double alpha = h(transPnt(pt)) / der.Magnitude(); | 
				
			|||
						for(const auto& uCan : candidates) { | 
				
			|||
							double tNew = t + alpha * uCan; | 
				
			|||
							if(tNew > pCurveLastParam || tNew < pCurveFirstParam) { | 
				
			|||
								std::cout << "排除\n"; | 
				
			|||
								continue; | 
				
			|||
							} | 
				
			|||
							std::cout << "tNew:" << tNew << "\n"; | 
				
			|||
							gp_Pnt2d tNewSeedInPCurve; | 
				
			|||
							geomPCurve->D0(tNew, tNewSeedInPCurve); | 
				
			|||
							gp_Pnt ptNew; | 
				
			|||
							geomCurve->D0(tNew, ptNew); | 
				
			|||
							gp_Pnt ptNew2; | 
				
			|||
							geomSurface->D0(tNewSeedInPCurve.X(), tNewSeedInPCurve.Y(), ptNew2); | 
				
			|||
							std::cout << "ptNew: " << ptNew.X() << "," << ptNew.Y() << "," << ptNew.Z() << '\n'; | 
				
			|||
							std::cout << "ptNew2: " << ptNew2.X() << "," << ptNew2.Y() << "," << ptNew2.Z() << '\n'; | 
				
			|||
							double checkradius = pt.SquareDistance(ptNew); | 
				
			|||
							std::cout << "CheckRadius: " << checkradius << '\n'; | 
				
			|||
							double d_sq_loc = treeLocal.query(transPnt(ptNew)).second[0]; | 
				
			|||
							std::cout << "d_sq_loc: " << d_sq_loc << '\n'; | 
				
			|||
							if(d_sq_loc >= (shape.zeta * shape.zeta * checkradius)) { | 
				
			|||
								domainParamLocalPatch.addInternalNodeWithT(transPnt2d(tNewSeedInPCurve), tNew, 1); | 
				
			|||
								treeLocal.insert(transPnt(ptNew)); | 
				
			|||
								endNode++; | 
				
			|||
								double d_sq_global = treeGlobal.query(transPnt(ptNew)).second[0]; | 
				
			|||
								if(d_sq_global >= (shape.zeta * shape.zeta * checkradius)) { | 
				
			|||
									gp_Dir tSeedNormalNew; | 
				
			|||
									auto retStatus = GeomLib::NormEstim(geomSurface, tNewSeedInPCurve, 1e-6, tSeedNormalNew); | 
				
			|||
									if(retStatus >= 2) { | 
				
			|||
										std::cout << "calculate wrong!\n"; | 
				
			|||
										exit(-1); | 
				
			|||
									} | 
				
			|||
									if(reverseNormal) { | 
				
			|||
										tSeedNormalNew = -tSeedNormalNew; | 
				
			|||
									} | 
				
			|||
									domainGlobal.addBoundaryNode(transPnt(ptNew), type, transVec(tSeedNormalNew)); | 
				
			|||
									treeGlobal.insert(transPnt(ptNew)); | 
				
			|||
								} else { | 
				
			|||
									std::cout << "全局不添加点\n"; | 
				
			|||
								} | 
				
			|||
							} else { | 
				
			|||
								std::cout << "局部不添加点\n"; | 
				
			|||
							} | 
				
			|||
						} | 
				
			|||
						curNode++; | 
				
			|||
					} | 
				
			|||
					std::cout << "该边已经生成:" << genPoints << "个点\n"; | 
				
			|||
				} | 
				
			|||
			} | 
				
			|||
 | 
				
			|||
			//fill boundary surface!
 | 
				
			|||
			KDTree paramBoundarySearch; | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
		} | 
				
			|||
		return domainGlobal; | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
}; | 
				
			|||
@ -0,0 +1,23 @@ | 
				
			|||
#pragma once | 
				
			|||
#include "OccHelper.hpp" | 
				
			|||
#include "OccShape.hpp" | 
				
			|||
#include "DomainDiscretization.hpp" | 
				
			|||
#include <vector> | 
				
			|||
#include <Eigen/Core> | 
				
			|||
 | 
				
			|||
namespace meshless { | 
				
			|||
 | 
				
			|||
 | 
				
			|||
	DomainDiscretization<Eigen::Vector3d> discretizeBoundaryWithDensity(const OccShape& shape, const std::function<double(Eigen::Vector3d)>& h, int type); | 
				
			|||
 | 
				
			|||
	DomainDiscretization<Eigen::Vector3d> discretizeBoundaryWithStep(const OccShape& shape, double step, int type) { | 
				
			|||
		auto f = [=](Eigen::Vector3d) {return step; }; | 
				
			|||
		return discretizeBoundaryWithDensity(shape, f, type); | 
				
			|||
 | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
}; | 
				
			|||
@ -0,0 +1,30 @@ | 
				
			|||
#pragma once | 
				
			|||
#include <KDTree_fwd.hpp> | 
				
			|||
#include <assert.hpp> | 
				
			|||
 | 
				
			|||
namespace meshless { | 
				
			|||
	std::pair<std::vector<int>, std::vector<double>> KDTree::query(const Eigen::Vector3d& point, int k)const { | 
				
			|||
 | 
				
			|||
		assert_msg(point.array().isFinite().prod() == 1, "Invalid point."); | 
				
			|||
		std::vector<int> ret_index(k); | 
				
			|||
		std::vector<double> out_dist_sqr(k); | 
				
			|||
		int actual_k = tree.knnSearch(point.data(), k, &ret_index[0], &out_dist_sqr[0]); | 
				
			|||
		assert_msg(actual_k == k, "There were not enough points in the tree, you requested %d " | 
				
			|||
			"points, the tree only contains %d points.", k, actual_k); | 
				
			|||
		return { ret_index, out_dist_sqr }; | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	std::pair<std::vector<int>, std::vector<double>> KDTree::query(const Eigen::Vector3d& point, const double& radius_squared)const { | 
				
			|||
		assert_msg(point.array().isFinite().prod() == 1, "Invalid point."); | 
				
			|||
		std::vector<std::pair<int, double>> idx_dist; | 
				
			|||
		int k = tree.radiusSearch(point.data(), radius_squared, idx_dist, nanoflann::SearchParams()); | 
				
			|||
		std::vector<int> idx(k); std::vector<double> dists(k); | 
				
			|||
		for(int i = 0; i < k; ++i) { | 
				
			|||
			std::tie(idx[i], dists[i]) = idx_dist[i]; | 
				
			|||
		} | 
				
			|||
		return { idx, dists }; | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
}; | 
				
			|||
@ -0,0 +1,40 @@ | 
				
			|||
#pragma once | 
				
			|||
#include "assert.hpp" | 
				
			|||
#include "KDTreeMutable_fwd.hpp" | 
				
			|||
 | 
				
			|||
namespace meshless { | 
				
			|||
 | 
				
			|||
	void KDTreeMutable::insert(const Eigen::Vector3d& point) { | 
				
			|||
		assert_msg(point.array().isFinite().prod() == 1, "Invalid point."); | 
				
			|||
		auto n = points_.kdtree_get_point_count(); | 
				
			|||
		points_.add(point); | 
				
			|||
		tree.addPoints(n, n); | 
				
			|||
		++size_; | 
				
			|||
 | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	void KDTreeMutable::insert(const std::vector<Eigen::Vector3d>& points) { | 
				
			|||
		auto n = points_.kdtree_get_point_count(); | 
				
			|||
		for(const auto& p : points) { | 
				
			|||
			assert_msg(p.array().isFinite().prod() == 1, "One of the points is invalid."); | 
				
			|||
			points_.add(p); | 
				
			|||
		} | 
				
			|||
		size_ += points.size(); | 
				
			|||
		tree.addPoints(n, n + points.size() - 1); | 
				
			|||
 | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	std::pair<std::vector<int>, std::vector<double>> KDTreeMutable::query(const Eigen::Vector3d& point, int k) { | 
				
			|||
		assert_msg(point.array().isFinite().prod() == 1, "Invalid query point."); | 
				
			|||
		nanoflann::KNNResultSet<double, int> resultSet(k); | 
				
			|||
		std::vector<int> ret_index(k); | 
				
			|||
		std::vector<double> out_dist_sqr(k); | 
				
			|||
		resultSet.init(&ret_index[0], &out_dist_sqr[0]); | 
				
			|||
		tree.findNeighbors(resultSet, point.data(), nanoflann::SearchParams(k)); | 
				
			|||
		assert_msg(resultSet.full(), "Not enough points in the tree, you requested %d points, " | 
				
			|||
			"but the tree contains only %d points.", | 
				
			|||
			k, size()); | 
				
			|||
		return { ret_index, out_dist_sqr }; | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
}; | 
				
			|||
@ -0,0 +1,69 @@ | 
				
			|||
#pragma once | 
				
			|||
#include "nanoflann.hpp" | 
				
			|||
#include <array> | 
				
			|||
#include <iosfwd> | 
				
			|||
#include "PointCloud.hpp" | 
				
			|||
 | 
				
			|||
namespace meshless { | 
				
			|||
	class KDTreeMutable { | 
				
			|||
 | 
				
			|||
	private: | 
				
			|||
		typedef nanoflann::KDTreeSingleIndexDynamicAdaptor<nanoflann::L2_Simple_Adaptor<double, PointCloud>, PointCloud, 3, int> kd_tree_t; | 
				
			|||
		int size_; | 
				
			|||
		PointCloud points_; | 
				
			|||
		kd_tree_t tree; | 
				
			|||
 | 
				
			|||
	public: | 
				
			|||
		explicit KDTreeMutable(const std::vector<Eigen::Vector3d>& points) :points_(points), size_(points.size()), tree(3, points_, nanoflann::KDTreeSingleIndexAdaptorParams(20)) {} | 
				
			|||
 | 
				
			|||
		KDTreeMutable() :points_(), size_(0), tree(3, points_, nanoflann::KDTreeSingleIndexAdaptorParams(20)) {} | 
				
			|||
 | 
				
			|||
		void reset(const std::vector<Eigen::Vector3d>& points) { | 
				
			|||
			points_.setPts(points); | 
				
			|||
			size_ = points.size(); | 
				
			|||
			tree.reset(); | 
				
			|||
 | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		void insert(const Eigen::Vector3d& point); | 
				
			|||
		void insert(const std::vector<Eigen::Vector3d>& points); | 
				
			|||
 | 
				
			|||
		/// Check if any point exists in sphere centered at `p` with radius `r`.
 | 
				
			|||
		bool existsPointInSphere(const Eigen::Vector3d& p, double r) { | 
				
			|||
			if(size_ == 0) | 
				
			|||
				return false; | 
				
			|||
			return query(p).second[0] <= r * r; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		/**
 | 
				
			|||
		 * Removes a point with given index from the tree. The indexes of the points are given | 
				
			|||
		 * sequentially at insertion and do not change. The removal is lazy and point still takes | 
				
			|||
		 * up memory. | 
				
			|||
		 */ | 
				
			|||
		void remove(int index) { | 
				
			|||
			size_ -= tree.removePoint(index); | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		/// Returns number of points in the tree.
 | 
				
			|||
		int size() const { | 
				
			|||
			return size_; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		/**
 | 
				
			|||
		 * Find `k` nearest neighbors to given point. | 
				
			|||
		 * @param point Find closest points to this point. | 
				
			|||
		 * @param k How many nearest points to find. | 
				
			|||
		 * | 
				
			|||
		 * @return A pair of two vectors of size `k` containing | 
				
			|||
		 * indices of nearest neighbors and squared distances to said neighbors. | 
				
			|||
		 * @throw Assertion fails if there are not enough points in the tree. | 
				
			|||
		 */ | 
				
			|||
		std::pair<std::vector<int>, std::vector<double>> query(const Eigen::Vector3d& point, int k = 1); | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
	}; | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
}; | 
				
			|||
@ -0,0 +1,49 @@ | 
				
			|||
#pragma once | 
				
			|||
#include <PointCloud.hpp> | 
				
			|||
#include <nanoflann.hpp> | 
				
			|||
#include <Eigen/Core> | 
				
			|||
 | 
				
			|||
namespace meshless { | 
				
			|||
	class KDTree { | 
				
			|||
	private: | 
				
			|||
		typedef nanoflann::KDTreeSingleIndexAdaptor<nanoflann::L2_Simple_Adaptor<double, PointCloud>, PointCloud, 3, int> kd_tree_t; | 
				
			|||
		PointCloud points_; | 
				
			|||
		kd_tree_t tree; | 
				
			|||
	public: | 
				
			|||
		explicit KDTree(const std::vector<Eigen::Vector3d>& points) :points_(points), tree(3, points_, nanoflann::KDTreeSingleIndexAdaptorParams(20)) { | 
				
			|||
			tree.buildIndex(); | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		KDTree() :points_(), tree(3, points_, nanoflann::KDTreeSingleIndexAdaptorParams(20)) {} | 
				
			|||
 | 
				
			|||
		void reset(const std::vector<Eigen::Vector3d>& points) { | 
				
			|||
			points_.setPts(points); | 
				
			|||
			tree.buildIndex(); | 
				
			|||
		} | 
				
			|||
		std::pair<std::vector<int>, std::vector<double>> query(const Eigen::Vector3d& point, int k = 1)const; | 
				
			|||
 | 
				
			|||
		std::pair<std::vector<int>, std::vector<double>> query(const Eigen::Vector3d& point, const double& radius_squared) const; | 
				
			|||
 | 
				
			|||
		Eigen::Vector3d get(int index) const { | 
				
			|||
			return points_.get(index); | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		std::vector<Eigen::Vector3d> get(const std::vector<int>& indexes) const { | 
				
			|||
			const int n = indexes.size(); | 
				
			|||
			std::vector<Eigen::Vector3d> result(n); | 
				
			|||
			for(int i = 0; i < n; i++) { | 
				
			|||
				result[i] = points_.get(indexes[i]); | 
				
			|||
			} | 
				
			|||
			return result; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		int size() const { | 
				
			|||
			return points_.kdtree_get_point_count(); | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
	}; | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
}; | 
				
			|||
@ -0,0 +1,65 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
// OpenCascade includes
 | 
				
			|||
#include <Geom2d_TrimmedCurve.hxx> | 
				
			|||
#include <BRepClass_FaceClassifier.hxx> | 
				
			|||
#include <Interface_Static.hxx> | 
				
			|||
#include <STEPCAFControl_Writer.hxx> | 
				
			|||
#include <STEPControl_Reader.hxx> | 
				
			|||
#include <TopExp.hxx> | 
				
			|||
#include <TopoDS.hxx> | 
				
			|||
#include <TopExp_Explorer.hxx> | 
				
			|||
#include <iostream> | 
				
			|||
#include <TopoDS_Shape.hxx> | 
				
			|||
#include <Geom_Surface.hxx> | 
				
			|||
#include <BRepAdaptor_Surface.hxx> | 
				
			|||
#include <BRepBuilderAPI_NurbsConvert.hxx> | 
				
			|||
#include <Brep_Tool.hxx> | 
				
			|||
#include <GeomConvert.hxx> | 
				
			|||
#include <BRepLib_FindSurface.hxx> | 
				
			|||
#include <Geom_BSplineSurface.hxx> | 
				
			|||
#include <BRepAdaptor_CompCurve.hxx> | 
				
			|||
#include <BRepTools.hxx> | 
				
			|||
#include <ShapeFix_Wire.hxx> | 
				
			|||
#include <Adaptor3d_Curve.hxx> | 
				
			|||
#include <GeomAdaptor_Curve.hxx> | 
				
			|||
#include <BOPTools_AlgoTools3D.hxx> | 
				
			|||
#include <BRepBuilderAPI_Sewing.hxx> | 
				
			|||
#include <ShapeFix_Shape.hxx> | 
				
			|||
#include <ShapeFix_Shell.hxx> | 
				
			|||
#include <ShapeAnalysis.hxx> | 
				
			|||
#include <TopoDS_TShape.hxx> | 
				
			|||
#include <Geom_Plane.hxx> | 
				
			|||
#include <Geom_CylindricalSurface.hxx> | 
				
			|||
#include <Geom_ConicalSurface.hxx> | 
				
			|||
#include <Geom_SphericalSurface.hxx> | 
				
			|||
#include <Geom_ToroidalSurface.hxx> | 
				
			|||
#include <Geom_SurfaceOfLinearExtrusion.hxx> | 
				
			|||
#include <Geom_SurfaceOfRevolution.hxx> | 
				
			|||
#include <Geom_BezierSurface.hxx> | 
				
			|||
#include <Geom_BSplineSurface.hxx> | 
				
			|||
#include <Geom_RectangularTrimmedSurface.hxx> | 
				
			|||
#include <Geom_OffsetSurface.hxx> | 
				
			|||
#include <TopoDS_Compound.hxx> | 
				
			|||
#include <BRepBuilderAPI_Copy.hxx> | 
				
			|||
#include <TColgp_Array2OfPnt.hxx> | 
				
			|||
#include <TColStd_Array1OfReal.hxx> | 
				
			|||
#include <TColStd_Array2OfReal.hxx> | 
				
			|||
#include <TColStd_Array1OfInteger.hxx> | 
				
			|||
#include <BRepBuilderAPI_MakeSolid.hxx> | 
				
			|||
#include <GeomTools.hxx> | 
				
			|||
#include <Geom_Circle.hxx> | 
				
			|||
#include <BRep_Builder.hxx> | 
				
			|||
#include <GeomLib.hxx> | 
				
			|||
 | 
				
			|||
Eigen::Vector3d transVec(const gp_Vec& vec) { | 
				
			|||
	return Eigen::Vector3d(vec.X(), vec.Y(), vec.Z()); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
Eigen::Vector3d transPnt(const gp_Pnt& Pnt) { | 
				
			|||
	return Eigen::Vector3d(Pnt.X(), Pnt.Y(), Pnt.Z()); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
Eigen::Vector2d transPnt2d(const gp_Pnt2d& Pnt) { | 
				
			|||
	return Eigen::Vector2d(Pnt.X(), Pnt.Y()); | 
				
			|||
} | 
				
			|||
@ -0,0 +1,57 @@ | 
				
			|||
#pragma once | 
				
			|||
#include "OccHelper.hpp" | 
				
			|||
#include "assert.hpp" | 
				
			|||
 | 
				
			|||
namespace meshless { | 
				
			|||
	class OccShape { | 
				
			|||
	public: | 
				
			|||
		int max_points = 500000; | 
				
			|||
		int seed_; | 
				
			|||
		int n_samples = 15; | 
				
			|||
		double zeta = 1 - 1e-10; | 
				
			|||
		double epsilon = 0; | 
				
			|||
		TopoDS_Shape myShape; | 
				
			|||
	public: | 
				
			|||
		OccShape() {} | 
				
			|||
		OccShape(const TopoDS_Shape& myShape_) { | 
				
			|||
			max_points = 500000; | 
				
			|||
			seed_; | 
				
			|||
			n_samples = 15; | 
				
			|||
			zeta = 1 - 1e-10; | 
				
			|||
			epsilon = 0; | 
				
			|||
			myShape = myShape_; | 
				
			|||
		} | 
				
			|||
		OccShape& maxPoints(int max_points) { | 
				
			|||
			this->max_points = max_points; | 
				
			|||
			return *this; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		OccShape& seed(int seed) { | 
				
			|||
			seed_ = seed; | 
				
			|||
			return *this; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		OccShape& numSamples(int n_samples) { | 
				
			|||
			this->n_samples = n_samples; | 
				
			|||
			return *this; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
		OccShape& proximityTolerance(double zeta) { | 
				
			|||
			assert_msg((0 < zeta && zeta < 1), "Zeta must be between 0 and 1, got %f.", zeta); | 
				
			|||
			this->zeta = zeta; | 
				
			|||
			return *this; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		OccShape& boundaryProximity(double epsilon) { | 
				
			|||
			assert_msg((0 < epsilon && epsilon < 1), "Epsilon must be between 0 and 1, got %f.", epsilon); | 
				
			|||
			this->epsilon = epsilon; | 
				
			|||
			return *this; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
	}; | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
}; | 
				
			|||
@ -0,0 +1,56 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
/**
 | 
				
			|||
 * @file | 
				
			|||
 * Implementation of KDTree storage class. | 
				
			|||
 */ | 
				
			|||
 | 
				
			|||
#include <vector> | 
				
			|||
#include <Eigen/Core> | 
				
			|||
 | 
				
			|||
namespace meshless { | 
				
			|||
 | 
				
			|||
	/// Helper class for KDTree with appropriate accessors containing a set of points. @ingroup utils
 | 
				
			|||
	struct PointCloud { | 
				
			|||
		std::vector<Eigen::Vector3d> pts; ///< Points, contained in the tree.
 | 
				
			|||
 | 
				
			|||
		/// Construct an empty point set.
 | 
				
			|||
		PointCloud() = default; | 
				
			|||
 | 
				
			|||
		/// Construct from an array of points.
 | 
				
			|||
		PointCloud(const std::vector<Eigen::Vector3d>& pts) : pts(pts) {} | 
				
			|||
 | 
				
			|||
		/// Reset contained points.
 | 
				
			|||
		void setPts(const std::vector<Eigen::Vector3d>& pts) { | 
				
			|||
			PointCloud::pts = pts; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		/// Interface requirement: returns number of data points.
 | 
				
			|||
		inline int kdtree_get_point_count() const { | 
				
			|||
			return pts.size(); | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		/// Interface requirement: returns `dim`-th coordinate of `idx`-th point.
 | 
				
			|||
		inline typename double kdtree_get_pt(const size_t idx, int dim) const { | 
				
			|||
			return pts[idx][dim]; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		/// Access the points.
 | 
				
			|||
		inline Eigen::Vector3d get(const size_t idx) const { | 
				
			|||
			return pts[idx]; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		/// Add a point to the cloud.
 | 
				
			|||
		inline void add(const Eigen::Vector3d& p) { | 
				
			|||
			pts.push_back(p); | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		/// Comply with the interface.
 | 
				
			|||
		template <class BBOX> | 
				
			|||
		bool kdtree_get_bbox(BBOX& /* bb */) const { | 
				
			|||
			return false; | 
				
			|||
		} | 
				
			|||
	}; | 
				
			|||
 | 
				
			|||
} // namespace mm
 | 
				
			|||
 | 
				
			|||
@ -0,0 +1,110 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
/**
 | 
				
			|||
 * @file | 
				
			|||
 * Implementation of custom assert and debug utilities. | 
				
			|||
 */ | 
				
			|||
 | 
				
			|||
#include <tinyformat.h> | 
				
			|||
#include "print.hpp" | 
				
			|||
 | 
				
			|||
namespace meshless { | 
				
			|||
 | 
				
			|||
#ifdef _MSC_VER // Check if using MSVC
 | 
				
			|||
#define FUNCTION_NAME __FUNCSIG__ // Use __FUNCSIG__ for function name
 | 
				
			|||
#else | 
				
			|||
#define FUNCTION_NAME __PRETTY_FUNCTION__ // Use __PRETTY_FUNCTION__ for other compilers
 | 
				
			|||
#endif | 
				
			|||
 | 
				
			|||
 | 
				
			|||
	// print macro
 | 
				
			|||
	/// @cond
 | 
				
			|||
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1, 0) | 
				
			|||
#define VA_NUM_ARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N | 
				
			|||
#define macro_dispatcher(func, ...)     macro_dispatcher_(func, VA_NUM_ARGS(__VA_ARGS__)) | 
				
			|||
#define macro_dispatcher_(func, nargs)  macro_dispatcher__(func, nargs) | 
				
			|||
#define macro_dispatcher__(func, nargs) func ## nargs | 
				
			|||
#define addflag(a) {std::cerr << "flags=[flags, " << (a) << "];" << std::endl;} | 
				
			|||
#define prnv2(a, b) {std::cerr << a << " = " << (b) << ";" << std::endl;} | 
				
			|||
#define prnv1(a)   {std::cerr << #a << " = " << (a) << ";" << std::endl;} | 
				
			|||
/// @endcond
 | 
				
			|||
/**
 | 
				
			|||
 * Prints a variable name and value to standard output. Can take one or two parameters. | 
				
			|||
 * Example: | 
				
			|||
 * @code | 
				
			|||
 * int a = 6; | 
				
			|||
 * prn(a) // prints 'a = 6;' | 
				
			|||
 * prn("value", a) // prints 'value = 6;' | 
				
			|||
 * @endcode | 
				
			|||
 */ | 
				
			|||
#define prn(...) macro_dispatcher(prnv, __VA_ARGS__)(__VA_ARGS__) | 
				
			|||
 | 
				
			|||
	using tinyformat::printf; | 
				
			|||
	using tinyformat::format; | 
				
			|||
 | 
				
			|||
	/// Namespace holding custom assert implementation.
 | 
				
			|||
	namespace assert_internal { | 
				
			|||
		/**
 | 
				
			|||
		 * Actual assert implementation. | 
				
			|||
		 * @param condition Condition to test, e.g.\ `n > 0`. | 
				
			|||
		 * @param file File where the assertion failed. | 
				
			|||
		 * @param func_name Function name where the assertion failed. | 
				
			|||
		 * @param line Line on which the assertion failed. | 
				
			|||
		 * @param message Message as specified in the `assert_msg` macro. | 
				
			|||
		 * @param format_list List of format field values to pass to `tinyformat::format` function. | 
				
			|||
		 */ | 
				
			|||
		bool assert_handler_implementation(const char* condition, const char* file, const char* func_name, | 
				
			|||
			int line, const char* message, tfm::FormatListRef format_list); | 
				
			|||
		/// Assert handler that unpacks varargs.
 | 
				
			|||
		template<typename... Args> | 
				
			|||
		bool assert_handler(const char* condition, const char* file, const char* func_name, int line, | 
				
			|||
			const char* message, const Args&... args) {  // unpacks first argument
 | 
				
			|||
			tfm::FormatListRef arg_list = tfm::makeFormatList(args...); | 
				
			|||
			return assert_handler_implementation(condition, file, func_name, line, message, arg_list); | 
				
			|||
		} | 
				
			|||
	}  // namespace assert_internal
 | 
				
			|||
 | 
				
			|||
#ifdef NDEBUG | 
				
			|||
#define assert_msg(cond, ...) ((void)sizeof(cond)) | 
				
			|||
#else | 
				
			|||
/**
 | 
				
			|||
 * @brief Assert with better error reporting. | 
				
			|||
 * @param cond Conditions to test. | 
				
			|||
 * @param ... The second parameter is also required and represents the message to print on failure. | 
				
			|||
 * For every %* field in message one additional parameter must be present. | 
				
			|||
 * | 
				
			|||
 * Example: | 
				
			|||
 * @code | 
				
			|||
 * assert_msg(n > 0, "n must be positive, got %d.", n); | 
				
			|||
 * @endcode | 
				
			|||
 */ | 
				
			|||
#define assert_msg(cond, ...) ((void)(!(cond) && \ | 
				
			|||
    meshless::assert_internal::assert_handler( \ | 
				
			|||
            #cond, __FILE__, FUNCTION_NAME, __LINE__, __VA_ARGS__) && (assert(0), 1))) | 
				
			|||
 //            #cond, __FILE__, __PRETTY_FUNCTION__, __LINE__, __VA_ARGS__) && (exit(1), 1)))
 | 
				
			|||
#endif | 
				
			|||
 | 
				
			|||
/**
 | 
				
			|||
 * Prints given text in bold red. | 
				
			|||
 * @param s text to print. | 
				
			|||
 */ | 
				
			|||
	inline void print_red(const std::string& s) { | 
				
			|||
		std::cout << "\x1b[31;1m" << s << "\x1b[37;0m"; | 
				
			|||
	} | 
				
			|||
	/**
 | 
				
			|||
	 * Prints given text in bold white. | 
				
			|||
	 * @param s text to print. | 
				
			|||
	 */ | 
				
			|||
	inline void print_white(const std::string& s) { | 
				
			|||
		std::cout << "\x1b[37;1m" << s << "\x1b[37;0m"; | 
				
			|||
	} | 
				
			|||
	/**
 | 
				
			|||
	 * Prints given text in bold green. | 
				
			|||
	 * @param s text to print. | 
				
			|||
	 */ | 
				
			|||
	inline void print_green(const std::string& s) { | 
				
			|||
		std::cout << "\x1b[32;1m" << s << "\x1b[37;0m"; | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
}  // namespace meshless
 | 
				
			|||
 | 
				
			|||
								
									
										File diff suppressed because it is too large
									
								
							
						
					@ -0,0 +1,103 @@ | 
				
			|||
#ifndef MEDUSA_BITS_UTILS_PRINT_HPP_ | 
				
			|||
#define MEDUSA_BITS_UTILS_PRINT_HPP_ | 
				
			|||
 | 
				
			|||
/**
 | 
				
			|||
 * @file | 
				
			|||
 * Printing helpers for std types. | 
				
			|||
 */ | 
				
			|||
 | 
				
			|||
#include <iostream> | 
				
			|||
#include <vector> | 
				
			|||
#include <array> | 
				
			|||
#include <utility> | 
				
			|||
#include <tuple> | 
				
			|||
 | 
				
			|||
 // additional ostream operators
 | 
				
			|||
namespace std { | 
				
			|||
 | 
				
			|||
	/// Output pairs as `(1, 2)`. @ingroup utils
 | 
				
			|||
	template <class T, class U> | 
				
			|||
	std::ostream& operator<<(std::ostream& xx, const std::pair<T, U>& par) { | 
				
			|||
		return xx << "(" << par.first << "," << par.second << ")"; | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	/// Output arrays as `[1, 2, 3]`. @ingroup utils
 | 
				
			|||
	template <class T, size_t N> | 
				
			|||
	std::ostream& operator<<(std::ostream& xx, const std::array<T, N>& arr) { | 
				
			|||
		xx << "["; | 
				
			|||
		for(size_t i = 0; i < N; ++i) { | 
				
			|||
			xx << arr[i]; | 
				
			|||
			if(i < N - 1) | 
				
			|||
				xx << ", "; | 
				
			|||
		} | 
				
			|||
		xx << "]"; | 
				
			|||
		return xx; | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	/// Output vectors as `[1, 2, 3]`. @ingroup utils
 | 
				
			|||
	template <class T, class A> | 
				
			|||
	std::ostream& operator<<(std::ostream& xx, const std::vector<T, A>& arr) { | 
				
			|||
		// do it like the matlab does it.
 | 
				
			|||
		xx << "["; | 
				
			|||
		for(size_t i = 0; i < arr.size(); ++i) { | 
				
			|||
			xx << arr[i]; | 
				
			|||
			if(i < arr.size() - 1) | 
				
			|||
				xx << ", "; | 
				
			|||
		} | 
				
			|||
		xx << "]"; | 
				
			|||
		return xx; | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	/// Output nested vectors as `[[1, 2]; [3, 4]]`. @ingroup utils
 | 
				
			|||
	template <class T, class A> | 
				
			|||
	std::ostream& operator<<(std::ostream& xx, const std::vector<std::vector<T, A>>& arr) { | 
				
			|||
		xx << "["; | 
				
			|||
		for(size_t i = 0; i < arr.size(); ++i) { | 
				
			|||
			for(size_t j = 0; j < arr[i].size(); ++j) { | 
				
			|||
				xx << arr[i][j]; | 
				
			|||
				if(j < arr[i].size() - 1) | 
				
			|||
					xx << ", "; | 
				
			|||
			} | 
				
			|||
			if(i < arr.size() - 1) | 
				
			|||
				xx << "; "; | 
				
			|||
		} | 
				
			|||
		xx << "]"; | 
				
			|||
		return xx; | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	/// @cond
 | 
				
			|||
	namespace tuple_print_internal { | 
				
			|||
		template <class Tuple, std::size_t N> | 
				
			|||
		struct TuplePrinter { | 
				
			|||
			static void print(std::ostream& os, const Tuple& t) { // recursive
 | 
				
			|||
				TuplePrinter<Tuple, N - 1>::print(os, t); | 
				
			|||
				os << ", " << std::get<N - 1>(t); | 
				
			|||
			} | 
				
			|||
		}; | 
				
			|||
 | 
				
			|||
		template <class Tuple> | 
				
			|||
		struct TuplePrinter<Tuple, 1> { | 
				
			|||
			static void print(std::ostream& os, const Tuple& t) { // one element
 | 
				
			|||
				os << std::get<0>(t); | 
				
			|||
			} | 
				
			|||
		}; | 
				
			|||
 | 
				
			|||
		template <class Tuple> | 
				
			|||
		struct TuplePrinter<Tuple, 0> { | 
				
			|||
			static void print(std::ostream&, const Tuple&) {} | 
				
			|||
		}; // zero elt
 | 
				
			|||
 | 
				
			|||
	} // namespace tuple_print_internal
 | 
				
			|||
	/// @endcond
 | 
				
			|||
 | 
				
			|||
	/// Print a tuple as (1, 4.5, abc). @ingroup utils
 | 
				
			|||
	template <class... Args> | 
				
			|||
	std::ostream& operator<<(std::ostream& os, const std::tuple<Args...>& t) { | 
				
			|||
		os << "("; | 
				
			|||
		tuple_print_internal::TuplePrinter<decltype(t), sizeof...(Args)>::print(os, t); | 
				
			|||
		return os << ")"; | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
} // namespace std
 | 
				
			|||
 | 
				
			|||
#endif // MEDUSA_BITS_UTILS_PRINT_HPP_
 | 
				
			|||
								
									
										File diff suppressed because it is too large
									
								
							
						
					@ -0,0 +1,54 @@ | 
				
			|||
#pragma once | 
				
			|||
#include <Eigen/Core> | 
				
			|||
#include <cstring> | 
				
			|||
namespace meshless { | 
				
			|||
	template <int dim> | 
				
			|||
	void writePntVTK(const std::string& path, const Eigen::MatrixXd& pnts, const std::vector<double>& attri) { | 
				
			|||
		std::ofstream out(path); | 
				
			|||
		out << "# vtk DataFile Version 3.0\n" | 
				
			|||
			"Volume Mesh\n" | 
				
			|||
			"ASCII\n" | 
				
			|||
			"DATASET UNSTRUCTURED_GRID" | 
				
			|||
			<< std::endl; | 
				
			|||
		out << "POINTS " << pnts.rows() << " float" << std::endl; | 
				
			|||
		for(int i = 0; i < pnts.rows(); ++i) { | 
				
			|||
			for(int j = 0; j < dim; ++j) { | 
				
			|||
				out << std::setprecision(4) << pnts(i, j) << " "; | 
				
			|||
			} | 
				
			|||
			for(int j = dim; j < 3; ++j) { | 
				
			|||
				out << "0 "; | 
				
			|||
			} | 
				
			|||
			out << std::endl; | 
				
			|||
		} | 
				
			|||
		int innersize = 0; | 
				
			|||
		int interSize = 0; | 
				
			|||
		int bounSize = 0; | 
				
			|||
 | 
				
			|||
		out << "CELLS " << pnts.rows() << " " << pnts.rows() * (1 + 1) << std::endl; | 
				
			|||
		for(int i = 0; i < pnts.rows(); ++i) { | 
				
			|||
			out << "1 " << i << std::endl; | 
				
			|||
		} | 
				
			|||
		out << "CELL_TYPES " << pnts.rows() << std::endl; | 
				
			|||
		for(int i = 0; i < pnts.rows(); ++i) { | 
				
			|||
			out << 1 << std::endl; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		if(!attri.empty()) { | 
				
			|||
			out << "POINT_DATA " << attri.size() << "\n" | 
				
			|||
				<< "SCALARS point_scalars double 1\n" | 
				
			|||
				<< "LOOKUP_TABLE default" << std::endl; | 
				
			|||
			for(auto& d : attri) { | 
				
			|||
				out << d << std::endl; | 
				
			|||
				if(d == 1) | 
				
			|||
					innersize++; | 
				
			|||
				else | 
				
			|||
					bounSize++; | 
				
			|||
			} | 
				
			|||
		} | 
				
			|||
		std::cout << "ÄÚ²¿µã£º " << innersize << "\n"; | 
				
			|||
		std::cout << "±ß½çµã£º " << bounSize << "\n"; | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
}; | 
				
			|||
@ -0,0 +1,26 @@ | 
				
			|||
#include "assert.hpp" | 
				
			|||
 | 
				
			|||
/**
 | 
				
			|||
 * @file | 
				
			|||
 * Implementation of custom assert utilities. | 
				
			|||
 */ | 
				
			|||
 | 
				
			|||
namespace meshless { | 
				
			|||
 | 
				
			|||
	namespace assert_internal { | 
				
			|||
 | 
				
			|||
		bool assert_handler_implementation(const char* condition, const char* file, const char* func_name, | 
				
			|||
			int line, const char* message, tfm::FormatListRef format_list) { | 
				
			|||
			std::cerr << "\x1b[37;1m";  // white bold
 | 
				
			|||
			tfm::format(std::cerr, "%s:%d: %s: Assertion `%s' failed with message:\n", | 
				
			|||
				file, line, func_name, condition); | 
				
			|||
			std::cerr << "\x1b[31;1m";  // red bold
 | 
				
			|||
			tfm::vformat(std::cerr, message, format_list); | 
				
			|||
			std::cerr << "\x1b[37;0m\n";  // no color
 | 
				
			|||
			std::cerr.flush(); | 
				
			|||
			return true; | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
	}  // namespace assert_internal
 | 
				
			|||
 | 
				
			|||
}  // namespace meshless
 | 
				
			|||
@ -0,0 +1,38 @@ | 
				
			|||
#include <iostream> | 
				
			|||
#include <fstream> | 
				
			|||
#include <Eigen/Core> | 
				
			|||
#include "FillBoundary.hpp" | 
				
			|||
#include "writeVTK.hpp" | 
				
			|||
 | 
				
			|||
using namespace std; | 
				
			|||
using namespace meshless; | 
				
			|||
 | 
				
			|||
int main() { | 
				
			|||
	Eigen::MatrixXd mat; | 
				
			|||
	BRep_Builder brepBuilder; | 
				
			|||
	TopoDS_Shape myShape; | 
				
			|||
	//auto status = BRepTools::Read(myShape, "F:/CADMeshless/StepAndBrepModel/DWE_ADM102_ASSIGN.brep", brepBuilder);
 | 
				
			|||
	auto status = BRepTools::Read(myShape, "F:/CADMeshless/StepAndBrepModel/Exhaust_Manifold.brep", brepBuilder); | 
				
			|||
	OccShape occShape(myShape); | 
				
			|||
	auto domain = discretizeBoundaryWithStep(occShape, 1, -1); | 
				
			|||
	Eigen::MatrixXd quaPoints; | 
				
			|||
 | 
				
			|||
	quaPoints.resize(domain.positions().size(), 3); | 
				
			|||
	std::vector<double> attri; | 
				
			|||
	for(int i = 0; i < domain.positions().size(); i++) { | 
				
			|||
		if(domain.types()[i] == 1) { | 
				
			|||
			attri.push_back(1.0); | 
				
			|||
		} else { | 
				
			|||
			attri.push_back(0); | 
				
			|||
		} | 
				
			|||
		quaPoints(i, 0) = domain.positions()[i].x(); | 
				
			|||
		quaPoints(i, 1) = domain.positions()[i].y(); | 
				
			|||
		quaPoints(i, 2) = domain.positions()[i].z(); | 
				
			|||
	} | 
				
			|||
	writePntVTK<3>("Exhaust_Manifold.vtk", quaPoints, attri); | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
	return 0; | 
				
			|||
} | 
				
			|||
					Loading…
					
					
				
		Reference in new issue