How to create a 3D faceted model in MATLAB
What would be the best way to create a 3D MATLAB model made of (triangular) facets, similar to this one?
I would also like to be able to define normal and surface vectors for each facet if possible.
Any help is appreciated.
See also questions close to this topic

efficiently split data into bins
I want to split my
data
variable into different variablesa
b
andc
, and applymean
in the 1st dimension. Is there way to substantially (e.g. 1x order of magnitude) improve this code in terms of speed? General feedback welcomedata=rand(20,1000); %generate data bins=[5 10 5]; %given size of bins start_bins=cumsum([1 bins(1:end1)]); end_bins=cumsum([bins]); %split the data into 3 cell arrays and apply mean in 2nd dimension binned_data=cellfun(@(x,y) mean(data(x:y,:),1),num2cell(start_bins),num2cell(end_bins),'uni',0); %data (explicitly) has be stored into different variables [a,b,c]=deal(binned_data{:}); whos a b c Name Size Bytes Class Attributes a 1x1000 8000 double b 1x1000 8000 double c 1x1000 8000 double

How Can I compute True/ Table, Recall &Precision?
I want to create a program that read 3 different video files, extract 2 frames form each video, I have performed threshold, and Histogram Intersection. Now I want to create a Table that contains True/ False values of the extraced framed and compute, Recall, Precision and F1.
How can I calculate True Positive, False Positive & False Negative for each Intersection?
How can I store the result on the table?
To Compute Precision for each intersection we need Presision = True Positive/True Positive+False Positive
Compute Recall for each intersection
Recall= True Positive//True Positive/+False Negative
Compute F1 for each intersection F1= 2*[(P*R)/P+R]
Can someone please give me an indication on how to find true/false value and how to store my result on a table.
Thanks in advance.
function [output]= calculate_TruthTable(filename, fimename01,fimename02) % the First Video filename='C:\Users\User\Videos\videos\TestSet\01_DevilsAdvocate_01.mp4'; % From the first video we extract frame 40 % Convert the frame to greyscale % Perform threshold % Compute histogrma % Normalize histogram vObj= VideoReader(filename); vFrame01 = read(vObj, 40); vFrame01grey = rgb2gray(vFrame01); binaryImage = vFrame01grey < 40; hist01=imhist(binaryImage); hist01=hist01 ./max(abs(hist01)); % From the same video extract frame 135 % Convert the frame to grayscale % Perform threshold % Compute Histogram % Normalize histogram vFrame02 = read(vObj, 135); vFrame02grey = rgb2gray(vFrame02); binaryImage02 = vFrame02grey < 40; hist02=imhist(binaryImage02); hist02=hist02 ./max(abs(hist02)); % Find Histogram Intersection for the forst video histIntersect= sum(max(hist01hist02)); Intersect = find(histIntersect); % % % the Second Video fimename01= 'C:\Users\User\Videos\videos\TestSet\01_PulpFiction_01.mp4'; % From the second videoextract frame 40 % Convert the frame to greyscale % Perform threshold % Compute histogrma % Normalize histogram vObj= VideoReader(filename); vFrame03 = read(vObj, 40); vFrame03grey = rgb2gray(vFrame03); binaryImage03 = vFrame03grey < 40; hist03=imhist(binaryImage03); hist03=hist03 ./max(abs(hist03)); % From the same video extract frame 135 % Convert the frame to grayscale % Perform threshold % Compute Histogram % Normalize histogram vFrame04 = read(vObj, 135); vFrame04grey = rgb2gray(vFrame04); binaryImage04 = vFrame04grey < 40; hist04=imhist(binaryImage04); hist04=hist04 ./max(abs(hist04)); % Compute histogram intersection mysec_histIntersect= sum(max(hist03hist04)); myInter02 = sort(mysec_histIntersect); % % % the Third Video fimename02= 'C:\Users\User\Videos\videos\TestSet\02_HowSheMove_01.mp4'; % From the third video extract frame 40 % Convert the frame to greyscale % Perform threshold % Compute histogrma % Normalize histogram vObj= VideoReader(filename); vFrame05 = read(vObj, 40); vFrame05grey = rgb2gray(vFrame05); binaryImage05 = vFrame05grey < 40; hist05=imhist(binaryImage05); hist05=hist05 ./max(abs(hist05)); % From the same video extract frame 135 % Convert the frame to grayscale % Perform threshold % Compute Histogram % Normalize histogram vFrame06 = read(vObj, 60); vFrame06grey = rgb2gray(vFrame06); binaryImage06 = vFrame06grey < 40; hist06=imhist(binaryImage06); hist06=hist06 ./max(abs(hist06)); % Compute histogram intersection mythird_histIntersect= sum(max(hist05hist06)); MovieName = {'DevilsAdvocate';'PulpFiction';'HowSheMov'}; MovieGenre= {'Thriller';'Thriller';'Dance'}; True= {''; '';'';'';'' }; False= {''; '';'';'';'' }; Recall= {''; '';'';'';'' }; Precision={'';'';'';'';''}; F1={'';'';'';'';''}; TruthTable = table(MovieName,MovieGenre,True,False,Recall,Precision,F1); output= sortrows(TruthTable);

Howto compress timeseries data in Matlab (e.g. deltarle)?
We have terabytes of timeseries data, handled with Matlab, filling our disks.
I know that rlecompression could greatly reduce the storage requirement of timeseries data, if it were deltaencoded (or even deltaofdelta).
(Reason: The differences between consecutive values are mostly small, often just 0, +1, 1, and rlecompression works great if data contains some values much more often than others.)
As the admin I want our Matlabusers to save disk space. Is there an easy way to do this in Matlab? Ideally mostly transparent, so they do not need to manually rewrite all places in their scripts where they access data.
I don't even need the actual compression, because the filesystem already does that, just automatic deltaencoding would be sufficient.

Pixel Programming: Color not setting on pixel in pixelWriter
I just started learning to make graphics pixel by pixel in java. However, I cannot figure out how to write to pixels. It's just showing a gray screen. Could someone please help me out with it?
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools  Templates * and open the template in the editor. */ package pixelprogramming; import java.util.Random; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.image.PixelWriter; import javafx.scene.image.WritableImage; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.stage.Stage; /** * * @author Ish Chhabra */ public class PixelProgramming extends Application { @Override public void start(Stage primaryStage) { StackPane root = new StackPane(); root.getChildren().add(new ImageView(createImage(300, 250))); Scene scene = new Scene(root, 300, 250); primaryStage.setTitle("Hello World!"); primaryStage.setScene(scene); primaryStage.show(); } public Image createImage(int width, int height) { WritableImage img = new WritableImage(width, height); PixelWriter pw = img.getPixelWriter(); Random rnd = new Random(); for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { pw.setColor(x, y, Color.rgb(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256))); } } return img; } /** * @param args the command line arguments */ public static void main(String[] args) { launch(args); } }

Optimizations for Raycasting
I've been wanting to build a 3D engine starting from scratch as a coding challenge with the end objective of implementing it on a fantasy console. The best (i.e. most simple?) way I found was raytracing/raycasting. I haven't found much by looking online for raycasting algorithms, only finding pointinpolygon problems (which only tell me whether a ray intersects a polygon or not, not quite my interest since I wouldn't have info about the first intersection nor I'd have the intersection points).
The only solution I could think of is brute forcing the ray by moving it at small intervals and every time check whether that point is occupied by something or not (which would require having filled shapes and wouldn't let me have 2D shapes since they would never be rendered, although none of those is a problem). Still, it looks way too complex performancewisely.
As far as I know, most of those problems are solved using linear algebra, but I'm not quite as competent as to build up a solution on my own. Does this problem have a practical solution?
EDIT: I just found an algebric solution in 2D which could maybe be expanded in 3D. The idea is:
 For each edge, check whether one of the two vertices are in the field of view (i.e. if O is the origin of every ray and P is the vertex, you have to check first that the point is inside the far point of sight, and then whether the angle with the forward vector is less than the angle of vision). If at least one of the two vertices is inside the field of view, add them to an array E.
 If we have an array R of rays to shoot and an array of arrays I of info about hit points, we can loop for each ray in R and for each edge in E and then store f(ray, edge) in I, where f is a function that gives us info on whether the ray and the edge collided and where they did.
 f uses basic linear algebra: both the ray and the edge are, for all purposes, two segments. Two segments are just parts of two lines. Let's say that if the edge has vertices A and B (AB is the vector that goes from A to B) and if the far point is called P (OP is the vector that goes from O to P). We can create two lines, r and s, defined by A + ηAB and O + λOP. After we do a check to see whether r and s are parallel (check if the absolute value of the dot product of AB and OP is equal to the norm of AB times the norm of OP), it's trivial to get the values for η and λ.
 Now, if η < 0 OR η > 1 we have that the two segments are not colliding.
 After we've done this for every ray and every edge, we compare every element in each array i in I to see which one had the lowest λ. The lowest λ carries the first collision and hence the data to show on screen.
Everything here is linear algebra, though I fear that it might still be computationally heavy, since there's a lot going on, and it's still only 2D.
 For each edge, check whether one of the two vertices are in the field of view (i.e. if O is the origin of every ray and P is the vertex, you have to check first that the point is inside the far point of sight, and then whether the angle with the forward vector is less than the angle of vision). If at least one of the two vertices is inside the field of view, add them to an array E.

Unity: Project/Draw 3d object onto 2d plane
I want to recreate something like the image below. I created a
quad
, placed it in front of the camera, then added aWebCamTexture
to play the camera feed on the 2d plane.I then want to place a 3d object, say a cube, in between the 2d plane and the camera, and project/draw the 3d object onto the 2d plane. How can I accomplish this in Unity? What are the basic steps?
Also, would doing something like this be possible using OpenGL? Would it be complex? What are the basic steps?

How can I manually rotate a 3D sphere based on x and y positions?
This is my first BabylonJS project and I'm stuck on understanding rotations of a sphere. Also, this is my first 3D project ever so I can't say I'm very good at this.
I'm working on a pool/snooker game developed in 2d with PixiJS (so there's a fixed camera) and now I want 3D animated balls just like Miniclip's 8 Ball Pool. Miniclip is using spritesheets to simulate 3D rotation.
I came to the conclusion that integrating BabylonJS will solve this request and it almost did excepting the balls rotations which will have to be solved manually, since the spheres will follow the 2D balls coordinates, X and Y (Z is fixed on zero). Just like here: https://zippy.gfycat.com/ShorttermFortunateFanworms.webm
I found this tutorial and it works excellent in Unity, exactly what I needed, but it doesn't work in my project. http://kwarp.blogspot.com/2015/07/unityrotate3dballusing2dphysics.html
I think the problem is where the quaternion needs to be multiplied with a vector, I'm not sure. Also tried this with no result. http://www.html5gamedevs.com/topic/32934multiplyavector3timesaquaternion/#comment188880
Can someone please help me with this?
I created something similar here, based on the mouse coordinates. The earth should rotate while the mouse is moved. https://www.babylonjsplayground.com/#0HCCW7#29
PS: I did search and investigated a lot of topics and solutions but none worked or maybe it's beyond my capacity of understanding quaternions and math.

Some buildings don't appear in 3d using mapbox gl js, how to fix it?
I'm trying to adopt this Display buildings in 3D example, but I found out that in my city (Minsk, Belarus) some buildings look flat like this:
The coordinates of this particular building are 27.552516, 53.897726 (lon, lat).
I checked out the attributes os this building in OSM and didn't find any special:
There is only a number of floors as data about height, but it's the same for the rest of buildings which appear volumetric.
I haven't changed the code yet so I don't leave it here coz it's in the Mapbox example above. Could someone tells me how to fix that problem?

GKAgent3D Rotation Parts Break Down
The Docs just mention that GKAgent3D rotation is a matrix_float3x3, but I'd like to know what each of the 9 parts are related too. I am trying to limit rotation so that it only yaws/rotates around the yaxis so its facing the direction that its moving.
I as thinking that the 3 arrays were Orientation, EularAngles and Rotation, but I'm not sure which is which and I've tried each value in the yaxis location.
All the other rotations get wonky in the collisions/process of my game and is not needed (at least not now anyway) https://developer.apple.com/documentation/gameplaykit/gkagent3d/1640665rotation
@objc override func agentDidUpdate(_ agent: GKAgent3D) { let ap = agent.position self.position = SCNVector3(ap.x, 0, ap.z) // HERE IS WHERE I WOULD GRAB ONLY Y_AXIS let ar = agent.rotation self.simdEulerAngles = float3(0,ar[0].y,0) //self.rotation = //self.orientation = }

plot, subset, and facet by multiple columns and variables
I have 12 values for Person A, B, and C with SMA2 grouped by Person and Period.
# A tibble: 36 x 5 # Groups: Person, Period [6] Person Time Period Value SMA2 <chr> <dbl> <dbl> <dbl> <dbl> 1 A 1 1 14 NA 2 A 2 1 8 11 3 A 3 1 13 10.5 4 A 4 1 12 12.5 5 A 5 1 19 15.5 6 A 6 1 9 14 7 A 7 2 14 NA 8 A 8 2 7 10.5 9 A 9 2 11 9 10 A 10 2 14 12.5 # ... with 26 more rows
I would like to be able to plot SMA2 based on Person and Period. As well as be able to facet based on Person and Period. This is what I've used.
DataSet %>% subset(Period %in% c("1","2")) %>% subset(Person %in% c("A")) %>% ggplot(aes(Time, SMA2))+ geom_line()+ facet_grid(Person~.)+ facet_grid(Period~.)
This works if I only subset by one Person, but if I subset by multiple people say
subset(Person %in% c("A", "B"))
it plots them on the same graph.Also, when I plot, I'd like to be able to get rid of the blank space created by the opposing Period
Any help is appreciated

Hide root node when faceting in ggraph with circlepack
I have a table of widgets; each widget has a unique ID, a color, and a category. I want to make a
circlepack
graph of this table inggraph
that facets on category, with the hierarchy category > color > widget ID:The problem is the root node. In this MWE, the root node doesn't have a category, so it gets its own facet.
library(igraph) library(ggraph) # Toy dataset. Each widget has a unique ID, a fill color, a category, and a # count. Most widgets are blue. widgets.df = data.frame( id = seq(1:200), fill.hex = sample(c("#0055BF", "#237841", "#81007B"), 200, replace = T, prob = c(0.6, 0.2, 0.2)), category = c(rep("a", 100), rep("b", 100)), num.widgets = ceiling(rexp(200, 0.3)), stringsAsFactors = F ) # Edges of the graph. widget.edges = bind_rows( # One edge from each color/category to each related widget. widgets.df %>% mutate(from = paste(fill.hex, category, sep = ""), to = paste(id, fill.hex, category, sep = "")) %>% select(from, to) %>% distinct(), # One edge from each category to each related color. widgets.df %>% mutate(from = category, to = paste(fill.hex, category, sep = "")) %>% select(from, to) %>% distinct(), # One edge from the root node to each category. widgets.df %>% mutate(from = "root", to = category) ) # Vertices of the graph. widget.vertices = bind_rows( # One vertex for each widget. widgets.df %>% mutate(name = paste(id, fill.hex, category, sep = ""), fill.to.plot = fill.hex, color.to.plot = "#000000") %>% select(name, category, fill.to.plot, color.to.plot, num.widgets) %>% distinct(), # One vertex for each color/category. widgets.df %>% mutate(name = paste(fill.hex, category, sep = ""), fill.to.plot = "#FFFFFF", color.to.plot = "#000000", num.widgets = 1) %>% select(name, category, fill.to.plot, color.to.plot, num.widgets) %>% distinct(), # One vertex for each category. widgets.df %>% mutate(name = category, fill.to.plot = "#FFFFFF", color.to.plot = "#000000", num.widgets = 1) %>% select(name, category, fill.to.plot, color.to.plot, num.widgets) %>% distinct(), # One root vertex. data.frame(name = "root", category = "", fill.to.plot = "#FFFFFF", color.to.plot = "#BBBBBB", num.widgets = 1, stringsAsFactors = F) ) # Make the graph. widget.igraph = graph_from_data_frame(widget.edges, vertices = widget.vertices) widget.ggraph = ggraph(widget.igraph, layout = "circlepack", weight = "num.widgets") + geom_node_circle(aes(fill = fill.to.plot, color = color.to.plot)) + scale_fill_manual(values = sort(unique(widget.vertices$fill.to.plot))) + scale_color_manual(values = sort(unique(widget.vertices$color.to.plot))) + theme_void() + guides(fill = F, color = F, size = F) + theme(aspect.ratio = 1) + facet_nodes(~ category, scales = "free") widget.ggraph
If I omit the root node entirely,
ggraph
issues a warning that the graph has multiple components and plots only the first category.If I assign the root node to the first category, the plot of that first category is shrunk down (because the whole root node is being graphed too, while
scales="free"
displays all the other categories as desired).I also tried adding
filter = !is.na(category)
to theaes
ofgeom_node_circle
anddrop = T
tofacet_nodes
, but this didn't seem to have any effect.As a last resort, I can keep the facet for the root node but make it completely blank (make category name an empty string, change circle color to white). If the root node facet is always last, it will be less obvious that something extraneous is there. But I would love to find a better solution.
I'm open to using something other than
ggraph
, but I have the following technical constraints:I need to fill each widget's circle with the actual color of the widget. I believe this rules out
circlepackeR
.I need two levels in each graph (color and widget ID); I believe this rules out
packcircles
+ggiraph
, as described here.The graphs are part of a Shiny app where I'm using this solution to add tooltips (the ID for each widget; this has to be a tooltip rather than a label because in the real dataset, the circles are small and the IDs are very long). I believe this is incompatible with making separate graphs for each category and plotting them with
grid.arrange
. I've never usedd3
, so I don't know whether this approach could be modified to accommodate faceting and tooltips.
Edit: Another MWE that includes the Shiny part:
library(dplyr) library(shiny) library(igraph) library(ggraph) # Toy dataset. Each widget has a unique ID, a fill color, a category, and a # count. Most widgets are blue. widgets.df = data.frame( id = seq(1:200), fill.hex = sample(c("#0055BF", "#237841", "#81007B"), 200, replace = T, prob = c(0.6, 0.2, 0.2)), category = c(rep("a", 100), rep("b", 100)), num.widgets = ceiling(rexp(200, 0.3)), stringsAsFactors = F ) # Edges of the graph. widget.edges = bind_rows( # One edge from each color/category to each related widget. widgets.df %>% mutate(from = paste(fill.hex, category, sep = ""), to = paste(id, fill.hex, category, sep = "")) %>% select(from, to) %>% distinct(), # One edge from each category to each related color. widgets.df %>% mutate(from = category, to = paste(fill.hex, category, sep = "")) %>% select(from, to) %>% distinct(), # One edge from the root node to each category. widgets.df %>% mutate(from = "root", to = category) ) # Vertices of the graph. widget.vertices = bind_rows( # One vertex for each widget. widgets.df %>% mutate(name = paste(id, fill.hex, category, sep = ""), fill.to.plot = fill.hex, color.to.plot = "#000000") %>% select(name, category, fill.to.plot, color.to.plot, num.widgets) %>% distinct(), # One vertex for each color/category. widgets.df %>% mutate(name = paste(fill.hex, category, sep = ""), fill.to.plot = "#FFFFFF", color.to.plot = "#000000", num.widgets = 1) %>% select(name, category, fill.to.plot, color.to.plot, num.widgets) %>% distinct(), # One vertex for each category. widgets.df %>% mutate(name = category, fill.to.plot = "#FFFFFF", color.to.plot = "#000000", num.widgets = 1) %>% select(name, category, fill.to.plot, color.to.plot, num.widgets) %>% distinct(), # One root vertex. data.frame(name = "root", fill.to.plot = "#FFFFFF", color.to.plot = "#BBBBBB", num.widgets = 1, stringsAsFactors = F) ) # UI logic. ui < fluidPage( # Application title titlePanel("Widget Data"), # Make sure the cursor has the default shape, even when using tooltips tags$head(tags$style(HTML("#widgetPlot { cursor: default; }"))), # Main panel for plot. mainPanel( # Circlepacking plot. div( style = "position:relative", plotOutput( "widgetPlot", width = "700px", height = "400px", hover = hoverOpts("widget_plot_hover", delay = 20, delayType = "debounce") ), uiOutput("widgetHover") ) ) ) # Server logic. server < function(input, output) { # Create the graph. widget.ggraph = reactive({ widget.igraph = graph_from_data_frame(widget.edges, vertices = widget.vertices) widget.ggraph = ggraph(widget.igraph, layout = "circlepack", weight = "num.widgets") + geom_node_circle(aes(fill = fill.to.plot, color = color.to.plot)) + scale_fill_manual(values = sort(unique(widget.vertices$fill.to.plot))) + scale_color_manual(values = sort(unique(widget.vertices$color.to.plot))) + theme_void() + guides(fill = F, color = F, size = F) + theme(aspect.ratio = 1) + facet_nodes(~ category, scales = "free") widget.ggraph }) # Render the graph. output$widgetPlot = renderPlot({ widget.ggraph() }) # Tooltip for the widget graph. # https://gitlab.com/snippets/16220 output$widgetHover = renderUI({ # Get the hover options. hover = input$widget_plot_hover # Find the data point that corresponds to the circle the mouse is hovering # over. if(!is.null(hover)) { point = widget.ggraph()$data %>% filter(leaf) %>% filter(r >= (((x  hover$x) ^ 2) + ((y  hover$y) ^ 2)) ^ .5) } else { return(NULL) } if(nrow(point) != 1) { return(NULL) } # Calculate how far from the left and top the center of the circle is, as a # percent of the total graph size. left_pct = (point$x  hover$domain$left) / (hover$domain$right  hover$domain$left) top_pct < (hover$domain$top  point$y) / (hover$domain$top  hover$domain$bottom) # Convert the percents into pixels. left_px < hover$range$left + left_pct * (hover$range$right  hover$range$left) top_px < hover$range$top + top_pct * (hover$range$bottom  hover$range$top) # Set the style of the tooltip. style = paste0("position:absolute; zindex:100; backgroundcolor: rgba(245, 245, 245, 0.85); ", "left:", left_px, "px; top:", top_px, "px;") # Create the actual tooltip as a wellPanel. wellPanel( style = style, p(HTML(paste("Widget id and color:", point$name))) ) }) } # Run the application shinyApp(ui = ui, server = server)

Facet streaming expression in solr
I am new to solr streaming, and wondering how can i use facet streaming expression to get multiple facet counts.
facet( collection1, q="*:*", buckets="brand,assortment", bucketSorts="count(*) desc", bucketSizeLimit=1000, count(*) )
I have document :
Doc1: brand: AB assortment : TG brand : CD assortment : TG
I expect it to give two buckets one for each field.But the response is like
response: [{ "brand" : "AB" "assortment" : "TG" "count" : 1 }, "brand" : "CD" "assortment" : "TG" "count" : 1 }] I was expecting : response :[{ "brandfacet" : [ { "brand" : "AB" "count" : 1}, { "brand" : "CD" "count" : 1} ] "assortmentfacet" : [ { "assortment" : "TG" "count" : 2} }]

Recovering pose from 3D triangulated points
I have a stereocamera setup where I use the OpenCV method cv::triangulatePoints to detect the checkeboard corners in 3D space. I was wondering what the method is to take these triangulated points and accurately estimate a 3D pose of the checkerboard.
One method I have encountered was found here, feeding the points into a PnP algorithm:
While this is a simple solution to my problem, I am not sure if this is completely correct, as most of my experience with method is for single camera use.
Any insight would be appreciated!

Boost. Triangulation from arbitrary set of points
Is it possible to triangulate an arbitrary set of points(double) using boost?
I know about CGAL, but I can't use it because of the license.
I found this Delaunay from Voronoi with boost: missing triangle with nonintegral point coordinates, it means I can't use boost?

Triangulating a specific class of polygon
I've checked multiple related answers but none seem to capture the problem I face.
 I have to triangulate various polyhedra.
 Each polyhedral face is closed.
 Faces are usually convex but not exclusively.
 Faces can occasionally be selfintersecting but if so they probably have radial symmetry (for example a pentagram)
 Each face is mostly planar (I'm prepared to suffer the consequences if not as it's technically an error)
By observation it seems that adding a new vertex at the centroid and creating a new face by connecting each edge to this vertex always successfully triangulates the face. However  it has a performance cost and simple fan triangulation also succeeds in 95% of cases. However when it fails it fails badly.
Is there an efficient way to detect selfintersecting and/or concave faces so I can fall back to the slower path? Obviously the detection algorithm has to be pretty efficient if the cost of checking isn't to exceed the cost of just assuming the worst and using centroid triangulation in all cases.
I actually suspect my energies are better spent on optimising centroid triangulation rather than working on detecting if it's actually necessary but I was curious what the Stack Overflow community thought.