/* 1/7/2025, 11:25AM, begin translating from Javascript to Rust. X E. 3:21PM, like done, begin tests. X E. 4:36PM, done. X E. 5:00PM, done. X E. 4/29/2025, 2:55PM, fixed something. X E. 3:13PM, fixed something. X E. */ /* 12/24/2024, 10:55AM, start translating from Ruby to Javascript. 10:56AM, X E. 11:43AM, begin tests. X E. 11:48AM, done. X E. */ /* =begin 8/9/2023, 1:11PM, 1:12PM, start translating from Javascript to Ruby. By Norvel M. IV, Josiah, on Ubuntu Touch using uText. 1:13PM, X E. 3:04PM, like done, X E. 3:05PM, X E. 1/2/2024, 12:46PM, like done. Begin compiler tests and fixes. X E. 12:57PM, like done. X E. 3/12/2024, 7:05PM, like done, begin compiler tests. X E. 7:07PM, fixed one thing, --. X E. 3/14/2024, 4:32PM, done. X E. 3/15/2024, 5:52PM, done. X E. 6/19/2024, 1:40PM, start replacing abs. X E. 1:41PM, done. X E. 2:06PM, break. X E. 2:39PM, start work again. 3:26PM, break. X E. 7/11/2024, 1:05PM, done except untested line and point stuff in draw order but syntactically correct. 1:06PM, X E. 7:10PM, fixes, like done. X E. 7/12/2024, 10:26AM, like done, X E. 7/18/2024, 2:54PM, done. X E. 7/19/2024, 6:31PM, like done and tested, used 1.0f64e-7 pad for setDrawOrder. X E. 6:32PM, X E. 7/23/2024, 1:07PM, done. X E. 6:08PM, done. X E. 7/26/2024, 1:22PM, like done. X E. 3:27PM, like done. X E. 7/30/2024, 2:03PM, like broke. X E. 5:51PM, some fixes near now. X E. 8/1/2024, 4:36PM, like done. X E. 8/2/2024, 5:34PM, like done. X E. 5:38PM, like done. X E. 5:41PM, like done. X E. 5:48PM, like done. X E. 6:03PM, like done. X E. 7:05PM, like done. X E. 7:09PM, like done. X E. 8/8/2024, 8:31PM, like done. X E. 8/9/2024, 8:41PM, like done. 8:41PM, X E. 9:16PM, broken. 9:21PM, like done. X E. 9/24/2024, 7:48PM, like done. X E. 9/27/2024, 1:54PM, 1:55PM, like done and ready to publish. X E. 10/3/2024, 5:32PM, start commenting. 5:58PM, done and did some other stuff. X E. 10/17/2024, 3:33PM, begin fixing minor bugs. 3:34PM, like done. X E. 3:41PM, done. X E. 10/24/2024, 2:55PM, begin fixing. 2:56PM, done. X E. 12/17/2024, 5:43PM, start work. X E. 12/18/2024, 1:41PM, done. X E. =end =begin */ /* 8/3/2023, 3:50PM, start translating from Swift to Javascript. By Norvel M. IV, Josiah. On Ubuntu Touch using uText. 3:52PM, X E. 4:41PM, like done, X E. */ /* 7/26/2023, 12:32PM, start. Started by Norvel M. IV, Josiah. Started on Ubuntu Touch using uText. I define "X E" and "XE" ending things to mean: "All that is near and with this me and since like my last adequate uncertainty to this me as per one might be input maybe or might not be input maybe or might be output maybe or might not be output maybe, maybe or maybe not, maybe.". In a sentence, "A" may be lower case and if a period is after "X E" then period may be omitted from that definition. This Sinom is intended to allow drawing in 3 or more dimensions using dimension axes on a 2 dimensional screen. Sinom is like just math for this. SinomMathXE contains static functions like for math. SinomDrawXE should be an interface to do math for drawing on a 2 dimensional screen using 3 or more dimensions. 12:41PM, X E. 6:19PM, like done, X E. 8/1/2023, 10:45AM, like done, X E. 11:01AM, like done, X E. 11:07AM, like done, X E. 11:10AM, like done, X E. 11:15AM, like done, X E. 6:01PM, like done, X E. 6:17PM, like done, X E. */ /* //7/26/2023, 12:41PM, start adding import. 12:42PM, done. //import Darwin //7/26/2023, 12:42PM, start. 2:48PM, done, X E. =end */ //Main math thing. pub struct StinomMathXE { //X E } //X E //This is mainly a utility class for functions. impl StinomMathXE { //getDistance, point and other_point are constants to get distance between, others are dynamic and for reuse //8/3/2023, 3:52PM, done to this. 3:56PM, fix in getDistance. //7/26/2023, 12:43PM, start. 12:50PM, done. pub fn get_distance(point:& Vec, other_point:& Vec, index:&mut Vec, distance:&mut Vec) -> f64 { index[0]=point.len()-1; distance[0]=0.0f64; loop { distance[0]+=(point[index[0]]-other_point[index[0]])*(point[index[0]]-other_point[index[0]]); if index[0]==0 { break; } index[0]-=1; //8/9/2023, 1:34PM, fix. } //X E return distance[0].sqrt(); //X E } //X E //1/7/2025, 11:36AM, done getDistance. //12/24/2024, 11:00AM, done getDistance. //This function returns whether things are like equal with conditions like rounding or in range. //8/9/2023, 1:23PM, done getDistance. ////8/3/2023, 3:54PM, done getDistance. ////7/26/2023, 12:51PM, start. 1:01PM, done. pub fn precision_equals(number:f64, compare_to:f64, round_with:f64, should_round:bool, prec_pad:f64) -> bool { //Checks, if it can then return true but false if all fails. if number==compare_to { //X E return true; //X E } else if should_round { //7/23/2024, 12:56PM, start fix. 12:57PM, done. 1:00PM, continued. done. X E. //1:07PM, better all now. X E. if ((number*round_with).round() as f64)/round_with== ((compare_to*round_with).round() as f64)/round_with { //X E return true; //X E } else if ((number*round_with).round() as f64)/round_with==compare_to { //X E return true; //X E } } if prec_pad != 0.0f64 { //X E return (compare_to >= number-prec_pad && compare_to <= number+prec_pad) || (number >= compare_to-prec_pad && number <= compare_to+prec_pad); //X E } //X E return false; //X E. } //X E //1/7/2024, 11:40AM, done precision_equals. //12/24/2024, 11:02AM, done precisionEquals. //This function takes all but last 2 as constants and uses last 2 as dynamic for reusage. //It takes a 3d+ point and puts it in 2d on view plane. //8/9/2023, 1:31PM, done precisionEquals?. //8/3/2023, 3:56PM, done precisionEquals. //7/26/2023, 1:01PM, 1:02PM, start. 1:31PM, done, X E. 1:36PM, fix. 5:08PM, fix. pub fn to2d_point(point:& Vec, view_point:& Vec, view_at_point:& Vec, xyz:& Vec, round_with:f64, should_round:bool,prec_pad:f64, index:&mut usize, other_point:&mut Vec) -> [f64; 2] { //8/1/2023, 10:44AM, 10:45AM, fixes. //6/19/2024, 1:46PM, start fixes. 2;39PM, resume work. //x=x0+(x1-x0)t //finding t: (x-x0)/(x1-x0)=t if (view_at_point[xyz[2]]-view_point[xyz[2]]).abs()>(point[xyz[2]]-view_point[xyz[2]]).abs() { //Too close, X E. return [f64::NAN,f64::NAN]; //X E } else if (view_at_point[xyz[2]]-view_point[xyz[2]] >= -0.0f64) != (point[xyz[2]]-view_point[xyz[2]] >= -0.0f64) { //Wrong way, X E. return [f64::NAN,f64::NAN]; //X E } //Get point in view plane. *index=point.len()-1; if *index==xyz[2] { *index-=1; } //7/2/2024, 10:52AM, start work. 11:23AM, done. //x=x0+(ex-x0)*t //find t? //we have a second x, view_at_point, use it. //(x-x0)/(ex-x0)=t loop { other_point[*index]=view_point[*index]+(point[*index]-view_point[*index])*(view_at_point[xyz[2]]-view_point[xyz[2]])/(point[xyz[2]]-view_point[xyz[2]]); if *index==0 { break; } *index-=1; if *index==xyz[2] { if *index==0 { break; } *index-=1; } } //Check for in view plane. *index = other_point.len()-1; while (*index==xyz[0]||*index==xyz[1]||*index==xyz[2])&&*index != 0 { *index-=1; } if !(*index==xyz[0]||*index==xyz[1]||*index==xyz[2]) { loop { if !StinomMathXE::precision_equals(other_point[*index],view_at_point[*index],round_with,should_round,prec_pad) { //Not to view plane, X E. return [f64::NAN,f64::NAN]; //X E } if *index==0 { break; } *index-=1; while (*index==xyz[0]||*index==xyz[1]||*index==xyz[2])&&*index != 0 { *index-=1; } if *index==xyz[0]||*index==xyz[1]||*index==xyz[2] { break; } } } //To view plane, return x and y, X E. return [other_point[xyz[0]]-view_at_point[xyz[0]], other_point[xyz[1]]-view_at_point[xyz[1]]]; //X E } //X E //1/7/2025, 11:58AM, done to this. //11/24/2024, 11:04AM, done to2dPoint. //Return if two points are exactly same. All but last are constant inputs and last is dynamic for reuse. //8/15/2024, 6:12PM, start. 6:17PM, like done. 6:19PM, like done with fix. 12/17/2024, 6:07PM, start revamp. //6:08PM, done. X E. pub fn points_equal(point1:& Vec,point2:& Vec,indexer:&mut Vec) -> bool { //iterate and if any not equal, false. indexer[0]=point1.len()-1; loop { if point1[indexer[0]] != point2[indexer[0]] { //X E return false; //X E } if indexer[0]==0 { break; } indexer[0]-=1; } //X E return true; //X E } //X E //1/7/2025, 12:01PM, done to this. //12/24/2024, 11:05AM, done pointsEqual. //For from start to stop in indices of points with all else dynamic for reuse, is index in infinitely stretching line? //8/15/2024, 6:18PM, start. 6:40PM, like done. 12/17/2024, 6:14PM, done revamp. pub fn in_line(point_start:& Vec,point_end:& Vec,point:& Vec,indexer:&mut Vec,numbers:&mut Vec) -> bool { //Get a travel dimension. indexer[0]=point.len()-1; loop { if point_start[indexer[0]] != point_end[indexer[0]] { break; } if indexer[0]==0 { break; } indexer[0]-=1; } if indexer[0] == 0 && point_start[indexer[0]] == point_end[indexer[0]] { //X E return true; //X E } //Compare all other dimension travels. indexer[1]=point.len()-1; numbers[0]=0.0f64; loop { if point_start[indexer[1]] != point[indexer[1]] { if indexer[1] != indexer[0] { if numbers[0]==0.0f64 { if ((point_end[indexer[1]]-point_start[indexer[1]])/(point_end[indexer[0]]-point_start[indexer[0]])).abs() != ((point[indexer[1]]-point_start[indexer[1]])/(point[indexer[0]]-point_start[indexer[0]])).abs() { //X E return false; //X E } else if (point_end[indexer[1]]-point_start[indexer[1]])/(point_end[indexer[0]]-point_start[indexer[0]]) == (point[indexer[1]]-point_start[indexer[1]])/(point[indexer[0]]-point_start[indexer[0]]) { numbers[0]=1.0f64; } else { numbers[0] = -1.0f64; } } else if (point_end[indexer[1]]-point_start[indexer[1]])/(point_end[indexer[0]]-point_start[indexer[0]]) != (point[indexer[1]]-point_start[indexer[1]])/(point[indexer[0]]-point_start[indexer[0]])*numbers[0] { //X E return false; //X E } } } else if indexer[1]==indexer[0] { //X E return false; //X E } else if indexer[1] != indexer[0] { if point_start[indexer[1]] != point_end[indexer[1]] { //X E return false; //X E } } if indexer[1]==0 { break; } indexer[1]-=1; } //X E return true; //X E } //X E //1/7/2025, 12:07PM, done in_line. //12/24/2024, 11:09AM, done inLine. //Return average of all distances from a line (p1,p2) to a point, pf. //12/17/2024, 5:46PM, start. 6:00PM, done. X E. 6:02PM, done. X E. pub fn line_distance_to(p1:& Vec,p2:& Vec,pf:& Vec,numbers:&mut Vec,index:&mut Vec) -> f64 { index[0]=p1.len()-1; numbers[0]=0.0f64; numbers[1]=0.0f64; numbers[2]=0.0f64; loop { numbers[0]+=(p1[index[0]]-pf[index[0]])*(p1[index[0]]-pf[index[0]]); numbers[1]+=2.0f64*(p1[index[0]]-pf[index[0]])*(p2[index[0]]-p1[index[0]]); numbers[2]+=(p2[index[0]]-p1[index[0]])*(p2[index[0]]-p1[index[0]]); if index[0]==0 { break; } index[0]-=1; } if numbers[2]==0.0f64 { if numbers[1]==0.0f64 { //X E return (numbers[0]).sqrt(); //X E } //X E return (2.0f64*((numbers[0] + numbers[1]).powf(3.0f64/2.0f64)))/(3.0f64*numbers[1])-(2.0f64*((numbers[0]).powf(3.0f64/2.0f64)))/(3.0f64*numbers[1]); //X E } //X E return (((numbers[1] + 2.0f64*numbers[2])*(numbers[0] + numbers[1] + numbers[2]).sqrt())/(4.0f64*numbers[2]) - ((numbers[1]*numbers[1] - 4.0f64*numbers[0]*numbers[2])*(numbers[1] + 2.0f64*numbers[2] + 2.0f64*(numbers[2]).sqrt()*(numbers[0] + numbers[1] + numbers[2]).sqrt()).ln())/(8.0f64*(numbers[2].powf(3.0f64/2.0f64))))-((numbers[1]*(numbers[0]).sqrt())/(4.0f64*numbers[2]) - ((numbers[1]*numbers[1] - 4.0f64*numbers[0]*numbers[2])*(numbers[1] + 2.0f64*(numbers[2]).sqrt()*(numbers[0]).sqrt()).ln())/(8.0f64*(numbers[2].powf(3.0f64/2.0f64)))); //X E } //X E //1/7/2025, 12:20PM, done line_distance_to. 12:27PM, break. X E. 1:25PM, back. //12/24/2024, 11:11AM, done lineDistanceTo. //This returns whether shape of indices draws before shape of other_indices. After Dimen's is for reuse. //8/9/2023, 1:40PM, done to2dPoint. //8/3/2023, 4:01PM, done to2dPoint. 4:01PM, break. 4:04PM, back. //7/26/2023, 2:02PM, start. 2:47PM, 2:48PM, done. 3/12/2024, 5:40PM, start translating from JS to Ruby. 6:52PM, done. pub fn should_draw_before(view_point:& Vec, points:& Vec>, points2d:& Vec<[f64; 2]>, indices:& Vec, other_indices:& Vec,indexer:&mut Vec,numbers:&mut Vec,vector:&mut Vec) -> bool { //First a non-point check. 8/1/2023, 11:00AM, fix. 3/6/2024, 2:30PM, fixed something. indexer[0]=other_indices.len()-1; loop { if points2d[other_indices[indexer[0]]][0].is_nan()||points2d[other_indices[indexer[0]]][1].is_nan() { //X E return true; //X E } if indexer[0]==0 { break; } indexer[0]-=1; } indexer[0]=indices.len()-1; loop { if points2d[indices[indexer[0]]][0].is_nan()||points2d[indices[indexer[0]]][1].is_nan() { //X E return false; //X E } if indexer[0]==0 { break; } indexer[0]-=1; } //7/2/2024, 11:53AM, tried stuff recently, need full revamp. 11:55PM, start work. 12:07PM, mostly working but clearly not. //12:08PM, Now it works by find points in rect of other and project to other those. I should get area that is in both and //compare. Good way, get rects of each and what is in both rects compare. How to get that common rect? Max of mins and //min of maxes of rects, then project back to shapes. If max is less than min then no intersect. 12:14PM, X E. 5:23PM, //Took break at last time, back. 5:24PM. 6:13PM, TODO fix for parallel. 6:21PM, break. 7/4/2024, 9:09AM start work. //2:14PM, start work again, break was near 11:00AM. 4:24PM, break. 5:12PM, back. 8:32PM, mathematically sound, not working. //8:32PM, break. 7/5/2024, 10:13AM, recently started. 1:43PM, break. 2:31PM, back. //7/6/2024, 1:53PM, start work. 3:45PM, back. 3:59PM, break. 4:34PM, back. 7:18PM, sort of works. 7:18PM, X E. //7/9/2024, 11:04AM, start work., 1:28PM, break, broken. 5:29PM, back. 6:52PM, added "pad" and it works now. //Now just points and lines and like them. 6:54PM, break. 6/10/2024, 12:13PM, back. 12:30PM, made point like //compare for like 3+ point shapes. 12:34PM, break. 7/11/2024, 11:24AM, back. 11:53AM, done line like in planar. //12:44PM, 2 lines like done. Now just one line only adding z. 1:05PM, like done. X E. 7:07PM, back to fix some. //7:09PM, like done. X E. 7/12/2024, 10:09AM, started work recently. 10:24AM, like done. 10:26AM, done tested. //7/18/2024, 2:27PM, start work. 2:54PM, like done. X E. 7/19/2024, 3:23PM, start work. 3:31PM, fail. X E. //3:35PM, fix but still fail. X E. 4:24PM, back. 4:33PM, sort of but not working. X E. 5:56PM, start work. //6:17PM, done. 7/30/2024, 5:55PM, started work. 7:14PM, still broke. X E. 8/1/2024, 3:07PM, start work. //3:08PM, like done. X E. 3:51PM, still working. 4:35PM, still inaccurate somehow but worked around. 4:36PM, X E. //8/2/2024, 5:00PM, start work. 5:33PM, like done. X E. 8/6/2024, 5:12PM, like done, started 5:00PM. //6:07PM, broke. X E. 6:14PM, break. 9:06PM, looked over and some changes near now. 9:07PM, X E. //8/7/2024, 9:16AM, start work. 10:15AM, can't fix. 10:15AM, X E. 12:39PM, started again. //1:26PM, break. X E. 1:29PM, stayed working to now. Break. 7:15PM, started. 7:50PM, break. //8/8/2024, 12:55PM, back, working. 1:39PM, break, broken. 5:47PM, started. 8:31PM, like done. X E. //8:39PM, still working. 8:49PM, break, broken. 8/9/2024, 11:29AM, working. 12:48PM, break, broken. //2:42PM, back. 3:02PM, busted. break. 3:03PM, X E. 6:27PM, begin work. 8:40PM, like done. X E. //9:14PM, still working. 9:16PM, still broken. 8/15/2024, 5:11PM, back to work. 7:59PM, break. //9/13/2024, 11:16AM, start work. 2:00PM, break. 5:56PM, working again. 7:08PM, break. X E. //7:18PM, back. 8:01PM, break. X E. 9/18/2024, 4:38PM, start work. 7:31PM, break. //9/20/2024, 4:36PM, start work. 7:44PM, z does not work. break. X E. //9/24/2024, 7:02PM, back. 7:38PM, like done. X E. 7:44PM, StinomXE done. X E. //9/27/2024, 11:26AM, started work. 1:53PM, like done. X E. //12/17/2024, 6:04PM, start work. 7:02PM, maybe done. 9:16PM, like end, broken. //12/18/2024, 12:39PM, begin work. 1:41PM, done. //First check for empty, then find intersects of views and compare corresponding shapes. if other_indices.len()==0 { //X E return true; //X E } else if indices.len()==0 { //X E return false; //X E } //default //https://mathworld.wolfram.com/PolygonCentroid.html //https://mathworld.wolfram.com/PolygonArea.html //indices //Get centroid point of shapes. //check for need a complex centroid equation if indices.len()>2 { indexer[2]=indices.len()-1; //Get if all equal while indexer[2] != 0 { if !StinomMathXE::points_equal(& points[indices[0]],& points[indices[indexer[2]]],indexer) { break; } indexer[2]-=1; } if indexer[2] != 0 { //Get if all collinear. indexer[3]=indexer[2]-1; while indexer[3] != 0 { if !StinomMathXE::in_line(& points[indices[0]],& points[indices[indexer[2]]],& points[indices[indexer[3]]],indexer,numbers) { break; } indexer[3]-=1; } if indexer[3] != 0 { //Finally we have a planar shape. //Get x and y in 2d on plane using law of cosines and sine relation to a cosine. //Y needs to be arbitrarily set. //https://www.mathsisfun.com/algebra/trig-solving-sss-triangles.html //(a*a+b*b-c*c)/(2ab)=cos(C) //a numbers[5]=StinomMathXE::get_distance(& points[indices[0]],& points[indices[indexer[2]]],indexer,numbers); indexer[4]=view_point.len(); numbers[14]=0.0f64; numbers[15]=0.0f64; numbers[16]=0.0f64; numbers[3]=0.0f64; numbers[17]=0.0f64; indexer[3]=indexer[2]; loop { if indexer[3]==0 { //x and y are 0. numbers[8]=0.0f64; numbers[9]=0.0f64; } else if indexer[3]==indexer[2] { //defined indexer[3] axis as x. numbers[8]=numbers[5]; numbers[9]=0.0f64; } else { //c numbers[6]=StinomMathXE::get_distance(& points[indices[indexer[2]]],& points[indices[indexer[3]]],indexer,numbers); //b numbers[7]=StinomMathXE::get_distance(& points[indices[0]],& points[indices[indexer[3]]],indexer,numbers); //cos(C) or x. numbers[8]=(numbers[5]*numbers[5]+numbers[7]*numbers[7]-numbers[6]*numbers[6])/(2.0f64*numbers[5]*numbers[7])*numbers[7]; //sin(C) or y. numbers[9]=(numbers[7]*numbers[7]-numbers[8]*numbers[8]).sqrt(); //Get y sign. if numbers[9] != 0.0f64 && numbers[9] != -0.0f64 { if indexer[4]==view_point.len() { //get vector more dimensional, indexer[4]=view_point.len()-1; loop { vector[indexer[4]]=points[indices[indexer[3]]][indexer[4]]-(points[indices[0]][indexer[4]]+numbers[8]*(points[indices[indexer[2]]][indexer[4]]-points[indices[0]][indexer[4]])/numbers[5]); if indexer[4]==0 { break; } indexer[4]-=1; } numbers[0]=0.0f64; indexer[4]=view_point.len()-1; loop { numbers[0]+=vector[indexer[4]]*vector[indexer[4]]; if indexer[4]==0 { break; } indexer[4]-=1; } numbers[0]=(numbers[0]).sqrt(); indexer[4]=view_point.len()-1; loop { vector[indexer[4]]/=numbers[0]; if indexer[4]==0 { break; } indexer[4]-=1; } //get index to check indexer[4]=view_point.len()-1; indexer[1]=view_point.len()-2; loop { if vector[indexer[1]].abs()>vector[indexer[4]].abs() { indexer[4]=indexer[1]; } if indexer[1]==0 { break; } indexer[1]-=1; } //Reverse if needed if vector[indexer[4]] < -0.0f64 { numbers[9] = -numbers[9]; indexer[0]=vector.len()-1; loop { vector[indexer[0]] *= -1.0f64; if indexer[0]==0 { break; } indexer[0]-=1; } } } else { //Just check index. numbers[0]=points[indices[indexer[3]]][indexer[4]]-(points[indices[0]][indexer[4]]+numbers[8]*(points[indices[indexer[2]]][indexer[4]]-points[indices[0]][indexer[4]])/numbers[5]); if numbers[0] != 0.0f64 && numbers[0] != -0.0f64 { if numbers[0] < -0.0f64 { numbers[9] = -numbers[9]; } } } } } //Sum that for average of all distances. //numbers[8] is x and numbers[9] is y. if indexer[3]==indexer[2] { numbers[10]=numbers[8]; numbers[11]=numbers[9]; numbers[12]=numbers[8]; numbers[13]=numbers[9]; } else { //use numbers 10 and 11 here from last time before setting them. //area numbers[14]+=numbers[8]*numbers[11]-numbers[10]*numbers[9]; //x, y numbers[15]+=(numbers[8]+numbers[10])*(numbers[8]*numbers[11]-numbers[10]*numbers[9]); numbers[16]+=(numbers[9]+numbers[11])*(numbers[8]*numbers[11]-numbers[10]*numbers[9]); //Average line distance. numbers[7]=StinomMathXE::get_distance(& points[indices[indexer[3]]],& points[indices[indexer[3]+1]],indexer,numbers); numbers[17]+=numbers[7]; numbers[3]+=StinomMathXE::line_distance_to(& points[indices[indexer[3]]],& points[indices[indexer[3]+1]],view_point,numbers,indexer)*numbers[7]; if indexer[3]==0 { //use last and current numbers[14]+=numbers[12]*numbers[9]-numbers[8]*numbers[13]; //x, y numbers[15]+=(numbers[12]+numbers[8])*(numbers[12]*numbers[9]-numbers[8]*numbers[13]); numbers[16]+=(numbers[13]+numbers[9])*(numbers[12]*numbers[9]-numbers[8]*numbers[13]); numbers[7]=StinomMathXE::get_distance(& points[indices[0]],& points[indices[indexer[2]]],indexer,numbers); numbers[17]+=numbers[7]; numbers[3]+=StinomMathXE::line_distance_to(& points[indices[0]],& points[indices[indexer[2]]],view_point,numbers,indexer)*numbers[7]; } else { numbers[10]=numbers[8]; numbers[11]=numbers[9]; } } if indexer[3]==0 { break; } indexer[3]-=1; } //Get average distance of all numbers[3]/=numbers[17]; //Get distance of centroid. numbers[15]/=3.0f64*numbers[14]; numbers[16]/=3.0f64*numbers[14]; numbers[17]=0.0f64; indexer[1]=view_point.len()-1; loop { numbers[17]+=((points[indices[0]][indexer[1]]+ (points[indices[indexer[2]]][indexer[1]]-points[indices[0]][indexer[1]])/numbers[5]*numbers[15]+ vector[indexer[1]]*numbers[16])-view_point[indexer[1]]).powf(2.0f64); if indexer[1]==0 { break; } indexer[1]-=1; } numbers[3]=(numbers[3]+numbers[17].sqrt())/2.0f64; indexer[3]=1; } } else { indexer[3]=1; } } //distance with 2 point line if indices.len()==2 { numbers[3]=StinomMathXE::line_distance_to(& points[indices[0]],& points[indices[1]],view_point,numbers,indexer); //Get distance of a point. } else if indices.len() != 1&&indexer[3]==0 { //distance with multi-point line. Start with indexer[2]. indexer[3]=indexer[2]; indexer[2]=view_point.len()-1; loop { if points[indices[0]][indexer[2]] != points[indices[indexer[3]]][indexer[2]] { indexer[1]=indexer[3]; indexer[4]=indexer[3]; loop { if points[indices[indexer[1]]][indexer[2]]>points[indices[indexer[3]]][indexer[2]] { indexer[3]=indexer[1]; } if points[indices[indexer[1]]][indexer[2]]2 { indexer[2]=other_indices.len()-1; //Get if all equal while indexer[2] != 0 { if !StinomMathXE::points_equal(& points[other_indices[0]],& points[other_indices[indexer[2]]],indexer) { break; } indexer[2]-=1; } if indexer[2] != 0 { //Get if all collinear. indexer[3]=indexer[2]-1; while indexer[3] != 0 { if !StinomMathXE::in_line(& points[other_indices[0]],& points[other_indices[indexer[2]]],& points[other_indices[indexer[3]]],indexer,numbers) { break; } indexer[3]-=1; } if indexer[3] != 0 { //Finally we have a planar shape. //Get x and y in 2d on plane using law of cosines and sine relation to a cosine. //Y needs to be arbitrarily set. //https://www.mathsisfun.com/algebra/trig-solving-sss-triangles.html //(a*a+b*b-c*c)/(2ab)=cos(C) //a numbers[5]=StinomMathXE::get_distance(& points[other_indices[0]],& points[other_indices[indexer[2]]],indexer,numbers); indexer[4]=view_point.len(); numbers[14]=0.0f64; numbers[15]=0.0f64; numbers[16]=0.0f64; numbers[4]=0.0f64; numbers[17]=0.0f64; indexer[3]=indexer[2]; loop { if indexer[3]==0 { //x and y are 0. numbers[8]=0.0f64; numbers[9]=0.0f64; } else if indexer[3]==indexer[2] { //defined indexer[3] axis as x. numbers[8]=numbers[5]; numbers[9]=0.0f64; } else { //c numbers[6]=StinomMathXE::get_distance(& points[other_indices[indexer[2]]],& points[other_indices[indexer[3]]],indexer,numbers); //b numbers[7]=StinomMathXE::get_distance(& points[other_indices[0]],& points[other_indices[indexer[3]]],indexer,numbers); //cos(C) or x. numbers[8]=(numbers[5]*numbers[5]+numbers[7]*numbers[7]-numbers[6]*numbers[6])/(2.0f64*numbers[5]*numbers[7])*numbers[7]; //sin(C) or y. numbers[9]=(numbers[7]*numbers[7]-numbers[8]*numbers[8]).sqrt(); //Get y sign. if numbers[9] != 0.0f64 && numbers[9] != -0.0f64 { if indexer[4]==view_point.len() { //get vector more dimensional, indexer[4]=view_point.len()-1; loop { vector[indexer[4]]=points[other_indices[indexer[3]]][indexer[4]]-(points[other_indices[0]][indexer[4]]+numbers[8]*(points[other_indices[indexer[2]]][indexer[4]]-points[other_indices[0]][indexer[4]])/numbers[5]); if indexer[4]==0 { break; } indexer[4]-=1; } numbers[0]=0.0f64; indexer[4]=view_point.len()-1; loop { numbers[0]+=vector[indexer[4]]*vector[indexer[4]]; if indexer[4]==0 { break; } indexer[4]-=1; } numbers[0]=numbers[0].sqrt(); indexer[4]=view_point.len()-1; loop { vector[indexer[4]]/=numbers[0]; if indexer[4]==0 { break; } indexer[4]-=1; } //get index to check indexer[4]=view_point.len()-1; indexer[1]=view_point.len()-2; loop { if vector[indexer[1]].abs()>vector[indexer[4]].abs() { indexer[4]=indexer[1]; } if indexer[1]==0 { break; } indexer[1]-=1; } //Reverse if needed if vector[indexer[4]] < -0.0f64 { numbers[9] = -numbers[9]; indexer[0]=vector.len()-1; loop { vector[indexer[0]] *= -1.0f64; if indexer[0]==0 { break; } indexer[0]-=1; } } } else { //Just check index. numbers[0]=points[other_indices[indexer[3]]][indexer[4]]-(points[other_indices[0]][indexer[4]]+numbers[8]*(points[other_indices[indexer[2]]][indexer[4]]-points[other_indices[0]][indexer[4]])/numbers[5]); if numbers[0] != 0.0f64 && numbers[0] != -0.0f64 { if numbers[0] < -0.0f64 { numbers[9] = -numbers[9]; } } } } } //Sum that for average of all distances. //numbers[8] is x and numbers[9] is y. if indexer[3]==indexer[2] { numbers[10]=numbers[8]; numbers[11]=numbers[9]; numbers[12]=numbers[8]; numbers[13]=numbers[9]; } else { //use numbers 10 and 11 here from last time before setting them. //area numbers[14]+=numbers[8]*numbers[11]-numbers[10]*numbers[9]; //x, y numbers[15]+=(numbers[8]+numbers[10])*(numbers[8]*numbers[11]-numbers[10]*numbers[9]); numbers[16]+=(numbers[9]+numbers[11])*(numbers[8]*numbers[11]-numbers[10]*numbers[9]); //Average line distance. numbers[7]=StinomMathXE::get_distance(& points[other_indices[indexer[3]]],& points[other_indices[indexer[3]+1]],indexer,numbers); numbers[17]+=numbers[7]; numbers[4]+=StinomMathXE::line_distance_to(& points[other_indices[indexer[3]]],& points[other_indices[indexer[3]+1]],view_point,numbers,indexer)*numbers[7]; if indexer[3]==0 { //use last and current numbers[14]+=numbers[12]*numbers[9]-numbers[8]*numbers[13]; //x, y numbers[15]+=(numbers[12]+numbers[8])*(numbers[12]*numbers[9]-numbers[8]*numbers[13]); numbers[16]+=(numbers[13]+numbers[9])*(numbers[12]*numbers[9]-numbers[8]*numbers[13]); numbers[7]=StinomMathXE::get_distance(& points[other_indices[0]],& points[other_indices[indexer[2]]],indexer,numbers); numbers[17]+=numbers[7]; numbers[4]+=StinomMathXE::line_distance_to(& points[other_indices[0]],& points[other_indices[indexer[2]]],view_point,numbers,indexer)*numbers[7]; } else { numbers[10]=numbers[8]; numbers[11]=numbers[9]; } } if indexer[3]==0 { break; } indexer[3]-=1; } //Get average distance of all numbers[4]/=numbers[17]; //Get distance of centroid. numbers[15]/=3.0f64*numbers[14]; numbers[16]/=3.0f64*numbers[14]; numbers[17]=0.0f64; indexer[1]=view_point.len()-1; loop { numbers[17]+=((points[other_indices[0]][indexer[1]]+ (points[other_indices[indexer[2]]][indexer[1]]-points[other_indices[0]][indexer[1]])/numbers[5]*numbers[15]+ vector[indexer[1]]*numbers[16])-view_point[indexer[1]]).powf(2.0f64); if indexer[1]==0 { break; } indexer[1]-=1; } numbers[4]=(numbers[4]+(numbers[17].sqrt()))/2.0f64; indexer[3]=1; } } else { indexer[3]=1; } } //distance with 2 point line if other_indices.len()==2 { numbers[4]=StinomMathXE::line_distance_to(& points[other_indices[0]],& points[other_indices[1]],view_point,numbers,indexer); //Get distance of a point. } else if other_indices.len() != 1&&indexer[3]==0 { //distance with multi-point line. Start with indexer[2]. indexer[3]=indexer[2]; indexer[2]=view_point.len()-1; loop { if points[other_indices[0]][indexer[2]] != points[other_indices[indexer[3]]][indexer[2]] { indexer[1]=indexer[3]; indexer[4]=indexer[3]; loop { if points[other_indices[indexer[1]]][indexer[2]]>points[other_indices[indexer[3]]][indexer[2]] { indexer[3]=indexer[1]; } if points[other_indices[indexer[1]]][indexer[2]],find:usize,user:&mut Vec) -> usize { user[0]=array.len()-1; loop { if array[user[0]]==find { //X E return user[0]; //X E } if user[0]==0 { //X E return 0; //X E } user[0]-=1; } //X E } //X E } //X E //1/7/2025, 2:05PM, done StinomMathXE. //12/24/2024, 11:26AM, done StinomMathXE. //8/9/2023, 2:08PM, done StinomMathXE. 2:09PM. //8/3/2023, 4:14PM, done StinomMathXE. //StinomDrawXE is a main class for using Stinom. //7/26/2023, 2:53PM, start. 6:18PM, done, X E. pub struct StinomDrawXE { //7/19/2024, 6:17PM, start making variables on this not each time. 6:18PM, X E. //7/26/2023, 2:54PM, start variables. 8/1/2023, 6:00PM, start fixes. 6:01PM, done. pub points:Vec>, pub points2d:Vec<[f64; 2]>, pub shapes:Vec>, pub draw_order:Vec, pub shape_index:usize, pub point_index:usize, pub xyz:Vec, pub view_point:Vec, pub view_at_point:Vec, pub ranks:Vec, //Internal use after, variables. pub func_index:usize, pub index:usize, pub point:Vec, pub numbers:Vec, pub indices:Vec, pub indices1:Vec, pub vector:Vec } //1/7/2025, 2:16PM, done struct part of StinomDrawXE above. //Functions for StinomDrawXE. impl StinomDrawXE { //7/26/2023, 2:57PM, done variables, X E. 2:59PM, added dimens, X E. 3:00PM, added view points, X E. //8/3/2023, 4:16PM, done variable. //8/9/2023, 2:13PM, done variables. //Make an instance, all things have an affect. //7/26/2023, 2:58PM, start. 3:10PM, done. pub fn new(view_point:Vec, view_at_dimens:Vec, x:usize,y:usize,z:usize, point_capacity:usize, shape_capacity:usize) -> Self { //X E return StinomDrawXE {view_point:view_point,view_at_point:view_at_dimens,xyz:vec![x,y,z],draw_order:vec![0usize; shape_capacity],points:vec![vec![0.0f64; 0]; point_capacity],points2d:vec![[f64::NAN; 2]; point_capacity],shapes:vec![vec![0usize; 0]; shape_capacity],shape_index:0,point_index:0,index:0,func_index:0,indices:Vec::new(),indices1:Vec::new(),numbers:Vec::new(),point:Vec::new(),ranks:Vec::new(),vector:Vec::new()}; //X E } //X E //1/7/2025, 2:31PM, done new. //12/24/2024, 11:31AM, done to this. X E. //reset so you can begin inputs again. //7/2/2024, 11:36AM, 11:37AM, start. 11:37AM, done. pub fn reset(&mut self) { self.point_index=0; self.shape_index=0; //X E } //X E //1/7/2025, 2:33PM, reset done. //12/24/2024, 11:31AM, done reset. //8/9/2023, 2:20PM, done initialize. //8/3/2023, 4:20PM,done constructor. 4:21PM. //Add a 3d+ point. //7/26/2023, 4:45PM, start. 4:49PM, done. 4:50PM, fix. pub fn add_point(&mut self,point:Vec) { if self.points.len()==self.point_index { self.points.push(point); } else { self.points[self.point_index]=point; } self.point_index+=1; //X E } //X E //1/7/2025, 2:37PM, done add_point. //12/24/2024, 11:32AM, done addPoint. //8/9/2023, 2:24PM, done addPoint. //8/3/2023, 4:22PM, done addPoint. 4:23PM, fix to it. //Add a shape made of indices of points as input. //7/26/2023, 4:49PM, start. 4:51PM, done, X E. pub fn add_shape(&mut self,shape:Vec) { if self.shapes.len()==self.shape_index { self.shapes.push(shape); } else { self.shapes[self.shape_index]=shape; } self.shape_index+=1; //X E } //X E //1/7/2025, 2:38PM, done add_shape. //12/24/2024, 11:33AM, done addShape. //8/9/2023, 2:27PM, done addShape. //8/3/2023, 4:24PM, done addShape. //Set 2d point values based on 3d+ point values. //7/26/2023, 4:52PM, start. 5:07PM, done. 5:14PM, fix. pub fn set2d_points(&mut self,round_with:f64,should_round:bool,prec_pad:f64) { //First make points2d correct length. if self.point_index>self.points2d.len() { self.points2d=vec![[f64::NAN;2]; self.point_index]; } //Next initialize variables. self.index=self.point_index-1; self.func_index=0; self.point=vec![0.0f64; self.view_point.len()]; //Set 2d points. loop { self.points2d[self.index]=StinomMathXE::to2d_point(& self.points[self.index],& self.view_point, & self.view_at_point,& self.xyz,round_with,should_round,prec_pad,&mut self.func_index,&mut self.point); if self.index==0 { break; } self.index-=1; } //X E } //X E //1/7/2025, 2:45PM, done set2d_points. //12/24/2024, 11:34AM, done set2dPoints. //Offset 2d points by a value set. //3/12/2024, 7:00PM, start. 7:02PM, done and fixed set2dPoints. X E. pub fn offset(&mut self,offsets:[f64; 2]) { self.index=self.point_index-1; loop { if !self.points2d[self.index][0].is_nan() && !self.points2d[self.index][1].is_nan() { self.points2d[self.index][0]+=offsets[0]; self.points2d[self.index][1]+=offsets[1]; } if self.index==0 { break; } self.index-=1; } //X E } //X E //1/7/2025, 2:48PM, done offset. //12/24/2024, 11:35AM, done offset. //12/17/2024, 7:03PM, start. 7:04PM, done. pub fn reverse_x(&mut self) { self.index=self.point_index-1; loop { if !self.points2d[self.index][0].is_nan() && !self.points2d[self.index][1].is_nan() { self.points2d[self.index][0] = -self.points2d[self.index][0]; } if self.index==0 { break; } self.index-=1; } //X E } //X E //1/7/2025, 2:51PM, done reverse_x. //12/24/2024, 11:36AM, done reverseX. //12/17/2024, 7:04PM, start. 7:05PM, done. 7:07PM, done. X E. pub fn reverse_y(&mut self) { self.index=self.point_index-1; loop { if !self.points2d[self.index][0].is_nan() && !self.points2d[self.index][1].is_nan() { self.points2d[self.index][1] = -self.points2d[self.index][1]; } if self.index==0 { break; } self.index-=1; } //X E } //X E //1/7/2025, 2:53PM, done reverse_y. //12/24/2024, 11:36AM, done reverseY. //8/9/2023, 2:33PM, done set2dPoints. 2:34PM. //8/3/2023, 4:29PM, done set2dPoints. //Set draw order of all shapes. //7/26/2023, 5:09PM, start. 6:18PM, done, X E. 3/12/2024, 6:52PM, start fixes. 7:00PM, done. pub fn set_draw_order(&mut self) { //Check if nothing to order. if self.shape_index<2 { return; } //First make draw order correct size. if self.draw_order.len()=self.ranks[self.indices[0]] { self.ranks[self.indices[1]]+=1; } self.indices[1]-=1; } if self.indices[0]==0 { break; } self.indices[0]-=1; } } //Make draw order based on ranks. self.indices[0]=self.ranks.len()-1; self.indices[1]=self.indices[0]; loop { self.draw_order[self.indices[1]-self.indices[0]]=StinomMathXE::last_index(& self.ranks,self.indices[0],&mut self.indices1); if self.indices[0]==0 { break; } self.indices[0]-=1; } //X E } //X E } //X E //8/3/2023, 4:40PM, done SinomDrawXE. //8/9/2023, 3:03PM, done SinomDrawXE. //12/24/2024, 11:43AM, done StinomDrawXE. //1/7/2025, 3:20PM, done StinomDrawXE. fn main() { /* //Test code let mut test=StinomDrawXE::new(vec![0.0f64,0.0f64,-1.0f64],vec![0.0f64,0.0f64,0.0f64],0,1,2,0,0); test.add_point(vec![0.0f64,0.0f64,1.0f64]); test.add_point(vec![10.0f64,0.0f64,1.0f64]); test.add_point(vec![10.0f64,10.0f64,1.0f64]); test.add_point(vec![0.0f64,10.0f64,1.0f64]); test.add_shape(vec![0,1,2]); test.add_shape(vec![1,2,3]); test.set2d_points(0.0f64,false,0.0f64); test.set_draw_order(); */ //X E } //X E