Modeling: Connect Vertex Pair does not work when coordinates are large #113111

Open
opened 2023-10-01 13:09:38 +02:00 by Peng Yan · 10 comments
Contributor

This bug is found by @1D_inc. Thank him for providing the .blend file.

System Information
Operating system: Windows 10
Graphics card: NVIDIA RTX 2060

Blender Version
Broken: 3.5 / 4.1 alpha

Short description of error
connect vertex pair/connect vertex path does not work if the coordinates of the vertex pair are large

Exact steps for others to reproduce the error
1.Open the attached .blend file, two vertices are already selected in edit mode
2.use shortcut J to connect them, you'll get a "could not connect vertices" error message.
3. if you move all vertices a little bit (in edit mode!), the operator may or may not work.
4.try some other vertex pairs in the file, the operator may or may not work.

This bug is found by @1D_inc. Thank him for providing the .blend file. **System Information** Operating system: Windows 10 Graphics card: NVIDIA RTX 2060 **Blender Version** Broken: 3.5 / 4.1 alpha **Short description of error** connect vertex pair/connect vertex path does not work if the coordinates of the vertex pair are large **Exact steps for others to reproduce the error** 1.Open the attached .blend file, two vertices are already selected in edit mode 2.use shortcut J to connect them, you'll get a "could not connect vertices" error message. 3. if you move all vertices a little bit (in edit mode!), the operator may or may not work. 4.try some other vertex pairs in the file, the operator may or may not work.
Peng Yan added the
Priority
Normal
Type
Report
Status
Needs Triage
labels 2023-10-01 13:09:39 +02:00
Author
Contributor

The bug is caused by the constant CONNECT_EPS in bmo_connect_pair.cc. CONNECT_EPS is currently set to 0.0001. It is a threshold checking if the path passes through a vertex exactly. When the coordinates are large ( > 1000), float is not enough to accommodate so many decimal places. Sometimes the threshold will be exceeded, so the path may be unable to find the end point.

The bug is caused by the constant CONNECT_EPS in bmo_connect_pair.cc. CONNECT_EPS is currently set to 0.0001. It is a threshold checking if the path passes through a vertex exactly. When the coordinates are large ( > 1000), float is not enough to accommodate so many decimal places. Sometimes the threshold will be exceeded, so the path may be unable to find the end point.
Author
Contributor

I've written a python script to move the objects around and test this operator. Here are some scatter plot data I got. Note that Diff in the plots is the float variable defined in state_isect_co_exact(). It is the distance between the path and the vertex. Every plot gets 100 × 100 points in an xy grid.

From the first plot, the offset is set to -0.01 in x and -0.01 in y. The Diff does not show a clear feature. If you move the object around, you'll get 0.0000, +0.00024, -0.00024 as Diff.

In the second plot, the offset is set to -10 in x and 30 in y. In the third plot, the offset is set to 200 in x and 200 in y. It shows that if the coordinates are larger, the abs(Diff) is likely to be larger.

I've written a python script to move the objects around and test this operator. Here are some scatter plot data I got. Note that **Diff** in the plots is the float variable defined in state_isect_co_exact(). It is the distance between the path and the vertex. Every plot gets 100 × 100 points in an xy grid. From the first plot, the offset is set to -0.01 in x and -0.01 in y. The Diff does not show a clear feature. If you move the object around, you'll get 0.0000, +0.00024, -0.00024 as Diff. In the second plot, the offset is set to -10 in x and 30 in y. In the third plot, the offset is set to 200 in x and 200 in y. It shows that if the coordinates are larger, the abs(Diff) is likely to be larger.
Author
Contributor

A reasonable fix is to make CONNECT_EPS proportional to the (max abs) coordinate of the vertex pair. Again thanks @1D_inc for the idea. I'll work on this.

A reasonable fix is to make CONNECT_EPS proportional to the (max abs) coordinate of the vertex pair. Again thanks @1D_inc for the idea. I'll work on this.
Member

Hi, thanks for the report. If I understand correctly, operator is expected to split faces by connecting selected data with edges.
As long as selected vertices are not sharing any faces (so line can pass through it), the operation will fail, I believe.

does not work if the coordinates of the vertex pair are large

I brought the mesh near origin but it is still failing. Does it work for you when cords of vertices are near world origin?
Guess this is not a bug.

Hi, thanks for the report. If I understand correctly, operator is expected to split faces by connecting selected data with edges. As long as selected vertices are not sharing any faces (so line can pass through it), the operation will fail, I believe. > does not work if the coordinates of the vertex pair are large I brought the mesh near origin but it is still failing. Does it work for you when cords of vertices are near world origin? Guess this is not a bug.
Pratik Borhade added
Status
Needs Information from User
and removed
Status
Needs Triage
labels 2023-10-02 12:04:31 +02:00
Author
Contributor

As long as selected vertices are not sharing any faces (so line can pass through it), the operation will fail, I believe.

The operator (Vertex/Connect Vertex Path or Vertex/Connect Vertex Pair) is not simply splitting a single face by connecting two vertices. It can find a linear path between two vertices and split all faces on the path. It is powered by BMesh Operator "connect_vert_pair" in bmo_connect_pair.cc.

I brought the mesh near origin but it is still failing. Does it work for you when cords of vertices are near world origin?

Sorry I didn't explain it clearly. You can move all vertices to the world origin in edit mode. When the intrinsic coordinates of the vertices get smaller, the operator works well.

> As long as selected vertices are not sharing any faces (so line can pass through it), the operation will fail, I believe. The operator (Vertex/Connect Vertex Path or Vertex/Connect Vertex Pair) is not simply splitting a single face by connecting two vertices. It can find a linear path between two vertices and split all faces on the path. It is powered by BMesh Operator "connect_vert_pair" in bmo_connect_pair.cc. > I brought the mesh near origin but it is still failing. Does it work for you when cords of vertices are near world origin? Sorry I didn't explain it clearly. You can move all vertices to the world origin in edit mode. When the intrinsic coordinates of the vertices get smaller, the operator works well.
Pratik Borhade added
Status
Needs Triage
and removed
Status
Needs Information from User
labels 2023-10-02 13:03:18 +02:00
Member

Confirming this for now (even if in the grey-zone between bug and request for improved behavior)

A reasonable fix is to make CONNECT_EPS proportional to the (max abs) coordinate of the vertex pair. Again thanks @1D_inc for the idea. I'll work on this.

Seems reasonable.

Something like this seems to work just fine:


diff --git a/source/blender/bmesh/operators/bmo_connect_pair.cc b/source/blender/bmesh/operators/bmo_connect_pair.cc
index a651ed5345a..2b2c22c4a17 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.cc
+++ b/source/blender/bmesh/operators/bmo_connect_pair.cc
@@ -40,7 +40,7 @@
  * - run the standard connect operator.
  */
 
-#define CONNECT_EPS 0.0001f
+#define CONNECT_EPS 0.00001f
 #define VERT_OUT 1
 #define VERT_EXCLUDE 2
 
@@ -82,6 +82,7 @@ struct PathContext {
   HeapSimple *states;
   float matrix[3][3];
   float axis_sep;
+  float connect_eps;
 
   /* only to access BMO flags */
   BMesh *bm_bmoflag;
@@ -171,8 +172,8 @@ static int state_isect_co_pair(const PathContext *pc, const float co_a[3], const
   const float diff_a = dot_m3_v3_row_x(pc->matrix, co_a) - pc->axis_sep;
   const float diff_b = dot_m3_v3_row_x(pc->matrix, co_b) - pc->axis_sep;
 
-  const int test_a = (fabsf(diff_a) < CONNECT_EPS) ? 0 : (diff_a < 0.0f) ? -1 : 1;
-  const int test_b = (fabsf(diff_b) < CONNECT_EPS) ? 0 : (diff_b < 0.0f) ? -1 : 1;
+  const int test_a = (fabsf(diff_a) < pc->connect_eps) ? 0 : (diff_a < 0.0f) ? -1 : 1;
+  const int test_b = (fabsf(diff_b) < pc->connect_eps) ? 0 : (diff_b < 0.0f) ? -1 : 1;
 
   if ((test_a && test_b) && (test_a != test_b)) {
     return 1; /* on either side */
@@ -183,7 +184,7 @@ static int state_isect_co_pair(const PathContext *pc, const float co_a[3], const
 static int state_isect_co_exact(const PathContext *pc, const float co[3])
 {
   const float diff = dot_m3_v3_row_x(pc->matrix, co) - pc->axis_sep;
-  return (fabsf(diff) <= CONNECT_EPS);
+  return (fabsf(diff) <= pc->connect_eps);
 }
 
 static float state_calc_co_pair_fac(const PathContext *pc,
@@ -617,6 +618,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
   {
     pc.states = BLI_heapsimple_new();
     pc.link_pool = BLI_mempool_create(sizeof(PathLink), 0, 512, BLI_MEMPOOL_NOP);
+    pc.connect_eps = CONNECT_EPS * len_v3v3(pc.v_pair[0]->co, pc.v_pair[1]->co);
   }
 
   /* calculate matrix */

@ideasman42 might be interested

Confirming this for now (even if in the grey-zone between bug and request for improved behavior) > A reasonable fix is to make CONNECT_EPS proportional to the (max abs) coordinate of the vertex pair. Again thanks @1D_inc for the idea. I'll work on this. Seems reasonable. Something like this seems to work just fine: ```Diff diff --git a/source/blender/bmesh/operators/bmo_connect_pair.cc b/source/blender/bmesh/operators/bmo_connect_pair.cc index a651ed5345a..2b2c22c4a17 100644 --- a/source/blender/bmesh/operators/bmo_connect_pair.cc +++ b/source/blender/bmesh/operators/bmo_connect_pair.cc @@ -40,7 +40,7 @@ * - run the standard connect operator. */ -#define CONNECT_EPS 0.0001f +#define CONNECT_EPS 0.00001f #define VERT_OUT 1 #define VERT_EXCLUDE 2 @@ -82,6 +82,7 @@ struct PathContext { HeapSimple *states; float matrix[3][3]; float axis_sep; + float connect_eps; /* only to access BMO flags */ BMesh *bm_bmoflag; @@ -171,8 +172,8 @@ static int state_isect_co_pair(const PathContext *pc, const float co_a[3], const const float diff_a = dot_m3_v3_row_x(pc->matrix, co_a) - pc->axis_sep; const float diff_b = dot_m3_v3_row_x(pc->matrix, co_b) - pc->axis_sep; - const int test_a = (fabsf(diff_a) < CONNECT_EPS) ? 0 : (diff_a < 0.0f) ? -1 : 1; - const int test_b = (fabsf(diff_b) < CONNECT_EPS) ? 0 : (diff_b < 0.0f) ? -1 : 1; + const int test_a = (fabsf(diff_a) < pc->connect_eps) ? 0 : (diff_a < 0.0f) ? -1 : 1; + const int test_b = (fabsf(diff_b) < pc->connect_eps) ? 0 : (diff_b < 0.0f) ? -1 : 1; if ((test_a && test_b) && (test_a != test_b)) { return 1; /* on either side */ @@ -183,7 +184,7 @@ static int state_isect_co_pair(const PathContext *pc, const float co_a[3], const static int state_isect_co_exact(const PathContext *pc, const float co[3]) { const float diff = dot_m3_v3_row_x(pc->matrix, co) - pc->axis_sep; - return (fabsf(diff) <= CONNECT_EPS); + return (fabsf(diff) <= pc->connect_eps); } static float state_calc_co_pair_fac(const PathContext *pc, @@ -617,6 +618,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) { pc.states = BLI_heapsimple_new(); pc.link_pool = BLI_mempool_create(sizeof(PathLink), 0, 512, BLI_MEMPOOL_NOP); + pc.connect_eps = CONNECT_EPS * len_v3v3(pc.v_pair[0]->co, pc.v_pair[1]->co); } /* calculate matrix */ ``` @ideasman42 might be interested
Philipp Oeser added
Status
Confirmed
Module
Modeling
and removed
Status
Needs Triage
labels 2023-10-04 12:28:26 +02:00
Author
Contributor

Thank you for the code. I've also coded something but I think your version is better. I changed CONNECT_EPS into a static variable, this may not be consistent with Blender's code style.
Will you handle this fix? Or should I submit a pull request?

Thank you for the code. I've also coded something but I think your version is better. I changed CONNECT_EPS into a static variable, this may not be consistent with Blender's code style. Will you handle this fix? Or should I submit a pull request?
Member

I think @ideasman42 can handle (he had a suggestion for improvement)

I think @ideasman42 can handle (he had a suggestion for improvement)
Member

OK, made !113246 so it doesnt get lost

OK, made !113246 so it doesnt get lost
Author
Contributor

That's great. Thanks for your work on it.

That's great. Thanks for your work on it.
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#113111
No description provided.