0%

Resource

Events

  • A mechanism for communication between objects
  • Used in building Loosely Coupled Applications
  • Helps extending applications

Example

1
2
3
4
5
6
7
8
9
public class VideoEncoder{
public void Encode(Video video){
// Encoding logic
// ...

_mailService.Send(new Mail());

}
}

but, in the future, if we want to send text message to the video owner.

1
2
3
4
5
6
7
8
9
10
public class VideoEncoder{
public void Encode(Video video){
// Encoding logic
// ...

_mailService.Send(new Mail());

_messageService.Send(new Text());
}
}

but if we do it this way, the whole Encode() method will need to be recompiled, and the class depends on this function, will need to be recompiled and redeploied.

We want to design our application such that when you want to change that, it changes the minimum impact on the application

We can use Event to deal with this problem.

How we do event in this case

  • VideoEncoder
    1. publisher
    2. event sender
  • MailService
    1. Subscriber
    2. event receiver

So, in future.

  • MessageService
    1. Subscriber
    2. event receiver

Main changes

1
2
3
4
5
6
7
8
public class VideoEncoder{
public void Encode(Video video){
// Encoding logic
// ...

OnVideoEncoded();
}
}

OnVidoEncoded() method simply notify the subscribers.

VideoEncoder knows absoulately nothing about the MailService and MessageService or any other subscribers.
They(subscribers) can come later, and we can add more subscribers.

One Question Raise: How VideoEncoder(publisher) notify its subscribers

We need an agreement or contract between publisher and its subscribers.

1
2
3
public void OnVideoEncoded(object source, EventArgs e){

}

This is a very typical implementation of method in the subscribers, and it is called EventHandler.
This is also the method which called by the publisher when the event is raised.

Again, VideoEncoder(Event Publisher) do not know the existence of its publishers. Publisher decoupled from them(subscribers).
All the publisher knows, is a method(EventHandler).

How do you tell VideoEncoder(Publisher) what method to call?

That’s where a Delegate comes in.

Delegates

  • Agreement/ Contract between Publisher and Subscriber
  • Determines the signature of the event handler method in Subscriber
  1. Define a delegate
  2. Define an event based on that delegate
  3. Raise the event
1
public delegate void VideoEncodedEventHandler(object source, EventArgs args);
  • object source : source of that event
  • EventArgs args: any additional data we want to send to the event

Here we declare an event, which hold a reference to a function, look like

1
void VideoEncodedEventHandler(object source, EventArgs args);

Implementation

Program.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace EventsAndDelegates
{
class Program
{
static void Main(string[] args)
{
var video = new Video() { Title = "Video 1" };
var videoEncoder = new VideoEncoder(); // publisher
var mailService = new MailService(); // subscriber
var messageSerive = new MessageService(); // subscriber


videoEncoder.VideoEncoded += mailService.OnVideoEncoded; // VideoEncoded event behind the scene, is a list of function pointers. OnVideoEncoded is the function pointer
videoEncoder.VideoEncoded += messageSerive.OnVideoEncoded;


videoEncoder.Encode(video);
}
}
}

Video.cs

1
2
3
4
5
6
7
namespace EventsAndDelegates
{
public class Video
{
public string Title { get; set; }
}
}

VideoEncoder.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System;
using System.Threading;

namespace EventsAndDelegates
{
public class VideoEventArgs : EventArgs
{
public Video Video { get; set; }
}

public class VideoEncoder
{
// 1- Define a delegate
// 2- Define an event based on that delegate
// 3- Raise the event

public delegate void VideoEncodedEventHandler(object source, VideoEventArgs args); // 1. define a delegate
public event VideoEncodedEventHandler VideoEncoded; // 2. define an event based on the delegate

public event EventHandler VideoEncoding;
public void Encode(Video video)
{
Console.WriteLine("Encoding Video...");
Thread.Sleep(3000);

OnVideoEncoded(video); // 3. Raise the event
}
protected virtual void OnVideoEncoded(Video video)
{
if (VideoEncoded != null)
VideoEncoded(this, new VideoEventArgs() { Video = video });
}
}
}

MailService.cs

1
2
3
4
5
6
7
8
9
10
11
12
using System;

namespace EventsAndDelegates
{
public class MailService
{
public void OnVideoEncoded(object source, VideoEventArgs e)
{
Console.WriteLine("MailService: Sending an email..." + e.Video.Title);
}
}
}

MessageService.cs

1
2
3
4
5
6
7
8
9
10
11
12
using System;

namespace EventsAndDelegates
{
public class MessageService
{
public void OnVideoEncoded(object source, VideoEventArgs e)
{
Console.WriteLine("MessageService: Sending a text message..." + e.Video.Title);
}
}
}

Result

idea

clarification_about_IGH

All objects that want to be part of a GH_Document must implement the IGH_DocumentObject interface.

This interface provides core methods needed for all objects

  1. Undo
  2. Autosave
  3. Display
  4. Menu
  5. Tooltip

IGH_ActiveObject extends upon IGH_DocumentObject and it provides methods for participating in the solution.

Parameters

Parameters(via the IGH_Param interface and several GH_Param<T> classes) maintain a data tree which is associated with a special type of IGH_Goo data. They have the logic build in that allows them to communicate with other parameters via their input/output wires.

Components

Components tend to drive from GH_Component(or at the very least implemeny IGH_Component), as that class provides all the bookkeeping methods for managing a collection of input and output parameters.

Attribute

Attributes are used primary for display purposes. Every object must be capable of creating and maintaining a class which ultimately implements IGH_Attributes. The attributes are in charge of

  1. rendering the object to the canvas
  2. providing basic information about the shape of an object
  3. handling mouse and key events
  4. responding correctly to selection actions
  5. maintaining the object hierarchy (Basically, it means that component attributes must be able to talk to input and output parameters, and the parameters need to be able to figure out they are slaved to a component.)

Custom Attribute SDK
Objects on the Grasshopper canvas consist of two part.
The most important piece is the class that implements the IGH_DocumentObject interface.
This interface provides the basic plumbing needed to make objects work within a Grasshopper node network.

The interface part of objects however is handled seperately.

Every IGH_DocumentObject carries around an instance of a class that implements the IGH_Attriibutes interface(indeed, every IGH_DocumentOBject knows how to create its own stand-alone attributes).

It is not possible to have an IGH_Attributes instance work on its own, we need an IGH_DocoumentObject to tie it to.

SQL

Structured Query Langauge

SQL is a programming language used to talk to the databases

Databases that use SQL

  1. SQL server
  2. Oracle
  3. MySQL
  4. Postgre SQL
  5. SQLite
  6. DB2
  7. BigData

Tools to write SQL

  1. SQL Server Management Studio (SSMS)
  2. SQL Developer
  3. SQL Workbench
  4. TOAD

Create Database


What is a Database(DB)?

  • Phone Book
  • Shopping list
  • Todo list
  • Your 5 best friends
  • Facebook’s User Base

Database can be stored in different ways

  • On paper
  • In your mind
  • On a computer
  • This powerpoint
  • Comment Section

Computers + Databases = <3

Amazon.com

  • Keeps track of Products, Reviews, Purchase Orders, Credit Cards…etc
  • Information is extremely valuable and critical to Amazon.com’s functioning
  • Security is essential

Computers are great at keeping track of large amounts of information

Database Managemeny Systems(DBMS)

  • A special software program that hekps users create and maintain a database.
    • Make it easy to manage large amounts of information
    • Handle Security
    • Backups
    • Importing/Exporting data
    • Concurrency
    • Interacts with software applications
      • Programming Languages

Amazon.com will interact with the DBMS in order to create, read, update and delete information.

C.R.U.D

  • Create
  • Read
  • Update
  • Delete

Two Types of Databases

Rational Databases(SQL)

  • Organize data into one or more tables
    • Each table has columns and rows
    • A unique key identifies each row

Non-Retional(noSQL/ not just SQL)

  • Organize data is anything but a tranditional table
    • Key-value stores
    • Documents(JSON, XML, etc)
    • Graphs
    • Flexible Table

Relational Databases(SQL)

Student Table

ID#

Name

Major

1

Jack

Biology

2

Kate

Sociology

3

Claire

English

4

John

Chemistry

User Table

UserName

Password

Email

jsmith22

wordpass

catlover45

apple223

gamerkid

  • Retional Database Management Systems(RDBMS)

    • Help users create and maintain a relational database
      • mySQL, Oracle, postgreSQL, mariaDB, etc.
  • Structed Query Language(SQL)

    • Standardized language for interacting with RDBMS
    • Used to perfrom C.R.U.D operations, as well as other administrative tasks(user management, security, backup, etc)
    • Used to define tables and structures
    • SQL code used on one RDBMS is not always portable to another without modification
  • Non-Relational Databases

    • Non-Relational Database Management Systems(NRDBMS)
      • Help users create and maintain a non-relational database
        • mongoDB, dynamoDB, apache, cassandra, firebase,etc
  • Implementation Specific

    • Any non-relational database falls under this category, so there’s no set language standard
    • Most NRDBMS will implement their own language for performing C.R.U.D and administrative operations on the database

Summary

Warp up

  • Database is any collection of related information
  • Computer are great for storing databases
  • Database Management Systems(DBMS) make it easy to create, maintain and secure a database.
  • DBMS allows you to perform the C.R.U.D operations and other administrative tasks
  • two types of Database, Relational & Non-Relational
  • Relational databases uses SQL and store data in tables with rows and columns
  • Non-Relational data store data using other data structures

student_id

name

major

1

Kate

Sociology

2

Jack

Biology

3

Claire

English

4

Jack

Biology

5

Mike

Comp. Sci

Though there are two Jacks and they both major in Biology, we can use primary key, namely the student id, to identify them.

Structured Query Language(SQL)

  • SQL is a language used for interacting with Relational Database Management Systems(RDBMS)
    • You can use SQL to get the RDBMS to do things for you.
      • Create, retrieve, update & delete data
      • Create & manage databases
      • Design & create databases tables
      • Perform administration tasks(security, user management, import/export, etc)
    • SQL implementations cary between systems
      • Not all RDBMS’ follow the SQL standard to a T
      • The concepts are the same but the implementation may vary

Structured Query Language(SQL) _ Hybrid language

SQL is actually a hybrid language, it’s basically 4 types of languages in one

Data Query Language (DQL)

  • Used to query the database for information
  • Get information that is already stored there

Data Definition Language (DDL)

  • Used for defining database schemas

Data Control Language (DCL)

  • Used for controlling access to the data in the database.
  • User & permissions managemnet

Data Manipulation Language (DML)

  • Used for inserting, updating and deleting data from the databases

Queries

A query is a set of instructions given to the RDBMS(written is SQL) that tell the RDBMS what information you want it to retrieve for you.

  • Tons of data in a DB
  • Often hidden in a complex schema
  • Goal is only get the data you need
1
2
3
SELECT employee.name, employee.age
FROM employee
WHERE employee.salary > 30000;

How Cherno explain about Thread

How we could do multi-thread(parallel computating)

1
2
3
4
5
6
7
8
#include 
#include

static bool s_Finished = false;

void DoWork(){
while(!s_Finished){
std::cout<<"Working...."<

Here we want program to do two things at the same time.

  1. keep printing Working....
  2. receive the cin.get() from user, once get something from the user s_Finished = true

thread::join

The behavior will be like this
idea

However we might not want to let one single thread occupy whole CPU resource, we can use std::this_thread::sleep_for(1s).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include 
#include

static bool s_Finished = false;
void DoWork() {
using namespace std::literals::chrono_literals;
std::cout << "Started thread id=" << std::this_thread::get_id() << std::endl;
while (!s_Finished) {
std::cout << "Working...\n";
std::this_thread::sleep_for(1s); //sleep for a second
}
}

int main(){
std::thread worker(DoWork);
std::cin.get();
s_Finished = true;
worker.join(); //await in C#

std::cout << "Finished\n";
std::cout << "Started thread id=" << std::this_thread::get_id() << std::endl;

std::cin.get();
}

The demo of code above.
idea
Can notice that two std::this_thread::get_id() are different, cuz they are on the different threads.

How we could implement multi-thread in Grasshopper

Grasshopper Tutorial

Like this tutorial shown, we can use

1
2
3
System.Threading.Tasks.Parallel.For(0, loopCount, i =>{ {
//for loop body
}});

instead of using regular for-loop to achieve multi-thread.

unsafe problem and how to tackle it

This is the part I might not fully understand, and you are welcome to correct me. Thanks.
Seems simply use multi_thread with List, like the example in tutorial, is not safe.
Means multi-thread cannot merge to the List in the order correctly. As a result, this cause some data lost.

How we can tackle this problem

  1. We can use lock syntax to ensure the action of List
  2. We use regular array instead of List

Here are the codes.

Lock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void RunScript(List startPts, object y, ref object A)
{
List ptList = new List();
//for(int i = 0;i < startPts.Count; i++)
System.Threading.Tasks.Parallel.For(0, startPts.Count, i => {
{
//Declare out agent location
Point3d agentLoc = startPts[i];
//Add agents to ptLists
lock(ptList){
ptList.Add(agentLoc);
}
}
});
A = ptList;
}

array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void RunScript(List startPts, object y, ref object A)
{
//List ptList = new List();
Point3d[] ptList = new Point3d[startPts.Count];
//for(int i = 0;i < startPts.Count; i++)
System.Threading.Tasks.Parallel.For(0, startPts.Count, i => {
{
//Declare out agent location
Point3d agentLoc = startPts[i];
//Add agents to ptLists
ptList[i] = agentLoc;
}
});
A = ptList;
}

Rhino Official Documents_General Overview

multi-thread

Rhino Official Documents_Developer

Task Capable Component

Overview

Grasshopper for Rhino6 allows you to develop mult-threaded components by way of the new IGH_TaskCapableComponent interface. Benchmarks have shown that Grasshopper can run significantly faster when using multi-threaded components. Results may vary, as not all solutions can be compute in parallel

The Interface

When a component implement the IGH_TaskCapableComponent interface, Grasshopper will notice and potentially call a full enumeration of SolveInstance for the component twice in consecutive passes:

  1. The first pass is for collecting data and starting tasks to compute result
  2. The second pass is for using the results from the tasks to sets outputs.

https://discourse.mcneel.com/t/v6-feature-multi-threaded-gh-components/47049

I found that there are some Rhino official posts talk about mult-threaded in grasshopper.
From User interface, if you see the component has two grey dots on its upper-left corner, means that component support mult-threaded computation(parallel computing).

Still working on…. To be continue

(James_Ramsden_Multithreading)[http://james-ramsden.com/multithreading-a-foreach-loop-in-a-grasshopper-components-in-c/]

Recource Video
Thanks for the youtube channel, The Cherno. This post is basically a note I take to remind me what Function Pointer is about.

Function Pointer is a way to assign pointer to a variable.

Pass a function as a parameter.

The usual way about function

The implementation of a regular function should look like.

1
2
3
4
#include 

void HelloWorld(){
std::cout<< "Hello World!"<

The result should be like
idea

What if we try to use auto key for this function?

idea
then you will see an error at the auto.
That is because what HelloWorld() return is a void.

But what if we do like this. auto function = HelloWorld
idea
then the error disapper.
This is because HelloWorld now return a Function Pointer instead of void.
so if we try to print the variable function in the next line, we will get the pointer of the HelloWorld function.
idea
idea
Due to the implicitly conversion,

1
2
3
auto function = HelloWorld;
//much the same as
auto function = &HelloWorld;

What Function Pointer is about

Functions are of course just CPU instructions, and they are stored in somewhere in our binary/executable file.

Find the Hello World function inside the CPU instruction and give it a pointer, to remember the location of this function code.

idea
idea

so here we can assign a function to a varible.

But what type is this auto actually?

Here the auto hold the type write like

1
void(*function)()

void(*)() is the type eventually, but since we have to get it a name so it became void(*function)().
It works with any other name.(Like I named it jim here)
idea

Becauce this syntax is kinda confusing, programmer tend to either

  • use auto, like what we did above
  • use typedef/using it

idea
Here we make HelloWorld function require one int parameter
idea

Back to programmer want to use function pointer in the first place

Programmers can pass one function to another function as a variable.

idea

Here this code also show how to use lambda function instead of writing out the full function body.

Reference: Cherno’s video

Intersection in 3D

According to this post

Most 3D lines do not intersect. A reliable method is to find the shortest line between two 3D lines. If the shortest line has a lenght of zero(or less than whatever tolerance you specify) then you know that the two original lines intersect.

Therefore, the question become

How can we find the shortest line between two 3D lines.

Check this article by Paul
Two examples I read

In short, this article introduced two thoughts/ implementation to get the minimal distance between two 3D lines.

  1. Write down the lenght of the line segment joining the two lines and then find the minimum
  2. dot product

If the minimal distance == 0, then we can say these two lines intersected

Intersection.LineLine in RhinoCommon

Intersection.LineLine

Example code I made:

1
2
3
4
5
6
7
8
9
10
11
using Rhino.Geometry.Intersect;
//
private void RunScript(Line lineA, Line lineB, double tolerance, bool finiteSegments, ref object A, ref object a, ref object b)
{
double lineA_a;
double lineB_b;
A = Intersection.LineLine(lineA, lineB, out lineA_a, out lineB_b, tolerance, finiteSegments);

a = lineA_a;
b = lineB_b;
}

IntersectinoLineLine_RhinoCommon

Also, there’s a componeny called Line|Line in grasshopper, we can directly use.
Line|Line

Intersection in 2D

How to check if two given line segments intersect? (2D)
GeeksforGeeks
One can determine if two given line segments(2D/laid on the same plane) intersect by the Orientation.

Orinentation of an oedered triplet of points in the plane can be:

  • counterclockwise
  • clockwise
  • colinear

Orinetation constructed by 3 points

check orinetation
In short, three points can form 2 lines. By checking these two lines($m_1$ & $m_2$) slope change, we can determine either

  1. counterclockerwise($m_2>m_1$)
  2. clockwise ($ m_2 > m_1$)
  3. colinear ($ m_1 == m_2$)
1
2
3
4
5
6
7
8
9
10
11
12
private void RunScript(Point3d pointA, Point3d pointB, Point3d pointC, ref object orientation)
{
double m1 = (pointB.Y - pointA.Y) / (pointB.X - pointA.X);
double m2 = (pointC.Y - pointB.Y) / (pointC.X - pointB.X);

Print(m1.ToString());
Print(m2.ToString());
if(m1 == m2) orientation = "colinear";
else if(m1 > m2) orientation = "clockwise";
else orientation = "counterclockwise";

}

Orientation

Let’s assume there are two line segments Line A and Line B.

  • The end points on Line A are Point p1 and Point q1
  • The end points on Line B are Point p2 and Point q2
    as the picture shown below.
    Orientation of 3-ordered points

Example of lines intersect to each other

2D line Intersection

starting from Line A(p1)

$ p1 \rightarrow q1 \rightarrow p2$ is clockwise, while
$ p1 \rightarrow q1 \rightarrow q2$ is counterclockwise.

starting from Line B(p2)

$ p2 \rightarrow q2 \rightarrow p1$ is counterclockwise, while
$ p2 \rightarrow q2 \rightarrow q1$ is clockwise.

If both cases have different orientations, then we can say that they are intersected to each other.

Example of lines are not intersected

2D line Intersection

starting from Line A(p1)

$ p1 \rightarrow q1 \rightarrow p2$ is clockwise, while
$ p1 \rightarrow q1 \rightarrow q2$ is counterclockwise.

starting from Line B(p2)

$ p2 \rightarrow q2 \rightarrow p1$ is counterclockwise, and
$ p2 \rightarrow q2 \rightarrow q1$ is also counterclockwise.

Special Case - colinear

Two lines colinear

Node

Introduction

I have implemented Convex hull algorithm in grasshopper by creating one C# scripting component. Here, I would like to note some codes I have learned.
There are many algorithms for finding convex hull, Javis' March, also known as Gift Wrapping Algorithm, should be the most intuitive one.
Though it is not the fastest one, this algorithm solve the problem with only an simple geometric algebra sense.

Some other algorithms about Convex hull can be found here

Dive into Algorithm

idea

While marching, by the result of the cross Product to determine the next point.

  • Prepare point cloud(many points) on one plane.
  • Decided the starting point
  • Using crossProduct property to march through the points.

Starting point

I set the buttom-most point as the starting point, and if the y is the same then compare x-value.

1
2
3
bool compare(Point3d a, Point3d b){ // to find the starting point
return (a.Y < b.Y) || (a.Y == b.Y && a.X < b.Y);
}

CrossProduct

1
2
3
4
5
6
7
Vector3d crossProduct(Vector3d u, Vector3d v){
double x = u.Y * v.Z - u.Z * v.Y;
double y = u.Z * v.X - u.X * v.Z;
double z = u.X * v.Y - u.Y * v.X;

return new Vector3d(x, y, z);
}

Length2

Though we should calculate distance, which should use square root, we here can do the same thing without using it because we want the relationship, instead of the precise distance.
By doing this way, we get what we want, and because not using square root calculation, it is faster.

1
2
3
double length2(Point3d a, Point3d b){
return (a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y);
}

All code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
private void RunScript(List pts, ref object A)
{
A = Javis_march(pts);
}

//
// find the buttom-most points(left most if the y values are the same)
bool compare(Point3d a, Point3d b){
return (a.Y < b.Y) || (a.Y == b.Y && a.X < b.Y);
}

Vector3d crossProduct(Vector3d u, Vector3d v){
double x = u.Y * v.Z - u.Z * v.Y;
double y = u.Z * v.X - u.X * v.Z;
double z = u.X * v.Y - u.Y * v.X;

return new Vector3d(x, y, z);
}

double length2(Point3d a, Point3d b){
return (a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y);
}

bool far(Point3d o, Point3d a, Point3d b){
return length2(o, a) > length2(o, b);
}

List Javis_march(List pts){

List vertexs = new List();

int start = 0;
for(int i = 0; i < pts.Count;i++){
if(compare(pts[i], pts[start]))
start = i;
}

vertexs.Add(pts[start]);
int current = start;

do{
int next = current;
for(int i = 0; i < pts.Count; i++){
double c = crossProduct(new Vector3d(pts[i] - vertexs[vertexs.Count - 1]), new Vector3d(pts[i] - pts[next])).Z;
if(c > 0 || c == 0 && far(vertexs[vertexs.Count - 1], pts[i], pts[next])){
next = i;
}
}
vertexs.Add(pts[next]);
current = next;
}
while(current != start);
return vertexs;
}

I used do-while first ,cause I want to at least run once, which make sure the list contains at least two points.

Note

Let’s assume if there are n points in the point cloud, and m points on the convex hull.
Then the total time complexity will be O(NM).

There are some faster algorithms doing sorting before running cross Product calculation, Andrew's Monotone Chain, for example. I might try to implement this algorithm the other day.

References

Node

Content

I just learned this algorithm to simplified polyline, with Professor. Jose’s amazing tutorial. People who want to learn a bit more, should definitely follow this channel.

The idea is relatively simple, but the implementation could be thousands and millions way.
The goal of this algorithm is to reduce the points in one polyline(points + line), but still want to remain to soul(properity, or shape to be more specifically). There are tons of benefits by doing this, obvious one is that this can clearly releave your memory while speed up the computation time.

Implement

The method here is to recursively find the farthest point to the two segment endpoints. That’s it.

Dive into the Csharp code

Something should be took care

  • epilson
  • left points
  • right points
  • two lists combinition
  • recursive function
  • Point-Line distance

Because this blog is for recording something I have learned, it is definitely not detail-clear to everyone. Please refer to the Professor Jose’s tutorial video, if you want to have a clear idea of this.

code

crossProduct

Though in RhinoCommon, there are one predefined crossProduct method that we could use directly, it is convenient that we made by ourselves in the cases of bring this method to another Csharp-based platform.

1
2
3
4
5
6
7
Vector3d crossProduct(Vector3d u, Vector3d v){
double x = u.Y * v.Z - u.Z * v.Y;
double y = u.Z * v.X - u.X * v.Z;
double z = u.X * v.Y - u.Y * v.X;

return new Vector3d(x, y, z);
}

Point-Line distance

1
2
3
4
5
6
7
8
9
10
11
double distToLine(Point3d P, Point3d A, Point3d B){
Vector3d AB = B - A;
Vector3d AP = P - A;

Vector3d cross = crossProduct(AB, AP);
double lengthCross = cross.Length;
double lengthAB = AB.Length;

double h = lengthCross / lengthAB;
return h;
}

simplifyPolyline

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
List simplifyPolyline(List points, double epsilon){

double maxDist = -1.0;
int maxIndex = -1;

for( int i = 1; i < points.Count - 1 ;i++){
double d = distToLine(points[i], points[0], points[points.Count - 1]);
if( d > maxDist){
maxDist = d;
maxIndex = i;
}
}

Print("max index: " + maxIndex + "\t maxdist:" + maxDist);

List cleanPoints;

if(maxDist > epsilon){
// Subdivide poly in two parts
Print("should do subdivision here");
List leftPoly = points.GetRange(0, maxIndex +1);
List rightPoly = points.GetRange(maxIndex, points.Count - maxIndex);

// Apply recursion to each one
List leftSimplified = simplifyPolyline(leftPoly, epsilon);
List rightSimplified = simplifyPolyline(rightPoly, epsilon);

// Avoid duplicating split points
rightSimplified.RemoveAt(0);
//rightSimplified = rightSimplified.GetRange(1,rightSimplified.Count-1);

cleanPoints = leftSimplified;
cleanPoints.AddRange(rightSimplified);

}
else{

// remove all points between endpoints and return
cleanPoints = new List(){points[0], points[points.Count - 1]};
}

return cleanPoints;
}

Note from reading Wiki

Application

The algorithm is used for the processing of vector graphics and cateographic generalization.

It does not always preserve the property of non-self intersection for curves which has led to the development of variant algorithms.

Like Jose mentioned in his video, this method is widely used in robotics to perform simplification and denoiseing of range data acuquired by a rotating range scanner.

Complexity

Reference

前言

因為在grasshopper中slider的上下界是在創建的時後就被確定的,像是直接在canvas中輸入0..10.0..20.0這樣就能產生slider滿足

  • 上界是20.0,下界是0.0
  • 精準度是小數點下一位
  • slider產生時的起始值就是10.0

不過這樣做不能runtime的時候更改slider的上下界,雖然必要性沒有很大,而且想要在runtime有新的值不一定要改到slider本身,但因為相對起來slider還是滿直觀的,所以找了一下在runtime更改slider的文章。
主要內容參考來自James-Ramsden這篇

內文

有時候會想要很明確掌握slider的範圍。像下面我自己嘗試的一小例子。

Node

Node

這個範例的邏輯很簡單,就是有個大的矩形然後我用大矩形的四個頂點做出四個空間,但因為我想要讓大矩形長寬是可以調整的,如果調整的話其他四個房間的slider如果能在runtie的時候就決定上界到多少就不會有超過跟重疊的狀況了。
所以用一下以下的C# code可以幫助決定上下界。

1
2
3
4
5
6
7
8
9
10
private void RunScript(object x, double y, ref object A)
{
var input = Component.Params.Input[0].Sources[0]; //get the first thing connected to the first input of this component
var slider = (Grasshopper.Kernel.Special.GH_NumberSlider) input; //try to cast that thing as a slider

if(slider != null) //if the component was successfully cast as a slider
{
slider.Slider.Value = (decimal) y;
}
}

這是讓y的值去寫進x裡面
Node
但你也可以用slider.Slider.Minimumslider.Slider.Maximum去決定他的上下界。
比如我x的上界會等於y值的一半。就可以這樣寫

1
2
3
4
5
6
7
8
9
10
11
12
13
private void RunScript(object x, double y, ref object A)
{
var input = Component.Params.Input[0].Sources[0]; //get the first thing connected to the first input of this component
var slider = (Grasshopper.Kernel.Special.GH_NumberSlider) input; //try to cast that thing as a slider

if(slider != null) //if the component was successfully cast as a slider
{
if(slider.Slider.Value > (decimal) y / 2){
slider.Slider.Value = (decimal) y / 2;
}
slider.Slider.Maximum = (decimal) y/2;
}
}

我有寫一個防護的判斷如果原本x的值就超過y/2的話我就讓值變成x = y/2 就不會有奇怪的UI出現了XD
Node

那前面房間長寬slider上下界可以這樣修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private void RunScript(object x, object y, double z, ref object A)
{
var input1 = Component.Params.Input[0].Sources[0];
var slider1 = (Grasshopper.Kernel.Special.GH_NumberSlider) input1;

var input2 = Component.Params.Input[1].Sources[0];
var slider2 = (Grasshopper.Kernel.Special.GH_NumberSlider) input2;

decimal val = slider2.Slider.Value;
if(slider1 != null && slider2 != null){

if(slider2.Slider.Value > (decimal) z - slider1.Slider.Value){
slider2.Slider.Value = (decimal) z - slider1.Slider.Value;
}
slider2.Slider.Minimum = 0;
slider2.Slider.Maximum = (decimal) z - slider1.Slider.Value;

if(slider1.Slider.Value > (decimal) z - slider2.Slider.Value){
slider1.Slider.Value = (decimal) z - slider2.Slider.Value;
}

slider1.Slider.Minimum = 0;
slider1.Slider.Maximum = (decimal) z - slider2.Slider.Value;

}
//A = val;
}

可以觀察一下Dining RoomLiving Room 的水平方向 slider 調整一個另一個的上下界也會改,主要的邏輯是 大矩形的寬 = DiningRoom_width + LivingRoom_Width
這是邊界條件啦
Node

碰到了XD 但沒有超過~

最後阿,有個可以換slider顏色的方法滿酷的,雖然不知道有甚麼用
Node

1
2
3
4
5
6
7
8
9
10
11
12
13
private void RunScript(object x, double y, System.Drawing.Color z, ref object A)
{
var input = Component.Params.Input[0].Sources[0]; //get the first thing connected to the first input of this component
var slider = (Grasshopper.Kernel.Special.GH_NumberSlider) input; //try to cast that thing as a slider

if(slider != null) //if the component was successfully cast as a slider
{
slider.Slider.DrawControlBackground = true;
slider.Slider.DrawControlBorder = true;
slider.Slider.ControlEdgeColour = Color.Blue;
slider.Slider.ControlBackColour = z;
}
}

要記得先using System.Drawing; 這行喔

參考

James-Ramsden這篇
James感覺也是grasshopper/Revit相關的部落客/工程師,有很多很好的資源,推薦。