351 lines
9.9 KiB
Plaintext
Executable File
351 lines
9.9 KiB
Plaintext
Executable File
--COVERT
|
|
--COincident VERTex data
|
|
--list of coincident vertices
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--COVERT SUB-STRUCTS
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--struct to represent each coincidence
|
|
struct COVERT_Match
|
|
(
|
|
position = [0,0,0],
|
|
objectList = #() --list of each COVERT_Object items
|
|
)
|
|
|
|
--struct for each object
|
|
struct COVERT_Object
|
|
(
|
|
obj, --an object involved in a coincident vertex data list
|
|
vertList = #{} --coincident vertices
|
|
)
|
|
|
|
struct COVERT_List
|
|
(
|
|
public
|
|
matchList = #(), --array of coincidences
|
|
tolerance = 0.01, --checking distance for coincident vertices
|
|
objList = #(), --list of objects involved with coincident vertices
|
|
|
|
private
|
|
objectEdgeVertList =#(), --working array for processing matchList
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--DATA FUNCTIONS
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--Returns a list of all the objects that have coincident vertices
|
|
fn GetCOVERT_Objects =
|
|
(
|
|
local objectList = #()
|
|
|
|
for match in this.matchList do
|
|
(
|
|
for thisObj in match.objectList do
|
|
(
|
|
if (findItem objectList thisObj.obj) == 0 then
|
|
append objectList thisObj.obj
|
|
)
|
|
)
|
|
|
|
this.objList = objectList
|
|
),
|
|
|
|
|
|
--function tests if two objects are in proximity
|
|
fn ProximityTest obj1 obj2 =
|
|
(
|
|
local proximity = false
|
|
|
|
if (obj1.min.x <= obj2.max.x and obj1.min.y <= obj2.max.y and obj1.min.z <= obj2.max.z) then
|
|
(
|
|
if (obj1.max.x >= obj2.min.x and obj1.max.y >= obj2.min.y and obj1.max.z >= obj2.min.z) then
|
|
(
|
|
proximity = true
|
|
)
|
|
)
|
|
|
|
return proximity
|
|
),
|
|
|
|
|
|
--function removes entries in the objectEdgeVertList array that are not proximal
|
|
fn ProximityCull =
|
|
(
|
|
local validNodes = #()
|
|
|
|
for item in this.objectEdgeVertList do
|
|
(
|
|
for comparison in this.objectEdgeVertList where (item != comparison) do
|
|
(
|
|
if (this.ProximityTest item.obj comparison.obj) then
|
|
(
|
|
appendIfUnique validNodes item
|
|
)
|
|
)
|
|
)
|
|
|
|
this.objectEdgeVertList = validNodes
|
|
),
|
|
|
|
--Once a coincidence is found, this function adds the object/id to the data
|
|
fn AppendMatchList position obj1 id1 obj2 id2 =
|
|
(
|
|
--check to see if the coincidence already exists
|
|
local found = false
|
|
|
|
for match in this.matchList do
|
|
(
|
|
if (distance match.position position < this.tolerance) then
|
|
(
|
|
found = true
|
|
|
|
--append the coincidence with the object/id's
|
|
this.AppendExistingMatch &match obj1 id1
|
|
this.AppendExistingMatch &match obj2 id2
|
|
)
|
|
)
|
|
|
|
--if it doesn't exist, create a new match item
|
|
if (not found) then
|
|
(
|
|
local newCOVERT_Match
|
|
|
|
--if the vertex match is on a single object
|
|
if (obj1.handle == obj2.handle) then
|
|
(
|
|
local newCOVERT_Object = COVERT_Object obj1 vertList:#{id1, id2}
|
|
newCOVERT_Match = COVERT_Match position:position objectList:#(newCOVERT_Object)
|
|
)
|
|
else -- the match is on separate objects
|
|
(
|
|
local COVERT_Object1 = COVERT_Object obj:obj1 vertList:#{id1}
|
|
local COVERT_Object2 = COVERT_Object obj:obj2 vertList:#{id2}
|
|
newCOVERT_Match = COVERT_Match position:position objectList:#(COVERT_Object1, COVERT_Object2)
|
|
)
|
|
|
|
append this.matchList newCOVERT_Match
|
|
)
|
|
),
|
|
|
|
--if the new coincidence matches with an existing coincidence, this function appends the coincidence item
|
|
--called exclusively from AppendMatchList
|
|
fn AppendExistingMatch &match newObj newID =
|
|
(
|
|
local foundObject = false
|
|
|
|
for objItem in match.objectList do
|
|
(
|
|
if (objItem.obj.handle == newObj.handle) then
|
|
(
|
|
--object found, so append the idList
|
|
local foundVertex = false
|
|
|
|
for id in objItem.vertList do
|
|
(
|
|
if (id == newID) then foundVertex = true
|
|
--don't need to add as we have already noted this vertex
|
|
)
|
|
|
|
if (not foundVertex) then
|
|
(
|
|
append objItem.vertList newID
|
|
)
|
|
|
|
foundObject = true
|
|
)
|
|
)
|
|
|
|
if (not foundObject) then
|
|
(
|
|
--add a new object/id for this position
|
|
append match.objectList (COVERT_Object obj:newObj vertList:#{newID})
|
|
)
|
|
),
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--PUBLIC FUNCTIONS
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
public
|
|
|
|
--function to process passed nodes into coincidences in the matchList array
|
|
--nodes: geometry objects
|
|
--return: list of COVERT_Match objects
|
|
fn InitCOVERT_List nodes =
|
|
(
|
|
local objSet = for this in nodes where superClassOf this == GeometryClass collect this
|
|
|
|
clearListener()
|
|
|
|
if (objSet.count > 0) then
|
|
(
|
|
for item in objSet do
|
|
(
|
|
local openEdgeList
|
|
local edgeVertList
|
|
local vertPositionList = #()
|
|
local idPositionList = #()
|
|
|
|
convertToPoly item
|
|
openEdgeList = polyop.getOpenEdges item
|
|
edgeVertList = polyop.getVertsUsingEdge item openEdgeList
|
|
|
|
for id in (edgeVertList as array) do
|
|
append idPositionList (dataPair id:id position:item.verts[id].position)
|
|
|
|
newObject = dataPair obj:item data:idPositionList
|
|
append this.objectEdgeVertList newObject
|
|
)
|
|
|
|
--test the objectEdgeVertList for coincident verts
|
|
-- this.PrintObjectEdgeVertList()
|
|
|
|
--test for coincident verts on single objects
|
|
for item in objectEdgeVertList do
|
|
(
|
|
for pair in item.data do
|
|
(
|
|
for compare in item.data where pair != compare do
|
|
(
|
|
if (distance pair.position compare.position) < this.tolerance then
|
|
this.AppendMatchList pair.position item.obj pair.id item.obj compare.id
|
|
)
|
|
)
|
|
)
|
|
|
|
--compare objects for coincident verts
|
|
--get a set of objects that are close enough to each other to have coincident vertices
|
|
this.ProximityCull()
|
|
|
|
local numObjs = objectEdgeVertList.count
|
|
|
|
if (objectEdgeVertList.count > 1) then
|
|
(
|
|
for i = 1 to numObjs do
|
|
(
|
|
for j = i + 1 to numObjs do
|
|
(
|
|
if (this.ProximityTest objectEdgeVertList[i].obj objectEdgeVertList[j].obj) then
|
|
(
|
|
for item in objectEdgeVertList[i].data do
|
|
(
|
|
local vertPosition = item.position
|
|
|
|
for test in objectEdgeVertList[j].data do
|
|
(
|
|
if distance item.position test.position < this.tolerance then
|
|
(
|
|
this.AppendMatchList item.position objectEdgeVertList[i].obj item.id objectEdgeVertList[j].obj test.id
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
else print "Please select a valid object."
|
|
|
|
--if we have coincident vertices, get the face data
|
|
if (this.matchList.count > 0) then
|
|
(
|
|
this.GetCOVERT_Objects()
|
|
return true
|
|
)
|
|
else return false
|
|
),
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--PRINT FUNCTIONS
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
fn PrintObjectEdgeVertList =
|
|
(
|
|
for item in this.objectEdgeVertList do
|
|
(
|
|
format "Name: %\n" item.obj.name
|
|
for this in item.data do
|
|
(
|
|
format "id: %\t%\n" this.id this.position
|
|
)
|
|
format "\n"
|
|
)
|
|
),
|
|
|
|
fn PrintCOVERT_List =
|
|
(
|
|
for match in this.matchList do
|
|
(
|
|
format "Position: %\n" match.position
|
|
for object in match.objectList do
|
|
(
|
|
format "Object: %\t" object.obj.name
|
|
format "IDs: "
|
|
for id in object.vertList do
|
|
(
|
|
format "% " id
|
|
)
|
|
format "\n"
|
|
)
|
|
format "\n"
|
|
)
|
|
|
|
format "Objects: %" this.objList[1].name
|
|
|
|
for object in this.objList where object != this.objList[1] do
|
|
(
|
|
format ", %" object.name
|
|
)
|
|
format "\n"
|
|
format "Tolerance: %\n" this.tolerance
|
|
)
|
|
)
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--OBJDATA COMMANDS
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
fn OBJDATA_GetVertNormsUsingSmoothingGroups obj vert =
|
|
(
|
|
local faces = (polyop.getFacesUsingVert obj #{vert}) as array
|
|
local OBJDATA_NormalList = #()
|
|
local groupedList = this.GroupFacesBySmoothingGroup obj faces
|
|
|
|
-- go through each list member and get the average normal
|
|
for item in groupedList do
|
|
(
|
|
local vertexNormal = [0,0,0]
|
|
local normalOp --alias for normal operation
|
|
|
|
if (classOf obj == editable_mesh) then
|
|
normalOp = getFaceNormal
|
|
else
|
|
normalOp = polyop.getFaceNormal
|
|
|
|
for id in item.faceids do
|
|
(
|
|
vertexNormal += normalOp obj id
|
|
)
|
|
|
|
append OBJDATA_NormalList (OBJDATA_Normal vector:(normalize vertexNormal) smoothingGroups:item.smoothingGroups vertexID:vert faceList:item.faceids)
|
|
)
|
|
|
|
return OBJDATA_NormalList
|
|
)
|
|
|
|
--structure used by OBJDATA_Ops.GetSmoothingGroupsUsingNormals <obj> <vertex>
|
|
struct OBJDATA_Normal
|
|
(
|
|
vector = [0,0,0],
|
|
smoothingGroups = #{},
|
|
vertexID,
|
|
faceID
|
|
)
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--TEST COMMANDS
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
-- timeValue = timestamp()
|
|
-- COVERT = COVERT_List()
|
|
-- COVERT.InitCOVERT_List (selection as array)
|
|
-- COVERT.PrintCOVERT_List()
|
|
-- format (((timestamp() - timeValue) as float / 1000) as string + " seconds\n") |