helical gear structure rendering planning 1250 or such ran into issue, take slower trying to plan above concept maybe put generalization-idea later or reduce importance a little the idea is that um we can subdivide a surface the same as a curve is subdivided but it seems it could be useful to do a little bit of generalization, at least, adding keypoints to the concept keypoints are points where if they were not included part of the structure could be lost. in our current example, there would be a keypoint at the tip and base of each tooth. this is being handled by subdividing each side of the tooth as a separate curve. this approach could be continued for a surface rather than a curve: each tooth side would be treated as a separate surface. either approach can work. maybe it seems there might be fewer [emotional?] issues by keeping it similar to as it is so for surfaces, we could do it as surface chunks -- there'd be two sets this way for the helical gear, one for the top, one for the bottom. we'd set the bounds for each, and tell it to subdivide them. not hard. alternative we could use keypoints. then we have a sequence of keypoints for the top ring, a sequence for the middle ring, and a sequence for the bottom. these are points in a curve that are already set to be included. the subdivision then happens between them. maybe the decision will look more reason-oriented if we figure how subdivision might work. one idea is, could subdivision be done with shared code between 2-dimensional and 3-dimensional? partly maybe one idea for 3-dimensional subdivision was to break the surface into triangles, and subdivide each edge of a triangle. one could also subdivide the midpoint. thinking about that. if we over-subdivide one edge, the triangle could get weird-looking. maybe it makes more sense to always subdivide them by adding a midpoint. does that work? uhhhhh maybe it makes sense to allocate a little [thinking thing ... time?] to considering how to do triangle subdivision. have say an equilateral triangle. when we subdivide, it would make sense to keep subdivided triangles also equilateral. we'd also want to handle both the middle of the triangle, where there could be a bump, and the edges of the triangles, where there could also. it seems it could make sense / would work to check 4 places, the middle, and the edge middles. ok reviewing other approach to consider its area too if we added a middle point to an equilateral triangle, we would then get three triangles that are not equilateral if we added middle points to the edge, this seems to work better! now we have 4 triangles that are all equilateral and smaller. we're even narrowing in on the middle a little in case it is different. there are 3 points much closer to the middle that weren't included before. what if we added a middle point to only 1 edge, since the others were already roughly flat? 2 triangles now. and if we added to 2 edges but not the 3rd? 1 triangle in the shared corner, then 3 triangles with one of the other corners being the corner of two ...? yeah if we subdivide 2 edges, i think we might as well subdivide the 3rd because there are 4 triangles total anyway ...? thinking if there are other approaches. also noting that this problem has been studied and there can be unexpected pitfalls looks like the shared corner triangle has to be there. if one of its points were different, the subdivided point wouldn't be included, because all the other points are in the same line as the subdivided points. so the problem is simplified to the /_\ shape in the rest. which needs 3 triangles to fill. so it makes sense to subdivide the 3rd side too. ok back to only 1 edge. the other two are the same plane. let's think of it again. a triangle with a single point halfway through one side, say the base (or a side). it makes sense to draw a line to the single point from the opposite corner, making two right triangles. whoops small stability issue if a line were instead drawn from one of the other two corners, it doesn't work, since they are on the same line. now there's a further issue sometimes, where a side can be subdivided from one triangle but not from another. so, subdividing an edge that is already in use, changes the use, because the point can move. that's the problem with adding the 3rd side to the 2-side case. but it looks to me like it would work simply if that isn't done. let's look up now how this is usually done. there are a handful of similar subdivision algorithms, that have different benefits i'm reading about 'loop subdivision', common for triangle meshes. when it subdivides a side, it picks the new point as a weighted average of the 4 surrounding points (2 from the line, 2 opposite from each triangle) the 2 line points get a weight of 3/8, and the 2 opposite points each get a weight of 1/8 (3+3+1+1=8) i like how it includes the 3rd dimension when considering where to subdivide, rather than just making rings we're #d45 or so and they are on #d10 subdivision for modeling (where a cube turns into a sphere or something) is different from subdivision for approximation found a 500 level class from 2016 (but it recommends a book from 1996) but it's the modeling kind of subdivision :/ maybe our kind of subdivision is called tesselation instead not quite hmm i'm not sure what a good search term is to find this! maybe sampling? how about rendering of nurbs or bezier patches? - uses tesselation or triangulation - note, nurbs are harder to render than bezier patches issue request seems somewhere to check what number they are on [have not sent this to action. the number display is around a corner. karl's judgement is that we would likely have missed at most 1 announcement which last one went by 10] [ok now we check i think ... it's still at D10. the announcements are pretty loud but we could get used to them. we are D45. [expression simplifies to time concern, unsure how long to spend exploring [we're ok exploring; we don't expect to finish this task waiting here, so things we learn can be helpful]] so, there's an update that nurbs and bezier patches can now be rendered without triangles [or approximation] -- possibly. they might have been overstating their research. this has stronger likelihood for the patches. D20. surface triangulation. thinking, to reduce triangle count, we'd probably want to avoid long thin triangles where not necessary. adaptive surface triangulation. marching method. undiscussed issue raised tesselation is _not_ the phrase, this is the modeling subdivision i think. D30. we're the next call. there's time after call so no rush. [but gotta notice it!] i'm wondering about defining constraints regarding triangulation. the general constrain is that no point on the triangles is outside the precision of the real surface. a triangle can be made that is insufficient, and then we subdivide it. it makes sense to add a point where the insufficiency is found! this then makes more triangles. eventually, the mesh is correct if the contraint is met. i think the approach of checking the edge midpoints makes sense. we could also check the surface midpoints. this makes for more conditions to combine the different triangles. . 1/4\3 ./_2_\. is there a general method to produce new triangles with the addition of any points among 1,2,3,4 to the original triangle? also what if we don't start with triangles? what we have at the start is a series of points. we don't know really what is between the points. :: :: these are rings or other points bounding the ends of a surface :: :: what points do we draw lines between? to define the surface? good question! we could just walk them in order? maybe that doesn't work? i think it makes sense to draw triangles between them. you point the tip of the triangle on the side that is more ahead, and advance the other side with the base of a triangle. you can do this by measuring the parameter, or by measuring the distance. what if one side has far fewer points than the other? wouldn't there be a lot of unneccessary triangles? grarg :s unsure how much to think about that. we have a different pending unsolved idea, so let's go back to that one . 1/4\3 ./_2_\. is there a general method to produce new triangles with the addition of any points among 1,2,3,4 to the original triangle? 1, 2, 3 single addition could be generalized by swizzling the endpoints: 2 of them are shared, one is not this then produces a new 4 along the base side. that would be a simpler approach. so it's simpler to only add a single point among 1, 2, 3; then the algorithm is shared and there is a new point that is near 4 to review. i imagine you'd add the most distant one, maybe. could compare squared distance to the surface. ok so what we have is lines. these lines form triangles, but we probably want to consider the triangles later because we are subdividing the lines. subdividing a line breaks triangles on both sides of it. it's a simple approach that appears sufficient. the triangles are not perfectly shaped. another idea is to use quad subdivision. this can make triangular bends, but since we would have two parameters it's somewhat intuitive. oh! since there are two parameters, you could skip the initial curve subdivision, and subdivide the whole area. you could draw two triangles covering them. then subdivide all the coordinates. this seems simplest. ok. this solves the second problem, and simplifies the first. great. checking number. they're still only up to D30. so the next will only be D40 we actually have two calls. ok so you're worried that subdividing only one line at a time will make a funny triangle set with skinny triangles around. maybe it's nicer to subdivide all the lines, as well as even the midpoints, then draw even triangles from them. . 1/4\3 ./_2_\. conditions: only 1,2,3 are subdivided: make 2 right triangles skinnier; further subdivision could worsen only 4 is subidivided: make 3 isosceles triangles skinnier but has symmetry one of 1,2,3 as well as 4 is subdivided: make 2 right triangles to 4, and 2 isosceles triangles two of 1,2,3 are subdivided: pretend 3 is subdivided and draw 4 triangles including it, but do not update its position. alternatively update the points such that all 3 are subdivided all points are subdivided: 6 triangles, all with 4 as one corner, a side mid as another corner, and a corner as another the best csae seems to be when 1, 2, and 3 are all subdivided. this makes a very balanced mesh. if 4 is wrong, one could handle it by subdividing 1, 2, and 3. maybe that could be a way to go, to have triangles that may be further subdivided all break into 4 triangles. this seems simpleish and somewhat reasonable. ok so the idea is to keep the curves as unsubdivided, for the surface case, and to subdivide them as a parametric surface, starting with a quad formed by 2 triangles. it's a little harder to subdivide a triangle 1,2,3 at once because the triangle must be tracked as an object w/ adjacent objects. what about just having lines? you still need to add new lines. it makes sense t ohave triangle objects. and line objects too? linking to the triangle objects? to update them? i guess. at least it's reasonably simple to think about. maybe we could start implementing a subdivision algorithm, and then an interface that emerges could inform how to pass the curve data to it. [the extra objects make this feel more inhibity] [prusaslicer already has a smidge of the functionality of interest here, but it is not a modeler] [maybe the curve could be stored as a nurb or in a parametric format that could be imported] another concern is how to factor out the accuracy check it's basically a function call. if we didn't want to pass a function or functor in, an alternative would be for the subdivider to produce an iterable of potential points to check. the caller would process each one, saying good or inaccurate. one advantage of this is that it could also be used to remove the curve information from the subdivider. it could be given initial endpoints, and produce midpoints. the caller would either update them or accept them. if updated, it would produce more midpoints. i think the functor approach would be more concise and normal it's notable both approaches could be used for both attempts to relate a function to the processor. but i like how the iteration makes it seem simpler a little. maybe it is not the right location for the code though. better to make outer interface simpler. in c++ member functions get wrapped in objects to pass them somewhere. one approach is to give the owner a common base class, implement an interface. another approach is to wrap them in a lambda, which basically does that under the hood, but i think it uses tempaltes. D31-D40. the C approach is to pass a data pointer that is passed to the callback. c++ has std::function that can hold lambdas. this uses a virtual call which some consider slow. iteration may be faster, doesn't call a pointer for every point. maybe we will try iteration unsure then we could make super-precise shapes with tons of points i guess ok so was thinking of iteration approach to surface generation. you'd call a subdivider, and give it 4 points it subdivides the points and spews out more points (could do .next() or use begin() end()). call it back for each point; is this good or not. y'know it just doesn't seem easy enough to use the subdividor could have that function, and make inlined calls to passed functions. this seems easier to use. you could of course template the whole thing and pass the functions. maybe simpler. ok so maybe we would make it a template, and pass in two functions, could inline it maybe. one function for how to generate the surface; one function for how to check if points need to be subdivided. ok so for surfaces, we start with 4 points and might even use triangle objects. for curves, we start with 2 points and we just subdivide the lines. we could make the surfaces simpler if we used quads. the implementation seems simpler. it doesn't look as nice ... i guess adaptive quads are reasonable. now the 2d code and the 3d code are more similar. ok so now if we consider the surface in quads ... the 3d case our time to go up 1412 1523 some of us were thinking the quad could be broken into 4 triangles to keep the dimensions similar. then if the energy is still around, could let karl sort out a triangle subdivision algorithm. probably not going to generalize to n dimensions. will like have two separate functions, one for two-dimensional, and one for three-dimensional. unknownness exists around copying the two dimensional one to a different function. how about starting by writing the three dimensional one? there's not a lot of space between that and the triangle subdivision algorithm. most of it is the algorithm. how about we draft that? ... or not? ok so what interface for it. what does it need? what do we have? it needs a way to get a set of points among 2 changing parametric values. what do we have? ... i suppose we have two involute curves, that change over a second value. so because the curves are the same at both ends, it's simpler ... so there are two parameters: rolling angle, and helical angle we can generate a point based on the two. the involute class acts on rolling angle ok subdivision a little hard each triangle is made of 3 edges. each edge borders 2 triangles. say we subdivide 1 triangle into 4. this subdivides each edge. the opposite triangle on each edge would then be minimally subdivided too. triangle representation that lets us find triangles with shared edges. the order of the points in the triangle matters; so ideally they would either reference points directly, or reference reversed edges. negative edge number would be reversed? oh one of them is 0. can we look up edges by points ...? the points could reference the edges they're on ... the challenge we're dealing with is twofold: - difficulty remembering parts of task as move through - difficulty referencing/using past solutions to the problem the difficulties are associated likely with inner behaviors that strongly fight. we usually separate from the bulk of them. handling issue so usually karl would make a ton of member functions and references and just use what was helpful. he'd likely also cache everything. when there is a different idea, it would be more productive to add to the member functions than to restructure the whole thing. many member functions is more [triggering], so we have been approachign that delicately dang i messied it. what if we removed some of the templating and hardcoded it for the usecase that's not actually the primary issue, the primary issue is tesselating a mesh uses graph structures, usually and normally. it's a simple common task, but it uses graph structures. we're looking for a way to do it with fewer graph structures, but it's relevent to state that graph structures are a core part of software design without them, software looks like someething is specifically avoiding them, and it is clunky and hard even lisp and assembly have graph structures. yes we have important things stopped (huge trigger, learning to hold by demand). we still try to move forward even though important things are stopped so the answer is unknown, but we always continue in some way maybe exploring the space for solutions can help concerns: - when tesselating on etriangle, i want to be able to tesselate neighboring triangles synchronously. basically this means iterating edges and noting that they are subdivided. so, we don't actually need the neighboring triangle ... :} [- the other concern was storing triangle points in a clockwise manner] ok so edges would note when they are subdivided. then the triangles can subdivide afterward. triangles still need a reference to the edge, but they could also reference the points or have a flag indicating the edge is reversed. so an edge is a pair of points but a triangle refers to an edge in a certain way note, if points reference edges, then you could construct triangles with points we might not finish today. i'm picking design choices that make it easier to implement. so one can actually make two edges for each edge; one for each triangle. they would simply have their points reversed. it seems so hard what if we tried the approach that is full of whitespace and has a ton of classes there's still something making it messy, an action of changing the approach we have an action of changing the approach that might be the biggest issue in continuing productively the different approaches have been bumping into things that ended up stopping them the stuff higher in the file might seem nicer constructing the initial 4 triangles manually makes sense then the design choices can be informed by what the algorithm needs afterward why don't we do subdivision with a queue instead of a graph? we already have a queue in the other code. nice idea nobody thought of it. but already started this way. isn't it almost the same? maybe instead of processing the edges all at once, we would just process a corner triangle, and put other triangles on a queue like the other code. ok ummmmmmmm so basically we have some points to engage like consider ll, lr, ul, ur, center we would start with just one triangle like ll, lr, ul ... or ll, lr, center ... noting that center is the subdivision of the diagonal. oh ok. so we could start with ll, lr, ul. and upper right is the pending one. ok we want to do it similar to the existing code so it gets less messy from triggers it can be seen as starting as two triangles, with the 4 triangle approach being the result of subdividing a diagonal. so we would process one triangle, and the other is on a queue. it's just a single unprocessed point. it's adjacent to two of our points. if our triangle is good, we can move on to the next. if our triangle isn't good, we subdivide at least one edge .. maybe all of them ... when we subdivide we shrink the triangle we are looking at to one of the new triangles the other ones go on a queue. different ways to do queue it's nice to have it feel nicer :/ i think it's been very helpful to plan approaches in advance. triangle gets subdivided into four. references other triangles, those get subdivided into 2. point is corner of triangle ... we weren't sure how to represent the triangles: there are a lot of different ways that can work. in the queue approach, there's a single data structure where only one item needs to be accessed at once, right? but now we have information that propagates into the queue: whether or not an edge is subdivided. one idea is having each edge reference an outer edge, that it is subdivided from. then if a triangle references an edge that is an outer to something, it knows to subdivide down. we can use graphs if we want. it helps if there is a description of the structure in advance. since we want a good result, we do want to pick good design choices. that doesn't mean we want a lot of exposure to triggers. we do probably also want faster-to-write things ... we might not be too experienced around using new mind for subdivision-like tasks. it has two axes of concern which combinatorially makes more moving bits when considering. it's a more complex problem, with more parts to its solution. it's likely too complex for _some_ of us, which is confusing because karl has solved much harder problems in past, when more of his memory was stable across ideas, and reconsidering things worked more harmonically nowadays it is harder to move between two ideas in a productive manner, at least while working. taking calm in having recently desoldered shielding from phones successfully. although this task was physical, it takes manual dexterity that i lack, and i took it slowly and carefully and calmly, and feel inspired around improving on it. there's a good chance an older phone would have worked with what i did. ok sometimes we get overwhelmed holding more concepts at once than some parts expect and then we kind of trash the project a little. this is maybe biggest issue. it seems like it can be really helpful to plan in advance. could we start with a small problem? something i'm noticing is that these things simply take longer to type than many things. we did this kind of stuff a lot, and typed very fast and accurately. nowadays it takes time to do these things that karl used to do fast, because it was big complex stuff he was doing. typing now makes constant spasms, it's quite slow to do successfully. so below, the action of subdividing a triangle into 4 is thought of as fast and easy this is likely because karl used to use the coding norm of reusable libraries, and because he typed and thought fast and accurately ok so there's a lie in some of the considering, where boss-bit holds something as just-do-that (like build robot), but it's actually a complex task that uses skills that boss has harmed badly. so it's not easy at all. nothing is just-do-that, these are all skills we would heal. some wondering around what's healing around subdividing a triangle into 4 peacefulness, being aware of what's going on as doing it, finding paths to improve a skill ok so one issue when we do this is we find injured skills that we'd like to improve we have some kind of neural damage or harm patterns, small, in that situation -- and it's quite dangerous because the act of improving a habit is very triggering, can set boss and torture off really big. maybe the harmedness of [the?] habits is labeled as boss defending changing the scope of the task seems helpful maybe we should reevaluate how long things take here this part seems hard partly from triggeringness a lot of us operate blind from opportunistic finding we're not always sure what new things are hardest etc could we do it just in layers with too many polygons so that we have something. there is so much inhibition active. we did this so much yesterday :s yesterday we coded an adaptive subdivision algorithm right up using overprecise in-fpu floating point numbers, 120 bits or whatnot with code added on to specifically make it superprecise if the printer resolution is specified and we have small simple ideas to add on to it to make it have even tighter tolerances and the code was short and simple and organized enough this idea here seems so different it's true we didn't think this would be so hard. maybe we approached it poorly. ---- // next challenge is to update adjacent triangles i suppose // how about when subdivide is called, adjacent triangles are marked as needing a subdivision? // :s hard to think about the problem is simplified because the proposed solution does not use a center point. so there are two kinds of subdivision in the proposed solution: of one side, and of all sides. struct triangle { point points[3]; void subdivide() { point midpoints[3] = {points[0].mean(points[1]), points[1].mean(points[2]), points[2].mean(points[0])}; triangle subdivided[3] = { {points[0], midpoints[0], midpoints[2]}, {points[1], midpoints[1], midpoints[0]}, {points[2], midpoints[2], midpoints[1]} } } }; 2024-07-23 0422 so karl came up with an idea to approach the triangle with fewer problems. but the issue is still present, it energizes it less severely. it's still heartening. the idea is to start with just processing one triangle, and not concern with neighboring triangles or shared points. as well as to only subdivide edges that need subdivision. this way it can process only one triangle at once and just make a bunch of triangles. but it means that it relies on duplicate calculation and duplicate shared points for neighboring triangles, it is kept simple. then, if one wanted, later, could add references to neighboring triangles to the triangles, as well as flags for whether an edge is subdivided. but wouldn't actually need the edge class. could just indicate which part of the neighboring triangle it is, etc. it might add a lot of data to the triangle class but could remove the duplicate calculations and provide for subdividing in a more balanced manner. we're excited it can be made simple and may try it. but hearing other things are helpful, like getting-up 0425 no need for graphs :D no need for graphs :) !!! no need for graphs or subobjects other than just a triangle still feeling super scared 2024-07-26 1456 #if 0 // SANITY CHECK[S] // if you're not sane, precisely what part of you isn't and why? //assert(midpts[idx].pt != (pts[idx].pt+pts[(idx+1)%3].pt)/2 || midpts[idx].pt == line_midpts[idx]); assert(((line_midpts[idx] - pts[idx].pt).normed() - (pts[(idx+1)%3].pt - pts[idx].pt).normed()).magnitude() < 0.00001); // i dunno, do you really care about this, // or are you going to pretend to listen and then go away? #endif 1617 (417pm) ok, put the code in, starting to make a helical surface function. ran into concept that had been pushed aside for earlier task ;[applies elsewhere] we have a list of points for the gear profile, but not the actual profile function. it could make sense to factor that out, except we also want it in pieces to handle all the teeth so what can be factored out of involute_points to reduce code duplication? it's actually pretty simple it could be ok to copy it a little 1853 1921 // it needs to figure out the height and the angle // the angle progresses in a reversed direction each other idx // so the height and angle progress in opposite directions, // every other idx. // when this is the case, (helix_idx % 2) == 1. // otherwise it is 0. // actually it could be nice to have params go from 0 to 1 or such // two faces to each tooth // involute_min[tooth_face] 1950 // we'll need the twist of the helix given the depth and angle. // let's calculate it at the pitch radius. // ok so say we have the pitch circumference // then, we want a given angle at that circumference point // we can assume at very small increments that it's linear // so if we move d units down, we want ot move d units along // the circumference, to make an angle of 45 // basically, we calculate the arclength along the circumference // we would move to get a given angle // so is that sin? cos? // the angle is at the pitch point // one leg is depth // the other is arclength? // a hypotenuse is at the angle // yeah; the arclength is on the other end // ok ummm so the arclength is the adjacent, and the depth // is the opposite. // that can give us the arclength as a function of // depth. we don't know the hypotenuse length, // so tan = opposite/adjacent or somesuch // tan(helix) * adjacent = opposite // arclength = depth / tan(helix) // arclength = depth * cotan(helix) // then we have the arclength. // what is the angle change? // the arclength divided by the radius. // i think! // angle2 = angle1 + radius * depth * cotan(helix_angle) 2040 blergh big thing going on internal-social-space, disconnection from friend after delayed inadvertent harm looks like it is so close to working but the calculation of the twist from the helix angle is wrong let's see what it should be the angle at the pitch point may be given we want the rotation angle at other side imagining angle, say 45. put theta between vertical and angle base is opposite. depth is adjacent. so opposite/adjacent = tan angle the tangent of the angle is the depth times the arclength tan(helix angle) = depth * arclength no opposite/adjacent = tan angle base is opposite. depth is adjacent. arclength/depth = tan helix arclength = depth * tan helix arclength = angle * radius twist = depth * tan helix / radius there we go i was multiplying by radius instead of dividing 2043 it is rendering so slowly on desmos that i think i will make it output stl (although it doesn't have a cap on the top and bottom yet) oh hey the angle is pi/4. that's 90 isn't it? that can't render right. no it's 45. oh ok explains that it doesn't crash. the less-precise one renders on desmos and shows gaps in the triangles sadly. at the edge between the two helices. it's still pretty slow to render. maybe we could inspect the points at the helix line it should be at z=0. is it? no ... it's more at z=1 ... the solid extends from z=-1 to z=3 ... math does indeed do that. param = [-.5,.5] z = (helix_idx + param) * depth=4 / helical_count=2 ok what is correct expression at z=-2 we want param=-0.5 and helix_idx=0 at z=+2 we want param=+0.5 and helix_idx=1 (helix_idx + param) ... we need to subtract depth/2 from somewhere i guess .. or helical_count/2 (helix_idx + param - helical_count) i think param should go from 0 to 1 i kind of fudged it until the output was right since a different error is bigger atm. param goes from 0 to 1, and shifted by -0.5 for angle calculation to not propagate the change. to center it, -depth/2 is subtracted from z. otherwise it went from 0 to 4. there is a strange seam showing now, i think it is at z=0, +y, -x, the x coordinate is kind of small going to output stl i guess ascii stl then i can inspect it too sooo much faster to render as stl the top and bottom are symmetric in theory but are tesselated differently this is very clear on the failing tooth edge, the gap side is much more subdivided seems ot make sense to narrow in on that edge and only render it, like in the other attempt it's tooth 1 face 1 i guess i can step through it the first helix is 1.22, 12.19, -2; -1.223, 12.19, 0; -3.6955, 6.33, -2 -4.879, 5.47, 0; -3.6955, 6.33, -2; -1.223, 12.19, 0 negative z i'm looking at the bisects that are at the plane with the mistake that means only the second triangle, edge 2 triangle 1 edge 2, midpt = -4.34, 8.518, 0; line_midpt = -3.478, 8.047, 0 it isn't subdivided. ok i thought about the issue a bit. the failing edge connects back in the middle. so it may have been not subdivided, and then its subtriangles were. i wonder if this could have been caused by one quad having its triangle sliced in a different direction than the other. changing that might likely fix it, but the problem remains that the subdivision is very poor. it shouldn't happen that a subdividee is subdivided when the parent isn't. that's a bug. and technically it indicates the parent should have been subdivided. i'm not convinced. both curves are coplanar. if one is subdivided the other should be. because it processes all line segments. well it could be that it doesn't quite do that maybe ... we'd have to look at what it is doing different between the two when it runs. it would have to be picking a different midpoint in one than the other maybe due to it being the back of a tooth rather than the front. but it's true that the subdivision is still performed wrongly. workarounds include: - propagating subdivisions to neighboring triangles, sharing edge information between them - ensuring one helix properly mirrors the other via changing details of parameters but we should look into the failing subdivision since it shows an algorithmic problem that wouldn't be resolved by the workarounds. it's the deepest issue. and it makes incorrect geometry. sorry for removing two lines, we are worried they could be grossly misinterpreted [by scrape [some of us think through the scraping :/ we accept them being removed though, maybe were still thinking of [some say is sad but it looks like the sad feeling is made by mc to encourage us to report rather than based on judgement around edge 2 is first retained twice ... the second time reversed compared to the first it is then retained a third time. quite strange ...? after the third engagement, it is then subdivided after being retained, and we get the weird rendering. so the geometry is technically not wrong. the subdivision produces a weird blip but is within the precision. :) so the bug, hole in the model appears associated with this pattern: - the edge is retained on one helix - on the next helix, it is retained _twice_ and the second pass subdivides it. ok this sounds like a complex logic error. a simple question is, why is it doing it twice on one side and not the other. it sounds like it must be staying on the queue to be engaged a second time. it looks reasonably possible that it is because the quad diagonals are not mirrored across the helices. the first helix, the quad is considered sufficient. the second helix, the quad has a different edge that needs subdivision, and is subdivided and pushed back onto the stack ... strangely when it is then encountered again, it has the same edge present ... it also has an additional edge that connects to the line midpoint. so there's a further bug here than just the quad diagonal. (note: the midpoints of both diagonals are the same.) so when the edge is encountered in the first helix, the 3rd point is at -3.6955,6.33,-2.0 when it is encountered in the second helix, the 3rd point is 1.22,12.19,2.0 it's as if it was already subdivided in the first helix somehow no not quite. it has the extreme coordinate of -2, so it hasn't been subdivided along z. but it does have different X and Y coordinates. this could indeed explain subdividing a little different well i think that could indeed happen from different quad diagonals. let's see if the midpoint is still the same. oh maybe it's not shown. one of the midpoints is indeed the same. however the other one, the one that isn't a diagonal, is not the same. oh well it would be the same for the other half of the quad yes ... it looks like what actually happened is the shared midpoint was not as near to the line point on the second helix triangle. it's 1.02 off on X, a hair over a 1.0 cutoff. it sounds like a quick fix is mirroring the quads. is there a way to do this without passing a flag. i guess you'd pass the points in reverse order, i think i can do that .. is a little hard we don't need to iterate the teeth in reverse order, just the order of points looks like that fixed it // - calculate rolling points from involute points still a lot of similar-looking gaps in more detailed renderings putting camera inside gear shows them pretty clearly it's so cool to see the shape rendering but sad that it still has bugs. it's 10:25 pm :s some of these are definitely the same issue. i can see the same gap shape of the middle connecting but further subdivisions not. some of these are vertical between teeth in the same helix. i wonder if adjacent tooth faces could reverse their order too. now i'm seeing pretty much just diagonal forms of the issue i think. as well as horizontals that are not between helices also some small ones between teeth i think notably there were none on a helix centered at z=0. so, when they are middle-band, it would make sense the top and bottom would get subdivided differently because they are at different angles and the precision is done in a raster, box-aligned manner that kind of elucidates more a general bug in the algorithm i think where one quad touching another can subdivide separate from its shared edge, leaving the shared edge with a point in the middle, and then further subdivide the triangles underneath that ... but why does it put them in new places? ... this would imply they need to be subdivided, when the parent triangle did not. it seems to happen to both at once basically we have curves here, so the curve is going through the right box, and its endpoints are on the right boxes, but there must be spots at the 1/4 and 3/4 where it is actually not on the right box. and this is only found by trying two subdivisions :/ this would happen maybe by having it go through the corner of a box just barely and if that is true, it should go away if a euclidean distance is used for the precision :s yeah it goes away if euclidean distance is used for precision. since it doesn't happen around z=0 it may have to do with the alignment of the z faces of the boxes does the goal of umm ensuring the curve goes in the right voxels, have a simple solution? well you could check every voxel. you could bound the curve, and check fewer voxels. with subdividing? making the assumption that the curvature is much larger than the box size i'm imagining an example where a line between points goes through a voxel and a curve barely touches the edge of the voxel, maybe due to a corner but the curve is off the line at other voxels. this would be one way to produce this artefact. i think the plan was to up the precision to handle pathological issues like that. like you could just make it half or something to do with sqrt(3) or whatnot the problem is it happens on one edge and not the other. this would be resolved by sharing edges, or refraining from subdividing. given the solution is approximate, i think you could meet a voxel precision by simply taking the euclidean precision to be half the side edge of a box. yeah that makes sense, spheres instead of boxes, a sphere fits within a box. if it's within half the side edge, then it's in the box. so let's do it that way. can we put caps on it quickly somehow so it might print it would also load faster if it was binary binary easier than caps i guess binary has more fun ... it also speeds up further displaying we could shrink to display. ok caps it is options for caps include: let's make a separate parametric surface for the caps instead of depth we now have radius. other is same. not completing, likely bug in function it's notable one of [the triangles would have two identical points in it] hmm when i use the curve by rolling angle it makes angles throughout. i think the curve by involute angle would work better although i worry it could make gaps at the edges unless i do the other by involute angle too i'm testing it still looks ok after change, then change function to use involute angle and calculate rolling inside i suppose k that certainly wasn't the issue it was the duplicate point. some conditions were missing in the check. works better two issues: 1. the cap is only filled up to an involute that reaches the other end of each tooth. for some reason it fills in a curve 2. the cap is rotate by some amount on one side, missing alignment with the teeth. could 1 relate to the involute angle not being compensated for the change in distance yeah i think that makes sense .. it finds the point on the involute with that angle, but doesn't scale it right ...? it should draw the same curve and scale it down i think hte issue must be that the params are not subdivided when the triangle with identical sides is removed. it would probably be more effective to do something like enumerating the curve and drawing triangles manually, or making a cap function. the issue is the north pole of the function it would be reoslved if we udnerstood why an infinite loop develops the multiple point is 0,0,7.5. it gets real and line midpoints, despite being the same. the line midpoint is nan, probably from the norm at the start after fixing norm for magnitude=0, it renders, but the caps have very dense triangles which appear to swirl .. the swirl would be because the helix angle is using param[1] which is now radius this could fix the offset on one side too runs much faster reverting the involute angle precalculation removal it's not swirling the cap triangles any more but they are stlil dense. i don't know why it is subdividing them when they are planar and radial. :( i'm going to make a binary stl output we might debug it. all we have to do is only show a cap, and then see what is different about the points. when it makes a quad (with two points equal), it makes a "diagonal" that goes from one equal point to the opposite distant point. the point in the middle of this diagonal doesn't tend to match the line because of the angular parameter interpolating to a different point it seems we could put a triangle or something around the middle point :s too bad the tesselater doesn't like radial surfaces. gets confused around center. it's called a degenerate point kind of. has lines to itself of zero length. but the radials that aren't the diagonal, these shouldn't subdivide, right? they must just be matching the diagonal? and when the diagonal subdivides, it would make a new radial what would be the right way, rather than using 2 triangles in a quad, to subdivide a radial surface? well i guess you could use one triangle that has points on the circumferences we have wedges though i see there is a problem that one of the parameters kind of multiplies the other by 0 at the center. and yet, anywhere that points are placed here, is a fine subdivision. there is no need even to have points near the center. we actually only need the points around the circumference. couldn't you use the curve subdivision? wouldn't it be the same? maybe when using the euclidean approximation. it uses a 2d callback for that instead ... it would make sense to just link all the points at the edge [it's pretty fudgey :s] code reduces in quality as deadlines approach it seems also it's saturday tomorrow. maybe we will think on it, how to draw a parametric surface with a center radius point on the surface. you'd draw triangles out from the center to different points on the radius. you wouldn't have "diagonals". instead, each time you calculated a triangle edge, i guess you'd change the parameter that has a degeneracy to match the other edge, at the degenerate point. ok it isn't made to match. the point is degenerate, so the parameter needs to be changed when the edge is calculated, at the degenerate point when params[1] is 0, then params[0] should be copied from the other edge. that did fix that. notable the param issue can be detected via the duplicate point. struct: < is little endian, I is unsigned int, f is float