147 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
 | 
						|
/*
 | 
						|
-----------------------------------------------------------------------------
 | 
						|
This source file is part of GIMPACT Library.
 | 
						|
 | 
						|
For the latest info, see http://gimpact.sourceforge.net/
 | 
						|
 | 
						|
Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
 | 
						|
email: projectileman@yahoo.com
 | 
						|
 | 
						|
 This library is free software; you can redistribute it and/or
 | 
						|
 modify it under the terms of EITHER:
 | 
						|
   (1) The GNU Lesser General Public License as published by the Free
 | 
						|
       Software Foundation; either version 2.1 of the License, or (at
 | 
						|
       your option) any later version. The text of the GNU Lesser
 | 
						|
       General Public License is included with this library in the
 | 
						|
       file GIMPACT-LICENSE-LGPL.TXT.
 | 
						|
   (2) The BSD-style license that is included with this library in
 | 
						|
       the file GIMPACT-LICENSE-BSD.TXT.
 | 
						|
   (3) The zlib/libpng license that is included with this library in
 | 
						|
       the file GIMPACT-LICENSE-ZLIB.TXT.
 | 
						|
 | 
						|
 This library is distributed in the hope that it will be useful,
 | 
						|
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
 | 
						|
 GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
 | 
						|
 | 
						|
-----------------------------------------------------------------------------
 | 
						|
*/
 | 
						|
 | 
						|
#include "gim_contact.h"
 | 
						|
 | 
						|
#define MAX_COINCIDENT 8
 | 
						|
 | 
						|
void gim_contact_array::merge_contacts(
 | 
						|
	const gim_contact_array & contacts, bool normal_contact_average)
 | 
						|
{
 | 
						|
	clear();
 | 
						|
 | 
						|
	if(contacts.size()==1)
 | 
						|
	{
 | 
						|
		push_back(contacts.back());
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	gim_array<GIM_RSORT_TOKEN> keycontacts(contacts.size());
 | 
						|
	keycontacts.resize(contacts.size(),false);
 | 
						|
 | 
						|
	//fill key contacts
 | 
						|
 | 
						|
	GUINT i;
 | 
						|
 | 
						|
	for (i = 0;i<contacts.size() ;i++ )
 | 
						|
	{
 | 
						|
		keycontacts[i].m_key = contacts[i].calc_key_contact();
 | 
						|
		keycontacts[i].m_value = i;
 | 
						|
	}
 | 
						|
 | 
						|
	//sort keys
 | 
						|
	gim_heap_sort(keycontacts.pointer(),keycontacts.size(),GIM_RSORT_TOKEN_COMPARATOR());
 | 
						|
 | 
						|
	// Merge contacts
 | 
						|
 | 
						|
	GUINT coincident_count=0;
 | 
						|
	btVector3 coincident_normals[MAX_COINCIDENT];
 | 
						|
 | 
						|
	GUINT last_key = keycontacts[0].m_key;
 | 
						|
	GUINT key = 0;
 | 
						|
 | 
						|
	push_back(contacts[keycontacts[0].m_value]);
 | 
						|
	GIM_CONTACT * pcontact = &back();
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	for( i=1;i<keycontacts.size();i++)
 | 
						|
	{
 | 
						|
	    key = keycontacts[i].m_key;
 | 
						|
		const GIM_CONTACT * scontact = &contacts[keycontacts[i].m_value];
 | 
						|
 | 
						|
		if(last_key ==  key)//same points
 | 
						|
		{
 | 
						|
			//merge contact
 | 
						|
			if(pcontact->m_depth - CONTACT_DIFF_EPSILON > scontact->m_depth)//)
 | 
						|
			{
 | 
						|
				*pcontact = *scontact;
 | 
						|
                coincident_count = 0;
 | 
						|
			}
 | 
						|
			else if(normal_contact_average)
 | 
						|
			{
 | 
						|
				if(btFabs(pcontact->m_depth - scontact->m_depth)<CONTACT_DIFF_EPSILON)
 | 
						|
                {
 | 
						|
                    if(coincident_count<MAX_COINCIDENT)
 | 
						|
                    {
 | 
						|
                    	coincident_normals[coincident_count] = scontact->m_normal;
 | 
						|
                        coincident_count++;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{//add new contact
 | 
						|
 | 
						|
		    if(normal_contact_average && coincident_count>0)
 | 
						|
		    {
 | 
						|
		    	pcontact->interpolate_normals(coincident_normals,coincident_count);
 | 
						|
		        coincident_count = 0;
 | 
						|
		    }
 | 
						|
 | 
						|
		    push_back(*scontact);
 | 
						|
		    pcontact = &back();
 | 
						|
        }
 | 
						|
		last_key = key;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void gim_contact_array::merge_contacts_unique(const gim_contact_array & contacts)
 | 
						|
{
 | 
						|
	clear();
 | 
						|
 | 
						|
	if(contacts.size()==1)
 | 
						|
	{
 | 
						|
		push_back(contacts.back());
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	GIM_CONTACT average_contact = contacts.back();
 | 
						|
 | 
						|
	for (GUINT i=1;i<contacts.size() ;i++ )
 | 
						|
	{
 | 
						|
		average_contact.m_point += contacts[i].m_point;
 | 
						|
		average_contact.m_normal += contacts[i].m_normal * contacts[i].m_depth;
 | 
						|
	}
 | 
						|
 | 
						|
	//divide
 | 
						|
	GREAL divide_average = 1.0f/((GREAL)contacts.size());
 | 
						|
 | 
						|
	average_contact.m_point *= divide_average;
 | 
						|
 | 
						|
	average_contact.m_normal *= divide_average;
 | 
						|
 | 
						|
	average_contact.m_depth = average_contact.m_normal.length();
 | 
						|
 | 
						|
	average_contact.m_normal /= average_contact.m_depth;
 | 
						|
 | 
						|
}
 | 
						|
 |