[Plugin] Hatchfaces (v1.8 beta) UPDATED 15-Dec-2012
-
Hi. I trying to figure out the "clever" way to setup the structure of the code. If anyone has any comments, I would be most greatful. Having decision anxiety.
I am little afraid to destroy the structure of current code and getting flamed for doing something inappropriate.
I'm trying to avoid using @varibles everywhere. I get the impression that could give some troubles later on.
The simplest way would of course be to repeat the whole last part(linecreation, intersection) without nesting so many methods, but that would probably be cheating. However the script is not that long so I guess it would not be a catastrophy to repeat things.
Also having trouble grouping. Where as we will have the structure:
(maingroup)/(hatchgroup1) (hatchgroup2)Questions are. Should "face-cloning" be a separate method?
Should one create a method for only using 1 inputbox getting values twice?(2 promts, 1 box) OVERKILL?
Another possiblities is to recreate the linehatching and intersection in a submethod calling on @gents?
-
Collect all of your dialog data at the very start.
If the 1st dialog has 'Yes' for 'Crosshatching?' then a second dialog opens with the -ve version of the angle and the same spacing - the user can change these if desired and press OK, or Cancel to skip crosshatching.
After the dialogs you use the data to make the grouped hatching.
If there is no crosshatching then the code is as currently.
If there is crosshatching then you simply run the coder twice.
However, as explained before - you remove the hatch code into a sub-def method where you pass values this
def hatch(angle, spacing, gents)
where 'gents' is ANY entities set that's passed to it [I left it called that because when you move the code into the method the name can remain - however, note how the angle/spacing variables can NO LONGER be @ variables inside the hatch def because they can be different @'s depending on whether you are making a hatch or a crosshatch from dialog input!]
and to use for the non-crosshatched version
self.hatch(@angle, @spacing, gents)
where you pass the @angle/@spacing variables
and 'gents' is entities of the 'group' that contains the hatching.
When you have crosshatching you first make 'group' to contain the TWO groups needed.
Then add two sub-groups
hgroup=gents.add_group() cgroup=gents.add_group()
here 'hgroup' will contain the hatching and 'cgroup' the crosshatching
To make then first make the hatching
self.hatch(@angle, @spacing, hgroup.entities)
note how we have passed a different entities set this time
To make the other part of the crosshatching use
self.hatch(@cangle, @cspacing, cgroup.entities)
Note here we have used different @ variables for the crosshatching - derived from the 2nd dialog AND we use the other entities set too...
By using the sub-def method for 'hatch' you can reuse the code for hatching or crosshatching as the values are remembered separately as @'s for the two types and if there is crosshatching then a simple extra step of making sub-groups inside the main hatch-group is all you need... -
Thank you TIG! Much appreciated, was a bit stuck.
I think I understand better now what you meant before. Before when you said "code into a sub-def method", I thought you meant ADDING a method or "doubbling" the code. There's where I was lost, should have asked earlier for help but pride got in the way.
Very clever solution! And probably quite natural solution for some off you guys in here
I will digest this and continue. Thanks again.
-
Unexpected results of hatching.
All hatches are made with the same distance and with the same angle.
Maybe is necessary to select not only the face, but also the baseline?
(And maybe the baseline can be anywhere in the drawing, not necessary on the face?)
-
Hmm interesting.. I get the same result. Very disturbing. This must be fixed I agree!
I was thinking of modifying TIG's script later on so it will copy lines in 2 directions, from center-> out. Or at least be aligned from center. Maybe that will take care of things. Although I have the feeling it has something to do with how the diagonal is created and vector comparison. Eg that it has to do with vertices 0 and 1 (vectorcreation). Depending of how the boundingbox is created, those points will be on different positions.
At the moment I'm trying to fix the crosshatching(having some difficulties), so I will look at this later.
Thank you Sergey for experimenting and notifying this!
-
Currently the hatching's rotation is calculated relative to the vector formed by the face's first edge - and this is clearly variable.
A consistent and simple way would be to make it relative the the X-axis that has been transformed to lie on the face.plane ??? -
At the moment the ;reference-edge' is actually the vector from the face's fist vertex to the second vertex.
This bound to be on the face.plane as all vertices are coplanar.
To make another vector to use instead you can make that vector and project it onto the face.plane and use that... So
p0=face.vertices[0].position p1=p0.clone p1.x=p1.x+1 p1=p1.project_to_plane(face.plane) vector=p0.vector_to(p1)
This projects the equivalent of a vector [1,0,0] onto the face's plane...
That vector can now be used to base the hatch angle upon... -
He he. This is bothering me badly. Most annoying.
One of my first ideas when I thought about this plugin was to let the user select from a scroll list, Front, Right, Left Back view etc, and have determined pt from bounds according to selection. That of course is not a flexible and smart solution. But maybe viable? Will be troublesome for in between angles.. It's not a good solution...@unknownuser said:
relative to the vector formed by the face's first edge
Oh, yeah that's right
@unknownuser said:
A consistent and simple way would be to make it relative the the X-axis that has been transformed to lie on the face.plane ???
Do you mean create edge first on X and move to face.plane?
Or maybe select a reference edge as Sergey idea?
-
Hmm, no? I must have gotten it wrong. Doesent work in Y,Z axis.
-
Genious TIG!
I think I got it right. It work for me in a few tests.
Like this, no?
pt=face.vertices[0].position p1=pt.clone p1.x=p1.x+1 p1=p1.project_to_plane(face.plane) ve=pt.vector_to(p1) bb=face.bounds di=bb.diagonal po=pt.clone
I mean is that correct for an update, cause this problem is(was) irritating.
-
You need to trap for the case when the X-axis is parallel with the palne and then use another axis - i.e. offset the y instead of the x value of p1...
To do this get the n=face.normal and then use the alternative vector [offset in y] if n.x.abs==1 or n.z.abs==1
etc... -
Hmm I will try..
Where do you learn all these commands?? It feels like I'm missing some information source(exept from this forum).
BTW won't there be a conflict of axes if one for ex. have a face rotated 45 degrees?
-
No.
The problem arises if you try to project a p1 onto a face with a plane that is square to the x-axis or flat to it, as that p1 is then back on p0 and the vector can't have a zero length! -
@unknownuser said:
vector can't have a zero length!
That I can understand. Alright, I will have a go at it. I'm not sure a fully grasp this
This is more and more your plugin, it's starting to be too complicated for me. My level is more icons and stuff.
Maybe one day I can contribute more.Thanks for your invaluable help TIG
-
@jolran said:
Hmm I will try..
Where do you learn all these commands?? It feels like I'm missing some information source(exept from this forum).
You have to learn the ruby language itself. I'm lacking in this area, too.
-
@unknownuser said:
You have to learn the ruby language itself
Yeah, you are right. Working on that.
Good news is the code seams to be working for sorting irregular faces and hatching.
p1=pt.clone p1.x=p1.x+1 # X value = x axis needs to be replaced if using another axis p1=p1.project_to_plane(face.plane) ve=pt.vector_to(p1) bb=face.bounds di
So something like this does not do the trick yet. Will work on it..
p1.each {|e|e.z+1 if face.normal.z.abs==1 e.x+1 if face.normal.x.abs==1 e.y+1 if face.normal.y.abs==1}
-
Read this and try to understand...
p0=face.vertices[0].position p1=p0.clone if face.normal.x.abs>0.9999 p1.y=p1.y+1 else p1.x=p1.x+1 end#if p1=p1.project_to_plane(face.plane) ve=p0.vector_to(p1) ### etc
This should always result in a 've'ctor with a non=zero length.
To test it set up a cube and test add temporary 'puts' into the code after ve=
puts face.normal puts ve.length
-
Wow, thanks! So if I understand it correctly one do only need to compare x to y to get the required results. Where if>0,9999 switches to other axis-comparison=under1? Clever.
It works for faces without holes if I switch values p0 to pt, with your last posted code.
Or do you mean p0 to be po, (typo)? Cause that is a whole different thing. That does not makes sence though, wonder why I think that...I will try that meanwhile..Se if holes get fixed.
po=pt.clone:
ps=pt.offset(vp) pe=pt.offset(vp.reverse) gents.add_line(ps,pe) pt.offset!(vs,spacing) ps=po.offset(vp) etc
-
Anyway heres how I implemented your code, between ents erase(facestogo) and intersection. It does not work on faces with holes, as mentioned.
Is there a clash with 2 pt.clones? Maybe I HAVE put your code in wrong places. I will continue..bb=face.bounds di=bb.diagonal pt=face.vertices[0].position p1=pt.clone if face.normal.x.abs>0.9999 p1.y=p1.y+1 else p1.x=p1.x+1 end#if p1=p1.project_to_plane(face.plane) ve=pt.vector_to(p1) po=pt.clone tr=Geom;;Transformation.rotation(pt,face.normal,@angle.degrees) vp=ve.transform(tr) vp.length=di*2 vs=face.normal.cross(vp) #spacing vector perpendicular to hatch line tot=0 until tot>=di*2 ps=pt.offset(vp) pe=pt.offset(vp.reverse) gents.add_line(ps,pe) pt.offset!(vs,spacing) ps=po.offset(vp) pe=po.offset(vp.reverse) gents.add_line(ps,pe) po.offset!(vs.reverse,spacing) tot=
-
May have found something? Commented out the last parts. Line hatching and intersection.
The results of faces with holes is a group(clone) with reversed face? Faces without holes is created as expected.
Since using face.normal that might (in my theory logic) pose some trouble?Updated Hmmm, no. Grr. Did not matter if faces was reversed or not. Problem remains..
This code reverses the faces anyway.
Could be useful later on, but it will reverse ALL faces, wich is not useful right now. Faces without holes do not need reversing.faces2=[] gents.each{|e|faces2 << e.reverse! if e.class==Sketchup;;Face
Advertisement