- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在开发一个需要在 OpenGL 中显示 STL 文件的 C# 项目。为此,我创建了一个返回自定义 Part 对象的 STL 解析类。我有解析类,我可以在其中导入 ASCII 和二进制文件。到目前为止,ASCII 导入似乎工作正常。这是我从维基百科获得的 ASCII 文件的线框示例: Wireframe Image of a Sphereicon Link to Model
橙色线是表面边缘,青色线是表面法线(为了便于查看而缩短)。这告诉我我的显示代码、ASCII 导入器和 Part 类都没有问题。但是,二进制导入器出现了一个奇怪的问题。这是导入 Blender 的球体 STL 对象的图像: Sphere in Blender这是同一球体在我的 OpenGL 软件中的渲染图: My render of the same sphere
表面以一种奇怪的方式在它们之间划分了顶点。每个四边形的中心似乎还有一个额外的顶点。
我正在关注 STL Format维基百科上的规范。
/** importBinary attempts to import the specified Binary STL file and returns a Part object.
*
* This function is responsible for reading and decoding Binary style STL files.
*
* @Param fileName The path to the STL file to import
*/
private static Part importBinary(string fileName)
{
Part retPart = new Part(fileName);
try
{
// In order to read a binary format, a BinaryReader must be used. BinaryReader itself
// is not thread safe. To make it so, a locker object and lock() must be used.
Object locker = new Object();
lock (locker)
{
using (BinaryReader br = new BinaryReader(File.Open(fileName, FileMode.Open)))
{
// Read header info
byte[] header = br.ReadBytes(80);
byte[] length = br.ReadBytes(4);
int numberOfSurfaces = BitConverter.ToInt32(length,0);
string headerInfo = Encoding.UTF8.GetString(header, 0, header.Length).Trim();
Console.WriteLine(String.Format("\nImporting: {0}\n\tHeader: {1}\n\tNumber of faces:{2}\n", fileName, headerInfo, numberOfSurfaces));
// Read Data
byte[] block;
int surfCount = 0;
// Read from the file until either there is no data left or
// the number of surfaces read is equal to the number of surfaces in the
// file. This can prevent reading a partial block at the end and getting
// out of range execptions.
while ((block = br.ReadBytes(50)) != null && surfCount++ < numberOfSurfaces)
{
// Declare temp containers
Surface newSurf = new Surface();
List<Vector3d> verts = new List<Vector3d>();
byte[] xComp = new byte[4];
byte[] yComp = new byte[4];
byte[] zComp = new byte[4];
// Parse data block
for (int i = 0; i < 4; i++)
{
for (int k = 0; k < 12; k++)
{
int index = k + i * 12;
if (k < 4)
{
// xComp
xComp[k] = block[index];
}
else if (k < 8)
{
// yComp
yComp[k - 4] = block[index];
}
else
{
// zComp
zComp[k - 8] = block[index];
}
}
// Convert data to useable structures
float xCompReal = BitConverter.ToSingle(xComp, 0);
float yCompReal = BitConverter.ToSingle(yComp, 0);
float zCompReal = BitConverter.ToSingle(zComp, 0);
if (i == 1)
{
// This is a normal
Vector3d norm = new Vector3d();
norm.X = xCompReal;// * scaleFactor;
norm.Y = yCompReal;// * scaleFactor;
norm.Z = zCompReal;// * scaleFactor;
//if(Math.Abs(Math.Pow(norm.X,2) + Math.Pow(norm.X, 2) + Math.Pow(norm.X, 2) - 1) > .001)
//{
// Console.WriteLine("ERROR: Improper file read. Surface normal is not a unit vector.");
//}
newSurf.normal = norm;
}
else
{
// This is a vertex
Vector3d vert = new Vector3d();
vert.X = xCompReal * scaleFactor;
vert.Y = yCompReal * scaleFactor;
vert.Z = zCompReal * scaleFactor;
verts.Add(vert);
}
}
newSurf.vertices = verts;
retPart.addSurface(newSurf);
}
}
}
}
catch (Exception e) // This is too general to be the only catch statement.
{
Console.WriteLine("The file could not be read:");
Console.WriteLine(e.Message);
return null; // This should rethrow an error instead of returning null
}
return retPart;
}
/** Part is a container for a 3D model consisting of a list surfaces.
*/
class Part
{
private List<Surface> surfaces = null; /**< A list of surfaces. */
public String name { get; set; } = ""; /**< The name of the object. */
/** The constructor.
*
* A name, even a blank one, must be provided. This can be changed later by direct accesss to
* the name parameter if desired.
*
*
* @Param name The name of the object.
*
* @Param surfaces A premade list of surfaces. This is usefull when copying another object.
*/
public Part(String name, List<Surface> surfaces = null)
{
this.name = name;
if (surfaces != null) this.surfaces = surfaces;
else this.surfaces = new List<Surface>();
}
/** Add a surface to the surface list.
*
* This function simply adds a surface. It does not attempt to interconnect it with other surfaces
* that already exist. Any movement of points to make room for the new face must be done on the user's
* end.
*
* @Param surface The face to add to the part.
*/
public void addSurface(Surface surface)
{
surfaces.Add(surface);
}
/** Get the surface at a specific index.
*
* Retrieve a surface at a given index. There is no structure as to the indexing of the faces.
* In order to find a specific surface, the user must iterate through the entire list of surfaces
* using whatever algorithm is desireable.
*
* @Param index The index of the surface to return
*
* @Return The surface object found at index.
*/
public Surface getSurface(int index)
{
return surfaces[index];
}
/** Get the number of surfaces in the part.
*
* @Return The number of surfaces contained within the part.
*/
public int size()
{
return surfaces.Count;
}
/** Removes a surface at a specific index.
*
* Find a surface at the specified index and remove it from list.
*
* @Param index The index of the surface to remove.
*/
public void removeSurface(int index)
{
surfaces.Remove(surfaces[index]);
}
/** Removes the specified surface.
*
* Removes the given surface specified by the user.
*
* @Param surface The surface to remove.
*/
public void removeSurface(Surface surface)
{
surfaces.Remove(surface);
}
/** Recalculates the normal vectors for each face.
*
* @Param outward If true all the normal vectors will face out from the mesh. If false, then the opposite.
*/
public void recalculateNormals(bool outward = true)
{
foreach(Surface surf in surfaces)
{
// Extract vertices
Vector3d p1 = surf.vertices[0]; // Vertex 1
Vector3d p2 = surf.vertices[1]; // Vertex 2
Vector3d p3 = surf.vertices[2]; // Vertex 3
// Create edge vectors
Vector3d l21 = new Vector3d(); // Line from Vertex 2 to Vertex 1
Vector3d l23 = new Vector3d(); // Line from Vertex 2 to Vertex 3
l21.X = p1.X - p2.X;
l21.Y = p1.Y - p2.Y;
l21.Z = p1.Z - p2.Z;
l23.X = p3.X - p2.X;
l23.Y = p3.Y - p2.Y;
l23.Z = p3.Z - p2.Z;
// Find the normal using the cross-product
Vector3d norm = new Vector3d();
norm.X = l21.Y * l23.Z - l23.Y * l21.Z;
norm.Y = l21.Z * l23.X - l23.Z * l21.X;
norm.Z = l21.X * l23.Y - l23.X * l21.Y;
norm.Normalize(); // Ensure that the vector is unit length
// Make sure the normal faces outwards
Vector3d surfVec = surf.surfaceVector();
if(surfVec.X * norm.X + surfVec.Y * norm.Y + surfVec.Z * norm.Z >= 0)
{
//Console.WriteLine("New Normal is facing outside of the mesh.");
}
else
{
//Console.Write("New Normal is facing inside of the mesh. Fixing...");
norm *= -1.0; // Flip the normal
//Console.WriteLine(" Done.");
}
// DEBUG
//Console.WriteLine(String.Format("Old Normal <{0},{1},{2}>, New Normal <{3},{4},{5}>", surf.normal.X, surf.normal.Y, surf.normal.Z, norm.X, norm.Y, norm.Z));
surf.normal = norm;
}
}
}
/** Surface is an object that contains a surface normal and a list of points making up that surface.
*/
class Surface
{
// Surface Properties, Getters, and Setters
public Vector3d normal { get; set; } = new Vector3d(); /**< The normal vector. */
public List<Vector3d> vertices { get; set; } = new List<Vector3d>(); /**< The perimeter verticies. */
// Constructors
/** Default constructor
*/
public Surface()
{
init(new Vector3d(), new List<Vector3d>());
}
/** Constructor with assignable data fields
*/
public Surface(Vector3d normal, List<Vector3d> vertices)
{
init(normal, vertices);
}
/** Returns a vector from the origin of the object to the center of the face.
*/
public Vector3d surfaceVector()
{
// Create a new vector and make sure it's components are 0
Vector3d surfVector = new Vector3d();
surfVector.X = 0;
surfVector.Y = 0;
surfVector.Z = 0;
// Sum the components of each vertext that makes up the surface
foreach (Vector3d vec in vertices)
{
surfVector += vec;
}
// Divide each component by the number of vertices
surfVector *= (1.0 / vertices.Count);
return surfVector;
}
/** The constructor helper function
*
* This function assigns the proper data to the correct members.
*
* @Param _normal The normal vector.
*
* @Param _vertices A list of vertices.
*/
private void init(Vector3d _normal, List<Vector3d> _vertices)
{
normal = _normal;
vertices = _vertices;
}
}
我不确定下一步该去哪里。这看起来有点像 off by 1 error 或者我在某处跳过数据。虽然,除了中间面的顶点,网格看起来很干净。任何想法表示赞赏。提前致谢。
最佳答案
事实证明这是一种错误。在导入二进制文件中:
if (i == 1) //<- WRONG!!!
{
// This is a normal
Vector3d norm = new Vector3d();
norm.X = xCompReal;// * scaleFactor;
norm.Y = yCompReal;// * scaleFactor;
norm.Z = zCompReal;// * scaleFactor;
//if(Math.Abs(Math.Pow(norm.X,2) + Math.Pow(norm.X, 2) + Math.Pow(norm.X, 2) - 1) > .001)
//{
// Console.WriteLine("ERROR: Improper file read. Surface normal is not a unit vector.");
//}
newSurf.normal = norm;
}
应该是
if (i == 0) //<- RIGHT!!!
{
// This is a normal
Vector3d norm = new Vector3d();
norm.X = xCompReal;// * scaleFactor;
norm.Y = yCompReal;// * scaleFactor;
norm.Z = zCompReal;// * scaleFactor;
//if(Math.Abs(Math.Pow(norm.X,2) + Math.Pow(norm.X, 2) + Math.Pow(norm.X, 2) - 1) > .001)
//{
// Console.WriteLine("ERROR: Improper file read. Surface normal is not a unit vector.");
//}
newSurf.normal = norm;
}
我只是交换法线和第一个顶点的值。
关于C# 如何解析 STL 文件。当前函数没有正确地将顶点链接到面中。算法错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68568214/
我一直在使用 AJAX 从我正在创建的网络服务中解析 JSON 数组时遇到问题。我的前端是一个简单的 ajax 和 jquery 组合,用于显示从我正在创建的网络服务返回的结果。 尽管知道我的数据库查
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我在尝试运行 Android 应用程序时遇到问题并收到以下错误 java.lang.NoClassDefFoundError: com.parse.Parse 当我尝试运行该应用时。 最佳答案 在这
有什么办法可以防止etree在解析HTML内容时解析HTML实体吗? html = etree.HTML('&') html.find('.//body').text 这给了我 '&' 但我想
我有一个有点疯狂的例子,但对于那些 JavaScript 函数作用域专家来说,它看起来是一个很好的练习: (function (global) { // our module number one
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 8 年前。 Improve th
我需要编写一个脚本来获取链接并解析链接页面的 HTML 以提取标题和其他一些数据,例如可能是简短的描述,就像您链接到 Facebook 上的内容一样。 当用户向站点添加链接时将调用它,因此在客户端启动
在 VS Code 中本地开发时,包解析为 C:/Users//AppData/Local/Microsoft/TypeScript/3.5/node_modules/@types//index而不是
我在将 json 从 php 解析为 javascript 时遇到问题 这是我的示例代码: //function MethodAjax = function (wsFile, param) {
我在将 json 从 php 解析为 javascript 时遇到问题 这是我的示例代码: //function MethodAjax = function (wsFile, param) {
我被赋予了将一种语言“翻译”成另一种语言的工作。对于使用正则表达式的简单逐行方法来说,源代码过于灵活(复杂)。我在哪里可以了解更多关于词法分析和解析器的信息? 最佳答案 如果你想对这个主题产生“情绪化
您好,我在解析此文本时遇到问题 { { { {[system1];1;1;0.612509325}; {[system2];1;
我正在为 adobe after effects 在 extendscript 中编写一些代码,最终变成了 javascript。 我有一个数组,我想只搜索单词“assemble”并返回整个 jc3_
我有这段代码: $(document).ready(function() { // }); 问题:FB_RequireFeatures block 外部的代码先于其内部的代码执行。因此 who
背景: netcore项目中有些服务是在通过中间件来通信的,比如orleans组件。它里面服务和客户端会指定网关和端口,我们只需要开放客户端给外界,服务端关闭端口。相当于去掉host,这样省掉了些
1.首先贴上我试验成功的代码 复制代码 代码如下: protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
什么是 XML? XML 指可扩展标记语言(eXtensible Markup Language),标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。 你可以通过本站学习 X
【PHP代码】 复制代码 代码如下: $stmt = mssql_init('P__Global_Test', $conn) or die("initialize sto
在SQL查询分析器执行以下代码就可以了。 复制代码代码如下: declare @t varchar(255),@c varchar(255) declare table_cursor curs
前言 最近练习了一些前端算法题,现在做个总结,以下题目都是个人写法,并不是标准答案,如有错误欢迎指出,有对某道题有新的想法的友友也可以在评论区发表想法,互相学习🤭 题目 题目一: 二维数组中的
我是一名优秀的程序员,十分优秀!