You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
391 lines
15 KiB
391 lines
15 KiB
# pragma once
|
|
#include<iostream>
|
|
#include<vector>
|
|
#include<math.h>
|
|
#include<map>
|
|
#include<set>
|
|
#include"../geo/geocal.h"
|
|
#include"../display/Struct3d.h"
|
|
using namespace std;
|
|
|
|
// 这里是CNT之后再划分一次点
|
|
// 原文
|
|
// The first step is to refine the tessellation. To do so, we first
|
|
// insert a vertex at the midpoint of each edge of the CNT of CHoCC
|
|
// of each chopped-ball. Then, for each triangle of that CNT, we
|
|
// refine it into four new triangles, where one of the new triangles
|
|
// is incident on the three inserted vertices. Similarly, for each quad
|
|
// (approximating a corridor), we also insert one new vertex at its
|
|
// centroid and refine the quad into eight triangles (as shown in
|
|
// Fig. 18—left).
|
|
// This refinement step does not change the shape of the mesh,
|
|
// and hence does not improve its approximation accuracy. To im-
|
|
// prove accuracy, a vertex that was inserted on an edge of a
|
|
// polygonal approximation of a circle is snapped radially onto its
|
|
// closest projection on that circle (see Fig. 18—right). Note that after
|
|
// this process, some flat edges may become concave.
|
|
// Next, we adjust the positions of the refined and snapped ver-
|
|
// tices of the CNT associated with the ball. To do this, our central-
|
|
// projection step moves each one of these vertices towards or away
|
|
// from the center of the ball, so as to bring it to the boundary of
|
|
// the exact lattice. A typical result is shown in Fig. 19—left.
|
|
|
|
class ACHoCC{
|
|
//FilletSurface中计算的d(P)
|
|
static double FilletSurface(const vector<double>& nums,double b=-1){
|
|
if(b<0){
|
|
double numssum=nums[0];
|
|
for(int i=1;i<nums.size();i++){
|
|
numssum=min(numssum,nums[i]);
|
|
}
|
|
return numssum;
|
|
}else{
|
|
double numssum=0;
|
|
for(auto num:nums){
|
|
numssum+=exp(-b*num);
|
|
}
|
|
return -log(numssum)/b;
|
|
}
|
|
|
|
}
|
|
|
|
//cone-sphere distance
|
|
static double distance(const Point3D& p,const Sphere& s,const double& r,const Vector3d& dir){
|
|
double x=dir.normalized().dot(p-s.center);
|
|
double rp2cenline=sqrt((p-s.center).squaredNorm()-x*x);
|
|
if(x>0){
|
|
return rp2cenline-r;
|
|
}
|
|
else{
|
|
return (s.center-p).norm()-r;
|
|
}
|
|
}
|
|
|
|
//对一个点进行移动
|
|
static void movetolattice(const Struct3d& s,Point3D& p,bool IfAddPoint=false,double binpaper=-1){
|
|
double a=1;
|
|
double b=0;
|
|
double tmp=(a+b)/2;
|
|
vector<double> nums;
|
|
int cirsize=s.circs.size();
|
|
if(IfAddPoint){
|
|
cirsize--;
|
|
}
|
|
while(abs(a-b)>0.02){
|
|
tmp=(a+b)/2;
|
|
nums.clear();
|
|
auto tmppoint=(1-tmp)*s.sphere.center+tmp*p;
|
|
for(int i=0;i<cirsize;i++){
|
|
nums.push_back(distance(tmppoint,s.sphere,s.circs[i].r,s.circs[i].dir));
|
|
}
|
|
double distmp=FilletSurface(nums,binpaper);
|
|
if(distmp>0){
|
|
a=tmp;
|
|
}
|
|
else{
|
|
b=tmp;
|
|
}
|
|
}
|
|
tmp=(a+b)/2;
|
|
p=(1-tmp)*s.sphere.center+tmp*p;
|
|
}
|
|
|
|
//记录下coneedge的四个特征点
|
|
static void ShowEdge(map<edgeNum,vector<int>>& ms,Struct3d& s){
|
|
for(int i=0;i<s.circsnum.size();i++){
|
|
ms[edgeNum(s.circsnum[i].x(),s.circsnum[i].y())].push_back(
|
|
s.tris[i].x()
|
|
);
|
|
ms[edgeNum(s.circsnum[i].x(),s.circsnum[i].y())].push_back(
|
|
s.tris[i].y()
|
|
);
|
|
ms[edgeNum(s.circsnum[i].y(),s.circsnum[i].z())].push_back(
|
|
s.tris[i].y()
|
|
);
|
|
ms[edgeNum(s.circsnum[i].y(),s.circsnum[i].z())].push_back(
|
|
s.tris[i].z()
|
|
);
|
|
ms[edgeNum(s.circsnum[i].x(),s.circsnum[i].z())].push_back(
|
|
s.tris[i].z()
|
|
);
|
|
ms[edgeNum(s.circsnum[i].x(),s.circsnum[i].z())].push_back(
|
|
s.tris[i].x()
|
|
);
|
|
}
|
|
}
|
|
|
|
//对angle排序,x也按照angle的排序而排序
|
|
static void mysort(vector<int>& x,vector<double>& angles){
|
|
for(int i=0;i<x.size();i++){
|
|
for(int j=i+1;j<x.size();j++){
|
|
if(angles[i]<angles[j]){
|
|
swap(angles[i],angles[j]);
|
|
swap(x[i],x[j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//展示圆面的obj文件
|
|
static void ShowCirFace(Struct3d& s,print3d& result,map<edgeNum,int>& getmid,map<int,int>& circenter,int& pnum,
|
|
set<int,greater<int>>& need_adjust,bool IfAddPoint=false)
|
|
{
|
|
//将这些点归类到各个圆形上面
|
|
vector<vector<int>> x(s.circs.size());
|
|
for(int i=0;i<s.circsnum.size();i++){
|
|
x[s.circsnum[i].x()].push_back(s.tris[i].x());
|
|
x[s.circsnum[i].y()].push_back(s.tris[i].y());
|
|
x[s.circsnum[i].z()].push_back(s.tris[i].z());
|
|
}
|
|
//生成多边形
|
|
vector<double> angles;
|
|
for(int i=0;i<s.circs.size();i++){
|
|
angles.clear();
|
|
//多边形的中心点
|
|
Vector3d centerpoint(0,0,0);
|
|
for(int j=0;j<x[i].size();j++){
|
|
auto tmp=s.circs[i].getangle(s.ps[x[i][j]]);
|
|
angles.push_back(tmp);
|
|
centerpoint+=s.ps[x[i][j]]/x[i].size();
|
|
}
|
|
mysort(x[i],angles);
|
|
//加入多边形的中心点
|
|
result.p.push_back(centerpoint);
|
|
if(i==s.circs.size()-1&&IfAddPoint){
|
|
need_adjust.insert(pnum);
|
|
}
|
|
circenter[i]=pnum++;
|
|
|
|
for(int j=0;j<angles.size();j++){
|
|
int u0=x[i][getmod(j-1,angles.size())];
|
|
int u1=x[i][j];
|
|
int u2=x[i][(j+1)%angles.size()];
|
|
int u3=x[i][(j+2)%angles.size()];
|
|
getmid[edgeNum(u1,u2)]=pnum++;
|
|
//这里有个我排查了很久的bug,当椭圆锥细化到一定程度退化为线段,
|
|
//两个点(例如这两个点是1,2)退化为一个点这就导致了getmid中可能会出现一些点索引是1,3找的到,但换成2,3就找不到了,
|
|
//这里遇到这种先把getmid里面的数值统一一下
|
|
bool repeatposition1=APequal(angles[j],angles[getmod(j-1,angles.size())]);
|
|
bool repeatposition2=APequal(angles[(j+1)%angles.size()],angles[(j+2)%angles.size()]);
|
|
if(repeatposition1){
|
|
getmid[edgeNum(u0,u2)]=pnum-1;
|
|
}
|
|
if(repeatposition2){
|
|
getmid[edgeNum(u1,u3)]=pnum-1;
|
|
}
|
|
if(repeatposition1&&repeatposition2){
|
|
getmid[edgeNum(u0,u3)]=pnum-1;
|
|
}
|
|
//加入圆上多边形的中点
|
|
result.p.push_back((result.p[u1]+result.p[u2])/2);
|
|
int u=getmid[edgeNum(u1,u2)];
|
|
int uc=circenter[i];
|
|
|
|
result.f.push_back(Vector3i(uc,u1,u));
|
|
result.f.push_back(Vector3i(uc,u,u2));
|
|
}
|
|
}
|
|
}
|
|
|
|
//输入三角形的点
|
|
static void getinitpoint(Struct3d& s,print3d& result,set<int,greater<int>>& need_adjust,bool IfAddPoint=false){
|
|
for(int i=0;i<s.ps.size();i++){
|
|
result.p.push_back(s.ps[i]);
|
|
}
|
|
if(IfAddPoint){
|
|
need_adjust.insert(s.ps.size()-3);
|
|
need_adjust.insert(s.ps.size()-2);
|
|
need_adjust.insert(s.ps.size()-1);
|
|
}
|
|
}
|
|
|
|
//加入三角形的中间点
|
|
static void AddTriEdgeCenter(Struct3d& s,print3d& result,map<edgeNum,int>& getmid,int& pnum){
|
|
for(int i=0;i<s.tris.size();i++){
|
|
result.p.push_back(
|
|
(s.ps[s.tris[i].x()]+s.ps[s.tris[i].y()])/2
|
|
);
|
|
getmid[edgeNum(s.tris[i].x(),s.tris[i].y())]=pnum++;
|
|
result.p.push_back(
|
|
(s.ps[s.tris[i].y()]+s.ps[s.tris[i].z()])/2
|
|
);
|
|
getmid[edgeNum(s.tris[i].y(),s.tris[i].z())]=pnum++;
|
|
result.p.push_back(
|
|
(s.ps[s.tris[i].z()]+s.ps[s.tris[i].x()])/2
|
|
);
|
|
getmid[edgeNum(s.tris[i].z(),s.tris[i].x())]=pnum++;
|
|
}
|
|
}
|
|
|
|
//加入coneedge的中心点
|
|
static void Addconeedgecenter(Struct3d& s,print3d& result,map<edgeNum,vector<int>>& ms,map<FaceNum,int>& facenum,int& pnum){
|
|
for(auto m:ms){
|
|
result.p.push_back(
|
|
(s.ps[m.second[0]]+s.ps[m.second[1]]+s.ps[m.second[2]]+s.ps[m.second[3]])/4
|
|
);
|
|
facenum[m.second]=pnum++;
|
|
}
|
|
}
|
|
|
|
//三角形的obj输入
|
|
static void ShowTri(Struct3d& s,print3d& result,map<edgeNum,int>& getmid){
|
|
for(int i=0;i<s.tris.size();i++){
|
|
assert(getmid.count(edgeNum(s.tris[i].x(),s.tris[i].y()))!=0);
|
|
assert(getmid.count(edgeNum(s.tris[i].z(),s.tris[i].x()))!=0);
|
|
assert(getmid.count(edgeNum(s.tris[i].y(),s.tris[i].z()))!=0);
|
|
int xy=getmid[edgeNum(s.tris[i].x(),s.tris[i].y())];
|
|
int xz=getmid[edgeNum(s.tris[i].z(),s.tris[i].x())];
|
|
int yz=getmid[edgeNum(s.tris[i].y(),s.tris[i].z())];
|
|
int x=s.tris[i].x();
|
|
int y=s.tris[i].y();
|
|
int z=s.tris[i].z();
|
|
result.f.push_back(Vector3i(x,xy,xz));
|
|
result.f.push_back(Vector3i(y,yz,xy));
|
|
result.f.push_back(Vector3i(z,xz,yz));
|
|
result.f.push_back(Vector3i(yz,xz,xy));
|
|
}
|
|
}
|
|
|
|
//展示coneedge的obj文件
|
|
static void ShowConeedge(Struct3d& s,print3d& result,map<FaceNum,int>& facenum,map<edgeNum,int>& getmid
|
|
,map<edgeNum,vector<int>> ms){
|
|
for(auto m:ms){
|
|
int center=facenum[m.second];
|
|
int mid01=getmid[edgeNum(m.second[0],m.second[1])];
|
|
int mid12=getmid[edgeNum(m.second[1],m.second[2])];
|
|
int mid23=getmid[edgeNum(m.second[2],m.second[3])];
|
|
int mid30=getmid[edgeNum(m.second[3],m.second[0])];
|
|
|
|
assert(getmid.count(edgeNum(m.second[0],m.second[1]))!=0);
|
|
assert(getmid.count(edgeNum(m.second[1],m.second[2]))!=0);
|
|
assert(getmid.count(edgeNum(m.second[2],m.second[3]))!=0);
|
|
assert(getmid.count(edgeNum(m.second[3],m.second[0]))!=0);
|
|
|
|
result.f.push_back(Vector3i(m.second[0],mid01,center));
|
|
result.f.push_back(Vector3i(center,mid01,m.second[1]));
|
|
|
|
result.f.push_back(Vector3i(m.second[1],mid12,center));
|
|
result.f.push_back(Vector3i(center,mid12,m.second[2]));
|
|
|
|
result.f.push_back(Vector3i(m.second[2],mid23,center));
|
|
result.f.push_back(Vector3i(center,mid23,m.second[3]));
|
|
|
|
result.f.push_back(Vector3i(m.second[3],mid30,center));
|
|
result.f.push_back(Vector3i(center,mid30,m.second[0]));
|
|
|
|
}
|
|
}
|
|
|
|
//CNT+插入中间点
|
|
static void WritePoint(Struct3d& s,print3d& result,set<int,greater<int>>& need_adjust,bool IfAddPoint=false){
|
|
map<edgeNum,vector<int>> ms;//标记椭圆锥上的四个特征点
|
|
ShowEdge(ms,s);
|
|
map<edgeNum,int> getmid;//标记边的中点
|
|
map<int,int> circenter;//标记圆中多边形的中点
|
|
map<FaceNum,int> facenum;//圆形中点
|
|
|
|
//加入CNT中已经有的点
|
|
getinitpoint(s,result,need_adjust,IfAddPoint);
|
|
int pnum=result.p.size();
|
|
//加入三角形中点
|
|
AddTriEdgeCenter(s,result,getmid,pnum);
|
|
//加入三角形面
|
|
ShowTri(s,result,getmid);
|
|
// //加入椭圆锥的中心点并记录到facenum
|
|
Addconeedgecenter(s,result,ms,facenum,pnum);
|
|
// //圆面中心点,圆面的连接
|
|
ShowCirFace(s,result,getmid,circenter,pnum,need_adjust,IfAddPoint);
|
|
// //连接椭圆锥
|
|
ShowConeedge(s,result,facenum,getmid,ms);
|
|
|
|
for(auto i:getmid){
|
|
need_adjust.insert(i.second);
|
|
}
|
|
for(auto i:facenum){
|
|
need_adjust.insert(i.second);
|
|
}
|
|
}
|
|
|
|
//对点的位置进行调整
|
|
static void adjustpoint(Struct3d& s,print3d& result,set<int, greater<int>>& need_adjust,bool IfAddPoint=false,double binpaper=-1){
|
|
for(auto i:need_adjust){
|
|
//投影到圆心
|
|
auto tmpp=result.p[i];
|
|
tmpp=s.sphere.getSurPoint(tmpp);
|
|
//投影到面上面
|
|
movetolattice(s,tmpp,IfAddPoint,binpaper);
|
|
result.p[i]=tmpp;
|
|
}
|
|
}
|
|
|
|
static int IfAddPoint(Struct3d& s){
|
|
vector<Point3D> p;
|
|
int i;
|
|
for(i=0;i<s.tris.size();i++){
|
|
p.clear();
|
|
p.push_back(s.ps[s.tris[i].x()]);
|
|
p.push_back(s.ps[s.tris[i].y()]);
|
|
p.push_back(s.ps[s.tris[i].z()]);
|
|
if(!IfPlanefromPointRight(p,s.sphere.center)){
|
|
break;
|
|
}
|
|
}
|
|
if(i!=s.tris.size()){
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
static void pre_deal(Struct3d& s,int num){
|
|
//计算圆形与中心
|
|
Vector3d tmpp;
|
|
tmpp<<(s.ps[s.tris[num].x()]+s.ps[s.tris[num].y()]+s.ps[s.tris[num].z()])/3;
|
|
tmpp=s.sphere.center-(tmpp-s.sphere.center);
|
|
tmpp=s.sphere.getSurPoint(tmpp);
|
|
Circ c(s.sphere.center+s.sphere.r*(tmpp-s.sphere.center).normalized(),(tmpp-s.sphere.center).normalized(),0.00001);
|
|
s.circs.push_back(c);
|
|
s.ps.push_back(
|
|
c.center+((s.ps[s.tris[num].y()]-c.center)+(s.ps[s.tris[num].z()]-c.center)).normalized()*c.r
|
|
);
|
|
s.ps.push_back(
|
|
c.center+((s.ps[s.tris[num].x()]-c.center)+(s.ps[s.tris[num].z()]-c.center)).normalized()*c.r
|
|
);
|
|
s.ps.push_back(
|
|
c.center+((s.ps[s.tris[num].x()]-c.center)+(s.ps[s.tris[num].y()]-c.center)).normalized()*c.r
|
|
);
|
|
//加入三角形
|
|
Vector3i tmp;
|
|
tmp<<s.ps.size()-3,s.tris[num].y(),s.tris[num].z();
|
|
s.tris.push_back(tmp);
|
|
tmp<<s.tris[num].x(),s.ps.size()-2,s.tris[num].z();
|
|
s.tris.push_back(tmp);
|
|
tmp<<s.tris[num].x(),s.tris[num].y(),s.ps.size()-1;
|
|
s.tris.push_back(tmp);
|
|
s.tris.erase(s.tris.begin()+num);
|
|
//加入圆形坐标
|
|
tmp<<s.circs.size()-1,s.circsnum[num].y(),s.circsnum[num].z();
|
|
s.circsnum.push_back(tmp);
|
|
tmp<<s.circsnum[num].x(),s.circs.size()-1,s.circsnum[num].z();
|
|
s.circsnum.push_back(tmp);
|
|
tmp<<s.circsnum[num].x(),s.circsnum[num].y(),s.circs.size()-1;
|
|
s.circsnum.push_back(tmp);
|
|
s.circsnum.erase(s.circsnum.begin()+num);
|
|
}
|
|
|
|
public:
|
|
static void ShowACHoCC(Struct3d& s,print3d& result,double binpaper=-1){
|
|
//写入点与面
|
|
int choice=IfAddPoint(s);
|
|
set<int, greater<int>> need_adjust;
|
|
if(choice==-1){
|
|
WritePoint(s,result,need_adjust);
|
|
//调整点的位置
|
|
adjustpoint(s,result,need_adjust,false,binpaper=binpaper);
|
|
}
|
|
else{
|
|
pre_deal(s,choice);
|
|
WritePoint(s,result,need_adjust,true);
|
|
//调整点的位置
|
|
adjustpoint(s,result,need_adjust,true,binpaper);
|
|
}
|
|
}
|
|
};
|