JSTS (JavaScript Topology Suite) is a powerful JavaScript library for geometric operations. In this tutorial, we’ll explore how to use JSTS’s simplification algorithms with interactive code examples.
Topology-Preserving RDP
The Douglas-Peucker (RDP) algorithm is excellent for simplifying polylines by removing points within a tolerance epsilon. However, standard RDP only guarantees geometric proximity — it doesn’t prevent topological violations like self-intersections, collapsed holes, or accidental crossings between nearby features.
In this post, we’ll explore what topology-preserving simplification means and how to implement it using RhinoCommon.
Visvalingam-Whyatt
Visvalingam-Whyatt is an algorithm similar to Douglas-Peucker algorithm for approximating a list of points (Polyline), but it often produces results that are visually more pleasing because it iteratively removes the “least important” features based on area, rather than distance.
Concept
While RDP removes points based on perpendicular distance to a line segment (ignoring local geometry), Visvalingam-Whyatt (VW) focuses on Effective Area.
The “Effective Area” of a point is defined as the area of the triangle formed by the point and its two immediate neighbors.
- Calculate the triangular area for every internal point.
- Find the point with the minimum effective area.
- Remove that point.
- Update the effective areas of the adjacent points (since their neighbors have changed).
- Repeat until the desired number of points is left or the minimum area exceeds a tolerance.
Why Determinant?
The area of a triangle with vertices $A=(x_1, y_1)$, $B=(x_2, y_2)$, and $C=(x_3, y_3)$ can be calculated using the determinant of a matrix:
Graphically Meaning
Graphically, this is related to the Cross Product of two vectors. If we form vectors $\vec{AB}$ and $\vec{AC}$, their cross product represents the area of the parallelogram formed by them. The triangle area is exactly half of that parallelogram.
In 2D (or projected on XY plane), this magnitude corresponds to the determinant formula above. Points that form a straight line have an area of 0 (collinear). Points that form a sharp spike have a small area (if the base is narrow). This metric ensures we keep points that contribute significantly to the shape’s overall character.
Implementation with Priority Queue
A naive implementation would scan the entire list to find the minimum area point in every iteration, leading to $O(N^2)$ complexity.
To make this efficient, we can use a Priority Queue.
- Initialization: Calculate areas for all points and insert them into a Min-Heap (Priority Queue).
- Loop:
ExtractMin()to get the point with the smallest area ($O(\log N)$).- Mark it as removed.
- Recalculate areas for its left and right neighbors.
- Update their positions in the Priority Queue ($O(\log N)$).
This reduces the complexity to $O(N \log N)$.
Code
Below is a C# implementation using RhinoCommon. Note that since .NET 6, PriorityQueue<TElement, TPriority> is built-in. For older versions (like Rhino 7/Classic), you might need a custom MinHeap class, but logic remains the same. Here I use SortedSet as a makeshift priority queue for simplicity.
1 | using System; |
FPS in ThreeJS
Preface
It’s been a while that I updated my blog, and it’s about time. I spent some time learning Three.js recently. Before this, I only know basic html, css and javascript. Though some people might think that’s totally enough for being a front-end developer in the old days, there’s tons of great tools I needed to catch up with. I think I will catch up through doing some side projects.
To name a few, which at this point, I think I should definitely check them out in near future.
- TypeScript
- React
- Webpack
FrontEnd - Roadmap
By a quick google search,
https://roadmap.sh/frontend
Though I am not sure if I will end up being a front-end developer, I want to put AEC models on web, so it kinda means I have to learn these…
I’ll do my best.
First Person Shooter
https://en.wikipedia.org/wiki/First-person_shooter
Basically, I was following this tutorial.
https://www.youtube.com/watch?v=Q_I0Tq61Ud8&t=744s
So, yeah.
The key ideas is to combine thess two parts.
PointerLockContorlswasd control
https://threejs.org/docs/#examples/en/controls/PointerLockControls
PointerLockContorls
1 | import { |
wasd contorls
1 | //前進か後進か変数宣言 |
OpenCV_Course_Note
Preface
I have absolutely zero idea of the openCV library before watching this tutorial. I hope I can take away some useful knowledge by noting down some code here.
Reference
Reading Image and Video
Read Image
1 | import cv2 as cv |
Read Video
1 | capture = cv.VideoCapture('../Resources/Videos/dog.mp4') |
Resizing and Rescaling
We often resize and rescale the image to relieve the computational strain.
Drawing Shapes and Putting Texts
5 Essential Function in OpenCV
- Converting to grayScale
- Blur
- Edge Cascade
- Dilating the image
- Eroding
- Resize
Converting to grayScale
1 | gray = cv.cvtColor(img, cv.COLOR2GRAY) |
Blur
1 | blur = cv.GussianBlur(img, (7,7), cv.BORDER_DEFAULT) |
Edge Cascade
1 | canny = cv.Canny(img, 125, 175,) |
Dilating the image
1 | dilated = cv.dilated(canny, (3,3), iteration=1) |
Eroding
1 | eroded = cv.erode(dilated, (3,3), iteration=3) |
Resize
1 | resized = cv.resized(img, (500, 500), interpolation=cv.INTER_CUBIC) |
Cropping
1 | cropped = img[50:200, 200:400] |
Image Transformation
- Translation
- Rotation
- Resizing
- Flipping
- Cropping
Contour detection
shift_list_rotate_Array
Preface
In grasshopper, there’s one component called shift_list and basically it did things like Rotate_Array. People can plug in one number and make the list shift/rotate with that number.
Recently, I am trying to catch up some algorithms from Leetcode, and Rotate_Array is one of them.
Example:
Input:
[1,2,3,4,5]
3
Output:
[4,5,1,2,3]
There are obviously some solution for this question. The one I am looking for is the one can acchieve in_place property.
1 | public: |
Reference
https://leetcode.com/problems/rotate-array/
https://www.geeksforgeeks.org/array-rotation/
https://leetcode.com/problems/rotate-array/discuss/1729976/C%2B%2B-or-O(N)-or-GCD-or-GCD)
CustomUI_for_GH_component
Preface
Happy new year, it’s 2022 now. It’s been a while since the last time I updated my blog. Though I didn’t write something in a quite long period of time, I still check some interesting fellows’ work. There’s an open source project from Arup was released on github, so I decided to give it a look.
Reference
https://github.com/arup-group/Custom-Grasshopper-UI-Components
Code
1 | using Grasshopper.Kernel; |
Skills
THIS PAGE IS NOT YET FINISHED
AutoCAD_Dev_with_Csharp
Preface
Apparently, we can develop APIs with LISP and .NET . Though I have been checking some articles mentioning the pros and cons for using one another, it is still unclear to me, which scenario suit for which development method. I think I might realize the answer of this question along my development journey. Few weeks ago, I learned some basic LISP, but the materials that I checked wasn’t completed. LISP is the second oldest programming language that still exist, which make the programmer like me a bit hard to catch up easily. Since I spent more time developing in C#, it won’t hurt if I learn a bit how to develop AutoCAD API in .NET framework.
DLLs
- ACMGD.DLL
- ACDBGD.DLL
- ACCOREMGD.DLL
using lines
1 | using Autodesk.AutoCAD.ApplicationServices; |
Workflow
- Create the
Class Library(.NET framework) - Add those 3 dlls listed above
- Add
the using lines
1 |
|
Reference
Priority Queue & Binary Heap
Introduction
A Priority Queue is an extension of a normal Queue. In a standard Queue (FIFO - First In First Out), the “next” item is always the one that arrived earliest. However, in a Priority Queue, the “next” item is the one with the highest priority.
Think of a hospital emergency room:
- Queue: Patients are treated in the order they walked in.
- Priority Queue: A patient with a heart attack is treated before someone with a sprained ankle, even if the heart attack patient arrived later.
The Binary Heap
While a Priority Queue is an Abstract Data Type (ADT)—meaning it defines behavior—a Binary Heap is the most common Data Structure used to implement it efficiently.
A Binary Heap is a Binary Tree with two specific properties:
- Shape Property: It is a Complete Binary Tree. All levels are fully filled except possibly the last level, which is filled from left to right. This allows us to store it efficiently in an Array.
- Heap Property:
- Min Heap: The value of each node is $\le$ the values of its children. The root is the minimum element.
- Max Heap: The value of each node is $\ge$ the values of its children. The root is the maximum element.
Array Representation
Because of the “Complete Tree” property, we don’t need point-and-node classes. We can map the tree directly to an index-based array which is cache-friendly.
Given a node at index i:
- Parent: $\lfloor \frac{i-1}{2} \rfloor$
- Left Child: $2i + 1$
- Right Child: $2i + 2$
Core Operations
The magic of the Heap lies in how it maintains the Heap Property efficiently during modification. Operations typically take $O(\log N)$ time, which is the height of the tree.
1. Insert (Push) - “Bubble Up”
When we add a new element:
- Place the new element at the end of the array (the first empty spot in the tree).
- Compare it with its Parent.
- If it violates the heap property (e.g., in a MinHeap, it’s smaller than the parent), swap them.
- Repeat step 2-3 until the property is restored or the root is reached.
2. Extract Min/Max (Pop) - “Bubble Down”
When we remove the root (the highest priority item):
- Replace the root with the last element in the array.
- Remove the last element.
- Compare the new root with its Children.
- Swap it with the smaller/larger child (depending on Min/Max heap type).
- Repeat until the property is restored or a leaf is reached.
Complexity Analysis
| Operation | Array (Unsorted) | Array (Sorted) | Binary Heap |
|---|---|---|---|
| Peek (Get Top) | $O(N)$ | $O(1)$ | $O(1)$ |
| Insert | $O(1)$ | $O(N)$ (shift items) | $O(\log N)$ |
| Extract | $O(N)$ (find max) | $O(N)$ (shift items) | $O(\log N)$ |
The Heap provides the best balance. It’s not as fast as a sorted array for peeking, but insertion and deletion are strictly logarithmic, making it scalable for millions of items.
C# Implementation
Here is a clean implementation of a Min-Heap in C#.
1 | using System; |
Modern .NET 6+ Note
If you are using .NET 6 or later (which you likely are for modern development), you no longer need to roll your own class! C# now includes a built-in System.Collections.Generic.PriorityQueue<TElement, TPriority>.
1 | // Example using built-in .NET 6 PriorityQueue |
Applications
- Graph Algorithms:
- Dijkstra’s Algorithm: Finds the shortest path in a weighted graph. It always explores the “closest” node next, which is efficiently retrieved using a Min-Heap.
- Prim’s Algorithm: Used for Minimum Spanning Trees.
- Geometry Processing:
- Visvalingam-Whyatt: As mentioned in my Visvalingam-Whyatt post, we process triangles with the smallest area first.
- Sweepline Algorithms: Processing events (intersections, start/end points) in order of their X-coordinate.
- Systems:
- Task Scheduling: CPU scheduling processes based on priority levels.
Reference
RetrieveGraphInfo_InAutoCAD_autoLISP
entsel
1 | (setq en1 (entsel)) |
If you want to prompt user with a sentence
1 | (setq e (entsel "Please choose an object: ")) |
More about entsel
Return value:
A list whose first element is the entity name of the chosen object and whose second element is the coordinates (in terms of the current UCS) of the point used to pick the object.
The pick point returned by entsel does not represent a point that lies on the selected object.
car
1 | (car en1) |
In the previos example, (car en1) here will return the first element in the list, which is the EntityName
cadr
1 | (cadr en1) |
In the previos example, (car en1) here will return the second element in the list, which is the point location
entget
Retrieves an object’s (entity’s) definition data
1 | (setq en1_data (entget (car en1))) |

If the entity you selected is in the different types, entget may return different geometry infomation.
If the graph info pair separated by
., (1 . “ABC”) for example, we need to usecdrto retrieve the secend element, instead ofcadr
1 | (cons 1 "ABC") |
can create an dot pair, (1 . “ABC”)
How to revise the data?
entgetto get the entity informationassocto find the correct group_code string pair. The new string pair can be created byconssubstto swap/change the new/old string pairsentmodto renew the autocad canvas and show the new string pair!ent_data
(setq oldr (assoc 40 en1_data))
(setq newr (cons 40 23.8))
(setq en1_data (subst newr oldr en1_data))
(entmod en1_data)