# coding: utf-8
#
# Copyright © 2020 MSC.Software Corporation
#  
# Permission to use Scripts
#  
# Permission is granted to MSC.Software customers with valid licenses of the MSC Apex™ software 
# to use script files posted on this page (collectively “Scripts”) solely for customers’ own authorized 
# internal use in conjunction with licensed use of the MSC Apex software.  
# No other use is permitted.  No license to MSC Apex or other software is granted under this Permission.
#  
# SCRIPTS ARE PROVIDED ON AN "AS-IS" BASIS, WITH NO WARRANTIES OF ANY KIND.  USE OF THE SCRIPTS IS AT CUSTOMER'S SOLE RISK.
#  
# IN NO EVENT SHALL MSC.SOFTWARE CORPORATION, ITS AFFILIATES, SUBSIDIARIES, SUPPLIERS, AGENTS, REPRESENTATIVES OR EMPLOYEES BE LIABLE FOR ANY 
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, TORT, 
# STRICT LIABILITY, OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION USE OF THE SCRIPTS, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
#  
# Customer shall indemnify, defend and hold MSC.Software Corporation, its affiliates, subsidiaries, suppliers, agents, 
# employees or representatives (collectively, “Indemnified Parties”) harmless from and against any third-party claims 
# brought against Indemnified Parties rising out of or in connection with Customer’s use of the Scripts.
#

# Author: Larry Pearce
# Revised by: Larry Pearce
# Revision History
# Date         Change                                 By
# 2020-10-12   Original code (1.0)                    Larry Pearce

import apex

from operator import itemgetter

#tol = .0001
#deleteOnlyInCommonPart = False

def main(dict={}):
    tol = float(dict["tol"])
    if dict["deleteOnlyInCommonPart"].lower() == "true":
        deleteOnlyInCommonPart = True
    else:
        deleteOnlyInCommonPart = False

    print("Tolerance: "+str(tol))
    print("Delete only if in common Part: "+str(deleteOnlyInCommonPart))

    apex.setScriptUnitSystem(unitSystemName = r'''in-slinch-s-lbf''')
    myModel = apex.currentModel()

    parts = myModel.getParts(True)
    allSurfs = apex.entityCollection()
    for part in parts:
        surfs = part.getSurfaces()
        if surfs.len() > 0: allSurfs += surfs

    allFaces = []
    k = 0
    for surf in allSurfs:
        faces = surf.getFaces()
        nFaces = faces.len()

        for face in faces:
            area  = face.getArea()
            loc   = face.getCentroid()
            edges = face.getEdges()
            verts = face.getVertices()

            allFaces.append([k, face, area, loc, edges.len(), edges, verts.len(), verts, nFaces, surf, surf.getParent(), False])
            k += 1

    kID     = 0
    kFace   = 1
    kArea   = 2
    kLoc    = 3
    kNEdges = 4
    kEdges  = 5
    kNVerts = 6
    kVerts  = 7
    kNFaces = 8
    kSurf   = 9
    kPart   = 10
    kIsDeleted = 11

    fData = sorted(allFaces, key=itemgetter(kArea)) # 1 is area

    numDeletedSurfs = 0
    numDeletedFaces = 0

    for d1 in fData:
        if d1[kIsDeleted]: continue
        d1Edges = apex.IPhysicalCollection()
        for edge in d1[kEdges]:
            d1Edges.append(edge)
        edgeSearch = apex.utility.ProximitySearch()
        edgeSearch.insertCollection(d1Edges)
        for d2 in fData:
            if d2[kIsDeleted]:     continue
            if d1[kID] == d2[kID]: continue

            if deleteOnlyInCommonPart:
                if d1[kPart].getFullName() != d2[kPart].getFullName(): continue

            delta = abs(d1[kArea] - d2[kArea])
            if delta > tol: continue

            dist  = (d1[kLoc].getX() - d2[kLoc].getX())**2
            dist += (d1[kLoc].getY() - d2[kLoc].getY())**2
            dist += (d1[kLoc].getZ() - d2[kLoc].getZ())**2
            if dist > tol: continue

            if d1[kNEdges] - d2[kNEdges] != 0: continue
            if d1[kNVerts] - d2[kNVerts] != 0: continue

            # check edges
            edgeMismatch = False
            for edge in d2[kEdges]:
                loc = edge.getMidPoint()
                nearObj = edgeSearch.findNearestObject(loc)
                dist = nearObj.getDistance()
                if dist > tol:
                    edgeMismatch = True
                    break
                d2Length = edge.getLength()
                nearEdge = nearObj.getNearestObject().asEdge()
                d1Length = nearEdge.getLength()
                if abs(d2Length - d1Length) > tol:
                    edgeMismatch = True
                    break
            if edgeMismatch: continue

            # check vertices.  not checking vertices yet.  not sure if I need to.

            entsToDelete = apex.entityCollection()
            if d2[kNFaces] == 1:
                entsToDelete.append(d2[kSurf])
                d2[kIsDeleted] = True
                numDeletedSurfs += 1
                apex.deleteEntities(entsToDelete)
            else:
                entsToDelete.append(d1[kFace])
                d1[kIsDeleted] = True
                numDeletedFaces += 1
                apex.deleteEntities(entsToDelete)
                break # get a new d1

    print("Deleted Surfaces: "+str(numDeletedSurfs))
    print("Deleted Faces: "+str(numDeletedFaces))
