* prevent resizing brushes to zero volume by faces drag, try to stop at minimal configuration
This commit is contained in:
parent
2ef794539c
commit
bfc66aa6af
|
|
@ -540,3 +540,49 @@ void Brush::vertexModeSnap( const float snap, bool all ){
|
||||||
vector3_snap( i.m_vertexTransformed, snap );
|
vector3_snap( i.m_vertexTransformed, snap );
|
||||||
vertexModeBuildHull( all );
|
vertexModeBuildHull( all );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "grid.h"
|
||||||
|
void BrushInstance::transformComponents( const Matrix4& matrix ){
|
||||||
|
auto transform = [this]( const Matrix4& matrix ){
|
||||||
|
for ( auto& fi : m_faceInstances )
|
||||||
|
fi.transformComponents( matrix );
|
||||||
|
};
|
||||||
|
|
||||||
|
transform( matrix );
|
||||||
|
|
||||||
|
const Vector3 translation = matrix4_get_translation_vec3( matrix );
|
||||||
|
if( translation != g_vector3_identity ){ //has translation
|
||||||
|
Matrix4 ma( matrix );
|
||||||
|
Vector3& tra = vector4_to_vector3( ma.t() );
|
||||||
|
tra = g_vector3_identity;
|
||||||
|
if( g_matrix4_identity == ma ){ //only translation
|
||||||
|
for ( const auto& fi : m_faceInstances ){
|
||||||
|
if( fi.isSelected() ){ //has faces selected
|
||||||
|
if( !m_brush.contributes() ){ //do binary search of worthy transform
|
||||||
|
for( std::size_t axis = 0; axis < 3; ++axis ){
|
||||||
|
const float grid = translation[axis] < 0? -GetGridSize() : GetGridSize();
|
||||||
|
int maxI = static_cast<int>( translation[axis] / grid + .5f );
|
||||||
|
int minI = 0;
|
||||||
|
while( maxI > minI ){
|
||||||
|
const int curI = minI + ( maxI - minI + 1 ) / 2;
|
||||||
|
tra[axis] = curI * grid;
|
||||||
|
m_brush.revertTransform();
|
||||||
|
transform( ma );
|
||||||
|
if( m_brush.contributes() ){
|
||||||
|
minI = curI;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
maxI = curI - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tra[axis] = minI * grid;
|
||||||
|
}
|
||||||
|
m_brush.revertTransform();
|
||||||
|
transform( ma );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1307,6 +1307,9 @@ const Plane3& plane3() const {
|
||||||
m_observer->evaluateTransform();
|
m_observer->evaluateTransform();
|
||||||
return m_planeTransformed.plane3();
|
return m_planeTransformed.plane3();
|
||||||
}
|
}
|
||||||
|
const Plane3& plane3_() const {
|
||||||
|
return m_planeTransformed.plane3();
|
||||||
|
}
|
||||||
FacePlane& getPlane(){
|
FacePlane& getPlane(){
|
||||||
return m_plane;
|
return m_plane;
|
||||||
}
|
}
|
||||||
|
|
@ -2232,6 +2235,74 @@ void copy( const Brush& other ){
|
||||||
planeChanged();
|
planeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// for the only use to quickly check, if about to be transformed brush makes sense
|
||||||
|
bool contributes() const {
|
||||||
|
/* plane_unique() ripoff, calling no evaluation */
|
||||||
|
auto plane_unique_ = [this]( std::size_t index ) -> bool {
|
||||||
|
// duplicate plane
|
||||||
|
for ( std::size_t i = 0; i < m_faces.size(); ++i )
|
||||||
|
{
|
||||||
|
if ( index != i && !plane3_inside( m_faces[index]->plane3_(), m_faces[i]->plane3_(), index < i ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* windingForClipPlane() ripoff, calling no evaluation */
|
||||||
|
auto windingForClipPlane_ = [this, &plane_unique_]( const Plane3& plane ) -> bool {
|
||||||
|
FixedWinding buffer[2];
|
||||||
|
bool swap = false;
|
||||||
|
|
||||||
|
// get a poly that covers an effectively infinite area
|
||||||
|
Winding_createInfinite( buffer[swap], plane, m_maxWorldCoord );
|
||||||
|
|
||||||
|
// chop the poly by all of the other faces
|
||||||
|
for ( std::size_t i = 0; i < m_faces.size(); ++i )
|
||||||
|
{
|
||||||
|
const Face& clip = *m_faces[i];
|
||||||
|
|
||||||
|
if ( plane3_equal( clip.plane3_(), plane )
|
||||||
|
|| !plane3_valid( clip.plane3_() ) || !plane_unique_( i )
|
||||||
|
|| plane3_opposing( plane, clip.plane3_() ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( buffer[swap].points.empty() ){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[!swap].clear();
|
||||||
|
|
||||||
|
{
|
||||||
|
// flip the plane, because we want to keep the back side
|
||||||
|
Plane3 clipPlane( vector3_negated( clip.plane3_().normal() ), -clip.plane3_().dist() );
|
||||||
|
Winding_Clip( buffer[swap], plane, clipPlane, i, buffer[!swap] );
|
||||||
|
}
|
||||||
|
swap = !swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer[swap].size() > 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
std::size_t contributing = 0;
|
||||||
|
|
||||||
|
for ( std::size_t i = 0; i < m_faces.size(); ++i )
|
||||||
|
{
|
||||||
|
Face& f = *m_faces[i];
|
||||||
|
|
||||||
|
if ( plane3_valid( f.plane3_() ) && plane_unique_( i ) ) {
|
||||||
|
if( windingForClipPlane_( f.plane3_() ) ){
|
||||||
|
++contributing;
|
||||||
|
if( contributing > 3 )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void edge_push_back( FaceVertexId faceVertex ){
|
void edge_push_back( FaceVertexId faceVertex ){
|
||||||
m_select_edges.push_back( SelectableEdge( m_faces, faceVertex ) );
|
m_select_edges.push_back( SelectableEdge( m_faces, faceVertex ) );
|
||||||
|
|
@ -3782,12 +3853,8 @@ void selectVerticesOnTestedFaces( SelectionTest& test ){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void transformComponents( const Matrix4& matrix ){
|
void transformComponents( const Matrix4& matrix );
|
||||||
for ( FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i )
|
|
||||||
{
|
|
||||||
( *i ).transformComponents( matrix );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const AABB& getSelectedComponentsBounds() const {
|
const AABB& getSelectedComponentsBounds() const {
|
||||||
m_aabb_component = AABB();
|
m_aabb_component = AABB();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user