Getting 'normal vector' of non-planar surface

Getting 'normal vector' of non-planar surface

R.Gerritsen4967
Advocate Advocate
1,610 Views
8 Replies
Message 1 of 9

Getting 'normal vector' of non-planar surface

R.Gerritsen4967
Advocate
Advocate

I'm trying to indicate the direction for a thicken operation on a surface by drawing temporary vectors in the editor.

For planar surfaces I can use:

surface.getplane.normal

But (obviously) this does not work on non-planar surfaces.

 

Is there a way to determine the direction for the thickening operation?

0 Likes
Accepted solutions (1)
1,611 Views
8 Replies
Replies (8)
Message 2 of 9

Alexander.Rivilis
Mentor
Mentor

Every point on surface has owned 'normal vector'. Maybe this article help you: https://adndevblog.typepad.com/autocad/2012/07/retrieving-a-solid3d-face-normal-through-brep-api.htm...

Відповідь корисна? Клікніть на "ВПОДОБАЙКУ" цім повідомленням! | Do you find the posts helpful? "LIKE" these posts!
Находите сообщения полезными? Поставьте "НРАВИТСЯ" этим сообщениям!
На ваше запитання відповіли? Натисніть кнопку "ПРИЙНЯТИ РІШЕННЯ" | Have your question been answered successfully? Click "ACCEPT SOLUTION" button.
На ваш вопрос успешно ответили? Нажмите кнопку "УТВЕРДИТЬ РЕШЕНИЕ"


Alexander Rivilis / Александр Ривилис / Олександр Рівіліс
Programmer & Teacher & Helper / Программист - Учитель - Помощник / Програміст - вчитель - помічник
Facebook | Twitter | LinkedIn
Expert Elite Member

0 Likes
Message 3 of 9

R.Gerritsen4967
Advocate
Advocate

Thanks Alexander, I'll look into it.

Do you know a way to access the surface with the brep api?

0 Likes
Message 4 of 9

Alexander.Rivilis
Mentor
Mentor

As far as I remember BREP API can work with Surface: https://adndevblog.typepad.com/autocad/2012/08/retrieving-native-curve-geometry-using-brep-api.html

 

Відповідь корисна? Клікніть на "ВПОДОБАЙКУ" цім повідомленням! | Do you find the posts helpful? "LIKE" these posts!
Находите сообщения полезными? Поставьте "НРАВИТСЯ" этим сообщениям!
На ваше запитання відповіли? Натисніть кнопку "ПРИЙНЯТИ РІШЕННЯ" | Have your question been answered successfully? Click "ACCEPT SOLUTION" button.
На ваш вопрос успешно ответили? Нажмите кнопку "УТВЕРДИТЬ РЕШЕНИЕ"


Alexander Rivilis / Александр Ривилис / Олександр Рівіліс
Programmer & Teacher & Helper / Программист - Учитель - Помощник / Програміст - вчитель - помічник
Facebook | Twitter | LinkedIn
Expert Elite Member

0 Likes
Message 5 of 9

Alexander.Rivilis
Mentor
Mentor

Other way is creating Solid3d from Surface with method  Solid3d.CreateFrom(...)

Відповідь корисна? Клікніть на "ВПОДОБАЙКУ" цім повідомленням! | Do you find the posts helpful? "LIKE" these posts!
Находите сообщения полезными? Поставьте "НРАВИТСЯ" этим сообщениям!
На ваше запитання відповіли? Натисніть кнопку "ПРИЙНЯТИ РІШЕННЯ" | Have your question been answered successfully? Click "ACCEPT SOLUTION" button.
На ваш вопрос успешно ответили? Нажмите кнопку "УТВЕРДИТЬ РЕШЕНИЕ"


Alexander Rivilis / Александр Ривилис / Олександр Рівіліс
Programmer & Teacher & Helper / Программист - Учитель - Помощник / Програміст - вчитель - помічник
Facebook | Twitter | LinkedIn
Expert Elite Member

0 Likes
Message 6 of 9

R.Gerritsen4967
Advocate
Advocate

Unfortunately this gives me an error.

However I've made some progression with the other links you provided.

 

Instead of Solid3d.CreateFrom(...), i now use a temporary solid made with thicken from the surface. (because a surface does not seem to have a face)

Then I use a face (the original surface) of the temp solid to determine a normal vector of the edges.

But as far as I can see, all the edges have different normal vectors.

Only points on the surface(not on the edges) have a usable normal vector. but this normal vector is not always the real normal vector unfortunately...

My code is a real mess now, so I'll do some cleaning up and try to find a working solution.

 

I have also tried to access the curve geometry of the edges of the surface (your 2nd link). But those curves don't seem to have anything like a 'normal' property.

0 Likes
Message 7 of 9

Alexander.Rivilis
Mentor
Mentor

@R.Gerritsen4967 wrote:

 

I have also tried to access the curve geometry of the edges of the surface (your 2nd link). But those curves don't seem to have anything like a 'normal' property.


Second link is only to see that it is possible to get Brep from Surface directly.

Відповідь корисна? Клікніть на "ВПОДОБАЙКУ" цім повідомленням! | Do you find the posts helpful? "LIKE" these posts!
Находите сообщения полезными? Поставьте "НРАВИТСЯ" этим сообщениям!
На ваше запитання відповіли? Натисніть кнопку "ПРИЙНЯТИ РІШЕННЯ" | Have your question been answered successfully? Click "ACCEPT SOLUTION" button.
На ваш вопрос успешно ответили? Нажмите кнопку "УТВЕРДИТЬ РЕШЕНИЕ"


Alexander Rivilis / Александр Ривилис / Олександр Рівіліс
Programmer & Teacher & Helper / Программист - Учитель - Помощник / Програміст - вчитель - помічник
Facebook | Twitter | LinkedIn
Expert Elite Member

0 Likes
Message 8 of 9

R.Gerritsen4967
Advocate
Advocate
@Alexander.Rivilis wrote:

Brep from Surface directly.

Ok. Thanks. I guess I misunderstood...;)

 

I think I have now solved the problem.

In a part of my code I was breaking down a surface into nurbs (according to https://through-the-interface.typepad.com/through_the_interface/2011/02/gathering-points-defining-3d... ) to access points across the surface.

I just found out that nurbs have a normal property which I can use directly.

So now I'm able to draw temp vectors in the direction of the surface 'normal'.

 

vectors.png

 

0 Likes
Message 9 of 9

R.Gerritsen4967
Advocate
Advocate
Accepted solution

OK, I cleaned up my code a bit.

Here is a function to draw temp vectors in the normal direction of a surface:

 

 

<CommandMethod("THICKEN3D", CommandFlags.Modal)> Public Shared Sub THICKEN3D()
Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
Dim ed As Editor = doc.Editor
Dim db As Database = doc.Database
Dim peo As New PromptEntityOptions(vbLf & "Select surface:")
peo.SetRejectMessage(vbLf & "Needs to be a SURFACE!")
peo.AddAllowedClass(GetType(Autodesk.AutoCAD.DatabaseServices.Surface), True)
peo.AddAllowedClass(GetType(Autodesk.AutoCAD.DatabaseServices.PlaneSurface), True)
peo.AddAllowedClass(GetType(Autodesk.AutoCAD.DatabaseServices.ExtrudedSurface), True)
peo.AddAllowedClass(GetType(Autodesk.AutoCAD.DatabaseServices.SweptSurface), True)
peo.AddAllowedClass(GetType(Autodesk.AutoCAD.DatabaseServices.LoftedSurface), True)
peo.AddAllowedClass(GetType(Autodesk.AutoCAD.DatabaseServices.RevolvedSurface), True)
peo.AddAllowedClass(GetType(Autodesk.AutoCAD.DatabaseServices.NurbSurface), True)
Dim per As PromptEntityResult = ed.GetEntity(peo)
If per.Status <> PromptStatus.OK Then Return
        Using trx As Transaction = db.TransactionManager.StartTransaction()
            Dim btr As BlockTableRecord = TryCast(trx.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)
            Dim ent As Entity = TryCast(trx.GetObject(per.ObjectId, OpenMode.ForWrite), Entity)

            Dim solPlate As New Solid3d With {
                .RecordHistory = True
            }
            Dim Thickness As Double = Nothing

            If TypeOf ent Is Autodesk.AutoCAD.DatabaseServices.Surface Then
                Try
                    Dim srf As Autodesk.AutoCAD.DatabaseServices.Surface = TryCast(trx.GetObject(per.ObjectId, OpenMode.ForWrite), Autodesk.AutoCAD.DatabaseServices.Surface)
                    ExtrusionVectors(srf)

                    Thickness = SelDbl("Thickness: ")
                    If Thickness = Nothing Then Exit Sub

                    solPlate = srf.Thicken(Thickness, False)
                    btr.AppendEntity(solPlate)
                    trx.AddNewlyCreatedDBObject(solPlate, True)

                Catch ModelingFailure As Autodesk.AutoCAD.Runtime.Exception When ModelingFailure.Message = "eGeneralModelingFailure"
                    ed.WriteMessage(vbLf & "Probably a self-intersecting surface...")
                    trx.Abort()
                    Return

                End Try

            End If

            ent.Erase()
            trx.Commit()
        End Using
    End Sub

Public Shared Sub ExtrusionVectors(srf As Autodesk.AutoCAD.DatabaseServices.Surface)
        'https://through-the-interface.typepad.com/through_the_interface/2011/02/gathering-points-defining-3d-autocad-geometry-using-net.html

Dim ed As Editor = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor
Dim vec_size As Double = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("VIEWSIZE") / 10 
Dim cross_size As Double = vec_size / 10
Dim nurbs As Autodesk.AutoCAD.DatabaseServices.NurbSurface() = srf.ConvertToNurbSurface

For Each nurb As Autodesk.AutoCAD.DatabaseServices.NurbSurface In nurbs
     Dim ustart As Double = nurb.UKnots.StartParameter, uend As Double = nurb.UKnots.EndParameter, uinc As Double = 2 * (uend - ustart) / nurb.UKnots.Count, vstart As Double = nurb.VKnots.StartParameter, vend As Double = nurb.VKnots.EndParameter, vinc As Double = 2 * (vend - vstart) / nurb.VKnots.Count
            Dim u As Double = ustart

            While u <= uend
                Dim v As Double = vstart

                While v <= vend
                    Dim vec As Vector3d = nurb.GetNormal(u, v) * vec_size
                    If Not vec = Nothing Then
                        Dim pt2 As Point3d = nurb.Evaluate(u, v).TransformBy(Matrix3d.Displacement(vec))
                        ed.DrawVector(nurb.Evaluate(u, v), pt2, 6, True)
                        ed.DrawVector(New Point3d(pt2.X - cross_size, pt2.Y - cross_size, pt2.Z), New Point3d(pt2.X + cross_size, pt2.Y + cross_size, pt2.Z), 6, False)
                        ed.DrawVector(New Point3d(pt2.X - cross_size, pt2.Y + cross_size, pt2.Z), New Point3d(pt2.X + cross_size, pt2.Y - cross_size, pt2.Z), 6, False)
                    End If

                    v += vinc
                End While

                u += uinc
            End While
        Next

    End Sub

 

0 Likes