Added python func Blender.Geometry.LineIntersect2D(v1,v2,v3,v4)

updated archimap and cookie cutter to use it, removed python version from BPyMathutils
archimap island merging is noticibly faster
This commit is contained in:
Campbell Barton 2006-10-07 04:56:36 +00:00
parent dda63a9dde
commit 30d207e650
9 changed files with 132 additions and 117 deletions

@ -182,86 +182,3 @@ def convexHull(point_list_2d):
# Concatenate both halfs and return.
return [p[1] for ls in (upper, lower) for p in ls]
SMALL_NUM = 0.000001
def lineIntersect2D(v1a, v1b, v2a, v2b):
'''
Do 2 lines intersect, if so where.
If there is an error, the retured X value will be None
the y will be an error code- usefull when debugging.
the first line is (v1a, v1b)
the second is (v2a, v2b)
by Campbell Barton
This function accounts for all known cases of 2 lines ;)
'''
x1,y1= v1a.x, v1a.y
x2,y2= v1b.x, v1b.y
_x1,_y1= v2a.x, v2a.y
_x2,_y2= v2b.x, v2b.y
# Bounding box intersection first.
if min(x1, x2) > max(_x1, _x2) or \
max(x1, x2) < min(_x1, _x2) or \
min(y1, y2) > max(_y1, _y2) or \
max(y1, y2) < min(_y1, _y2):
return None, 100 # Basic Bounds intersection TEST returns false.
# are either of the segments points? Check Seg1
if abs(x1 - x2) + abs(y1 - y2) <= SMALL_NUM:
return None, 101
# are either of the segments points? Check Seg2
if abs(_x1 - _x2) + abs(_y1 - _y2) <= SMALL_NUM:
return None, 102
# Make sure the HOZ/Vert Line Comes first.
if abs(_x1 - _x2) < SMALL_NUM or abs(_y1 - _y2) < SMALL_NUM:
x1, x2, y1, y2, _x1, _x2, _y1, _y2 = _x1, _x2, _y1, _y2, x1, x2, y1, y2
if abs(x2-x1) < SMALL_NUM: # VERTICLE LINE
if abs(_x2-_x1) < SMALL_NUM: # VERTICLE LINE SEG2
return None, 111 # 2 verticle lines dont intersect.
elif abs(_y2-_y1) < SMALL_NUM:
return x1, _y1 # X of vert, Y of hoz. no calculation.
yi = ((_y1 / abs(_x1 - _x2)) * abs(_x2 - x1)) + ((_y2 / abs(_x1 - _x2)) * abs(_x1 - x1))
if yi > max(y1, y2): # New point above seg1's vert line
return None, 112
elif yi < min(y1, y2): # New point below seg1's vert line
return None, 113
return x1, yi # Intersecting.
if abs(y2-y1) < SMALL_NUM: # HOZ LINE
if abs(_y2-_y1) < SMALL_NUM: # HOZ LINE SEG2
return None, 121 # 2 hoz lines dont intersect.
# Can skip vert line check for seg 2 since its covered above.
xi = ((_x1 / abs(_y1 - _y2)) * abs(_y2 - y1)) + ((_x2 / abs(_y1 - _y2)) * abs(_y1 - y1))
if xi > max(x1, x2): # New point right of seg1's hoz line
return None, 112
elif xi < min(x1, x2): # New point left of seg1's hoz line
return None, 113
return xi, y1 # Intersecting.
# Accounted for hoz/vert lines. Go on with both anglular.
b1 = (y2-y1)/(x2-x1)
b2 = (_y2-_y1)/(_x2-_x1)
a1 = y1-b1*x1
a2 = _y1-b2*_x1
if b1 - b2 == 0.0:
return None, 200
xi = - (a1-a2)/(b1-b2)
yi = a1+b1*xi
if (x1-xi)*(xi-x2) >= 0 and (_x1-xi)*(xi-_x2) >= 0 and (y1-yi)*(yi-y2) >= 0 and (_y1-yi)*(yi-_y2)>=0:
return xi, yi
else:
return None, 300

@ -24,7 +24,6 @@
import Blender
Vector= Blender.Mathutils.Vector
Ang= Blender.Mathutils.AngleBetweenVecs
LineIntersect= Blender.Mathutils.LineIntersect
CrossVecs= Blender.Mathutils.CrossVecs
import BPyMesh

@ -1,6 +1,6 @@
import Blender
from Blender import Mathutils, Window, Scene, Draw, Mesh
from Blender.Mathutils import CrossVecs, Matrix, Vector, Intersect, LineIntersect
from Blender.Mathutils import CrossVecs, Matrix, Vector, Intersect
# DESCRIPTION:
# screen_x, screen_y the origin point of the pick ray

@ -119,6 +119,7 @@ def main():
# -------------------------------
appstring = appstring.replace('%f', imageFileName)
print '\tediting image with command "%s"' % appstring
os.system(appstring)
if __name__ == '__main__' and os != None:

@ -32,8 +32,8 @@ import Blender
import BPyMathutils
from math import sqrt
reload(BPyMathutils)
lineIntersect2D= BPyMathutils.lineIntersect2D
Vector= Blender.Mathutils.Vector
LineIntersect2D= Blender.Geometry.LineIntersect2D
# Auto class
def auto_class(slots):
@ -97,7 +97,7 @@ def point_in_poly2d(pt, fvco):
#fvco= [v.co for v in face]
isect=0
for i in xrange(len(fvco)):
isect+= (lineIntersect2D(pt, crazy_point, fvco[i], fvco[i-1])[0] != None)
isect+= (LineIntersect2D(pt, crazy_point, fvco[i], fvco[i-1]) != None)
return isect%2 # odd number is an intersect which wouold be true (inside the face)
@ -289,11 +289,10 @@ def terrain_cut_2d(t, c, PREF_Z_LOC):
if bounds_intersect(eb_t, eb_c): # face/edge bounds intersect?
# Now we know the 2 edges might intersect, we'll do a propper test
xi, yi= lineIntersect2D(ed_t.v1.co, ed_t.v2.co, ed_c.v1.co, ed_c.v2.co)
if xi != None:
x= LineIntersect2D(ed_t.v1.co, ed_t.v2.co, ed_c.v1.co, ed_c.v2.co)
if x:
ed_isect= edge_isect_type()
ed_isect.point= Vector(xi,yi,0) # fake 3d
ed_isect.point= x.resize3D() # fake 3d
# Find the interpolation Z point
@ -637,9 +636,7 @@ def main():
if point_in_bounds(c, t.bounds):
isect_count= 0
for edv1, edv2 in edge_verts_c:
xi, yi= lineIntersect2D(c, crazy_point, edv1, edv2)
if xi!=None:
isect_count+=1
isect_count += (LineIntersect2D(c, crazy_point, edv1, edv2) != None)
if isect_count%2:
f.sel= 1

@ -42,7 +42,7 @@ selected faces, or all faces.
# --------------------------------------------------------------------------
from Blender import Object, Scene, Draw, Window, sys, Mesh
from Blender import Object, Scene, Draw, Window, sys, Mesh, Geometry
from Blender.Mathutils import CrossVecs, Matrix, Vector, RotationMatrix, DotVecs, TriangleArea
from math import cos
@ -262,7 +262,9 @@ def island2Edge(island):
# If 2 are the same then they will be together, but full [a,b] order is not correct.
# Sort by length
length_sorted_edges = [(key[0], key[1], value) for key, value in edges.iteritems() if value != 0]
length_sorted_edges = [(Vector(key[0]), Vector(key[1]), value) for key, value in edges.iteritems() if value != 0]
length_sorted_edges.sort(lambda A, B: cmp(B[2], A[2]))
# Its okay to leave the length in there.
@ -316,7 +318,7 @@ def pointInIsland(pt, island):
# box is (left,bottom, right, top)
def islandIntersectUvIsland(source, target, xSourceOffset, ySourceOffset):
def islandIntersectUvIsland(source, target, SourceOffset):
# Is 1 point in the box, inside the vertLoops
edgeLoopsSource = source[6] # Pretend this is offset
edgeLoopsTarget = target[6]
@ -324,28 +326,20 @@ def islandIntersectUvIsland(source, target, xSourceOffset, ySourceOffset):
# Edge intersect test
for ed in edgeLoopsSource:
for seg in edgeLoopsTarget:
xi, yi = lineIntersection2D(\
seg[0][0], seg[0][1], seg[1][0], seg[1][1],\
xSourceOffset+ed[0][0], ySourceOffset+ed[0][1], xSourceOffset+ed[1][0], ySourceOffset+ed[1][1])
if xi != None:
i = Geometry.LineIntersect2D(\
seg[0], seg[1], SourceOffset+ed[0], SourceOffset+ed[1])
if i:
return 1 # LINE INTERSECTION
# 1 test for source being totally inside target
SourceOffset.resize3D()
for pv in source[7]:
p = pv.__copy__()
p.x += xSourceOffset
p.y += ySourceOffset
if pointInIsland(p, target[0]):
if pointInIsland(pv+SourceOffset, target[0]):
return 2 # SOURCE INSIDE TARGET
# 2 test for a part of the target being totaly inside the source.
for pv in target[7]:
p = pv.__copy__()
p.x -= xSourceOffset
p.y -= ySourceOffset
if pointInIsland(p, source[0]):
if pointInIsland(pv+SourceOffset, source[0]):
return 3 # PART OF TARGET INSIDE SOURCE.
return 0 # NO INTERSECTION
@ -457,7 +451,6 @@ def optiRotateUvIsland(faces):
for ROTMAT in RotMatStepRotation:
uvVecs = best2dRotation(uvVecs, ROTMAT[0], ROTMAT[1])
# Only if you want it, make faces verticle!
if currentArea[1] > currentArea[2]:
# Rotate 90d
@ -616,7 +609,7 @@ def mergeUvIslands(islandList, islandListArea):
##testcount+=1
#print 'Testing intersect'
Intersect = islandIntersectUvIsland(sourceIsland, targetIsland, boxLeft, boxBottom)
Intersect = islandIntersectUvIsland(sourceIsland, targetIsland, Vector(boxLeft, boxBottom))
#print 'Done', Intersect
if Intersect == 1: # Line intersect, dont bother with this any more
pass
@ -655,8 +648,7 @@ def mergeUvIslands(islandList, islandListArea):
# targetIsland[6].extend(sourceIsland[6])
#while sourceIsland[6]:
targetIsland[6].extend( [ (\
((e[0][0]+boxLeft, e[0][1]+boxBottom),\
(e[1][0]+boxLeft, e[1][1]+boxBottom), e[2])\
(e[0]+offset, e[1]+offset, e[2])\
) for e in sourceIsland[6] ] )
sourceIsland[6][:] = [] # Empty

@ -45,13 +45,19 @@
/* needed for EXPP_ReturnPyObjError and EXPP_check_sequence_consistency */
#include "gen_utils.h"
//#include "util.h" /* MIN2 and MAX2 */
#include "BKE_utildefines.h"
#define SWAP_FLOAT(a,b,tmp) tmp=a; a=b; b=tmp
#define eul 0.000001
/*-------------------------DOC STRINGS ---------------------------*/
static char M_Geometry_doc[] = "The Blender Geometry module\n\n";
static char M_Geometry_PolyFill_doc[] = "(veclist_list) - takes a list of polylines (each point a vector) and returns the point indicies for a polyline filled with triangles";
static char M_Geometry_LineIntersect2D_doc[] = "(lineA_p1, lineA_p2, lineB_p1, lineB_p2) - takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None";
/*-----------------------METHOD DEFINITIONS ----------------------*/
struct PyMethodDef M_Geometry_methods[] = {
{"PolyFill", ( PyCFunction ) M_Geometry_PolyFill, METH_VARARGS, M_Geometry_PolyFill_doc},
{"LineIntersect2D", ( PyCFunction ) M_Geometry_LineIntersect2D, METH_VARARGS, M_Geometry_LineIntersect2D_doc},
{NULL, NULL, 0, NULL}
};
/*----------------------------MODULE INIT-------------------------*/
@ -66,7 +72,7 @@ PyObject *Geometry_Init(void)
/*----------------------------------Geometry.PolyFill() -------------------*/
/* PolyFill function, uses Blenders scanfill to fill multiple poly lines */
PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * args )
static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * args )
{
PyObject *tri_list; /*return this list of tri's */
PyObject *polyLineSeq, *polyLine, *polyVec;
@ -164,3 +170,98 @@ PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * args )
return tri_list;
}
static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args )
{
VectorObject *line_a1, *line_a2, *line_b1, *line_b2;
float a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y, xi, yi, a1,a2,b1,b2, c1,c2, det_inv, m1, m2, newvec[2];
if( !PyArg_ParseTuple ( args, "O!O!O!O!",
&vector_Type, &line_a1,
&vector_Type, &line_a2,
&vector_Type, &line_b1,
&vector_Type, &line_b2)
)
return ( EXPP_ReturnPyObjError
( PyExc_TypeError, "expected 4 vector types\n" ) );
a1x= line_a1->vec[0];
a1y= line_a1->vec[1];
a2x= line_a2->vec[0];
a2y= line_a2->vec[1];
b1x= line_b1->vec[0];
b1y= line_b1->vec[1];
b2x= line_b2->vec[0];
b2y= line_b2->vec[1];
if((MIN2(a1x, a2x) > MAX2(b1x, b2x)) ||
(MAX2(a1x, a2x) < MIN2(b1x, b2x)) ||
(MIN2(a1y, a2y) > MAX2(b1y, b2y)) ||
(MAX2(a1y, a2y) < MIN2(b1y, b2y)) ) {
Py_RETURN_NONE;
}
/* Make sure the hoz/vert line comes first. */
if (fabs(b1x - b2x) < eul || fabs(b1y - b2y) < eul) {
SWAP_FLOAT(a1x, b1x, xi); /*abuse xi*/
SWAP_FLOAT(a1y, b1y, xi);
SWAP_FLOAT(a2x, b2x, xi);
SWAP_FLOAT(a2y, b2y, xi);
}
if (fabs(a1x-a2x) < eul) { /* verticle line */
if (fabs(b1x-b2x) < eul){ /*verticle second line */
Py_RETURN_NONE; /* 2 verticle lines dont intersect. */
}
else if (fabs(b1y-b2y) < eul) {
/*X of vert, Y of hoz. no calculation needed */
newvec[0]= a1x;
newvec[1]= b1y;
return newVectorObject(newvec, 2, Py_NEW);
}
yi = ((b1y / fabs(b1x - b2x)) * fabs(b2x - a1x)) + ((b2y / fabs(b1x - b2x)) * fabs(b1x - a1x));
if (yi > MAX2(a1y, a2y)) {/* New point above seg1's vert line */
Py_RETURN_NONE;
} else if (yi < MIN2(a1y, a2y)) { /* New point below seg1's vert line */
Py_RETURN_NONE;
}
newvec[0]= a1x;
newvec[1]= yi;
return newVectorObject(newvec, 2, Py_NEW);
} else if (fabs(a2y-a1y) < eul) { /* hoz line1 */
if (fabs(b2y-b1y) < eul) { /*hoz line2*/
Py_RETURN_NONE; /*2 hoz lines dont intersect*/
}
/* Can skip vert line check for seg 2 since its covered above. */
xi = ((b1x / fabs(b1y - b2y)) * fabs(b2y - a1y)) + ((b2x / fabs(b1y - b2y)) * fabs(b1y - a1y));
if (xi > MAX2(a1x, a2x)) { /* New point right of hoz line1's */
Py_RETURN_NONE;
} else if (xi < MIN2(a1x, a2x)) { /*New point left of seg1's hoz line */
Py_RETURN_NONE;
}
newvec[0]= xi;
newvec[1]= a1y;
return newVectorObject(newvec, 2, Py_NEW);
}
b1 = (a2y-a1y)/(a2x-a1x);
b2 = (b2y-b1y)/(b2x-b1x);
a1 = a1y-b1*a1x;
a2 = b1y-b2*b1x;
if (b1 - b2 == 0.0) {
Py_RETURN_NONE;
}
xi = - (a1-a2)/(b1-b2);
yi = a1+b1*xi;
if ((a1x-xi)*(xi-a2x) >= 0 && (b1x-xi)*(xi-b2x) >= 0 && (a1y-yi)*(yi-a2y) >= 0 && (b1y-yi)*(yi-b2y)>=0) {
newvec[0]= xi;
newvec[1]= yi;
return newVectorObject(newvec, 2, Py_NEW);
}
Py_RETURN_NONE;
}

@ -38,6 +38,7 @@
#include "vector.h"
PyObject *Geometry_Init( void );
PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * args );
static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * args );
static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args );
#endif /* EXPP_Geometry_H */

@ -43,3 +43,10 @@ def PolyFill(polylines):
Blender.Redraw()
"""
def LineIntersect2D(vec1, vec2, vec3, vec4):
"""
Takes 2 lines vec1, vec2 for the 2 points of the first line and vec2, vec3 for the 2 points of the second line.
@rtype: Vector
@return: a 2D Vector for the intersection or None where there is no intersection.
"""