Rewriting the Cross Section Script

This is my first attempt at a real script so be nice :slight_smile:

My weekend project was to rewrite the Cross Section script/addon for Blender 2.5. If this has already been done, please let me know (or maybe don’t since I have already worked on it ha ha).

As far as I know the first script was written by Yorik and has not been updated yet.

This may become useless if the exact mode in knife cut ever gets back to like 2.49



#Im not sure the best way to import these things.  Ive heard "wildcard"
#imports are bad?  But I'm not sure exactly how to import things correctly
#This seems to work fine

import bpy
import math
from math import *
from mathutils import *
from mathutils import Vector
from mathutils import Matrix
import time

def invRotation(mx):
    """
    Finds the matrix that does the inverse rotation of the given matrix but takes
    scale out of the way to keep things sane
	
    mx: Matrix - the matrix whose rotation you want to invert
	
    Returns: Matrix - a matrix of the inverse rotation
    """
    r = mx.rotation_part()
    s = mx.scale_part()

    smx = Matrix()
    for i in range(0,3):
        smx[i][i] = s[i]  #should this be 1/s[i] to undo any scaling too?
    rmx = r.resize4x4().invert() * smx
    
    return rmx

def section(cut_object, world_pp, world_pno, FILL=False):
    """
    Finds the section between a mesh and a plane mesh
    cut_me: Blender Mesh - the mesh to be cut
    mx: world matrix of mesh
    pp: Vector - a point on the plane
    pno: Vector - The cutting plane normal
    together, pp and pno define the cutting plane
    FILL:  Boolean - check if you want to fill mesh
        
    Returns: Mesh - the resulting mesh of the cut
    """
    
    #First get the mesh and it's transformation matrix
    cut_me=cut_object.data
    mx=cut_object.matrix_world
    
    irot=invRotation(mx)  
    
    #Now, my plan is to take the plane from world coordinates
    #to local (for each object) and then compute the cross section
    #after that, just apply the world matrix of the object to the cross
    #section and it will be all good....in most cases.
    
    pno=world_pno*mx #this is weird.  At first I thought I would need the INVERSE matrix.  But this works...any guesses why?
    pp=(world_pp-mx.translation_part())*irot  #the reverse of scale, rotate, translate, is translate, rotate, scale...
    
        
    verts = []
    edges = []
    faces = []
    ed_xsect = {}  #why is this a dictionary? I don't know

    for ed in cut_me.edges:
        #get a vector from each edge to a point on the plane
        
        v1index = ed.vertices[0]
        v1=cut_me.vertices[v1index].co
        co1=v1-pp
        v2index=ed.vertices[1]
        v2=cut_me.vertices[v2index].co
        co2=v2-pp
        
        #project them onto normal
        proj1 = co1.project(pno).length
        proj2 = co2.project(pno).length
        
        if (proj1 != 0):
            angle1=co1.angle(pno)
        else: angle1 = 0
        if (proj2 != 0):
            angle2=co2.angle(pno)
        else: angle2 = 0
            

    #Check to see if edge intersects.  Also check if coplanar cutting plane
        if ((proj1 == 0) or (proj2 == 0) or \
            (angle1 > math.pi/2) != (angle2 > math.pi/2)) and \
                (proj1+proj2 > 0):

            #edge intersects...ill take your word for it :-)
            
            proj1 /= proj1+proj2
            co = ((v2-v1)*proj1)+v1
            verts.append(co)
            #store a mapping between the new vertices and the mesh's edges
            ed_xsect[ed.key] = len(ed_xsect)
            
    
    for f in cut_me.faces:
        # get the edges that the intersection points form
        
        ps = [ ed_xsect[key] for key in f.edge_keys if key in ed_xsect]
        if len(ps) == 2:
            edges.append(tuple(ps))
    
            
   
    x_me=bpy.data.meshes.new("cross section")        
    x_me.from_pydata(verts,edges,faces)
    
    #Create a new object and link it to scene
    sce = bpy.context.scene
    new_ob = bpy.data.objects.new("cross section", x_me)
    sce.objects.link(new_ob)
    new_ob.matrix_world=mx
        
    return new_ob


sorry about the terrible posting…I thought the tabs would have shown up. Here is a video showing it working/not working in different scenarios.

I manually define a plane (3d point and a normal) in world coords and then try and tranform them into each objects local space, then make the section, then tranform it back into world space. It seems that the point is the problem as the normals appear to always work.

also, can I post the .blend or the .py or even a link to a screen cast? It say’s I’m not allowed to post attachments or link in my posts?

pm me for a .blend, .py or link to youtube…sigh

Just a tip, your post count has to be above a certain number before you can post links, it’s an anti-spam measure. To post code, scroll down the page and check out the ‘BB code’ link at the bottom of this page…

Randy

Awesome thanks Randy. I edited it appropriately. Some day I’ll be able to post links :slight_smile:

is this the one that makes only across on any given object with a plane ?

would like to see the plane cut knife

can you make this one too?

Thanks and happy 2.5

That’s not all the code is it?

Hi Ricky,

This is my first real stab at doing any programming or writing a script (python, blender or otherwise) outside of matlab so I want to get this one figured out and polished before undertaking the plane cut knife since that involves mouse clicks and the angle of the 3d view. The math should be more or less the same so once I get this one behaving properly maybe some of us can get together and make that happen.

-Patrick

@ Dune2k

No that’s definitely not all of it, just the relevant bit for actually computing the cross section. I’ve left out the buttons/panel, the license etc. I have also left out some of the looking for duplication and testing for edges that are coplanar with the cutting plane. But since this isn’t acting “quite right” at the moment, I figured I could start with the core part.

bit as i said is it the script that makes a copy of the cross section with a plane at angle through an object ?

i’m not very good yet with vertices list ect…

definitively would be interested in seeing this plane cut knife in 2.5

it’s very usefull and faster to use the knife tool just place the plane at whaterver angle and cut the objecct in 2 !

thanks

@Ricky

I think we can make that happen. To find out if an edge intersects the plane, we test to see if each of the vertices (belonging to that edge) lies on opposite sides of the plane. So by default, we have already determined on what side of the cutting plane all the vertices are on. This makes it easy to divide the object into two pieces.

Ok, so I “made that happen.” It only does the edges right now. Here it is in action. Give me a few days to clean it up, see what kind of idiotic repetition and unnecessary calculations I have in there. Then I will post it so we can get it polished.

did you think about the plane cut thing!

Thanks

http://www.4shared.com/file/_5_MOTSs/filltesting.html
This is a script I wrote to fill holes in complicated shapes, it works most of the time, but it is in 2.49, if you could convert it, it might solve your filling problem.

does it do the plane cut like in the french knife plane cut we had in 2.49 ?

thanks

Heeey! the forum is back! I haven’t had much time to work on it since I was studying for boards, but, it is in an “almost there” state. The problems it has are as follows.

  1. Some of the new faces aren’t connected correctly. Eg a quad which is supposed to have edge keys (0,1)(1,2)(2,3)(3,0) is (0,1)(1,3)(3,2)(2,4)

  2. Something is wrong with the matrix transformations. For now, I just have the script make duplicates, apply the matrices, and then calculate the cross section.

  3. It leaves all the old vertices on the other half…

number 3 I can fix
number 2 is fine for now, but kind of a pain
number 1, I haven’t brainstormed on.

video to come shortly to show you what I mean.

ok, actually there are more problems than that. It wont cut suzanne and it wont cut a UV sphere…but it will cut an icosphere? And blender crashes after I use it? Life is tough today.

well can you upload the script so we can look at it and may be help!

did you look at the knife plane script to give you some ideas may be!

happy 2.5

Ok, here is just the cross section script. This seems to work in most situations. use at own risk!

http://dl.dropbox.com/u/2586482/cross_section_matrix_apply.py

Usage…

  1. Put this file in your “addons” folder
  2. In “User Preferences,” activate this addon by checking it
  3. Select the object (mesh only!) which you want to “slice”
  4. Select the plane which is your cutting tool
  5. In the “Object Properties” panel, “Make Cross Section” will appear, indicating which mesh is to be cut, and what the name of your cutting plane is.
  6. Click the button

A new object labeled “cross section” should appear. The cutting plane will also have it’s origin shifted to the origin.

Try it with:

an icosphere
a uv sphere
a monkey
something complicated of your own.

Report back initial bugs here.

Bug 1…

Using Blender 2.56a

1.add plane
2.add uv sphere
3. Make cross section

yields an empty object “cross section”

but

  1. add uv sphere
  2. add plane
  3. make cross section

yields a cross section ?? Go figure

edit: It seems that this is the case with many objects. The plane needs to be added to the scene after the object to be cut? Makes no sense to me??